【王喆-推荐系统】模型篇-(task6)NeuralCF模型

举报
野猪佩奇996 发表于 2022/01/23 01:25:58 2022/01/23
【摘要】 学习心得 (1)首先学习了经典推荐算法协同过滤的深度学习进化版本 NerualCF。相比于矩阵分解算法,NeuralCF 用一个多层的神经网络,替代了矩阵分解算法中简单的点积操作,让用户和物品隐向量之间...

学习心得

(1)首先学习了经典推荐算法协同过滤的深度学习进化版本 NerualCF。相比于矩阵分解算法,NeuralCF 用一个多层的神经网络,替代了矩阵分解算法中简单的点积操作,让用户和物品隐向量之间进行充分的交叉。通过改进物品隐向量和用户隐向量互操作层的方法,增强模型的拟合能力。
(2)利用 NerualCF 的思想,改进出双塔模型。其特点优势:
1)它通过丰富物品侧和用户侧的特征,让模型能够融入除了用户 ID 和物品 ID 外更丰富的信息,ex:YouTube就使用召回层的双塔模型,融入除了用户id和物品id,还有如:

用户正在观看的视频 ID、频道 ID(图中的 seed features)、该视频的观看数、被喜欢的次数,以及用户历史观看过的视频 ID 等等。物品侧的特征包括了候选视频的 ID、频道 ID、被观看次数、被喜欢次数等等。

2)模型服务的便捷性,由于最终的互操作层是简单的内积操作或浅层神经网络。因此,我们可以把物品塔的输出当作物品 Embedding,用户塔的输出当作用户 Embedding 存入特征数据库(即不用将整个模型都部署线上),在线上服务只要实现简单的互操作过程就可以了。
在这里插入图片描述

一、NeuralCF 模型的结构

协同过滤:利用用户和物品之间的交互行为历史,构建出一个像图 1 左一样的共现矩阵。在共现矩阵的基础上,利用每一行的用户向量相似性,找到相似用户,再利用相似用户喜欢的物品进行推荐。
在这里插入图片描述
矩阵分解:进一步加强了协同过滤的泛化能力,它把协同过滤中的共现矩阵分解成了用户矩阵和物品矩阵,从用户矩阵中提取出用户隐向量,从物品矩阵中提取出物品隐向量,再利用它们之间的内积相似性进行推荐排序。结构图如下。
在这里插入图片描述

图2 矩阵分解的神经网络化示意图

图 2 中的输入层是由用户 ID 和物品 ID 生成的 One-hot 向量,Embedding 层是把 One-hot 向量转化成稠密的 Embedding 向量表达,这部分就是矩阵分解中的用户隐向量和物品隐向量。输出层使用了用户隐向量和物品隐向量的内积作为最终预测得分,之后通过跟目标得分对比,进行反向梯度传播,更新整个网络。

把矩阵分解神经网络化之后,把它跟 Embedding+MLP 以及 Wide&Deep 模型做对比,我们可以看出网络中的薄弱环节:矩阵分解在 Embedding 层之上的操作是直接利用内积得出最终结果。这会导致特征之间还没有充分交叉就直接输出结果,模型会有欠拟合的风险。NeuralCF 基于这点对矩阵分解进行了改进,结构图如下。
在这里插入图片描述

图3 NeuralCF的模型结构图 (出自论文Neural Collaborative Filtering)

区别就是 NeuralCF 用一个多层的神经网络替代掉了原来简单的点积操作。这样就可以让用户和物品隐向量之间进行充分的交叉,提高模型整体的拟合能力。

二、NeuralCF拓展—双塔模型

NeuralCF 的模型结构的思想:可以把模型分成用户侧模型和物品侧模型两部分,然后用互操作层把这两部分联合起来,产生最后的预测得分。

这里的用户侧模型结构和物品侧模型结构,可以是简单的 Embedding 层,也可以是复杂的神经网络结构,最后的互操作层可以是简单的点积操作,也可以是 MLP 结构。这种物品侧模型 + 用户侧模型 + 互操作层的模型结构,统称为“双塔模型”结构。

在这里插入图片描述

图4 双塔模型结构 (出自论文 Sampling-Bias-Corrected Neural Modeling for Large Corpus Item Recommendations)

2.1 YouTube召回层的双塔模型

对于 NerualCF 来说,它只利用了用户 ID 作为“用户塔”的输入特征,用物品 ID 作为“物品塔”的输入特征。其实也可以把其他用户和物品相关的特征也分别放入用户塔和物品塔,让模型能够学到的信息更全面。比如说,YouTube 在构建用于召回层的双塔模型时,就分别在用户侧和物品侧输入了多种不同的特征。
在这里插入图片描述

图5 YouTube双塔召回模型的架构
(出自论文 Sampling-Bias-Corrected Neural Modeling for Large Corpus Item Recommendations)

YouTube 召回双塔模型:
用户侧特征包括了用户正在观看的视频 ID、频道 ID(图中的 seed features)、该视频的观看数、被喜欢的次数,以及用户历史观看过的视频 ID 等等。
物品侧的特征包括了候选视频的 ID、频道 ID、被观看次数、被喜欢次数等等。
在经过了多层 ReLU 神经网络的学习之后,双塔模型最终通过 softmax 输出层连接两部分,输出最终预测分数。

2.2 双塔模型的优势

这个双塔模型相比我们之前学过的 Embedding MLP 和 Wide&Deep 有什么优势呢?
在实际工作中,双塔模型最重要的优势:易上线、易服务。

具体说:物品塔和用户塔分别生成各自的embedding(这里说是u(x)和v(y)表示),可以将这两个embedding存入特征数据库(即不用将整个模型都部署线上),然后再线上服务时,只需要将它们取出来做【互操作层】得到最后的模型预估结果。

三、NeuralCF 的 TensorFlow 实现

3.1 NeuralCF模型

# neural cf model arch two. only embedding in each tower, then MLP as the interaction layers
def neural_cf_model_1(feature_inputs, item_feature_columns, user_feature_columns, hidden_units):
    # 物品侧特征层
    item_tower = tf.keras.layers.DenseFeatures(item_feature_columns)(feature_inputs)
    # 用户侧特征层
    user_tower = tf.keras.layers.DenseFeatures(user_feature_columns)(feature_inputs)
    # 连接层及后续多层神经网络
    interact_layer = tf.keras.layers.concatenate([item_tower, user_tower])
    for num_nodes in hidden_units:
        interact_layer = tf.keras.layers.Dense(num_nodes, activation='relu')(interact_layer)
    # sigmoid单神经元输出层
    output_layer = tf.keras.layers.Dense(1, activation='sigmoid')(interact_layer)
    # 定义keras模型
    neural_cf_model = tf.keras.Model(feature_inputs, output_layer)
    return neural_cf_model

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

代码中定义的生成 NeuralCF 模型的函数,它接收了四个输入变量:
feature_inputs 代表着所有的模型输入;
item_feature_columnsuser_feature_columns 分别包含了物品侧和用户侧的特征。

在训练时,如果我们只在 item_feature_columns 中放入 movie_id ,在 user_feature_columns 放入 user_id, 就是 NeuralCF 的经典实现了。

通过 DenseFeatures 层创建好用户侧和物品侧输入层之后,我们会再利用 concatenate 层将二者连接起来,然后输入多层神经网络进行训练。如果想要定义多层神经网络的层数和神经元数量,我们可以通过设置 hidden_units 数组来实现。

3.2 Neural双塔模型

基于双塔模型的原理实现了一个 NeuralCF 的双塔版本。与上面的经典 NerualCF 实现不同,把多层神经网络操作放到了物品塔和用户塔内部,让塔内的特征进行充分交叉,最后使用内积层作为物品塔和用户塔的交互层。

# neural cf model arch one. embedding+MLP in each tower, 
# then dot product layer as the output
def neural_cf_model_2(feature_inputs, item_feature_columns, user_feature_columns, hidden_units):
    # 物品侧输入特征层
    item_tower = tf.keras.layers.DenseFeatures(item_feature_columns)(feature_inputs)
    # 物品塔结构
    for num_nodes in hidden_units:
        item_tower = tf.keras.layers.Dense(num_nodes, activation='relu')(item_tower)
    # 用户侧输入特征层
    user_tower = tf.keras.layers.DenseFeatures(user_feature_columns)(feature_inputs)
    # 用户塔结构
    for num_nodes in hidden_units:
        user_tower = tf.keras.layers.Dense(num_nodes, activation='relu')(user_tower)
    # 使用内积操作交互物品塔和用户塔,产生最后输出
    output = tf.keras.layers.Dot(axes=1)([item_tower, user_tower])
    # 定义keras模型
    neural_cf_model = tf.keras.Model(feature_inputs, output)
    return neural_cf_model

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

四、作业

双塔模型把物品侧的 Embedding 和用户侧的 Embedding 存起来,就可以进行线上服务了。但如果我们把一些场景特征,比如当前时间、当前地点加到用户侧或者物品侧,那我们还能用这种方式进行模型服务吗?为什么?

(1)如果从model serving的角度考虑,如果在物品侧或者用户侧加入场景特征的话,就没法做到预存embedding的serving方式了。因为场景特征是在线上不断变化的。
(2)栗子:一些地点和时间波动这种波动较大的特征就不能通过预存embedding来表示当前的用户或者当前的物品,如新闻推荐和外卖推荐,比如在公司和家时的embedding都是应该是不一样的,或者新闻网站早晨和晚上的embedding也不一样。

五、课后答疑

(1)embedding之后,如果使用点积,那么这两个embedding是在同一个向量空间;如果使用的MLP则不在同一个向量空间。因为点积不影响向量空间,线性变换矩阵会影响。

(2)把context特征放进user塔或者item塔,那么离线生成user embedding或者item embedding的数量就要翻好多倍,能否考虑把context特征单独作为context塔呢?

【答】离线有组合爆炸的风险。
一般不会有context塔,如果希望引入context特征,最好就不用双塔模型,因为双塔模型易线上serving的优势就不存在了。

(3)双塔模型对于新闻场景是不是也不太好?新闻时效性很强,在一些公司的数据里,大部分新闻曝光在2个小时内,双塔的训练数据有足够的曝光时,新闻的价值也失去了很多了。

【答】新闻的场景确实是很有意思的场景,因为时效性很强。这时候新闻id类的特征就不太管用了,因为如果不重新训练,id类特征对应的embedding没办法引入。

所以对于这类时效性很强的场景,还是推荐基于一些与id无关的feature来构建模型,比如新闻的类型、人物、地点、关键词等等。

(4)为什么不能加入context的特征。在训练DSSM的时候除了user和item的特征外,在user塔加入context的特征,比如用户的地理位置、手机型号等等,训练完后,将user和item的embedding存入redis后。线上请求时,将user的静态特征和实时context特征再过一遍DSSM,得到新的user embedding后,与存入redis的item emebdding取topN即可,为什么不妥呢?

【答】因为将user的静态特征和实时context特征再过一遍DSSM是一个非常重的操作,需要把深度模型部署上线,做实时推断。这样当然是可以的。但跟离线生成user 和 item emb预存起来,线上只做简单dot product这样的部署方式,显然复杂了许多。业界往往追求的实用性的效率,这就是加不加入context特征的区别所在。

(5)双塔版本的模型是不是有些问题,点积之后应该还要加一层输出层吧?
output = tf.keras.layers.Dense(1, activation='sigmoid')(output)
【答】理论上不是一定要加sigmoid函数。但tf这里如果值超过1会报错,所以加上。

Reference

(1)https://github.com/wzhe06/Reco-papers
(2)《深度学习推荐系统实战》,王喆

文章来源: andyguo.blog.csdn.net,作者:山顶夕景,版权归原作者所有,如需转载,请联系作者。

原文链接:andyguo.blog.csdn.net/article/details/121135302

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。