CTR 系列文章:
- 广告点击率(CTR)预测经典模型 GBDT + LR 理解与实践(附数据 + 代码)
- CTR经典模型串讲:FM / FFM / 双线性 FFM 相关推导与理解
- CTR深度学习模型之 DeepFM 模型解读
- 【CTR模型】TensorFlow2.0 的 DeepFM 实现与实战(附代码+数据)
- CTR 模型之 Deep & Cross (DCN) 与 xDeepFM 解读
- 【CTR模型】TensorFlow2.0 的 DCN(Deep & Cross Network) 实现与实战(附代码+数据)
- 【CTR模型】TensorFlow2.0 的 xDeepFM 实现与实战(附代码+数据)
本篇文章讲解 CTR 经典模型 Deep & Cross (DCN) 与 xDeepFM,之所以把这两个模型放一起讲是因为它们有很近的“血缘关系”。理解了 DCN 的思想,再去理解 xDeepFM 就不觉得困难了。
以下文章对这两个模型的讲解很到位:
首先了解揭秘 Deep & Cross : 如何自动构造高阶交叉特征
推荐系统遇上深度学习(二十二)–DeepFM升级版XDeepFM模型强势来袭!
xDeepFM:名副其实的 ”Deep” Factorization Machine
因此,本文主要是对上述文章内容的梳理。
Deep & Cross (DCN)
首先来看看网络结构:

首先来看看网络的输入部分。元素特征需要做如下处理:
-
对sparse特征进行embedding,对于multi-hot的sparse特征,embedding之后再做一个简单的average pooling;
-
对dense特征归一化,然后和embedding特征拼接,作为随后Cross层与Deep层的共同输入:
x 0 = [ x e m b e d , 1 T , x e m b e d , 2 T , . . . x e m b e d , k T , x d e n s e T ] T x_0 = [x^T_{embed, 1},x^T_{embed, 2},...x^T_{embed, k},x^T_{dense}]^T x0=[xembed,1T,xembed,2T,...xembed,kT,xdenseT]T
接下来看看 Cross 部分。
上图中模型的左半部分是包含了许多层的 Cross network,目标是以显式、可控、高效的方式自动构建有限高阶交叉特征。其中第 l + 1 l + 1 l+1 层的计算过程为:

x
l
+
1
=
f
(
x
l
,
w
l
,
b
l
)
+
x
l
=
x
0
x
l
T
w
l
+
b
l
+
x
l
x_{l+1} = f(x_l, w_l, b_l)+x_l =x_0x^T_lw_l + b_l + x_l
xl+1=f(xl,wl,bl)+xl=x0xlTwl+bl+xl
其中,
x
l
+
1
,
x
l
,
x
0
x_{l+1}, x_l, x_0
xl+1,xl,x0 是 d 维向量。计算过程有两个特点:
- 输出神经元个数与输入网络的 x 0 x_0 x0 维度相同;
- 每一层的 f f f 都是在拟合 x l + 1 − x l x_{l+1} - x_l xl+1−xl 的残差,这样可以减缓梯度消失问题,使得网络更深。
为什么这么设计呢?先看一些计算的例子:
假设 Cross 网络有两层,
x
0
=
[
x
0
,
1
x
0
,
2
]
T
x_0 = [x_{0, 1} x_{0, 2}]^T
x0=[x0,1x0,2]T,为方便讨论令
b
i
=
0
b_i = 0
bi=0,则有:
x
1
=
x
0
x
0
T
w
0
+
x
0
=
[
x
0
,
1
x
0
,
2
]
[
x
0
,
1
,
x
0
,
2
]
[
w
0
,
1
w
0
,
2
]
+
[
x
0
,
1
x
0
,
2
]
=
[
w
0
,
1
x
0
,
1
2
+
w
0
,
2
x
0
,
1
x
0
,
2
+
x
0
,
1
w
0
,
1
x
0
,
2
x
0
,
1
+
w
0
,
2
x
0
,
2
2
+
x
0
,
2
]
\begin{aligned} \boldsymbol{x}_{1} &=\boldsymbol{x}_{0} \boldsymbol{x}_{0}^{T} \boldsymbol{w}_{0}+\boldsymbol{x}_{0}=\left[\begin{array}{c} x_{0,1} \\ x_{0,2} \end{array}\right]\left[x_{0,1}, x_{0,2}\right]\left[\begin{array}{c} w_{0,1} \\ w_{0,2} \end{array}\right]+\left[\begin{array}{c} x_{0,1} \\ x_{0,2} \end{array}\right]=\left[\begin{array}{c} w_{0,1} x_{0,1}^{2}+w_{0,2} x_{0,1} x_{0,2}+x_{0,1} \\ w_{0,1} x_{0,2} x_{0,1}+w_{0,2} x_{0,2}^{2}+x_{0,2} \end{array}\right] \\ \end{aligned}
x1=x0x0Tw0+x0=[x0,1x0,2][x0,1,x0,2][w0,1w0,2]+[x0,1x0,2]=[w0,1x0,12+w0,2x0,1x0,2+x0,1w0,1x0,2x0,1+w0,2x0,22+x0,2]
进而有:
x
2
=
x
0
x
1
T
w
1
+
x
1
=
[
w
1
,
1
x
0
,
1
x
1
,
1
+
w
1
,
2
x
0
,
1
x
1
,
2
+
x
1
,
1
w
1
,
1
x
0.2
x
1
,
1
+
w
1
,
2
x
0
,
2
x
1
,
2
+
x
1
,
2
]
=
[
w
0
,
1
w
1
,
1
z
0
,
1
3
+
(
w
0
,
2
w
1
,
1
+
w
0
,
1
w
1
,
2
)
x
0
,
1
2
x
0
,
2
+
w
0
,
2
w
1
,
2
x
0
,
1
x
0
,
2
2
+
(
w
0
,
1
+
w
1
,
1
)
x
0
,
1
2
+
(
w
0
,
2
+
w
1
,
2
)
x
0
,
1
z
0
,
2
+
x
0
,
1
⋅
⋅
⋅
⋅
⋅
⋅
⋅
]
\begin{aligned} x_{2}=& x_{0} x_{1}^{T} w_{1}+x_{1} \\ =&\left[\begin{array}{c} w_{1,1} x_{0,1} x_{1,1}+w_{1,2} x_{0,1} x_{1,2}+x_{1,1} \\ w_{1,1} x_{0.2} x_{1,1}+w_{1,2} x_{0,2} x_{1,2}+x_{1,2} \\ \end{array}\right] \\ =& \left[\begin{array}{c} {w_{0,1} w_{1,1} z_{0,1}^{3}+\left(w_{0,2} w_{1,1}+w_{0,1} w_{1,2}\right) x_{0,1}^{2} x_{0,2}+w_{0,2} w_{1,2} x_{0,1} x_{0,2}^{2}+\left(w_{0,1}+w_{1,1}\right) x_{0,1}^{2}+\left(\operatorname{w}_{0,2}+w_{1,2}\right) x_{0,1} z_{0,2}+x_{0,1}} \\ \cdot \cdot \cdot \cdot \cdot \cdot \cdot \end{array}\right] \end{aligned}
x2===x0x1Tw1+x1[w1,1x0,1x1,1+w1,2x0,1x1,2+x1,1w1,1x0.2x1,1+w1,2x0,2x1,2+x1,2][w0,1w1,1z0,13+(w0,2w1,1+w0,1w1,2)x0,12x0,2+w0,2w1,2x0,1x0,22+(w0,1+w1,1)x0,12+(w0,2+w1,2)x0,1z0,2+x0,1⋅⋅⋅⋅⋅⋅⋅]
可以看到
x
1
x_1
x1 包含了从一阶到二阶所有的可能交叉组合,而
x
2
x_2
x2 包含了从一阶到三阶的所有可能交叉组合,并且有下面的特点:
- 有限高阶:交叉的阶数由层数决定,深度 L c L_c Lc 具最高有 L c + 1 L_c + 1 Lc+1 阶的交叉特征;
- 参数线性增长:模型参数数量与输入维度成线性增长关系: 2 × d × L c 2\times d \times L_c 2×d×Lc;
- 参数共享:并不是每个交叉组合都具有独立的权重参数,而是共享了 2 × d × L c 2\times d \times L_c 2×d×Lc 个权重参数。参数共享机制使得模型具有更强的泛化性和鲁棒性。
这里对第三点加以解释:如果每个交叉特征有独立的参数,那么当训练样本中某个交叉特征 x i x j x_i x_j xixj 没有出现,那么此交叉特征的权重参数就是 0 。而参数共享的情况下,权重几乎不可能是 0,并且对于一些噪声数据也可以由大部分正常样本来纠正参数的学习。
要注意的是,输入的 x 0 x_0 x0 是在 embedding 之后得到的,后续的交叉也是对 embedding 后的数值进行交叉。直接将 sparse 特征输入网络进行交叉才是最合理的做法,但是这么做的话参数过多,所以先进行一次 embedding 操作,这实际上也是一种 trade-off。
其他的 DNN 部分和输出的部分都比较好理解,这里就不多做叙述了。
xDeepFM
我第一次看到 xDeepFM 以为是 DeepFM 的改进版本,后来才发现他更像是在 DCN 的基础上改进的。
在正式讲解之前,先了解下什么是 bit-wise 什么是vector-wise:
假设隐向量的维度为3维,如果两个特征(对应的向量分别为(a1,b1,c1)和(a2,b2,c2)的话)在进行交互时,交互的形式类似于f(w1 * a1 * a2,w2 * b1 * b2 ,w3 * c1 * c2)的话,此时我们认为特征交互是发生在元素级(bit-wise)上。如果特征交互形式类似于 f(w * (a1 * a2 ,b1 * b2,c1 * c2))的话,那么我们认为特征交互是发生在特征向量级(vector-wise)。
对于包括 DCN 在内的许多模型在构造交叉特征时,都是以 bit-wise 的方式进行特征组合,而FM是以向量为最细粒度学习相关性,即vector-wise。xDeepFM的动机,正是将 FM 的 vector-wise 思想引入Cross部分。
下图是 xDeepFM 的整体结构:

模型的输入部分与 DCN 类似,本节重点讲解 CIN 部分,如下图所示:

CIN 的输入来自 embedding 层,假设有 m 个 field,每个 field 的 embedding 维度为 D ,则输入可以表示为矩阵 X 0 ∈ R m ∗ D X^0 \in \mathbb R^{m * D} X0∈Rm∗D。
CIN 内部有 k 层,每一层都会输出一个矩阵
X
k
∈
R
H
k
∗
D
X^k \in \mathbb R^{H_k * D}
Xk∈RHk∗D ,k 表示第 k 层的输出,
H
k
H_k
Hk 表示第 k 层有
H
k
H_k
Hk 个维度为 D 的向量。要得到
X
k
X^{k}
Xk ,需要接收两个矩阵作为输入,一个是
X
k
−
1
X^{k-1}
Xk−1 ,另一个是
X
0
X^0
X0 ,具体的计算公式如下:
X
h
,
∗
k
=
∑
i
=
1
H
k
−
1
∑
j
=
1
m
W
i
j
k
,
h
(
X
i
,
∗
k
−
1
∘
X
j
,
∗
0
)
∈
R
1
∗
D
,
where
1
≤
h
≤
H
k
\boldsymbol{X}_{h, *}^{k}=\sum_{i=1}^{H_{k-1}} \sum_{j=1}^{m} \boldsymbol{W}_{i j}^{k, h}\left(\boldsymbol{X}_{i, *}^{k-1} \circ \boldsymbol{X}_{j, *}^{0}\right) \in \mathbb{R}^{1 * D}, \quad \text { where } 1 \leq h \leq H_{k}
Xh,∗k=i=1∑Hk−1j=1∑mWijk,h(Xi,∗k−1∘Xj,∗0)∈R1∗D, where 1≤h≤Hk
其中
W
k
,
h
∈
R
H
k
−
1
∗
m
W^{k, h} \in \mathbb R^{H_{k-1} * m}
Wk,h∈RHk−1∗m,表示要得到第 k 层第 h 个向量所需要的权重矩阵,
H
k
−
1
H_{k-1}
Hk−1 表示第
k
−
1
k-1
k−1 层的输出矩阵
X
k
−
1
X^{k-1}
Xk−1 由
H
k
−
1
H_{k-1}
Hk−1 个维度为 D 的向量组成。
∘
\circ
∘ 表示Hadamard乘积,即逐元素乘,例如:
<
a
1
,
b
1
,
c
1
>
∘
<
a
2
,
b
2
,
c
2
>
=
<
a
1
b
1
,
a
2
b
2
,
a
3
b
3
>
<a_1, b_1, c_1> \circ <a_2, b_2, c_2> = <a_1b_1, a_2b_2, a_3b_3>
<a1,b1,c1>∘<a2,b2,c2>=<a1b1,a2b2,a3b3>
式子中
X
i
,
∗
k
−
1
∘
X
j
,
∗
0
\boldsymbol{X}_{i, *}^{k-1} \circ \boldsymbol{X}_{j, *}^{0}
Xi,∗k−1∘Xj,∗0 是表示取出
X
k
−
1
X^{k-1}
Xk−1 的第
i
i
i 个向量与输入层
X
0
X^{0}
X0 中第
j
j
j 个向量进行 Hadamard 乘积运算。整个公式的计算过程可以用下图表示:

上面的公式的计算结果只得到了第 h 个向量 X h , ∗ k \boldsymbol{X}_{h, *}^{k} Xh,∗k ,实际上我们会使用 H k H_k Hk 个不同的权重矩阵 W k , h W^{k,h} Wk,h 来获得不同的向量,最后这些向量拼接成输出 X k ∈ R H k ∗ D X^{k} \in \mathbb R^{H_k * D} Xk∈RHk∗D 。
需要注意的是,在第 l l l 层实际上只包含了第 l + 1 l+1 l+1 阶的交叉特征,为了得到不同阶的输出,需要在每一层得到计算结果后通过 sum pooling 进行输出。至于一阶特征,则单独由模型的结构图最左侧的 Linear 模块进行加权求和。最右侧的 DNN 模块比较好理解,就不做解释了。
从计算过程就可以看出此模型的复杂度比较高,需要的参数也比较多,因此训练的时候可能出现过拟合现象,为此可以配合 Droupout 或者其他防止过拟合的方法使用。
7万+



被折叠的 条评论
为什么被折叠?



