行為序列建模:基于Transformer行為表征的BST推薦算法實(shí)踐

關(guān)鍵詞TransformerBST翰铡,推薦算法

內(nèi)容摘要

  • 推薦算法中行為序列建模概述
  • BST網(wǎng)絡(luò)結(jié)構(gòu)解析
  • BST代碼實(shí)戰(zhàn),對(duì)比WDL,DIN的增益

推薦算法中行為序列建模概述

Embedding+MLP是推薦算法中使用深度學(xué)習(xí)的一般泛式承冰,即將用戶,商品食零,上下文等其他特征映射到低維稠密向量困乒,再拼接送入全連接層完成二分類(lèi)任務(wù),這種模型架構(gòu)忽略了用戶的行為序列贰谣,包括用戶在一段連續(xù)時(shí)間內(nèi)對(duì)商品的點(diǎn)擊收藏購(gòu)買(mǎi)等行為娜搂,而行為序列表達(dá)了用戶強(qiáng)烈的興趣信息可以輔助對(duì)用戶的下一個(gè)商品進(jìn)行預(yù)測(cè),以往有基于求和/均值池化的方法將用戶交互的商品id序列直接求和/平均吱抚,以及基于DIN Attention通過(guò)計(jì)算和候選商品的相似度對(duì)交互的商品id加權(quán)求和的方式百宇,這些方法丟棄了行為序列的順序信息,而隨著Transformer在自然語(yǔ)言處理上的成功和對(duì)上下文的強(qiáng)大表征能力秘豹,阿里巴巴團(tuán)隊(duì)將Transformer應(yīng)用在用戶行為序列的表征上携御,充分學(xué)習(xí)商品和商品之間的依賴(lài)關(guān)系,從而引出本文介紹的BST算法既绕。

DIN中候選商品和用戶行為序列商品的權(quán)重關(guān)系

BST網(wǎng)絡(luò)結(jié)構(gòu)解析

BST(Behavior Sequence Transformer)是阿里巴巴團(tuán)隊(duì)在2019年提出的推薦排序算法啄刹,網(wǎng)絡(luò)結(jié)構(gòu)如下


BST網(wǎng)絡(luò)結(jié)構(gòu)

自下而上解析網(wǎng)絡(luò),底層有三塊輸入分別時(shí):

  • Other Feature:包括user特征凄贩,item特征鸵膏,上下文特征,cross特征怎炊,其中cross特征為人工設(shè)計(jì)的交叉統(tǒng)計(jì)特征谭企,比如年齡和目標(biāo)商品的交互特征廓译,性別對(duì)目標(biāo)商品的交互特征等
  • User Behavior Sequence:用戶行為序列特征,輸入1~N長(zhǎng)度的歷史交互商品id和位置信息债查,其中位置信息采用歷史商品交互時(shí)間和當(dāng)前推薦時(shí)點(diǎn)的時(shí)間差在分箱的embedding進(jìn)行表征
  • Target Item:目標(biāo)候選商品特征非区,也包括商品embedding和位置編碼embedding

每塊的特征進(jìn)行拼接輸入上層網(wǎng)絡(luò),其中歷史行為序列和候選商品一齊進(jìn)入Transformer層盹廷,通過(guò)Transformer層得到每個(gè)商品的表征征绸,BST將待預(yù)測(cè)的 item 也加入Transformer來(lái)達(dá)到抽取行為序列中的商品與待推薦商品之間的相關(guān)性的目的。最終所有特征進(jìn)行拼接進(jìn)入一個(gè)三層的全連接俄占,通過(guò)sigmod進(jìn)行輸出預(yù)測(cè)結(jié)果管怠。 右上角是標(biāo)準(zhǔn)的Transformer的Encoder層,包括多頭self attention缸榄,殘差連接渤弛,layer norm等操作,在BST中同樣可以堆疊多層Encoder層甚带。
BST的網(wǎng)絡(luò)結(jié)構(gòu)比較清楚明了她肯,除此之外作者對(duì)一些細(xì)節(jié)進(jìn)行了補(bǔ)充描述

  • 1.Transformer的目的是用來(lái)學(xué)習(xí)商品之間的依賴(lài)關(guān)系
  • 2.序列中的商品特征僅使用商品id和商品類(lèi)別id已經(jīng)足夠好,增加其他維度表征序列成本太高
  • 3.為什么使用時(shí)間相減表征位置編碼鹰贵,而不是使用Transformer的sin-cos晴氨,作者說(shuō)是在他們的數(shù)據(jù)上時(shí)間相減的效果好于sin-cos編碼
  • 4.僅使用一層Transformer Encoder就夠了,推疊越多效果越差碉输,原因可能是在推薦場(chǎng)景下學(xué)習(xí)序列遠(yuǎn)遠(yuǎn)沒(méi)有機(jī)器翻譯中學(xué)習(xí)上下文那么復(fù)雜

BST代碼實(shí)戰(zhàn)籽前,對(duì)比WDL,DIN的增益

本例使用自有的業(yè)務(wù)數(shù)據(jù)進(jìn)行復(fù)現(xiàn)測(cè)試敷钾,特征如下

特征歸屬 特征 類(lèi)型
user 性別 離散
user 年齡 分箱離散
user 注冊(cè)年限 分箱離散
user 渠道來(lái)源 離散
user 會(huì)員等級(jí) 離散
... ... ...
item 商品id 離散
item 大類(lèi)id 離散
item 中類(lèi)id 離散
item 小類(lèi)id 離散
item 產(chǎn)地id 離散
item 品牌id 離散
... ... ...
行為序列 商品id,行為日期 序列

使用均值池化序列的WDL模型

先建立WDL(wide deep learn)和DIN兩個(gè)模型進(jìn)行對(duì)比聚假,其中WDL加入了序列的平均池化,WDL核心代碼部分如下

history_seq_emb = tf.concat(
            [self.history_seq_item_id_emb, self.history_seq_pty1_id_emb, self.history_seq_pty2_id_emb,
             self.history_seq_pty3_id_emb, self.history_seq_brand_id_emb, self.history_seq_origin_id_emb], axis=2)
        # 去除mask的均值  [None, seq_len] => [None, seq_len]
        mask_weight = tf.expand_dims(self.mask / tf.reduce_sum(self.mask, axis=1, keepdims=True), axis=-1)
        history_seq_emb = tf.reduce_sum(history_seq_emb * mask_weight, axis=1)
        # [None, emb_size * 6]
        target_item_emb = tf.concat(
            [self.target_item_id_emb, self.target_item_pty1_id_emb, self.target_item_pty2_id_emb,
             self.target_item_pty3_id_emb, self.target_item_brand_id_emb, self.target_item_origin_id_emb], axis=1)
        # concat => user_emb_size + emb_size * 6 + emb_size * 6
        input = tf.concat([self.user_feature_emb, history_seq_emb, target_item_emb], axis=1)

其中行為序列每個(gè)元素由6個(gè)embedding拼接而成闰非,采用帶有mask的求和平均膘格,最終將用戶特征,序列特征财松,目標(biāo)商品特征輸入給全連接瘪贱,最終驗(yàn)證集AUC維持在0.796±0.002

使用Attention加權(quán)序列的DIN模型

DIN采用DIN Attention采用序列的加權(quán)求和,辆毡,DIN的核心代碼如下

def din_attention(query, facts, mask=None, stag='null', mode='SUM', softmax_stag=1, time_major=False,
                  return_alphas=False):
    queries = tf.tile(query, [1, tf.shape(facts)[1]])
    queries = tf.reshape(queries, tf.shape(facts))  # [None, seq_len, emb_size * 6]
    din_all = tf.concat([queries, facts, queries - facts, queries * facts], axis=-1)
    d_layer_1_all = tf.layers.dense(din_all, 80, activation=tf.nn.sigmoid, name='f1_att' + stag)
    d_layer_2_all = tf.layers.dense(d_layer_1_all, 40, activation=tf.nn.sigmoid, name='f2_att' + stag)
    d_layer_3_all = tf.layers.dense(d_layer_2_all, 1, activation=None, name='f3_att' + stag)
    d_layer_3_all = tf.reshape(d_layer_3_all, [-1, 1, tf.shape(facts)[1]])
    scores = d_layer_3_all

    if mask is not None:
        mask = tf.equal(mask, tf.ones_like(mask))
        key_masks = tf.expand_dims(mask, 1)  # [B, 1, T]
        paddings = tf.ones_like(scores) * (-2 ** 32 + 1)
        scores = tf.where(key_masks, scores, paddings)  # [B, 1, T]

    if softmax_stag:
        scores = tf.nn.softmax(scores)  # [B, 1, T]

    if mode == 'SUM':
        output = tf.matmul(scores, facts)  # [B, 1, H]
    else:
        scores = tf.reshape(scores, [-1, tf.shape(facts)[1]])
        output = facts * tf.expand_dims(scores, -1)
        output = tf.reshape(output, tf.shape(facts))

    return output
        with tf.name_scope('Attention_layer'):
            attention_output = din_attention(target_item_emb, history_seq_emb, self.mask)
            att_fea = tf.reduce_sum(attention_output, 1)
        input = tf.concat([self.user_feature_emb, att_fea, target_item_emb], axis=1)

輸出和WDL類(lèi)似菜秦,只是行為序列變?yōu)榱俗⒁饬訖?quán)的結(jié)果,DIN的最終驗(yàn)證集AUC穩(wěn)定在0.801±0.001

BST模型

下面進(jìn)入進(jìn)入BST的復(fù)現(xiàn)舶掖,核心Encoder部分代碼如下

    def multi_head_attention(self, input):
        output_list = []
        k_dim = self.token_emb_size * 7 // self.n_head  # 28
        for n in range(self.n_head):
            k_out = tf.layers.dense(input, k_dim, activation=None)  # [None, seq_len, 28]
            q_out = tf.layers.dense(input, k_dim, activation=None)  # [None, seq_len, 28]
            v_out = tf.layers.dense(input, k_dim, activation=None)  # [None, seq_len, 28]
            # dot [None, seq_len, seq_len]
            dot = tf.matmul(k_out, tf.transpose(q_out, [0, 2, 1])) / tf.sqrt(
                tf.cast(tf.shape(k_out)[-1], dtype='float32'))
            self.dot = dot
            # mask [None, 1, seq]
            mmask = tf.expand_dims((-1e+9) * (1 - self.mask), axis=1)
            dot = dot + mmask
            attn = tf.nn.dropout(tf.nn.softmax(dot), self.dropout)
            #  [None, seq_len, seq_len] =>  [None, seq_len, 24]
            output = tf.matmul(attn, v_out)
            output_list.append(output)
        # [None, seq_len, 24] => [None, seq_len, 192]
        outputs = tf.concat(output_list, axis=-1)
        outputs = tf.layers.dense(outputs, self.token_emb_size * 7)
        outputs = tf.nn.dropout(outputs, self.dropout)
        return outputs

    def encoder_block(self, input):
        """多頭 -> add&norm -> ff -> add&norm"""
        attn_output = self.multi_head_attention(input)
        attn_output = tf.contrib.layers.layer_norm(inputs=attn_output + input, begin_norm_axis=-1, begin_params_axis=-1)
        pff = tf.layers.dense(attn_output, 512, activation=tf.nn.relu)
        pff = tf.layers.dense(pff, self.token_emb_size * 7, activation=None)
        pff = tf.nn.dropout(pff, self.dropout)
        output = tf.contrib.layers.layer_norm(attn_output + pff)  # [None, seq_len, 224]
        return output

    def build_hidden_layer(self):
        # transformer的輸入
        self.history_seq_emb = tf.concat(
            [self.history_seq_item_id_emb, self.history_seq_pty1_id_emb, self.history_seq_pty2_id_emb,
             self.history_seq_pty3_id_emb, self.history_seq_brand_id_emb, self.history_seq_origin_id_emb,
             self.pos_id_emb], axis=2)
        encoder_output = self.history_seq_emb
        for i in range(self.n_block):
            encoder_output = self.encoder_block(encoder_output)
        output = tf.reshape(encoder_output, [-1, encoder_output.get_shape()[1] * encoder_output.get_shape()[2]])
        output = tf.concat([self.user_feature_emb, output], axis=1)
        return output

其中build_hidden_layer為構(gòu)建Transformer層的入口球昨,將所有商品的Transformer結(jié)果全部concat作為輸出,在和用戶特征進(jìn)行合并眨攘,輸入全連接層主慰。最終驗(yàn)證集AUC維持在0.798±0.004嚣州。

模型效果總結(jié)

從驗(yàn)證集AUC來(lái)看BST基本優(yōu)于均值池化這種base模型,但是不能明顯優(yōu)于DIN共螺,且預(yù)測(cè)耗時(shí)明顯高于DIN该肴,存在繼續(xù)優(yōu)化的必要。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末藐不,一起剝皮案震驚了整個(gè)濱河市匀哄,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌雏蛮,老刑警劉巖涎嚼,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異挑秉,居然都是意外死亡法梯,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)衷模,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)鹊汛,“玉大人蒲赂,你說(shuō)我怎么就攤上這事阱冶。” “怎么了滥嘴?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵木蹬,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我若皱,道長(zhǎng)镊叁,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任走触,我火速辦了婚禮晦譬,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘互广。我一直安慰自己敛腌,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布惫皱。 她就那樣靜靜地躺著像樊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪旅敷。 梳的紋絲不亂的頭發(fā)上生棍,一...
    開(kāi)封第一講書(shū)人閱讀 51,688評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音媳谁,去河邊找鬼涂滴。 笑死友酱,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的氢妈。 我是一名探鬼主播粹污,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼首量!你這毒婦竟也來(lái)了壮吩?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤加缘,失蹤者是張志新(化名)和其女友劉穎鸭叙,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體拣宏,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡沈贝,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了勋乾。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片宋下。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖辑莫,靈堂內(nèi)的尸體忽然破棺而出学歧,到底是詐尸還是另有隱情,我是刑警寧澤各吨,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布枝笨,位于F島的核電站,受9級(jí)特大地震影響揭蜒,放射性物質(zhì)發(fā)生泄漏横浑。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一屉更、第九天 我趴在偏房一處隱蔽的房頂上張望徙融。 院中可真熱鬧,春花似錦瑰谜、人聲如沸欺冀。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)脚猾。三九已至,卻和暖如春砚哗,著一層夾襖步出監(jiān)牢的瞬間龙助,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留提鸟,地道東北人军援。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像称勋,于是被迫代替她去往敵國(guó)和親胸哥。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容