CTR预估 论文精读(九)--Deep & Cross Network for Ad Click Predictions

摘要

Feature engineering has been the key to the success of many prediction models. However, the process is nontrivial and often requires manual feature engineering or exhaustive searching. DNNs are able to automatically learn feature interactions; however, they generate all the interactions implicitly, and are not necessarily efficient in learning all types of cross features. In this paper, we propose the Deep & Cross Network (DCN) which keeps the benefits of a DNN model, and beyond that, it introduces a novel cross network that is more efficient in learning certain bounded-degree feature interactions. In particular, DCN explicitly applies feature crossing at each layer, requires no manual feature engineering, and adds negligible extra complexity to the DNN model. Our experimental results have demonstrated its superiority over the state-of-art algorithms on the CTR prediction dataset and dense classification dataset, in terms of both model accuracy and memory usage.

1. DCN(Deep & Cross Network) 介绍

CTR 预估全称是Click Through Rate,就是展示给用户的广告或者商品,估计用户点击的概率。公司规模较大的时候,CTR 直接影响的价值在数十亿美元的级别。广告支付一个非常流行的模型就是 CPC(cost-per-click),就是按照用户的点击来付钱。那么准确的进行 CTR 预估,展现给用户他们最可能点击的广告就非常重要了。

传统的CTR预估模型需要大量的特征工程,耗时耗力;引入 DNN 之后,依靠神经网络强大的学习能力,可以一定程度上实现自动学习特征组合。但是 DNN 的缺点在于隐式的学习特征组合带来的不可解释性,以及低效率的学习(并不是所有的特征组合都是有用的)。

DCN 全称 Deep & Cross Network,是谷歌和斯坦福大学在2017年提出的用于 Ad Click Prediction 的模型。DCN(Deep Cross Network) 在学习特定阶数组合特征的时候效率非常高,而且同样不需要特征工程,引入的额外的复杂度也是微乎其微的。

2. 相关工作

最开始 FM 使用隐向量的内积来建模组合特征;FFM 在此基础上引入 field 的概念,针对不同的 field 上使用不同隐向量。但是,这两者都是针对低阶的特征组合进行建模的。
随着 DNN 在计算机视觉、自然语言处理、语音识别等领域取得重要进展,DNN 几乎无限的表达能力被广泛的研究。同样也尝试被用来解决web产品中输入高维高稀疏的问题。DNN 可以对高维组合特征进行建模,但是DNN是否就是针对此类问题最高效的建模方式那?直到现在,业界也没有一个准确的答案。
在 Kaggle 上的很多比赛中,大部分的获胜方案都是使用的人工特征工程,构造低阶的组合特征,这些特征意义明确且高效。而 DNN 学习到的特征都是高度非线性的高阶组合特征,含义非常难以解释。那么是否能设计一种 DNN 的特定网络结构来改善 DNN,使得其学习起来更加高效那?

业内进行了很多探索,DCN 就是其中一个。

3. DCN特点

DCN 特点如下:

  1. 使用 cross network,在每一层都应用 feature crossing。高效的学习了 bounded degree 组合特征。不需要人工特征工程。
  2. 网络结构简单且高效。多项式复杂度由 layer depth 决定。
  3. 相比于 DNN,DCN 的 logloss 更低,而且参数的数量将近少了一个数量级。

4. DCN

DCN 的全称是 Deep & Cross Network,网络架构如下:

DCN架构图如上图所示:最开始是 Embedding and stacking layer,然后是并行的 Cross NetworkDeep Network,最后是 Combination LayerCross NetworkDeep Network 的结果组合得到 Output

4.1 Embedding and Stacking Layer

这一层说起来其实非常的简单,就两个功能EmbedStack

Embedding:

在网络规模推荐系统的 CTR 预测任务中,输入主要是分类特征,通常的处理办法就是 one-hot,但是 one-hot 之后输入特征维度非常高非常系数,如 “country=usa”。这些特征通常是编码为独热向量如 [0,1,0];然而,这通常会产生超高维度的特征空间。
所以有了 Embedding 来大大的降低输入的维度,就是把这些 binary features 转换成 dense vectors with real values(通常称为嵌入向量):
x e m b e d , i = W e m b e d , i x i x_{embed,i} =W_{embed,i}x_i xembed,i=Wembed,ixi
其中 x e m b e d , i x_{embed,i} xembed,i 是embedding vector, x i x_i xi 是第 i i i 个 category 的二元输入, W e m b e d , i ∈ R n e × n v W_{embed,i} \in R^{n_e \times n_v} Wembed,iRne×nv 是对应的 embedding matrix,会与网络中的其它参数一起进行优化, n e n_e ne, n v n_v nv 分别是embedding size和vocabulary size。

Embedding 操作其实就是用一个矩阵和 one-hot 之后的输入相乘,也可以看成是一次查询(lookup)。这个 Embedding 矩阵跟网络中的其他参数是一样的,是需要随着网络一起学习的。

Stacking
处理完了类别型特征,还有连续型特征没有处理那。所以我们把连续型特征规范化之后,和嵌入向量 stacking 到一起,就得到了原始的输入:
x 0 = [ x e m b e d , 1 T , . . . , X e m b e d , k T , X d e n s e T ] 。 x_0 = [ x_{embed,1}^T, ..., X_{embed,k}^T, X_{dense}^T]。 x0=[xembed,1T,...,Xembed,kT,XdenseT]
这一部分在tensorflow中,使用tf.feature_columnAPI可以很容易实现,大致代码结构如下:

embed0 = tf.feature_column.embedding_column(...)
...
dense0 = tf.feature_column.indicator_column(...)
dense1 = tf.feature_column.numeric_column(...)
...
columns = [embed0, ..., dense0, dense1, ...]
x0 = tf.feature_column.input_layer(features, feature_columns)

4.2 Cross Network

交叉网络的核心思想是以有效的方式应用显式特征交叉。交叉网络由交叉层组成,每个层具有以下公式:
x l + 1 = x 0 x l T w l + b l + x l = f ( x l , w l , b l ) + x l x_{l+1} = x_0 x_l^T w_l + b_l + x_l = f(x_l, w_l, b_l) + x_l xl+1=x0xlTwl+bl+xl=f(xl,wl,bl)+xl
其中:

  • x l , x l + 1 x_l,x_{l+1} xl,xl+1 是列向量(column vectors),分别表示来自第 l l l 层和第 ( l + 1 ) (l+1) (l+1) 层cross layers的输出;

  • w l , b l ∈ R d w_l, b_l \in R^d wl,blRd 是第 l l l 层 layer 的 weight 和 bias 参数。

在完成一个特征交叉 f 后,每个 cross layer 会将它的输入加回去,对应的mapping function f : R d → R d f:R^d \rightarrow R^d fRdRd,刚好等于残差 x l + 1 − x l x_{l+1} - x_l xl+1xl,这里借鉴了残差网络的思想。

特征的高阶交叉(high-degree interaction)

cross network的独特结构使得交叉特征的阶(the degress of cross features)随着layer的深度而增长。对于第 l l l 层 layer,它的最高多项式阶(在输入 x 0 x_0 x0 上)是 l + 1 l+1 l+1。 实际上,cross network由这些交叉项 x 1 α 1 x 2 α 2 … x d α d x_1^{\alpha_1} x_2^{\alpha_2} … x_d^{\alpha_d} x1α1x2α2xdαd 组成,对应的阶从 1 到 l + 1 l+1 l+1

Cross Layer 设计的巧妙之处全部体现在上面的计算公式中,我们先看一些明显的细节:1) 每层的神经元个数都相同,都等于输入 x 0 x_0 x0 的维度 d d d,也即每层的输入输出维度都是相等的;2) 受残差网络(Residual Network)结构启发,每层的函数拟合 f f f 的是 x l + 1 − x l x_{l+1} - x_l xl+1xl 的残差,残差网络有很多优点,其中一点是处理梯度消失的问题,使网络可以“更深”.

那么为什么这样设计呢?Cross 究竟做了什么?对此论文中给出了定理 3.1 以及相关证明,但定理与证明过程都比较晦涩,为了直观清晰地讲解清楚,我们直接看一个具体的例子:假设 Cross 有 2 层, x 0 = [ x 0 , 1 x 0 , 2 ] \boldsymbol{x}_{0}=\left[\begin{array}{l} x_{0,1} \\ x_{0,2} \end{array}\right] x0=[x0,1x0,2],为便于讨论令各层 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 ] x 2 = x 0 x 1 T w 1 + x 1 = [ w 1 , 1 x 1 , 1 2 + w 1 , 2 x 1 , 1 x 1 , 2 + x 1 , 1 w 1 , x x 1 , 2 x 1 , 1 + w 1 , x x 1 , 2 2 + x 1 , 2 ] = [ w 0 , 1 w 1 , 1 x 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 x 0 , 2 + x 0 , 1 ] \begin{array}{l} \boldsymbol{x}_{1}=\boldsymbol{x}_{0} \boldsymbol{x}_{0}^{T} \boldsymbol{w}_{0}+\boldsymbol{x}_{0}=\left[\begin{array}{l} x_{0,1} \\ x_{0,2} \end{array}\right]\left[x_{0,1}, x_{0,2}\right]\left[\begin{array}{l} w_{0,1} \\ w_{0,2} \end{array}\right]+\left[\begin{array}{l} x_{0,1} \\ x_{0,2} \end{array}\right]=\left[\begin{array}{l} 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] \\ x_{2}=x_{0} x_{1}^{T} w_{1}+x_{1} \\ \quad=\left[\begin{array}{ll} w_{1,1} x_{1,1}^{2}+w_{1,2} x_{1,1} x_{1,2}+x_{1,1} \\ w_{1, x} x_{1,2} x_{1,1}+w_{1, x} x_{1,2}^{2}+x_{1,2} \end{array}\right] \\ \quad=\left[\begin{array}{ll} w_{0,1} w_{1,1} x_{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(w_{0,2}+w_{1,2}\right) x_{0,1} x_{0,2}+x_{0,1} \end{array}\right] \end{array} 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]x2=x0x1Tw1+x1=[w1,1x1,12+w1,2x1,1x1,2+x1,1w1,xx1,2x1,1+w1,xx1,22+x1,2]=[w0,1w1,1x0,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,1x0,2+x0,1]

最后得到 y cross  = x 2 T ∗ w crovs ∈ R y_{\text {cross }}=\boldsymbol{x}_{2}^{T} * \boldsymbol{w}_{\text {crovs}} \in \mathbb{R} ycross =x2TwcrovsR 参与到最后的 loss 计算。可以看到 x 1 x_1 x1包含了原始特征 x 0 , 1 , x 0 , 2 x_{0,1}, x_{0,2} x0,1,x0,2 从一阶到二阶的所有可能叉乘组合,而 x 2 x_2 x2 包含了其从一阶到三阶的所有可能叉乘组合。现在大家应该可以理解 cross layer 计算公式的用心良苦了,上面这个例子也可以帮助我们更深入地理解 Cross 的设计:

  1. 有限高阶:叉乘阶数由网络深度决定,深度 L c L_c Lc 对应最高 L c + 1 L_c + 1 Lc+1 阶的叉乘

  2. 自动叉乘:Cross 输出包含了原始特征从一阶(即本身)到 L c + 1 L_c + 1 Lc+1 阶的所有叉乘组合,而模型参数量仅仅随输入维度成线性增长 2 ∗ d ∗ L c 2*d*L_c 2dLc

  3. 参数共享:不同叉乘项对应的权重不同,但并非每个叉乘组合对应独立的权重(指数数量级), 通过参数共享,Cross 有效 降低了参数量。此外,参数共享还使得模型有更强的 泛化性鲁棒性。例如,如果独立训练权重,当训练集中 x i ≠ 0 ⋂ x j ≠ 0 x_i \ne 0 \bigcap x_j \ne 0 xi=0xj=0 这个叉乘特征没有出现 ,对应权重肯定是零,而参数共享则不会,类似地,数据集中的一些噪声可以由大部分正常样本来纠正权重参数的学习
    这里有一点很值得留意,前面介绍过,文中将 dense 特征和 embedding 特征拼接后作为 Cross 层和 Deep 层的共同输入。这对于 Deep 层是合理的,但我们知道人工交叉特征基本是对原始 sparse 特征进行叉乘,那为何不直接用原始 sparse 特征作为 Cross 的输入呢?联系这里介绍的 Cross 设计,每层 layer 的节点数都与 Cross 的输入维度一致的,直接使用大规模高维的 sparse 特征作为输入,会导致极大地增加 Cross 的参数量。当然,可以畅想一下,其实直接拿原始 sparse 特征喂给 Cross 层,才是论文真正宣称的“省去人工叉乘”的更完美实现,但是现实条件不太允许。所以将高维 sparse 特征转化为低维的 embedding,再喂给 Cross,实则是一种 trade-off 的可行选择。

复杂度分析

假设 L c L_c Lc 表示 cross layers 的数目, d d d 表示输入 x 0 x_0 x0​ 的维度。那么,在该cross network中涉及的参数数目为:
d × L c × 2 d \times L_c \times 2 d×Lc×2
因为每一层的 W W W b b b 都是 d d d 维度的。从上式可以发现,复杂度是输入维度 d d d 的线性函数。所以相比于deep network,cross network引入的复杂度微不足道。这样就保证了 DCN 的复杂度和 DNN 是一个级别的。

论文中表示,Cross Network 之所以能够高效的学习组合特征,就是因为 x0 * xT 的秩为 1 ( rank-one 特性(两个向量的叉积)),使得我们不用计算并存储整个的矩阵就可以得到所有的 cross terms。

主流的实现 cross layer 的方法,代码如下:

def cross_layer(x0, x, name):
  with tf.variable_scope(name):
    input_dim = x0.get_shape().as_list()[1]
    w = tf.get_variable("weight", [input_dim], initializer=tf.truncated_normal_initializer(stddev=0.01))
    b = tf.get_variable("bias", [input_dim], initializer=tf.truncated_normal_initializer(stddev=0.01))
    xx0 = tf.expand_dims(x0, -1)  # shape <?, d, 1>
    xx = tf.expand_dims(x, -1)  # shape <?, d, 1>
    mat = tf.matmul(xx0, xx, transpose_b=True)  # shape <?, d, d>
    return tf.tensordot(mat, w, 1) + b + x  # shape <?, d>

这种方法在逻辑上没有什么问题,但实际上却是非常消耗计算和存储资源的,原因在于显式地计算 x 0 x l T x_0 x_l^T x0xlT 需要非常大的内存空间来存储临时计算结果。
我们来计算一下,一个 cross layer 仅仅是计算 x 0 x l T x_0 x_l^T x0xlT,这一个操作就需要消耗 b a t c h _ s i z e × d × d × 4 batch\_size \times d \times d \times 4 batch_size×d×d×4 字节的内存(一个浮点数占4个字节)。在企业级的模型中, d d d 通常是几千甚至几万的量级,假设 d = 1 k d=1k d=1k,则需要 b a t c h _ s i z e × 4 M batch\_size \times 4M batch_size×4M 的存储空间,这通常情况下已经是 G 级别的大小了,何况我们仅仅计算了一个 Layer,别忘了我们总共有 L c L_c Lc 个 cross layer。另外,该操作的结果(一个矩阵)再和 w w w 向量相乘时也是非常消耗计算资源的。即使你在离线训练时通过减少 cross layer 的个数,减小 batch_size 等手段完成了模型的训练,在模型部署中线上之后,线性的打分系统依然要面临 Out of Memory 的风险,因为线上预测我们总是希望一次请求尽可能返回多条记录的预测分数,否则要么是影响全局的效果,要么是需要更多的请求次数,从而面临巨大的性能压力。

正确的实现方式不是先计算 x 0 x l T x_0 x_l^T x0xlT,而是先计算 x l T w x_l^T w xlTw,因为 x l T w x_l^T w xlTw 的计算结果是一个标量,几乎不占用存储空间。这两种方法的计算结果是一致的,因为矩阵乘法是满足结合律的: (AB)C=A(BC)。高效的实现代码如下:

def cross_layer2(x0, x, name):
  with tf.variable_scope(name):
    input_dim = x0.get_shape().as_list()[1]
    w = tf.get_variable("weight", [input_dim], initializer=tf.truncated_normal_initializer(stddev=0.01))
    b = tf.get_variable("bias", [input_dim], initializer=tf.truncated_normal_initializer(stddev=0.01))
    xb = tf.tensordot(tf.reshape(x, [-1, 1, input_dim]), w, 1)
    return x0 * xb + b + x

在上面的实现中,我们使用了 tf.reshape 操作实现了 x l x_l xl​ 的转置,因为 x l x_l xl 实际上是一个向量,并不是一个矩阵,因此这种方法是可行的。下面给出构建整个交叉网络的tensorflow代码:

def build_cross_layers(x0, params):
  num_layers = params['num_cross_layers']
  x = x0
  for i in range(num_layers):
    x = cross_layer2(x0, x, 'cross_{}'.format(i))
  return x

泛化FM

跟 FM 一样,DCN 同样也是基于参数共享机制的,参数共享不仅仅使得模型更加高效而且使得模型可以泛化到之前没有出现过的特征组合,并且对噪声的抵抗性更加强。

  • 在 FM 模型中,特征 x i x_i xi 和权重向量 v i v_i vi 相关联,交叉项 x i x j x_i x_j xixj 的权重由 < v i , v j > <v_i, v_j> <vi,vj>
  • 在 DCN 模型中, x i x_i xi 和标量 { w k ( i ) } k = 1 l \{w_k^{(i)}\}_{k=1}^l {wk(i)}k=1l 相关联,并且 w i x j w_i x_j wixj 的权重从集合 { w k ( i ) } k = 1 l \{w_k^{(i)}\}_{k=1}^l {wk(i)}k=1l { w k ( j ) } k = 1 l \{w_k^{(j)}\}_{k=1}^l {wk(j)}k=1l 中计算而来。

两种模型的每个特征学习独立于其他特征的参数,交叉项的权重是对应参数的特定组合。
参数共享不仅使模型更有效,但也使模型可以泛化出不可见的特征组合,使得模型更健壮。例如,以具有稀疏特征的数据集,如果两个二进制特征 x i x_i xi x j x_j xj 在训练数据集中很少或从不共现,如 x i ≠ 0 ∩ x j ≠ 0 x_i \ne 0 \cap x_j \ne 0 xi=0xj=0 ,然后 x i x j x_i x_j xixj 学到的权重对于预测也没什么意义。

FM是一个非常浅的结构,并且限制在表达二阶组合特征上,DeepCrossNetwork(DCN) 把这种参数共享的思想从一层扩展到多层,并且可以学习高阶的特征组合 x 1 α 1 x 2 α 2 ⋯ x d α d x_1^{\alpha_1}x_2^{\alpha_2} \cdots x_d^{\alpha_d} x1α1x2α2xdαd

但是和FM的高阶版本的变体不同,DCN 的参数随着输入维度的增长是线性增长的。

有效映射

对于 cross layer 可以换一种理解方式。假设 x ~ ∈ R d ​ \tilde{x} \in R^d​ x~Rd 是一个 cross layer 的输入,cross layer 首先构建 d 2 ​ d^2​ d2 个关于 x i x ~ j ​ x_i \tilde{x}_j​ xix~j 的 pairwise 交叉,接着以一种内存高效的方式将它们投影到维度 d ​ d​ d 上。如果采用全连接 Layer 那样直接投影的方式会带来 3 次方的开销。Cross layer提供了一种有效的解决方式,将开销减小到维度 d ​ d​ d 的量级上:考虑到 x p = x 0 x ~ T w ​ x_p = x_0 \tilde{x}^T w​ xp=x0x~Tw 等价于:
x p T = [ x 1 x ~ 1 . . . x 1 x ~ d . . . x d x ~ 1 . . . x d x ~ d ] [ w 0 . . . 0 0 w . . . 0 ⋮ ⋮ ⋱ ⋮ 0 0 . . . w ] x_p^T = [x_1\tilde{x}_1 ... x_1\tilde{x}_d ... x_d\tilde{x}_1 ... x_d\tilde{x}_d] \left[ \begin{array}{ccc} w&0&...&0\\ 0&w&...&0\\ \vdots&\vdots&\ddots&\vdots\\ 0&0&...&w \end{array} \right] xpT=[x1x~1...x1x~d...xdx~1...xdx~d]w000w0.........00w
其中,行向量包含了所有 d 2 d^2 d2 个关于 x i x ~ j x_i \tilde{x}_j xix~j 的 pairwise 交叉,投影矩阵具有一个块对角化结构,其中 w ∈ R d w \in R^d wRd 是一个列向量。

值得注意的是,正是因为 cross network 的参数比较少导致它的表达能力受限,为了能够学习高度非线性的组合特征,DCN 并行的引入了 Deep Network。

4.3 Deep Network

交叉网络的参数数目少,从而限制了模型的能力(capacity)。为了捕获高阶非线性交叉,我们平行引入了一个深度网络。

深度网络就是一个全连接的前馈神经网络,每个深度层具有如下公式:
h l + 1 = f ( W l h l + b l ) h_{l+1} = f(W_l h_l + b_l) hl+1=f(Wlhl+bl)
其中:

  • h l ∈ R n l , h l + 1 ∈ R n l + 1 h_l \in R^{n_l}, h_{l+1} \in R^{n_{l+1}} hlRnl,hl+1Rnl+1 分别是第 l 层和第 (l+1) 层hidden layer;

  • W l ∈ R n l + 1 × n l , b l ∈ R n l + 1 W_l \in R^{n_{l+1} \times n_l}, b_l \in R^{n_{l+1}} WlRnl+1×nl,blRnl+1 第 l 层 deep layer 的参数;

  • f ( ⋅ ) f(⋅) f() 是ReLU function。

复杂度分析:出于简洁性,我们假设所有的 deep layers 具有相同的 size。假设 L d L_d Ld 表示 deep layers 的数目,m 表示 deep layer 的 size。
那么,在该 deep network 中的参数的数目为:
d × m + m + ( m 2 + m ) × ( L d − 1 ) d×m+m+(m^2+m)×(L_d−1) d×m+m+(m2+m)×(Ld1)
其中 d × m + m d \times m + m d×m+m 是第一层参数,而第二层至最后一层参数为: ( m × m + m ) × ( L d − 1 ) (m \times m + m)×(L_d−1) (m×m+m)×(Ld1),因为到了第二层,输入已经转变成了 m m m 维。

def build_deep_layers(x0, params):
  # Build the hidden layers, sized according to the 'hidden_units' param.
  net = x0
  for units in params['hidden_units']:
    net = tf.layers.dense(net, units=units, activation=tf.nn.relu)
  return net

4.4 Combination Layer

Combination Layer 把 Cross Network 和 Deep Network 的输出拼接起来,然后经过一个加权求和后得到 logits,然后经过 sigmoid 函数得到最终的预测概率。形式化如下:
p = σ ( [ x L 1 T , h L 2 T ] w l o g i t s ) p = \sigma ( [x_{L_1}^T, h_{L_2}^T] w_{logits}) p=σ([xL1T,hL2T]wlogits)
p p p 是最终的预测概率; X L 1 X_{L1} XL1 是 d 维的,表示 Cross Network 的最终输出; h L 2 h_{L2} hL2 是 m 维的,表示 Deep Network 的最终输出; W l o g i t s W_{logits} Wlogits 是 Combination Layer 的权重;最后经过 sigmoid 函数,得到最终预测概率。

损失函数使用带正则项的 log loss,形式化如下:
l o s s = − 1 N ∑ i = 1 N y i l o g ( p i ) + ( 1 − y i ) l o g ( 1 − p i ) + λ ∑ l ∣ ∣ w ∣ ∣ 2 loss = -\frac{1}{N} \sum_{i=1}^{N} y_i log(p_i) + (1-y_i)log(1-p_i) + \lambda \sum_{l} ||w||^2 loss=N1i=1Nyilog(pi)+(1yi)log(1pi)+λlw2
另外,针对Cross Network和Deep Network,DCN是一起训练的,这样网络可以知道另外一个网络的存在。

类似于WDL模型,我们对两个network进行jointly train,在训练期间,每个独立的network会察觉到另一个。下面给出整个模型的实现代码:

def dcn_model_fn(features, labels, mode, params):
  x0 = tf.feature_column.input_layer(features, params['feature_columns'])
  last_deep_layer = build_deep_layers(x0, params)
  last_cross_layer = build_cross_layers(x0, params)
  last_layer = tf.concat([last_cross_layer, last_deep_layer], 1)
  my_head = tf.contrib.estimator.binary_classification_head(thresholds=[0.5])
  logits = tf.layers.dense(last_layer, units=my_head.logits_dimension)
  optimizer = tf.train.AdagradOptimizer(learning_rate=params['learning_rate'])
  return my_head.create_estimator_spec(
    features=features,
    mode=mode,
    labels=labels,
    logits=logits,
    train_op_fn=lambda loss: optimizer.minimize(loss, global_step=tf.train.get_global_step())
  )

总结

DCN主要有以下几点贡献:

  • 提出一种新型的交叉网络结构,可以用来提取交叉组合特征,并不需要人为设计的特征工程;
  • 这种网络结构足够简单同时也很有效,可以获得随网络层数增加而增加的多项式阶(polynomial degree)交叉特征;
  • 十分节约内存(依赖于正确地实现),并且易于使用;
  • 实验结果表明,DCN相比于其他模型有更出色的效果,与DNN模型相比,较少的参数却取得了较好的效果。

参考文献

[1] Deep & Cross Network for Ad Click Prediction

[2] Deep&Cross Network模型理论和实践

[3] 谷歌DCN模型理论与实践

[4] 距离玩转企业级DCN(Deep & Cross Network)模型,你只差一步

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值