推薦系統(tǒng)遇上深度學(xué)習(xí)(二十三)--大一統(tǒng)信息檢索模型IRGAN在推薦領(lǐng)域的應(yīng)用

1塘娶、引言

信息檢索領(lǐng)域的一個(gè)重要任務(wù)就是針對用戶的一個(gè)請求query归斤,返回一組排好序的召回列表。

經(jīng)典的IR流派認(rèn)為query和document之間存在著一種生成過程刁岸,即q -> d 脏里。舉一個(gè)例子,搜索“哈登”虹曙,我們可以聯(lián)想到“保羅”迫横,“火箭”,“MVP”等等酝碳,每一個(gè)聯(lián)想出來的document有一個(gè)生成概率p(d|q)矾踱,然后根據(jù)這個(gè)生成概率進(jìn)行排序,這種模型被稱作生成模型疏哗。人們在研究生成模型的時(shí)候呛讲,設(shè)計(jì)了一系列基于query和document的特征,比方說TF-IDF,BM25贝搁。這些特征能非陈鹗希客觀的描述query和document的相關(guān)性,但沒有考慮document的質(zhì)量雷逆,用戶的反饋弦讽,pagerank等信息。

現(xiàn)代的IR流派則利用了機(jī)器學(xué)習(xí)膀哲,將query和document的特征放在一起往产,通過機(jī)器學(xué)習(xí)方法來計(jì)算query和document之間的匹配相關(guān)性: r=f(q,d)。舉個(gè)現(xiàn)實(shí)的例子某宪,我們知道“小白”更喜歡“吃雞”而不是“王者榮耀”捂齐,pointwise會(huì)優(yōu)化f(小白,吃雞)=1缩抡,f(小白奠宜,王者榮耀)=0;pairwise會(huì)優(yōu)化f(小白瞻想,吃雞)>f(小白压真,王者榮耀);listwise會(huì)考慮很多其他游戲蘑险,一起進(jìn)行優(yōu)化滴肿。機(jī)器學(xué)習(xí)的判別模型能夠很好地利用文本統(tǒng)計(jì)信息,用戶點(diǎn)擊信息等特征佃迄,但模型本身局限于標(biāo)注數(shù)據(jù)的質(zhì)量和大小泼差,模型常常會(huì)在訓(xùn)練數(shù)據(jù)上過擬合,或陷入某一個(gè)局部最優(yōu)解呵俏。

受到GAN的啟發(fā)堆缘,將生成模型和判別模型結(jié)合在一起,學(xué)者們便提出了IRGAN模型普碎。

2吼肥、IRGAN介紹

定義問題

假定我們又一些列的query{q1,...qN}并且有一系列的文檔document結(jié)合{d1,...dM},對于一個(gè)特定的query麻车,我們有一系列標(biāo)記的真實(shí)相關(guān)的文檔缀皱,但是這個(gè)數(shù)量是遠(yuǎn)遠(yuǎn)小于文檔總數(shù)量M的。query和document之間潛在的概率分布可以表示為條件概率分布ptrue(d|q,r)动猬。給定一堆從真實(shí)條件分布ptrue(d|q,r)觀察到的樣本啤斗, 我們可以定義兩種類型的IR model。

生成式檢索模型:該模型的目標(biāo)是學(xué)習(xí)pθ(d|q,r)赁咙,使其更接近于ptrue(d|q,r)钮莲。

判別式檢索模型:該模型的目標(biāo)是學(xué)習(xí)fΦ(q,d)免钻,即盡量能夠準(zhǔn)確的判別q和d的相關(guān)程度

因此,受到GAN的啟發(fā)臂痕,我們將上述的兩種IR模型結(jié)合起來做一個(gè)最大最小化的博弈:生成式模型的任務(wù)是盡可能的產(chǎn)生和query相關(guān)的document伯襟,以此來混淆判別式模型猿涨;判別式模型的任務(wù)是盡可能準(zhǔn)確區(qū)分真正相關(guān)的document和生成模型生成的document握童,因此,我們總體的目標(biāo)就是:

在上式中叛赚,生成式模型G為pθ(d|qn,r),生成式模型D對d是否與q相關(guān)進(jìn)行判定澡绩,通過下面的式子給出相關(guān)性得分:

優(yōu)化判別模型D

判別器的主要目標(biāo)是最大化我們的對數(shù)似然,即正確的區(qū)分真正相關(guān)的文檔和生成器生成的文檔俺附。最優(yōu)的參數(shù)通過下面的式子得到:

優(yōu)化生成模型G

生成器的主要目標(biāo)是產(chǎn)生能夠混淆判別器的document肥卡,判別器直接從給定的document池中選擇document。在固定判別器參數(shù)fΦ(q,d)的情況下事镣,生成器的學(xué)習(xí)目標(biāo)是(第一項(xiàng)不包含θ,因此可以省略):

我們把生成器的優(yōu)化目標(biāo)寫作JG(qn)步鉴。

由于生成的document是離散的,無法直接通過梯度下降法進(jìn)行優(yōu)化璃哟,一種通常的做法是使用強(qiáng)化學(xué)習(xí)中的策略梯度方法氛琢,我們將qn作為state,pθ(d|qn,r)作為對應(yīng)的策略随闪,而log(1+exp(fΦ(d阳似,qn))作為對應(yīng)的reward:

其中,第二步到第三步的變換利用了log函數(shù)求導(dǎo)的性質(zhì)铐伴,而在最后一步則基于采樣的document做了一個(gè)近似撮奏。

總體流程

IRGAN的整體訓(xùn)練流程如下:

Pair-wise的情況

在很多IR問題中,我們的數(shù)據(jù)是對一個(gè)query的一系列排序文檔對当宴,因?yàn)橄啾扰袛嘁粋€(gè)文檔的相關(guān)性畜吊,更容易判斷用戶對一對文檔的相對偏好(比如說通過點(diǎn)擊數(shù)據(jù),如果兩篇document同時(shí)展示給用戶户矢,用戶點(diǎn)擊了a而沒有點(diǎn)擊b定拟,則可以說明用戶對a的偏好大于對b的偏好),此外逗嫡,如果我們使用相關(guān)性進(jìn)行分級(jí)(用來表明不同文檔對同一個(gè)query的匹配程度)而不是使用是否相關(guān)青自,訓(xùn)練數(shù)據(jù)也可以自然的表示成有序的文檔對。

IRGAN在pairwise情況下是同樣適用的驱证,假設(shè)我有一堆帶標(biāo)記的document組合Rn = {<di延窜,dj>|di > dj}。生成器G的任務(wù)是盡量生成正確的排序組合來混淆判別器D抹锄,判別器D的任務(wù)是盡可能區(qū)分真正的排序組合和生成器生成的排序組合逆瑞≤伲基于下面的式子來進(jìn)行最大最小化博弈:

其中,o=<du,dv>,o'=<d'u,d'v>分別代表正確的組合和生成器生成的組合获高。而D(du,dv|q)計(jì)算公式如下:

接下來我們就來講一下生成器的生成策略哈肖。首先我們選擇一個(gè)正確的組合 <di,dj>,我們首先選取dj念秧,然后根據(jù)當(dāng)前的生成器G的策略pθ(d|q,r)淤井,選擇比dj生成概率大的dk,組成一組<dk,dj>摊趾。

有關(guān)更多的IRGAN的細(xì)節(jié)币狠,大家可以閱讀原論文,接下來砾层,我們來看一個(gè)簡單的Demo吧漩绵。

3、IRGAN的TF實(shí)現(xiàn)

本文的github代碼參考:
https://github.com/geek-ai/irgan/tree/master/item_recommendation

源代碼是python2.7版本的肛炮,修改為python3版本的代碼之后存放地址為:
https://github.com/princewen/tensorflow_practice/tree/master/recommendation/Basic-IRGAN-Demo

數(shù)據(jù)

先來說說數(shù)據(jù)吧止吐,數(shù)據(jù)用的是ml-100k的數(shù)據(jù),每一行的格式為“uid iid score"侨糟,我們把評(píng)分大于等于4分的電影作為用戶真正感興趣的電影碍扔。

Generator

對于訓(xùn)練Generator,我們需要輸入的有三部分:uid粟害,iid以及reward蕴忆,我們首先定義user和item的embedding,然后獲取uid和iid的item悲幅。同時(shí)套鹅,我們這里還給每個(gè)item定義了一個(gè)特征值:

self.user_embeddings = tf.Variable(tf.random_uniform([self.userNum,self.emb_dim],
                                                     minval=-initdelta,maxval=self.initdelta,
                                                     dtype =tf.float32))
self.item_embeddings = tf.Variable(tf.random_uniform([self.itemNum,self.emb_dim],
                                                     minval=-initdelta,maxval=self.initdelta,
                                                     dtype=tf.float32))
self.item_bias = tf.Variable(tf.zeros([self.itemNum]))

self.u = tf.placeholder(tf.int32)
self.i = tf.placeholder(tf.int32)
self.reward = tf.placeholder(tf.float32)

self.u_embedding = tf.nn.embedding_lookup(self.user_embeddings,self.u)
self.i_embedding = tf.nn.embedding_lookup(self.item_embeddings,self.i)
self.i_bias = tf.gather(self.item_bias,self.i)

接下來,我們需要計(jì)算傳入的user和item之間的相關(guān)性汰具,并通過傳入的reward來更新我們的策略:

self.all_logits = tf.reduce_sum(tf.multiply(self.u_embedding,self.item_embeddings),1) + self.item_bias
self.i_prob = tf.gather(
    tf.reshape(tf.nn.softmax(tf.reshape(self.all_logits, [1, -1])), [-1]),
    self.i)

self.gan_loss = -tf.reduce_mean(tf.log(self.i_prob) * self.reward) + self.lamda * (
    tf.nn.l2_loss(self.u_embedding) + tf.nn.l2_loss(self.i_embedding) + tf.nn.l2_loss(self.i_bias)
)

g_opt = tf.train.GradientDescentOptimizer(self.learning_rate)
self.gan_updates = g_opt.minimize(self.gan_loss,var_list=self.g_params)

Discriminator

傳入D的同樣有三部分卓鹿,分別是uid,iid以及l(fā)abel值留荔,與G一樣吟孙,我們也首先得到embedding值:

self.user_embeddings = tf.Variable(tf.random_uniform([self.userNum,self.emb_dim],
                                                    minval=-self.initdelta,maxval=self.initdelta,
                                                    dtype=tf.float32))
self.item_embeddings = tf.Variable(tf.random_uniform([self.itemNum,self.emb_dim],
                                                    minval=-self.initdelta,maxval=self.initdelta,
                                                    dtype=tf.float32))
self.item_bias = tf.Variable(tf.zeros(self.itemNum))

self.u = tf.placeholder(tf.int32)
self.i = tf.placeholder(tf.int32)
self.label = tf.placeholder(tf.float32)

self.u_embedding = tf.nn.embedding_lookup(self.user_embeddings,self.u)
self.i_embedding = tf.nn.embedding_lookup(self.item_embeddings,self.i)
self.i_bias = tf.gather(self.item_bias,self.i)

隨后,我們通過對數(shù)損失函數(shù)來更新D:

self.pre_logits = tf.reduce_sum(tf.multiply(self.u_embedding, self.i_embedding), 1) + self.i_bias
self.pre_loss = tf.nn.sigmoid_cross_entropy_with_logits(labels = self.label,
                                                        logits = self.pre_logits) + self.lamda * (
    tf.nn.l2_loss(self.u_embedding) + tf.nn.l2_loss(self.i_embedding) + tf.nn.l2_loss(self.i_bias)
)

d_opt = tf.train.GradientDescentOptimizer(self.learning_rate)
self.d_updates = d_opt.minimize(self.pre_loss,var_list=self.d_params)

D中還有很重要的一步就是聚蝶,計(jì)算reward:

self.reward_logits = tf.reduce_sum(tf.multiply(self.u_embedding,self.i_embedding),1) + self.i_bias
self.reward = 2 * (tf.sigmoid(self.reward_logits) - 0.5)

模型訓(xùn)練

我們的G和D是交叉訓(xùn)練的杰妓,D的訓(xùn)練過程如下,每隔5輪碘勉,我們就要調(diào)用generate_for_d函數(shù)產(chǎn)生一批新的訓(xùn)練樣本巷挥。

for d_epoch in range(100):
    if d_epoch % 5 == 0:
        generate_for_d(sess,generator,DIS_TRAIN_FILE)
        train_size = ut.file_len(DIS_TRAIN_FILE)
    index = 1
    while True:
        if index > train_size:
            break
        if index + BATCH_SIZE <= train_size + 1:
            input_user,input_item,input_label = ut.get_batch_data(DIS_TRAIN_FILE,index,BATCH_SIZE)
        else:
            input_user,input_item,input_label = ut.get_batch_data(DIS_TRAIN_FILE,index,train_size-index+1)
        index += BATCH_SIZE

        _ = sess.run(discriminator.d_updates,feed_dict={
            discriminator.u:input_user,discriminator.i:input_item,discriminator.label:input_label
        })

generate_for_d函數(shù)形式如下,其根據(jù)G的策略验靡,生成一批樣本倍宾。

def generate_for_d(sess,model,filename):
    data = []
    for u in user_pos_train:
        pos = user_pos_train[u]

        rating = sess.run(model.all_rating,{model.u:[u]})
        rating = np.array(rating[0]) / 0.2
        exp_rating = np.exp(rating)
        prob = exp_rating / np.sum(exp_rating)

        neg = np.random.choice(np.arange(ITEM_NUM),size=len(pos),p=prob)
        # 1:1 的正負(fù)樣本
        for i in range(len(pos)):
            data.append(str(u) + '\t' + str(pos[i]) + '\t' + str(neg[i]))

    with open(filename,'w') as fout:
        fout.write('\n'.join(data))

G的訓(xùn)練過程首先要通過D得到對應(yīng)的reward雏节,隨后更新自己的策略:

for g_epoch in range(50):
    for u in user_pos_train:
        sample_lambda = 0.2
        pos = user_pos_train[u]

        rating = sess.run(generator.all_logits,{generator.u:u})
        exp_rating = np.exp(rating)
        prob = exp_rating / np.sum(exp_rating)

        pn = (1-sample_lambda) * prob
        pn[pos] += sample_lambda * 1.0 / len(pos)

        sample = np.random.choice(np.arange(ITEM_NUM), 2 * len(pos), p=pn)

        reward = sess.run(discriminator.reward, {discriminator.u: u, discriminator.i: sample})
        reward = reward * prob[sample] / pn[sample]

        _ = sess.run(generator.gan_updates,
                     {generator.u: u, generator.i: sample, generator.reward: reward})

參考文獻(xiàn):
1、論文地址:https://arxiv.org/abs/1705.10513
2高职、https://github.com/geek-ai/irgan/tree/master/item_recommendation

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末钩乍,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子怔锌,更是在濱河造成了極大的恐慌寥粹,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件产禾,死亡現(xiàn)場離奇詭異排作,居然都是意外死亡牵啦,警方通過查閱死者的電腦和手機(jī)亚情,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來哈雏,“玉大人楞件,你說我怎么就攤上這事∩驯瘢” “怎么了土浸?”我有些...
    開封第一講書人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長彭羹。 經(jīng)常有香客問我黄伊,道長,這世上最難降的妖魔是什么派殷? 我笑而不...
    開封第一講書人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任还最,我火速辦了婚禮,結(jié)果婚禮上毡惜,老公的妹妹穿的比我還像新娘拓轻。我一直安慰自己,他們只是感情好经伙,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開白布扶叉。 她就那樣靜靜地躺著,像睡著了一般帕膜。 火紅的嫁衣襯著肌膚如雪枣氧。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,185評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼惜浅。 笑死路星,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的索昂。 我是一名探鬼主播怔毛,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼左痢,長吁一口氣:“原來是場噩夢啊……” “哼契耿!你這毒婦竟也來了瞒大?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬榮一對情侶失蹤搪桂,失蹤者是張志新(化名)和其女友劉穎透敌,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體踢械,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡酗电,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了内列。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片撵术。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖话瞧,靈堂內(nèi)的尸體忽然破棺而出嫩与,到底是詐尸還是另有隱情,我是刑警寧澤交排,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布划滋,位于F島的核電站,受9級(jí)特大地震影響埃篓,放射性物質(zhì)發(fā)生泄漏处坪。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一架专、第九天 我趴在偏房一處隱蔽的房頂上張望同窘。 院中可真熱鬧,春花似錦胶征、人聲如沸塞椎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽案狠。三九已至,卻和暖如春钱雷,著一層夾襖步出監(jiān)牢的瞬間骂铁,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來泰國打工罩抗, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留拉庵,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓套蒂,卻偏偏與公主長得像钞支,于是被迫代替她去往敵國和親茫蛹。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344

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

  • GAN烁挟,全稱為Generative Adversarial Nets婴洼,直譯為生成式對抗網(wǎng)絡(luò)。它一方面將產(chǎn)生式模型拉...
    MiracleJQ閱讀 3,358評(píng)論 0 14
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理撼嗓,服務(wù)發(fā)現(xiàn)柬采,斷路器,智...
    卡卡羅2017閱讀 134,601評(píng)論 18 139
  • 2017-09-12 00:38:31 起源于我看到的一篇旅游推文: 忙碌了一個(gè)夏天且警,還剩下一個(gè)秋天冬天粉捻,大家似乎...
    流年娃娃閱讀 198評(píng)論 0 1
  • 一個(gè)人走路,一個(gè)人看書斑芜,一個(gè)人喝茶肩刃,一個(gè)人做夢,這樣的寂寞也是叫人心動(dòng)押搪。也許只有一個(gè)人的時(shí)候树酪,所有世事才會(huì)如此波瀾...
    Harvest收獲閱讀 528評(píng)論 29 40
  • 未來陪你走完一生的不是你的伴侶浅碾, 不是你的孩子大州, 而是健康! 沒有全面健康就沒有全面小康垂谢, 我為從事健康行業(yè)而自豪...
    暖心滴果兒媽閱讀 162評(píng)論 0 0