2017发表于KDD的推荐系统类文章Deep & Cross Network for Ad Click Predictions
输入部分:离散特征通过word2vec进行嵌入,连续特征则直接使用原始的数值,最后将连续和离散的特征拼接到一起输入给DNN部分和CrossNet部分;
模型部分:首先介绍一下DCN模型的结构:主要分为两个部分,如图左边为CrossNet部分,右边为DNN部分下面会分别介绍CrossNet部分和DNN部分;
(1)输入部分的embedding方法介绍:通过embedding方法可以降低离散特征的数据维度,加快计算速度;
其中W的参数矩阵就是得到的第i个特征的表示;下面是特征融合的公式,表示连续特征和离散特征进行融合,这也是DCN模型两个部分的输入数据;
由此可以得到整个输入部分的维度为(batch, units)
(2)先介绍左边的CrossNet部分;
矩阵的交互可以用下图来表示,能够更好的理解特征之间的交互;
特征之间的交互主要发生FetureCrossing之间,然后加入偏置项,最后加了一个Input应该是参考残差结构,避免梯度消失;
(3)DNN部分相对比较简单,就是一个前馈的神经网络;
上图的公式代表的是每一层深度层的输出结果;
(4)CrossNet部分和DNN部分的特征组合;
(5)损失函数的设计,使用的是常用的log损失,公式如下;
(6)简单总结一下DCN模型的特点:
提出了一种新的交叉网络,在每个层上明确地应用特征交叉,有效地学习有界度的预测交叉特征,并且不需要手工特征工程或穷举搜索。 跨网络简单而有效。通过设计,各层的多项式级数最高,并由层深度决定。网络由所有的交叉项组成,它们的系数各不相同。 跨网络内存高效,易于实现。 实验结果表明,交叉网络(DCN)在LogLoss上与DNN相比少了近一个量级的参数量。
下面是代码实现,只写了核心的部分(CrossNet),基于tensorflow和keras实现,其他部分需要自己补充;
import tensorflow as tf from tensorflow.python.keras.layers import Layer from tensorflow.python.keras.initializers import Zeros, glorot_normal from tensorflow.python.keras.regularizers import l2 class cross_net(Layer): def __init__(self, l2_reg=0, seed=1024, **kwargs): self.l2_reg = l2_reg self.seed = seed super(cross_net, self).__init__(**kwargs) def build(self, input_shape): units = input_shape[-1].value self.kernels = [self.add_weight(name='kernel', shape=(units, 1), initializer=glorot_normal(seed=self.seed), regularizer=l2(self.l2_reg), trainable=True)] self.bias = [self.add_weight(name='bias', shape=(units, 1), initializer=Zeros(), regularizer=l2(self.l2_reg), trainable=True)] super(cross_net, self).build(input_shape) def call(self, inputs, **kwargs): x_0 = tf.expand_dims(inputs, axis=2)#(batch, units, 1) x_l = x_0 x_l_w = tf.tensordot(x_l, self.kernels, axes=(1, 0))#(batch, 1, 1) dot_ = tf.matmul(x_0, x_l_w)#(batch, units, 1) x_l = dot_ + self.bias + x_l x_l = tf.squeeze(x_l, axis=2) return x_l