深度学习模型需要加强处理特征交叉的能力
传统的Embedding MLP和Wide&Deep模型都没有针对性的处理特征交叉问题。虽然MLP有拟合任意函数的能力,但这是建立在MLP有任意多层网络,以及任意多个神经元的前提下的。因为在训练资源有限,调参时间有限的现实情况下,MLP对于特征交叉的处理其实还比较低效。 MLP是通过concatenate层把所有特征连接在一起成为一个特征向量的,这里面没有特征交叉,两两特征之间没有发生任何关系。 这个时候,人为地加入一些负责特征交叉的模型结构,其实对提升模型效果会非常有帮助。例如在Sparrow RecSys项目的训练样本中其实有两个这样的特征,一个是用户喜欢的电影风格,一个是电影本身的风格,这两个特征明显具有很强的相关性。如果我们能让模型利用起这样的相关性,肯定会对最后的推荐效果有正向的影响。
传统的机器学习模型FM
因子分解机模型(Factorization Machine)简称FM,是一种解决特征交叉的机器学习模型。 FM模型架构图 从上图中可以看到底层One-hot特征通过embedding层转换为稠密的embedding向量。 FM层是用来来专门处理特征之间的交叉问题的,FM层中有多个内积操作单元对不同特征向量进行两两组合,这些操作单元会把不同特征的内积操作的结果输入最后的输出神经元,以此来完成最后的预测。
深度学习模型DeepFM
我们可以把FM跟其他深度学习模型组合起来,生成一个全新的既有强特征组合能力,又有强拟合能力的模型。最终就诞生了DeepFM模型。 DeepFM模型架构图: 如上图,DeepFM利用了Wide&Deep组合模型的思想,用FM替换了 Wide&Deep左边的Wide部分,加强了浅层网络部分特征组合的能力,而右边的部分跟Wide&Deep的Deep部分一样,主要利用多层神经网络进行所有特征的深层处理,最后的输出层是把FM部分的输出和 Deep 部分的输出综合起来,产生最后的预估结果。这就是DeepFM的结构。
特征交叉新方法:元素积操作
FM和DeepFM中进行特征交叉的方式,都是进行Embedding向量的点积操作。当然,特征交叉还有新的方法叫元素积操作。举个例子,NFM(Neural Factorization Machines,神经网络因子分解机)采用的就是元素积操作,架构图如下: Embedding层和MLP层中间添加了Bi-Interaction Pooling层(两两特征交叉池化层)。假设 Vx 是所有特征域的 Embedding 集合,那么特征交叉池化层的具体操作公式如下: 元素积也称为哈达玛乘积或舒尔积,具体的定义为:若两个矩阵A 和B 具有相同的维度m × n,则它们的哈达玛积A ∘ B是一个具有相同维度的矩阵,其元素值为: 在进行两两特征Embedding向量的元素积操作后,再求取所有交叉特征向量之和,我们就得到了池化层的输出向量。接着,我们再把该向量输入上层的多层全连接神经网络,就能得出最后的预测得分。 总的来说,NFM使用元素积的操作,在得到交叉特征向量之后,采用了求和的池化操作,把它们叠加起来。
DeepFM的TensorFlow实现
读取数据,定义特征,训练模型等实现代码之前已经实现,本章节主要是从模型定义来进行代码实现:
item_emb_layer = tf. keras. layers. DenseFeatures( [ movie_emb_col] ) ( inputs)
user_emb_layer = tf. keras. layers. DenseFeatures( [ user_emb_col] ) ( inputs)
item_genre_emb_layer = tf. keras. layers. DenseFeatures( [ item_genre_emb_col] ) ( inputs)
user_genre_emb_layer = tf. keras. layers. DenseFeatures( [ user_genre_emb_col] ) ( inputs)
product_layer_item_user = tf. keras. layers. Dot( axes= 1 ) ( [ item_emb_layer, user_emb_layer] )
product_layer_item_genre_user_genre = tf. keras. layers. Dot( axes= 1 ) ( [ item_genre_emb_layer, user_genre_emb_layer] )
product_layer_item_genre_user = tf. keras. layers. Dot( axes= 1 ) ( [ item_genre_emb_layer, user_emb_layer] )
product_layer_user_genre_item = tf. keras. layers. Dot( axes= 1 ) ( [ item_emb_layer, user_genre_emb_layer] )
deep = tf. keras. layers. DenseFeatures( deep_feature_columns) ( inputs)
deep = tf. keras. layers. Dense( 64 , activation= 'relu' ) ( deep)
deep = tf. keras. layers. Dense( 64 , activation= 'relu' ) ( deep)
concat_layer = tf. keras. layers. concatenate( [ product_layer_item_user, product_layer_item_genre_user_genre,
product_layer_item_genre_user, product_layer_user_genre_item, deep] , axis= 1 )
output_layer = tf. keras. layers. Dense( 1 , activation= 'sigmoid' ) ( concat_layer)
model = tf. keras. Model( inputs, output_lay)
在构建FM部分的时候,先为FM部分选择了4个用于交叉的类别型特征,分别是用户ID、电影ID、用户喜欢的风格和电影自己的风格。接着使用Dot layer把用户特征和电影特征两两交叉,这就完成了FM部分的构建。 Deep部分的实现,其实和之前Wide&Deep模型的Deep部分完全一样。只不过最终使用concatenate层,去把FM部分的输出和Deep部分的输出连接起来,输入到输出层的sigmoid神经元,从而产生最终的预估分数。