1 背景说明
对于一个基于CTR预估的推荐系统,最重要的是学习到用户点击行为背后隐含的特征组合。在不同的推荐场景中,低阶组合特征或者高阶组合特征可能都会对最终的CTR产生影响。
人工方式的特征工程,通常有两个问题:(1)特征爆炸。以通常使用的Poly-2模型为例,该模型采用直接对2阶特征组合建模来学习它们的权重,这种方式构造的特征数量跟特征个数乘积相关,例如:加入某类特征有1万个可能的取值(如APP),另一类特征也有1万个可能的取值(如用户),那么理论上这两个特征组合就会产生1亿个可能的特征项,引起特征爆炸的问题;如果要考虑更高阶的特征,如3阶特征,则会引入更高的特征维度,比如第三个特征也有1万个(如用户最近一次下载记录),则三个特征的组合可能产生10000亿个可能的特征项,这样高阶特征基本上无法有效学习。(2)大量重要的特征组合都隐藏在数据中,无法被专家识别和设计。
实现特征的自动组合的挖掘,就成为推荐系统技术的一个热点研究方向,深度学习作为一种先进的非线性模型技术在特征组合挖掘方面具有很大的优势。
针对上述两个问题,广度模型和深度模型提供了不同的解决思路。
深度学习是通过神经网络结构和非线性激活函数,自动学习特征之间复杂的组合关系。目前在APP推荐领域中比较流行的深度模型有FNN/PNN/Wide&Deep;
FNN模型是用FM模型来对Embedding层进行初始化的全连接神经网络。PNN模型则是在Embedding层和全连接层之间引入了内积/外积层,来学习特征之间的交互关系。Wide&Deep模型由谷歌提出,将LR和DNN联合训练,在Google Play取得了线上效果的提升。
但目前的广度模型和深度模型都有各自的局限。广度模型(LR/FM/FFM)一般只能学习1阶和2阶特征组合;而深度模型(FNN/PNN)一般学习的是高阶特征组合。在之前的举例中可以看到无论是低阶特征组合还是高阶特征组合,对推荐效果都是非常重要的。Wide&Deep模型依然需要人工特征工程来为Wide模型选取输入特征。
DeepFM模型结合了广度和深度模型的有点,联合训练FM模型和DNN模型,来同时学习低阶特征组合和高阶特征组合。此外,DeepFM模型的Deep component和FM component从Embedding层共享数据输入,这样做的好处是Embedding层的隐式向量在(残差反向传播)训练时可以同时接受到Deep component和FM component的信息,从而使Embedding层的信息表达更加准确而最终提升推荐效果。DeepFM相对于现有的广度模型、深度模型以及Wide&Deep, DeepFM模型的优势在于:
- DeepFM模型同时对低阶特征组合和高阶特征组合建模,从而能够学习到各阶特征之间的组合关系
- DeepFM模型是一个端到端的模型,不需要任何的人工特征工程
下面我们就来探索下DeepFM的原理。
2 模型原理及理解
2.1 DeepFM整体结构图
先来了解下DeepFM整体的结构图:
可以将结构分为两部分:(1)FM部分$y{FM}$;(2)DNN部分$y{DNN}$;这两部分共享相同的Embedding输入;最终的prediction为:
$y{FM}$和$y{DNN}$分别为FM部分、DNN部分的输出。再分别来看下FM和DNN部分。
2.2 FM部分
FM部分的结构如下图所示:
FM部分的输出结果为:
FM部分比较简单,没什么好说的。
2.3 DNN部分
DNN部分的结构如下图所示:
如上图所示,DNN部分是一个前向神经网络,用来学习高阶交叉特征。其中的一个核心思想还是利用Embedding将稀疏的输入特征用稠密的隐向量来表示。
Embedding Layer的数据在进入DNN之前,有两个比较有意思的特点:(1)不同的输入field长度可能不一样,但是它们对应的Embeddings大小却是一样的,都是$(k)$;(2)FM中的隐向量$(V)$用作输入的权重。Embedding数据在进入DNN之前的处理如下图所示:
每一个Field的输出结果为$e_i$,整个Embedding的输出就是将所有Field的数据做拼接:
那么,将$a^{(0)}$就是最终DNN的输入,整个DNN前向处理过程为:
最终DNN层的输出为:
文中反复强调了一点:FM部分和DNN部分共享相同的feature Embedding,这么做有两点好处:(1)这样能同时学习到低阶和高阶交叉特征;(2)不在像Wide&Deep模型中那样,需要人为处理特征工程。
2.4 与其他基于DNN模型的比较
作者同时比较了DeepFM与其他基于DNN的模型的比较:
从上图中可以看出,DeepFM是唯一一个不需要pre-training、不需要特征工程、能同时考虑低阶和高阶交叉特征的模型!
2.5 实验和实现
实现和实验部分通常来说不怎么重要,不用看就知道作者提出的模型肯定是要秒杀之前的模型的,但是从作者的实现中,能提炼出一些实验经验,今后为我所用。
(1)激活函数
通常来讲,Relu和tanh要比sigmoid更适合deep model,这篇文章中,通过实验,最终表明Relu是最合适的激活函数,可能的原因是Relu能够使得模型稀疏,同输入的稀疏数据保持一致。
(2)Dropout
一定要用Dropout,这是共识,对不同的模型,dropout值可能不一样,大概在$[0.6, 0.9]$之间。
(3)每层神经元个数
增加神经元个数肯定会带来模型复杂度的提升,同时神经元个数越多,模型越有可能过拟合,样本也要求更多,但是并不是神经元个数越多,模型性能就越好。在实验中,作者认为每层200或者400个神经元是个比较好的选择。
(4)隐层层数
作者通过实验指出,模型性能最开始随着隐层层数的增加,性能提升;超过一定范围,再增加隐层层数,模型性能下降,当然是由于过拟合。
(5)模型形状
作者比较了固定大小的网络形状(每层神经元个数200-200-200),递增的网络形状(每层神经元个数100-200-300),递减的网络形状(每层神经元个数300-200-100),钻石形状网络(每层神经元个数150-300-150),结果表明,固定大小形状的网络效果更好一些。
2.6 实验结果
最终模型的性能如下图所示:
2.7 开源实现
已经有人给出了基于tensorflow的开源实现,想要快速验证的,就不需要重复造轮子啦!https://github.com/Johnson0722/CTR_Prediction/tree/master
3 总结
这篇文章,最主要的创新点在于以下两点:(1)FM和DNN部分共享feature Embedding;(2)完全不需要做人工特征工程。