推薦系統(tǒng)遇上深度學(xué)習(xí)(二十八)--知識(shí)圖譜與推薦系統(tǒng)結(jié)合之MKR模型原理及實(shí)現(xiàn)

知識(shí)圖譜特征學(xué)習(xí)在推薦系統(tǒng)中的應(yīng)用步驟大致有以下三種方式:

依次訓(xùn)練的方法主要有:Deep Knowledge-aware Network(DKN)
聯(lián)合訓(xùn)練的方法主要有:Ripple Network
交替訓(xùn)練主要采用multi-task的思路,主要方法有:Multi-task Learning for KG enhanced Recommendation (MKR)

本文先來(lái)介紹交替訓(xùn)練的方法MKR

網(wǎng)上沒(méi)有找到相關(guān)的論文,只有在一篇帖子里有所介紹,github上可以找到源代碼進(jìn)行學(xué)習(xí)。

1、MKR原理介紹

由于推薦系統(tǒng)中的物品和知識(shí)圖譜中的實(shí)體存在重合,因此可以采用多任務(wù)學(xué)習(xí)的框架,將推薦系統(tǒng)和知識(shí)圖譜特征學(xué)習(xí)視為兩個(gè)分離但是相關(guān)的任務(wù),進(jìn)行交替式的學(xué)習(xí)。

MKR的模型框架如下圖,其中左側(cè)是推薦系統(tǒng)任務(wù),右側(cè)是知識(shí)圖譜特征學(xué)習(xí)任務(wù)。推薦部分的輸入是用戶(hù)和物品的特征表示,點(diǎn)擊率的預(yù)估值作為輸出。知識(shí)圖譜特征學(xué)習(xí)部分使用的是三元組的頭節(jié)點(diǎn)和關(guān)系作為輸入,預(yù)測(cè)的尾節(jié)點(diǎn)作為輸出:

由于推薦系統(tǒng)中的物品和知識(shí)圖譜中的實(shí)體存在重合,所以?xún)蓚€(gè)任務(wù)并非相互獨(dú)立。所以作者在兩個(gè)任務(wù)中設(shè)計(jì)了交叉特征共享單元(cross-feature-sharing units)作為兩者的連接紐帶。

交叉特征共享單元是一個(gè)可以讓兩個(gè)任務(wù)交換信息的模塊。由于物品向量和實(shí)體向量實(shí)際上是對(duì)同一個(gè)對(duì)象的兩種描述,他們之間的信息交叉共享可以讓兩者都獲得來(lái)自對(duì)方的額外信息,從而彌補(bǔ)了自身的信息稀疏性的不足,其結(jié)構(gòu)如下:

關(guān)于這個(gè)交叉單元具體實(shí)現(xiàn),大家可以參照代碼進(jìn)行理解。

最后是損失函數(shù)部分,由于是交替訓(xùn)練的方式,所以在訓(xùn)練時(shí)首先固定推薦系統(tǒng)模塊的參數(shù),訓(xùn)練知識(shí)圖譜特征學(xué)習(xí)模塊的參數(shù);然后固定知識(shí)圖譜特征學(xué)習(xí)模塊的參數(shù),訓(xùn)練推薦系統(tǒng)模塊的參數(shù)。

推薦系統(tǒng)模塊是點(diǎn)擊率預(yù)估模型,損失函數(shù)是對(duì)數(shù)損失加l2正則項(xiàng);知識(shí)圖譜特征學(xué)習(xí)模塊希望預(yù)測(cè)得到的tail向量和真實(shí)的tail向量相近,因此首先計(jì)算二者的內(nèi)積(內(nèi)積可近似表示向量之間的余弦相似度),內(nèi)積經(jīng)過(guò)sigmoid之后取相反數(shù),再加上l2正則項(xiàng),即得到了知識(shí)圖譜特征學(xué)習(xí)模塊的損失。關(guān)于損失的計(jì)算,我們?cè)诖a里可以更清楚的看到。

2、MKR模型tensorflow實(shí)現(xiàn)

本文的代碼地址為:https://github.com/princewen/tensorflow_practice/tree/master/recommendation/Basic-MKR-Demo
參考代碼地址為:https://github.com/hwwang55/MKR
數(shù)據(jù)下載地址為:https://pan.baidu.com/s/1uHkQXK_ozAgBWcMUMzOfZQ 密碼:qw30

在對(duì)數(shù)據(jù)進(jìn)行預(yù)處理后,我們得到了兩個(gè)文件:kg_final.txt和rating_final.txt

rating_final.txt數(shù)據(jù)形式如下,三列分別是user-id,item-id以及l(fā)abel(0是通過(guò)負(fù)采樣得到的,正負(fù)樣本比例為1:1)。

kg_final.txt格式如下,三類(lèi)分別代表h,r,t(這里entity和item用的是同一套id):

好了,接下來(lái)我們重點(diǎn)介紹一下我們的MKR框架的構(gòu)建。

模型輸入

模型輸入有以下幾部分:用戶(hù)的id、物品的id、推薦系統(tǒng)部分的label、知識(shí)圖譜三元組的head、relation、tail的對(duì)應(yīng)id:

def _build_inputs(self):
    self.user_indices = tf.placeholder(tf.int32,[None],'user_indices')
    self.item_indices = tf.placeholder(tf.int32,[None],'item_indices')
    self.labels = tf.placeholder(tf.float32,[None],'labels')
    self.head_indices = tf.placeholder(tf.int32,[None],'head_indices')
    self.tail_indices = tf.placeholder(tf.int32,[None],'tail_indices')
    self.relation_indices = tf.placeholder(tf.int32,[None],'relation_indices')

低層網(wǎng)絡(luò)構(gòu)建

低層網(wǎng)絡(luò)指下面的部分:


可以看到,user_id、item_id、head_id以及relation_id首先轉(zhuǎn)換為對(duì)應(yīng)的embedding,user_id和relation_id經(jīng)由多層神經(jīng)網(wǎng)絡(luò)向上傳播、而head_id和item_id經(jīng)過(guò)交叉單元進(jìn)行傳播。

def _build_low_layers(self,args):
    self.user_emb_matrix = tf.get_variable('user_emb_matrix', [self.n_user, args.dim])
    self.item_emb_matrix = tf.get_variable('item_emb_matrix', [self.n_item, args.dim])
    self.entity_emb_matrix = tf.get_variable('entity_emb_matrix', [self.n_entity, args.dim])
    self.relation_emb_matrix = tf.get_variable('relation_emb_matrix', [self.n_relation, args.dim])

    # [batch_size, dim]
    self.user_embeddings = tf.nn.embedding_lookup(self.user_emb_matrix, self.user_indices)
    self.item_embeddings = tf.nn.embedding_lookup(self.item_emb_matrix, self.item_indices)
    self.head_embeddings = tf.nn.embedding_lookup(self.entity_emb_matrix, self.head_indices)
    self.relation_embeddings = tf.nn.embedding_lookup(self.relation_emb_matrix, self.relation_indices)
    self.tail_embeddings = tf.nn.embedding_lookup(self.entity_emb_matrix, self.tail_indices)

    for _ in range(args.L):
        user_mlp = Dense(input_dim=args.dim,output_dim=args.dim)
        tail_mlp = Dense(input_dim=args.dim,output_dim = args.dim)
        cc_unit = CrossCompressUnit(args.dim)

        self.user_embeddings = user_mlp(self.user_embeddings)
        self.item_embeddings,self.head_embeddings = cc_unit([self.item_embeddings,self.head_embeddings])
        self.tail_embeddings = tail_mlp(self.tail_embeddings)

        self.vars_rs.extend(user_mlp.vars)
        self.vars_rs.extend(cc_unit.vars)
        self.vars_kge.extend(tail_mlp.vars)
        self.vars_kge.extend(cc_unit.vars)

接下來(lái),我們來(lái)看一下交叉單元的代碼:

v,e = inputs

v = tf.expand_dims(v,dim=2)
e = tf.expand_dims(e,dim=1)


# [batch_size, dim, dim]
c_matrix = tf.matmul(v, e)
c_matrix_transpose = tf.transpose(c_matrix, perm=[0, 2, 1])

# [batch_size * dim, dim]
c_matrix = tf.reshape(c_matrix, [-1, self.dim])
c_matrix_transpose = tf.reshape(c_matrix_transpose, [-1, self.dim])

v_output = tf.reshape(tf.matmul(c_matrix,self.weight_vv) + tf.matmul(c_matrix_transpose,self.weight_ev),[-1,self.dim]) + self.bias_v

e_output = tf.reshape(tf.matmul(c_matrix, self.weight_ve) + tf.matmul(c_matrix_transpose, self.weight_ee),
                      [-1, self.dim]) + self.bias_e

return v_output,e_output

item對(duì)應(yīng)的embedding用v表示,head對(duì)應(yīng)的embedding用e表示,二者初始情況下都是batch * dim大小的。過(guò)程如下:
1、v擴(kuò)展成三維batch * dim * 1,e擴(kuò)展成三維batch * 1 * dim,隨后二者進(jìn)行矩陣相乘v * e,我們知道三維矩陣相乘實(shí)際上是后兩維進(jìn)行運(yùn)算,因此得到c_matrix的大小為 batch * dim * dim
2、對(duì)得到的c_matrix進(jìn)行轉(zhuǎn)置,得到c_matrix_transpose,大小為batch * dim * dim。這相當(dāng)于將e擴(kuò)展成三維batch * dim * 1,v擴(kuò)展成三維batch * 1 * dim,隨后二者進(jìn)行矩陣相乘e * v。這是兩種不同的特征交叉方式。
3、對(duì)c_matrix和c_matrix_transpose 進(jìn)行reshape操作,變?yōu)椋╞atch * dim ) * dim的二維矩陣
4、定義兩組不同的參數(shù)和偏置,分別得到交叉后的v_output和e_output.

高層網(wǎng)絡(luò)構(gòu)建

高層網(wǎng)絡(luò)指下面的部分:

對(duì)于推薦部分,可以采用內(nèi)積直接得到CTR的預(yù)估值,也可以經(jīng)過(guò)多層神經(jīng)網(wǎng)絡(luò)得到預(yù)估值;對(duì)于知識(shí)圖譜部分,將head和relation對(duì)應(yīng)的向量進(jìn)行拼接,經(jīng)過(guò)多層神經(jīng)網(wǎng)絡(luò),得到一個(gè)tail對(duì)應(yīng)向量的預(yù)估值,并與真實(shí)的tail向量計(jì)算內(nèi)積。代碼如下:

def _build_high_layers(self,args):
    #RS
    use_inner_product = True
    if use_inner_product:
        self.scores = tf.reduce_sum(self.user_embeddings*self.item_embeddings,axis=1)
    else:
        self.user_item_concat = tf.concat([self.user_embeddings,self.item_embeddings],axis=1)
        for _ in range(args.H - 1):
            rs_mlp = Dense(input_dim = args.dim * 2 , output_dim = args.dim * 2)
            self.user_item_concat = rs_mlp(self.user_item_concat)
            self.vars_rs.extend(rs_mlp.vars)

        rs_pred_mlp = Dense(input_dim=args.dim * 2,output_dim=1)
        self.scores = tf.squeeze(rs_pred_mlp(self.user_item_concat))
        self.vars_rs.extend(rs_pred_mlp)

    self.scores_normalized = tf.nn.sigmoid(self.scores)

    #KGE
    self.head_relation_concat = tf.concat([self.head_embeddings,self.relation_embeddings],axis=1)
    for _ in range(args.H - 1):
        kge_mlp = Dense(input_dim=args.dim * 2,output_dim = args.dim * 2)
        self.head_relation_concat = kge_mlp(self.head_relation_concat)
        self.vars_kge.extend(kge_mlp.vars)

    kge_pred_mlp = Dense(input_dim=args.dim * 2,output_dim = args.dim)
    self.tail_pred = kge_pred_mlp(self.head_relation_concat)
    self.vars_kge.extend(kge_pred_mlp.vars)
    self.tail_pred = tf.nn.sigmoid(self.tail_pred)

    self.scores_kge = tf.nn.sigmoid(tf.reduce_sum(self.tail_embeddings * self.tail_pred,axis=1))
    #self.rmse = tf.reduce_mean(tf.sqrt(tf.reduce_sum(tf.square(self.tail_embeddings - self.tail_pred),axis=1) / args.dim))

定義損失

推薦系統(tǒng)部分的損失是對(duì)數(shù)損失加l2正則項(xiàng):

# RS
self.base_loss_rs = tf.reduce_mean(
    tf.nn.sigmoid_cross_entropy_with_logits(labels=self.labels, logits=self.scores))
self.l2_loss_rs = tf.nn.l2_loss(self.user_embeddings) + tf.nn.l2_loss(self.item_embeddings)
for var in self.vars_rs:
    self.l2_loss_rs += tf.nn.l2_loss(var)
self.loss_rs = self.base_loss_rs + self.l2_loss_rs * args.l2_weight

知識(shí)圖譜特征學(xué)習(xí)模塊用上一步計(jì)算的scores_kge的相反數(shù)再加上l2正則項(xiàng):

# KGE
self.base_loss_kge = -self.scores_kge
self.l2_loss_kge = tf.nn.l2_loss(self.head_embeddings) + tf.nn.l2_loss(self.tail_embeddings)
for var in self.vars_kge:
    self.l2_loss_kge += tf.nn.l2_loss(var)
self.loss_kge = self.base_loss_kge + self.l2_loss_kge * args.l2_weight

參考文獻(xiàn)

1、http://baijiahao.baidu.com/s?id=1602210213239784098&wfr=spider&for=pc

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,825評(píng)論 6 546
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,814評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 178,980評(píng)論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 64,064評(píng)論 1 319
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,779評(píng)論 6 414
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 56,109評(píng)論 1 330
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,099評(píng)論 3 450
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 43,287評(píng)論 0 291
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,799評(píng)論 1 338
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,515評(píng)論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,750評(píng)論 1 375
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,221評(píng)論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,933評(píng)論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 35,327評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 36,667評(píng)論 1 296
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,492評(píng)論 3 400
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,703評(píng)論 2 380

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