0%

NeuralCF:如何用深度学习改造协同过滤?

NeuralCF 模型的结构

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

NeuralCF 模型的扩展,双塔模型

有了之前实现矩阵分解和深度学习模型的经验,我想你理解起来 NeuralCF 肯定不会有困难。事实上,NeuralCF 的模型结构之中,蕴含了一个非常有价值的思想,就是我们可以把模型分成用户侧模型和物品侧模型两部分,然后用互操作层把这两部分联合起来,产生最后的预测得分。

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

图 4 就是一个典型“双塔模型”的抽象结构。它的名字形象地解释了它的结构组成,两侧的模型结构就像两个高塔一样,而最上面的互操作层则像两个塔尖搭建起的空中走廊,负责两侧信息的沟通。

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

NeuralCF 的 TensorFlow 实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 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

小结

利用 NerualCF 的思想,我们进一步学习了双塔模型。它通过丰富物品侧和用户侧的特征,让模型能够融入除了用户 ID 和物品 ID 外更丰富的信息。除此之外,双塔模型最大的优势在于模型服务的便捷性,由于最终的互操作层是简单的内积操作或浅层神经网络。因此,我们可以把物品塔的输出当作物品 Embedding,用户塔的输出当作用户 Embedding 存入特征数据库,在线上只要实现简单的互操作过程就可以了。

Welcome to my other publishing channels