对于CTR问题,被证明的最有效的提升任务表现的策略是特征组合(Feature Interaction), 在CTR问题的探究历史上来看就是如何更好地学习特征组合,进而更加精确地描述数据的特点。可以说这是基础推荐模型到深度学习推荐模型遵循的一个主要的思想。而组合特征大牛们研究过组合二阶特征,三阶甚至更高阶,但是面临一个问题就是随着阶数的提升,复杂度就成几何倍的升高。这样即使模型的表现更好了,但是推荐系统在实时性的要求也不能满足了。所以很多模型的出现都是为了解决另外一个更加深入的问题:如何更高效的学习特征组合?
为了解决上述问题,出现了FM和FFM来优化LR的特征组合较差这一个问题。并且在这个时候科学家们已经发现了DNN在特征组合方面的优势,所以又出现了FNN和PNN等使用深度网络的模型。但是DNN也存在局限性。
当我们使用DNN网络解决推荐问题的时候存在网络参数过于庞大的问题,这是因为在进行特征处理的时候我们需要使用one-hot编码来处理离散特征,这会导致输入的维度猛增。以下借用AI大会的图片:
由图1-1可知,这样庞大的参数是不实际的,为了解决DNN参数量过大的局限性,可以采用非常经典的Field思想,将OneHot特征转换为Dense Vector,并通过增加全连接层就可以实现高阶的特征组合,如下图1-2,图1-3所示:
但是这种做法仍然缺少低阶的特征组合,于是增加FM来表示低阶的特征组合。
结合FM和DNN其实有两种方式,可以并行结合也可以串行结合。这两种方式各有几种代表模型。在DeepFM之前有FNN,虽然在影响力上可能并不如DeepFM,但是了解FNN的思想对我们理解DeepFM的特点和优点是很有帮助的。
FNN是使用预训练好的FM模块,得到隐向量,然后把隐向量作为DNN的输入,但是经过实验进一步发现,在Embedding layer和hidden layer1之间增加一个product层(如上图所示)可以提高模型的表现,所以提出了PNN,使用product layer替换FM预训练层。
FNN和PNN模型仍然有一个比较明显的尚未解决的缺点:对于低阶组合特征学习到的比较少,这一点主要是由于FM和DNN的串行方式导致的,也就是虽然FM学到了低阶特征组合,但是DNN的全连接结构导致低阶特征并不能在DNN的输出端较好的表现。看来我们已经找到问题了,将串行方式改进为并行方式能比较好的解决这个问题。于是Google提出了Wide&Deep模型,但是如果深入探究Wide&Deep的构成方式,虽然将整个模型的结构调整为了并行结构,在实际的使用中Wide Module中的部分需要较为精巧的特征工程,换句话说人工处理对于模型的效果具有比较大的影响(这一点可以在Wide&Deep模型部分得到验证)。
如图1-5所示,该模型仍然存在问题:在output Units阶段直接将低阶和高阶特征进行组合,很容易让模型最终偏向学习到低阶或者高阶的特征,而不能做到很好的结合。
综上所示,DeepFM模型横空出世。
通过上图2-5,我们可以发现,其实DeepFM前面的Field、Sparse Features和Dense Embeddings部分与之前的Wide&Deep是一样的(即上图蓝色框部分),Wide部分则DeepFM用FM Layer替代(即上图紫色框部分)。
从上图中大致可以看出FM Layer是由一阶特征和二阶特征Concatenate到一起再经过一个Sigmoid得到logits(结合FM的公式一起看),所以在实现的时候需要单独考虑linear部分和FM交叉特征部分。 y ^ F M ( x ) = w 0 + ∑ i = 1 N w i x i + ∑ i = 1 N ∑ j = i + 1 N v i T v j x i x j \hat{y}{FM}(x) = w_0+\sum_{i=1}^{N} w_ix_i + \sum_{i=1}^N \sum_{j=i+1}^N v_i^T v_j x_ix_j y^FM(x)=w0+i=1∑Nwixi+i=1∑Nj=i+1∑NviTvjxixj
Deep Component是为了学习高阶的特征组合,在上图中使用全连接的方式将Dense Embedding输入到Hidden Layer,这里面Dense Embeddings就是为了解决DNN中的参数爆炸问题,这也是推荐模型中常用的处理方法。
Embedding层的输出是将所有id类特征对应的embedding向量concat到到一起输入到DNN中。其中 v i v_i vi表示第i个field的embedding,m是field的数量。 z 1 = [ v 1 , v 2 , . . . , v m ] z_1=[v_1, v_2, ..., v_m] z1=[v1,v2,...,vm] 上一层的输出作为下一层的输入,我们得到: z L = σ ( W L − 1 z L − 1 + b L − 1 ) z_L=\sigma(W_{L-1} z_{L-1}+b_{L-1}) zL=σ(WL−1zL−1+bL−1) 其中 σ \sigma σ表示激活函数,$z, W, b $分别表示该层的输入、权重和偏置。
最后进入DNN部分输出使用sigmod激活函数进行激活: y D N N = σ ( W L a L + b L ) y_{DNN}=\sigma(W^{L}a^L+b^L) yDNN=σ(WLaL+bL)
嵌入层(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 Layer最左边的节点黄色节点黑色加号+)。文中将FM的预训练V向量作为网络权重初始化替换为直接将FM和DNN进行整体联合训练,从而实现了一个端到端的模型。
DeepFM在模型的结构图中显示,模型大致由两部分组成,一部分是FM,还有一部分就是DNN, 而FM又由一阶特征部分与二阶特征交叉部分组成,所以可以将整个模型拆成三部分,分别是一阶特征处理linear部分,二阶特征交叉FM以及DNN的高阶特征交叉。在下面的代码中也能够清晰的看到这个结构。此外每一部分可能由是由不同的特征组成,所以在构建模型的时候需要分别对这三部分输入的特征进行选择。
1.linear_logits: 这部分是有关于线性计算,也就是FM的前半部分 w 1 x 1 + w 2 x 2... w n x n + b w1x1+w2x2...wnxn+b w1x1+w2x2...wnxn+b的计算。对于这一块的计算,我们用了一个get_linear_logits函数实现。总之通过这个函数,我们就可以实现上面这个公式的计算过程,得到linear的输出。这部分特征由数值特征和类别特征的onehot编码组成的一维向量组成,实际应用中根据自己的业务放置不同的一阶特征(这里的dense特征并不是必须的,有可能会将数值特征进行分桶,然后在当做类别特征来处理)。
2.fm_logits: 这一块主要是针对离散的特征,首先通过embedding,然后使用FM特征交叉的方式,两两特征进行交叉,得到新的特征向量,最后计算交叉特征的logits。
3.dnn_logits: 这一块主要是针对离散的特征,首先通过embedding,然后将得到的embedding拼接成一个向量(具体的可以看代码,也可以看一下下面的模型结构图),通过dnn学习类别特征之间的隐式特征交叉并输出logits值。
def DeepFM(linear_feature_columns, dnn_feature_columns):
# 构建输入层,即所有特征对应的Input()层,这里使用字典的形式返回,方便后续构建模型
dense_input_dict, sparse_input_dict = build_input_layers(linear_feature_columns + dnn_feature_columns)
# 将linear部分的特征中sparse特征筛选出来,后面用来做1维的embedding
linear_sparse_feature_columns = list(filter(lambda x: isinstance(x, SparseFeat), linear_feature_columns))
# 构建模型的输入层,模型的输入层不能是字典的形式,应该将字典的形式转换成列表的形式
# 注意:这里实际的输入与Input()层的对应,是通过模型输入时候的字典数据的key与对应name的Input层
input_layers = list(dense_input_dict.values()) + list(sparse_input_dict.values())
# linear_logits由两部分组成,分别是dense特征的logits和sparse特征的logits
linear_logits = get_linear_logits(dense_input_dict, sparse_input_dict, linear_sparse_feature_columns)
# 构建维度为k的embedding层,这里使用字典的形式返回,方便后面搭建模型
# embedding层用户构建FM交叉部分和DNN的输入部分
embedding_layers = build_embedding_layers(dnn_feature_columns, sparse_input_dict, is_linear=False)
# 将输入到dnn中的所有sparse特征筛选出来
dnn_sparse_feature_columns = list(filter(lambda x: isinstance(x, SparseFeat), dnn_feature_columns))
fm_logits = get_fm_logits(sparse_input_dict, dnn_sparse_feature_columns, embedding_layers) # 只考虑二阶项
# 将所有的Embedding都拼起来,一起输入到dnn中
dnn_logits = get_dnn_logits(sparse_input_dict, dnn_sparse_feature_columns, embedding_layers)
# 将linear,FM,dnn的logits相加作为最终的logits
output_logits = Add()([linear_logits, fm_logits, dnn_logits])
# 这里的激活函数使用sigmoid
output_layers = Activation("sigmoid")(output_logits)
model = Model(input_layers, output_layers)
return model
整体模型结构图
下面是一个通过keras画的模型结构图,为了更好的显示,数值特征和类别特征都只是选择了一小部分
4.1如果对于FM采用随机梯度下降SGD训练模型参数,请写出模型各个参数的梯度和FM参数训练的复杂度。
由上述可知,FM公式为: y ^ ( X ) = ω 0 + ∑ i = 1 n ω i x i + ∑ i = 1 n − 1 ∑ j = i + 1 n ω i j x i x j \hat{y}(X) = \omega_{0}+\sum_{i=1}^{n}{\omega_{i}x_{i}}+\sum_{i=1}^{n-1}{\sum_{j=i+1}^{n} \omega_{ij}{x_{i}x_{j}}} y^(X)=ω0+i=1∑nωixi+i=1∑n−1j=i+1∑nωijxixj
定理:任意一个实对称矩阵(正定矩阵) W W W都存在一个矩阵 V V V,使得 W = V . V T W=V.V^{T} W=V.VT成立。
类似地,所有二次项参数 ω i j \omega_{ij} ωij可以组成一个对称阵 W W W(为了方便说明FM的由来,对角元素可以设置为正实数),那么这个矩阵就可以分解为 W = V T V W=V^TV W=VTV, V V V 的第 j j j列( v j v_{j} vj)便是第 j j j维特征( x j x_{j} xj)的隐向量。
所以FM公式可以写为 y ^ ( X ) = ω 0 + ∑ i = 1 n ω i x i + ∑ i = 1 n − 1 ∑ j = i + 1 n < v i , v j > x i x j \hat{y}(X) = \omega_{0}+\sum_{i=1}^{n}{\omega_{i}x_{i}}+\sum_{i=1}^{n-1}{\sum_{j=i+1}^{n} \color{red}{x_{i}x_{j}}} y^(X)=ω0+i=1∑nωixi+i=1∑n−1j=i+1∑n<vi,vj>xixj
需要估计的参数有 ω 0 ∈ R \omega_{0}∈ R ω0∈R, ω i ∈ R \omega_{i}∈ R ωi∈R, V ∈ R V∈ R V∈R, < ⋅ , ⋅ > < \cdot, \cdot> <⋅,⋅>是长度为 k k k的两个向量的点乘,公式如下:
< v i , v j > = ∑ f = 1 k v i , f ⋅ v j , f= \sum_{f=1}^{k}{v_{i,f}\cdot v_{j,f}} <vi,vj>=f=1∑kvi,f⋅vj,f
∑ i = 1 n − 1 ∑ j = i + 1 n < v i , v j > x i x j = 1 2 ∑ i = 1 n ∑ j = 1 n < v i , v j > x i x j − 1 2 ∑ i = 1 n < v i , v i > x i x i = 1 2 ( ∑ i = 1 n ∑ j = 1 n ∑ f = 1 k v i , f v j , f x i x j − ∑ i = 1 n ∑ f = 1 k v i , f v i , f x i x i ) = 1 2 ∑ f = 1 k [ ( ∑ i = 1 n v i , f x i ) ⋅ ( ∑ j = 1 n v j , f x j ) − ∑ i = 1 n v i , f 2 x i 2 ] = 1 2 ∑ f = 1 k [ ( ∑ i = 1 n v i , f x i ) 2 − ∑ i = 1 n v i , f 2 x i 2 ] \begin{aligned} \sum_{i=1}^{n-1}{\sum_{j=i+1}^{n}{x_ix_j}} &= \frac{1}{2}\sum_{i=1}^{n}{\sum_{j=1}^{n}{ i=1∑n−1j=i+1∑n<vi,vj>xixj=21i=1∑nj=1∑n<vi,vj>xixj−21i=1∑n<vi,vi>xixi=21⎝⎛i=1∑nj=1∑nf=1∑kvi,fvj,fxixj−i=1∑nf=1∑kvi,fvi,fxixi⎠⎞=21f=1∑k[(i=1∑nvi,fxi)⋅(j=1∑nvj,fxj)−i=1∑nvi,f2xi2]=21f=1∑k⎣⎡(i=1∑nvi,fxi)2−i=1∑nvi,f2xi2⎦⎤x_ix_j}} - \frac{1}{2} {\sum_{i=1}^{n}{ x_ix_i}} \\ &= \frac{1}{2} \left( \sum_{i=1}^{n}{\sum_{j=1}^{n}{\sum_{f=1}^{k}{v_{i,f}v_{j,f}x_ix_j}}} - \sum_{i=1}^{n}{\sum_{f=1}^{k}{v_{i,f}v_{i,f}x_ix_i}} \right) \\ &= \frac{1}{2}\sum_{f=1}^{k}{\left[ \left( \sum_{i=1}^{n}{v_{i,f}x_i} \right) \cdot \left( \sum_{j=1}^{n}{v_{j,f}x_j} \right) - \sum_{i=1}^{n}{v_{i,f}^2 x_i^2} \right]} \\ &= \frac{1}{2}\sum_{f=1}^{k}{\left[ \left( \sum_{i=1}^{n}{v_{i,f}x_i} \right)^2 - \sum_{i=1}^{n}{v_{i,f}^2 x_i^2} \right]} \end{aligned}
最后整理可得:
y ^ ( X ) = ω 0 + ∑ i = 1 n ω i x i + 1 2 ∑ f = 1 k [ ( ∑ i = 1 n v i , f x i ) 2 − ∑ i = 1 n v i , f 2 x i 2 ] \hat{y}(X) = \omega_{0}+\sum_{i=1}^{n}{\omega_{i}x_{i}}+\frac{1}{2}\sum_{f=1}^{k}{\left[ \left( \sum_{i=1}^{n}{v_{i,f}x_i} \right)^2 - \sum_{i=1}^{n}{v_{i,f}^2 x_i^2} \right]} y^(X)=ω0+i=1∑nωixi+21f=1∑k⎣⎡(i=1∑nvi,fxi)2−i=1∑nvi,f2xi2⎦⎤
ω 0 \omega_{0} ω0为全局偏置;
ω i \omega_{i} ωi是模型第 i i i个变量的权重;
ω i j = < v i , v j > \omega_{ij} = < v_{i}, v_{j}> ωij=<vi,vj>特征 i i i和 j j j的交叉权重;
v i v_{i} vi是第 i i i维特征的隐向量;
< ⋅ , ⋅ > <\cdot, \cdot> <⋅,⋅>代表向量点积;
所以,参数 ω 0 \omega_{0} ω0的梯度为1, ω i \omega_{i} ωi的梯度为 x i x_{i} xi, v i , f {v_{i,f}} vi,f的梯度为 ∑ f = 1 k ∑ i = 1 n v i , f x i − v i , f x i 2 \sum_{f=1}^{k}\sum_{i=1}^{n}{v_{i,f}x_i}-{v_{i,f}x_i}^2 ∑f=1k∑i=1nvi,fxi−vi,fxi2
4.2对于下图所示,根据你的理解Sparse Feature中的不同颜色节点分别表示什么意思?
由图2-4可知,Spare Features是特征通关One-hot处理完以后的稀疏特征,其中黄色节点为1的节点,蓝色则为0的节点。
DeepFM: A Factorization-Machine based Neural Network for CTR Prediction
FM
DeepCTR
DataWhale
FM算法公式推导
深度推荐模型之DeepFM
详解 Wide & Deep 结构背后的动机
推荐系统遇上深度学习(三)–DeepFM模型理论和实践