论文原文:
论文地址:https://arxiv.org/pdf/1703.04247.pdf
论文题目:《DeepFM: A Factorization-Machine based Neural Network for CTR Prediction》
一 、背景
特征的组合交叉
对于基于CTR预估的推荐系统,特征的组合交叉对整个模型的性能和准确率提升的意义是非常大的。在输入的特征中,低阶特征组合和高阶特征组合在不同的推荐任务中发挥着不同的作用,让特征更好地进行交互能让模型学习到用户的隐藏兴趣。
特征交叉,可以想到用内积,外积等操作来对两个特征进行组合,在FM(Factorization Machines)中,特征的交叉通过对于每一维特征的隐变量内积来提取特征组合。其实FM只是简单的进行来二阶特征的交叉,但是由于业务,场景复杂性的要求,我们需要对高阶特征组合进行建模,在推荐系统中特征处理是最重要的部分之一了,如果能把特征处理好,那么一个模型就能在准确率上达到理想的水平。
特征的交互,自然而然的联想到了用DNN,把特征输入到DNN中进行自动交互,但是这样低阶特征和高阶特征就都在DNN隐层体现了,但是我们想自己把低阶特征的交互跟DNN中的高阶特征分开怎么办?
ps:图均来自于张俊林老师AI大会 ps:图均来自于张俊林老师AI大会我们怎么将这两部分进行组合呢?
ps:图均来自于张俊林老师AI大会可以把这两部分并行操作,也可以进行串行操作:
ps:图均来自于张俊林老师AI大会 ps:图均来自于张俊林老师AI大会其实并行的很好理解,但是串行的个人无法理解,要把低阶特征跟高阶特征分开,那么并行的结构中,低阶特征经过FM后再输入到DNN中不还是把低阶特征和高阶特征都在DNN隐层中了吗?
二、模型结构
整个DeepFM分为两部分,两部分共享embedding层,一部分得到FM的结果,另一部分得到DNN的结果,最终的结果是两部分结果的和:
FM部分
<w, x>是一次项,后面是二次项,这里乍一看会觉得yFM的输出是一个值,其实不是,看DeepFm源码可以知道,一次项跟二次项得到的都是向量,后面会稍微讲一下为什么这里的输出是向量。
FM公式推导:
前面也说了DNN部分跟FM部分是共享embedding层的,所以公式中的v就是one-hot经过embedding后得到的向量。公式中的x是特征的值,如果是离散的特征,那么x就是1,如果特征是连续特征,那么x就是整个特征本身的值。
举个例子 比如特征是 男/女 星期 工资
这里有三组特征,或者说3个field的特征,分别是性别、星期几、工资。对应的特征数量分别为2、7、1。我们总的特征数量feature-size为2 + 7 + 1=10。如果转换为one-hot的话,每一个取值都会对应一个特征索引feature-index。
男 ->0, 女->1, 周一->2,周二->3,周三->4,周四->5,周五->6, 周六->7,周日->8,工资->9
那么如果有一个输入特征:男,周三,工资5000
对应的feature-index就是 0,4,9
在FM中每一个feature都对应着一个feature-value,就是公式里面的x,离散特征的feature-value是1,连续特征的feature-value是值本身
接着上面的例子,
这个输入特征的feature-value 就是 1,1,5000
有了feature-index,就可以得到对应的Vi了,其实就是去embedding矩阵里面按照index去找对应的向量。
现在Vi,x都有了,就可以进行FM的运算了.
假设embedding size大小为3,batch_size为2
batch[0] :特征 男 周一 5000
batch[1]:特征 女 周二 6000
embedding矩阵: [ [0.1, 0.2, 0.3], [0.2, 0.3, 0.1 ], [0.3, 0.2, 0.1],[0.3, 0.1, 0.2], ... , [0.1, 0.1, 0.1] ]
依然举个例子,根据上面FM公式的推导,计算如下:
batch[0] 经过embedding后变成
[0.1, 0.2, 0.3] -----------------feature-value :1
[0.3, 0.2, 0.1] -----------------feature-value :1
[0.1, 0.1, 0.1] -----------------feature-value :5000
batch[1] 经过embedding后变成
[0.2, 0.3, 0.1 ]-----------------feature-value :1
[0.3, 0.1, 0.2]-----------------feature-value :1
[0.1, 0.1, 0.1] -----------------feature-value :5000
计算FM的第一部分(先乘feature-value,后求和再平方)
(1)乘feature-value,2✖️3✖️3
batch[0] 变成:
[0.1, 0.2, 0.3]
[0.3, 0.2, 0.1]
[500, 500, 500]
batch[1] 变成:
[0.2, 0.3, 0.1 ]
[0.3, 0.1, 0.2]
[600, 600, 600]
(2)求和 2✖️3
沿axis = 1求和
batch[0] 变成:
[500.4, 500.4, 500.4]
batch[1] 变成:
[600.5, 600.4, 600.3]
(3)平方 2✖️3
batch[0] 变成:
[250400.16, 250400.16, 250400.16]
batch[1] 变成:
[360600.25, 360380.16, 360360.09]
计算FM的第二部分(先乘feature-value,后平方再求和)
(1)乘feature-value,2✖️3✖️3
batch[0] 变成:
[0.1, 0.2, 0.3]
[0.3, 0.2, 0.1]
[500, 500, 500]
batch[1] 变成:
[0.2, 0.3, 0.1 ]
[0.3, 0.1, 0.2]
[600, 600, 600]
(2)平方 2✖️3✖️3
batch[0] 变成:
[0.01, 0.04, 0.09]
[0,09, 0.04, 0.01]
[250000, 250000, 250000]
batch[1] 变成:
[0.04, 0.09, 0.01]
[0.09, 0.01, 0.04]
[360000, 360000, 360000]
(3)求和 2✖️3
batch[0] 变成:
[250000.10, 250000.08, 250000.10]
batch[1] 变成:
[360000.13, 360000.10, 360000.05]
FM第一部分减第二部分 2✖️3
batch[0] 变成:
[250400.16, 250400.16, 250400.16] - [250000.10, 250000.08, 250000.10] = [400.06, 400.08, 400.06]
batch[1] 变成:
[360600.25, 360380.16, 360360.09] - [360000.13, 360000.10, 360000.05] = [600.12, 600.06, 600. 04]
FM输出
batch[0] 沿着横轴求sum,变成:
[400.06+400.08+400.06] = [1200.20]
batch[1] 沿着横轴求sum,变成:
[600.12+600.06+600. 04] = [1800.22]
至此,我们一经把FM部分计算完成.
总体来看,FM的输入是batch*field*emb_size,输出是bacth*1
DNN部分
这里就不深入介绍DNN了,就是输入one-hot,转化为embedding后进行MLP层,输出一个向量yDNN
output层
之前我们得到yFM和yDNN都是向量,但是原论文里把他们当成了标量了,其实意思是一样的,把他们当成标量的意思是各自得到一个分数后求和并进行sigmoid,把他们当成向量的意思就是concat后直接送sigmoid,这也是代码与原论文不一样的地方,但是结果是一样的。
三、实验结果
DeepFM不愧是ctr预估的神,一出来就领先其他传统的模型,很多小公司在自己数据集不是很大的情况下,都是直接上的DeepFM模型进行调参,在自己数据量上去并且理解了自己的业务后才逐渐从DeepFM模型转换出来。而且,这种双塔模型是工业界特别喜欢用的模型,模型简单不复杂,线上ctr高,性能好,属实是万能的模型。
网友评论