契机
对用户兴趣进行进一步的抽象建模,从而更加精确地提取用户兴趣。
模型结构
模型的核心结构如下所示:
模型阐述
模型的核心组件分为四个部分:用户行为层、兴趣提取层、辅助loss以及兴趣进化层,如下会分别对这四个部分进行讲述。
用户行为层
这一层比较简单,即将用户的item播放历史中的item转换为embedding,为后续步骤提供数据基础。
兴趣提取层
这一层的核心目标为将用户的播放历史以时间为基础抽象出用户的兴趣。具体调用的计算模块为GRU。个人用一个较为简单易懂的例子来解释该场景:一开始用户点击了一个周杰伦的花海,听着还不错,然后他就比较喜欢周杰伦了,那么下次又听了一个周杰伦的七里香,他发现周杰伦的歌怎么变得这么难听了,所以他再次浏览feed时就刻意避开周杰伦的歌从而喜欢听张学友的歌了。可以看出,用户的行为会反映用户的兴趣,这里较为成功地捕捉到用户的兴趣信息。
辅助loss
文章的一大亮点在于引入辅助loss。其核心我个人理解为加重了模型对用户点击历史的学习。具体操作流程如下图所示:
其核心思想为构建click和not click loss从而显式加强模型对用户点击历史的学习过程。抽取当前用户的兴趣表示 h ( t ) h(t) h(t),与下一时刻点击资源的embedding e ( t + 1 ) e(t+1) e(t+1)构成click对,随机选择一个未点击资源embedding e ( t + 1 ) ′ e(t+1)' e(t+1)′作为not click对,构建如下损失函数,
L a u x = − 1 N ( ∑ i = 1 N ∑ i l o g σ ( h t i , e b i [ t + 1 ] ) + l o g ( 1 − σ ( h t i , e b i [ t + 1 ] ′ ) ) ) L_{aux}=-\frac{1}{N}(\sum_{i=1}^N\sum_i log\sigma(h_t^i,e^i_b[t+1])+log(1-\sigma(h^i_t,e^i_b[t+1]'))) Laux=−N1(i=1∑Ni∑logσ(hti,ebi[t+1])+log(1−σ(hti,ebi[t+1]′)))
最终的损失函数为 L = L o + α L a u x L=L_o+\alpha L_{aux} L=Lo+αLaux,即存在一个权衡的关系。其具体的实现逻辑见如下代码:
# h_states为当前兴趣向量,
# click_seq为下一时刻点击序列
# noclick_seq为下一时刻未点击序列
def auxiliary_loss(self, h_states, click_seq, noclick_seq, mask, stag = None):
mask = tf.cast(mask, tf.float32)
click_input_ = tf.concat([h_states, click_seq], -1)
noclick_input_ = tf.concat([h_states, noclick_seq], -1)
click_prop_ = self.auxiliary_net(click_input_, stag = stag)[:, :, 0]
noclick_prop_ = self.auxiliary_net(noclick_input_, stag = stag)[:, :, 0]
click_loss_ = - tf.reshape(tf.log(click_prop_), [-1, tf.shape(click_seq)[1]]) * mask
noclick_loss_ = - tf.reshape(tf.log(1.0 - noclick_prop_), [-1, tf.shape(noclick_seq)[1]]) * mask
loss_ = tf.reduce_mean(click_loss_ + noclick_loss_)
return loss_
def auxiliary_net(self, in_, stag='auxiliary_net'):
bn1 = tf.layers.batch_normalization(inputs=in_, name='bn1' + stag, reuse=tf.AUTO_REUSE)
dnn1 = tf.layers.dense(bn1, 100, activation=None, name='f1' + stag, reuse=tf.AUTO_REUSE)
dnn1 = tf.nn.sigmoid(dnn1)
dnn2 = tf.layers.dense(dnn1, 50, activation=None, name='f2' + stag, reuse=tf.AUTO_REUSE)
dnn2 = tf.nn.sigmoid(dnn2)
dnn3 = tf.layers.dense(dnn2, 2, activation=None, name='f3' + stag, reuse=tf.AUTO_REUSE)
y_hat = tf.nn.softmax(dnn3) + 0.00000001
return y_hat
# 调用过程
aux_loss_1 = self.auxiliary_loss(rnn_outputs[:, :-1, :], # 前N-1个兴趣向量
self.item_his_eb[:, 1:, :], # 后N-1个点击序列
self.noclk_item_his_eb[:, 1:, :], # 后N-1个未点击序列
self.mask[:, 1:], stag="gru")
兴趣进化层
这一层的核心目标是用当前待预测item去规范用户的兴趣表示,主要分为attention和AUGRU两个部分,attention的具体操作手段可以参考这里,AUGRU我理解它的作用是通过时序信息来融合用户在不同时间点的兴趣,从而得到更加客观的用户兴趣表示。
总结
该篇论文在用户兴趣表示上下了很大的文章,能够提取更高阶的用户兴趣向量。但个人觉得这个模型很复杂,不知道线上有没有耗时以及性能的一系列问题,因为用了两层GRU。