【DNN】DeepFM原理及源码

1、总结

三句话看透DeepFM,论文链接,发表于2017年。

Wide&Deep中Wide侧还需要人工构造特征交叉,而DeepFM在Wide侧用一个FM模型替换了LR,能够自动学习到所有二次交叉项的系数

  • 关键在于Deep侧与Wide侧共享一个embedding矩阵来映射categorical/id特征到稠密向量
  • Deep侧将embedding结果喂入DNN,来学习深层交互的权重,着重“扩展”
  • Wide侧将embedding结果喂入FM,来学习二次交互的权重,着重“记忆”

2.DeepFM模型:

先来看一下DeepFM的模型结构:

DeepFM包含两部分:神经网络部分与因子分解机部分,分别负责低阶特征的提取和高阶特征的提取。这两部分共享同样的输入。DeepFM的预测结果可以写为:

FM部分

模型结构:

FM部分是一个因子分解机。关于因子分解机可以参阅文章[Rendle, 2010] Steffen Rendle. Factorization machines. In ICDM, 2010.。因为引入了隐变量的原因,对于几乎不出现或者很少出现的隐变量,FM也可以很好的学习。

Deep部分

深度部分是一个前馈神经网络。与图像或者语音这类输入不同,图像语音的输入一般是连续而且密集的,然而用于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的对比。

3代码阅读注释:

搜索了一下,看着chenglongchen大佬的代码比较受欢迎,哈哈,围观下。

FM部分

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

Deep 部分:

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

Deep + FM

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)

 

4.其他

参数:

(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与其它算法的比较

通过第一节,大家了解到推荐其实是特征利用的一种博弈。 现在就通过特征利用程度介绍下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的方式我们就需要考虑到下面几个问题:

  1. 我们的Embedding是否学习的好(做过nlp的朋友都有这样的体验,使用预训练的embedding一般都会有帮助),所以embedding的学习是非常重要的;

  2. 因为全局上看,基本框架已经很不错了,那么细节的处理能否更加完善呢,比如Wide的左侧可以认为是人为的专家组合之后加入LR的模式,能否融入其他的形式,例如我们之前用的FM,FFM;

  3. 能否使我们的模型更加自动化,如何实现端到端的学习预测也是经常会考虑的。

 

参考:

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
DeepFM模型调参需要注意以下几点: 1. 学习率(learning rate):学习率控制模型参数更新的速度,在训练过程中需要适当调整学习率大小,过小可能导致收敛速度慢,过大可能导致无法收敛。 2. 正则化(regularization):正则化可以防止模型过拟合,可以使用L1正则化和L2正则化来约束模型参数。 3. Embedding维度(embedding dimension):Embedding维度表示将高维离散特征映射到低维稠密向量的维度,需要根据数据的稀疏程度和特征的重要性进行调整。 4. Batch大小(batch size):Batch大小表示每次迭代使用的样本数量,过小可能导致梯度估计不准确,过大可能导致内存不足。通常需要根据数据量和计算资源进行选择。 5. 迭代次数(epoch):迭代次数表示模型训练的轮数,需要根据模型在验证集上的性能进行选择,避免过拟合或欠拟合。 6. 激活函数(activation function):DeepFM模型中的DNN部分使用了多个隐藏层,每个隐藏层都可以选择不同的激活函数,常用的有ReLU、Sigmoid和Tanh等。不同的激活函数对模型的性能有影响,需要进行尝试和比较。 7. Dropout:Dropout可以在训练过程中随机丢弃一些神经元,以减少过拟合的风险。可以尝试不同的Dropout概率来优化模型性能。 8. 批标准化(Batch Normalization):批标准化可以加速模型训练,提高模型的收敛速度,并且有一定的正则化效果。需要根据模型表现进行选择是否使用批标准化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值