三句话看透DeepFM,论文链接,发表于2017年。
Wide&Deep中Wide侧还需要人工构造特征交叉,而DeepFM在Wide侧用一个FM模型替换了LR,能够自动学习到所有二次交叉项的系数。
先来看一下DeepFM的模型结构:
DeepFM包含两部分:神经网络部分与因子分解机部分,分别负责低阶特征的提取和高阶特征的提取。这两部分共享同样的输入。DeepFM的预测结果可以写为:
模型结构:
FM部分是一个因子分解机。关于因子分解机可以参阅文章[Rendle, 2010] Steffen Rendle. Factorization machines. In ICDM, 2010.。因为引入了隐变量的原因,对于几乎不出现或者很少出现的隐变量,FM也可以很好的学习。
深度部分是一个前馈神经网络。与图像或者语音这类输入不同,图像语音的输入一般是连续而且密集的,然而用于CTR的输入一般是及其稀疏的。因此需要重新设计网络结构。具体实现中为,在第一层隐含层之前,引入一个嵌入层来完成将输入向量压缩到低维稠密向量。
嵌入层(embedding layer)的结构如上图所示。当前网络结构有两个有趣的特性,1)尽管不同field的输入长度不同,但是embedding之后向量的长度均为K。2)在FM里得到的隐变量Vik现在作为了嵌入层网络的权重。
这里的第二点如何理解呢,假设我们的k=5,首先,对于输入的一条记录,同一个field 只有一个位置是1,那么在由输入得到dense vector的过程中,输入层只有一个神经元起作用,得到的dense vector其实就是输入层到embedding层该神经元相连的五条线的权重,即vi1,vi2,vi3,vi4,vi5。这五个值组合起来就是我们在FM中所提到的Vi。在FM部分和DNN部分,这一块是共享权重的,对同一个特征来说,得到的Vi是相同的。
标签:
点击的label为1,其他为0。预测的结果,也即是网络的输出为用户点击的概率,也就是标签为1的概率。
损失函数:
logloss,文中没有写出来logloss的公式,在实验阶段,对比的时候,有不同算法之间losloss的对比。
搜索了一下,看着chenglongchen大佬的代码比较受欢迎,哈哈,围观下。
FM 一阶部分:我们知道FM中有wx一项,这里是一阶特征,下面是计算wx的结果。
def first_order_part(self, sparse_id, sparse_value):
with tf.variable_scope("first-order"):
W = tf.get_variable("weight",(self.feature_size, 1), \
initializer=tf.random_normal_initializer(0.0, 0.01))
y_first_order = tf.nn.embedding_lookup(W, sparse_id) # None * F * 1
y_first_order = tf.reduce_sum(tf.multiply(y_first_order, \
sparse_value), 1) # None * 1
return y_first_order
FM二阶部分:可以看作两项,第一部分就是“和平方”,第二部分就是“平方和”。代码就是公式的直译。
那我们先看看公式:
def second_order_part(self, sparse_id, sparse_value):
with tf.variable_scope("second-order"):
V = tf.get_variable("weight",(self.feature_size, self.factor_size),
initializer=tf.random_normal_initializer(0.0, 0.01))
self.embeddings = tf.nn.embedding_lookup(V, sparse_id)
# None * F * K
self.embeddings = tf.multiply(self.embeddings, sparse_value)
# 平方和:None * K
sum_squared_part = tf.square(tf.reduce_sum(self.embeddings, 1))
# 和平方:None * K
squared_sum_part = tf.reduce_sum(tf.square(self.embeddings), 1)
y_second_order = 0.5 * tf.subtract(sum_squared_part, \
squared_sum_part)
return y_second_order
def deep_part(self):
with tf.variable_scope("deep-part"):
y_deep = tf.reshape(self.embeddings, shape=[-1, \
self.field_size * self.factor_size]) # None * (F*K)
for i in range(0, len(self.deep_layers)):
y_deep = tf.contrib.layers.fully_connected(y_deep, \
self.deep_layers[i], activation_fn= \
self.deep_layers_activation, scope = 'fc%d' % i)
return y_deep
def forward(self, sparse_id, sparse_value):
sparse_value = tf.expand_dims(sparse_value, -1)
y_first_order = self.first_order_part(sparse_id, sparse_value)
y_second_order = self.second_order_part(sparse_id, sparse_value)
y_deep = self.deep_part()
with tf.variable_scope("deep-fm"):
deep_out = tf.concat([y_first_order, y_second_order, y_deep], axis=1)
deep_out = tf.contrib.layers.fully_connected(deep_out, 1, \
activation_fn=tf.nn.sigmoid, scope = 'deepfm_out')
return tf.reduce_sum(deep_out, axis=1)
(1)dropout: 0.5;
(2) network structure: 400-400-400;
(3) optimizer: Adam;
(4) activation function: tanh for IPNN, relu for other deep models.
To be fair, our proposed DeepFM uses the same setting. The optimizers of LR and FM are FTRL and Adam respectively, and the latent dimension of FM is 10.
通过第一节,大家了解到推荐其实是特征利用的一种博弈。 现在就通过特征利用程度介绍下DeepFM与其它算法的区别:
逻辑回归(LR): 更多考虑线性特征,缺少特征交叉性和高阶特征
DNN: 考虑了高阶特征,缺少了对于低阶特征的考虑
CNN: 考虑近邻特征的关系。 较单一,适合图片分类
RNN: 考虑更多的是数据时序性,较单一
FM: 考虑更多低阶特征,缺少高阶特征
Wide&Deep: 同时考虑了低阶特征和高阶特征,但是低阶特征需要手动交叉生成,对用户不友好
DeepFM: 兼顾了低阶和高阶特征,且计算过程中不需要用户干预;
优点:
1.DeepFM将Wide&Deep的Wide部分的LR换成了FM,能更好地更新V_i,V_j(无需二者同时出现再一个record中再更新参数);
2.DeepFM无需人为的构建专家特征,能同时学习低阶和高阶的特征,达到的效果也是当时最好的;和一些早期的其他算法比较,无需任何初始化;
缺点:
2.DeepFM对于特征的交叉处理是否可以细化,过多的组合会带来很多不必要的冗余;
其他点:
Wide & Deep模型已经为模型带来了非常大的提升,同时也考虑了模型的低阶的交叉和高阶的交叉,从全局看上去已经做得非常好了,但是一旦使用Deep的方式我们就需要考虑到下面几个问题:
我们的Embedding是否学习的好(做过nlp的朋友都有这样的体验,使用预训练的embedding一般都会有帮助),所以embedding的学习是非常重要的;
因为全局上看,基本框架已经很不错了,那么细节的处理能否更加完善呢,比如Wide的左侧可以认为是人为的专家组合之后加入LR的模式,能否融入其他的形式,例如我们之前用的FM,FFM;
能否使我们的模型更加自动化,如何实现端到端的学习预测也是经常会考虑的。
参考:
0.论文链接:https://arxiv.org/pdf/1703.04247.pdf
1.原理及实现:https://www.cnblogs.com/wkang/p/9881921.html
2.原理及实现:https://www.jianshu.com/p/6f1c2643d31b
3.滴滴同学的讲解含代码:https://www.infoq.cn/article/0vXxt3_WwTHyNOo7Lrca
4.chenglongchen大佬代码github:https://github.com/ChenglongChen/tensorflow-DeepFM/blob/master/DeepFM.py
5.分层次代码:https://zhuanlan.zhihu.com/p/32563337