Deep Cross中的cross Layer详解(数学公式+代码+实现细节)

简介

再推荐模型中,对于特征feat interaction的探索占据了相当一部分的工作。

这也说明对于CTR问题来说,feature Interaction的探索是判断最终用户click的重要一环。
除了FM和FFM等因子分解机模型之外,还有Cross Layer的出现也是非常具有代表性的特征交互模型。

这里从DCN模型入手,然后单独将cross layer抽离出来,然后对于他的数学原理还有代码实现细节都进行比较深入的探索。

DCN中的Cross Layer

DCN模型整体架构是非常简单的:

在这里插入图片描述
从整体上来说,他和DeepFM模型有非常相似的结构,可以说只是把FM模块替换成了Cross Layer。

操作流程

这里我们从底向上来看DCN的整体流程。

  1. 对于Dense Feat,直接进行concat,对于Sparse Feature先进行emb,然后再concat

  2. 将得到的最终的输入向量输入到两个模块(Cross & DNN)

  3. 将两个部分的输出进行concat,然后输入到一个Dense层

  4. 通过predictor得到最终的prob

从整体来看,为什么再已经存在FM的情况下仍然出现了Cross模块,这里主要是因为FM只限于二阶的特征交叉,这是不够的,所以科学家们还致力于探索高阶的 特征交互所带来的意想不到的贡献。

So,Cross Layer的优势就是可以自动的学习高阶的特征interactionu权重和特征组合。摆脱了人工Feat interaction。

数学原理

在这里插入图片描述

图片引自:https://zhuanlan.zhihu.com/p/55234968

Cross Layer 有layer_num层,我们举第L层的例子,求解第L+1层。

这里我们可以看到,这是一个非常简单的计算公式,我们做一个简单的变换:

x l − 1 − x l = x 0 ∗ x l T ∗ w + b x_{l-1} - x_l = x_0 * x_l^T * w + b xl1xl=x0xlTw+b

可以看出每一层其实是对上一层的残差的拟合,残差的使用的好处主要是防止了梯度消失问题,也使得训练更加快速。

那么经过layer_num次的迭代之后我们就可以得到如下式子:

在这里插入图片描述

图片引自: https://zhuanlan.zhihu.com/p/55234968

这里就再次证明了Cross确实可以自动的学习feat interaction权重和组合。

Torch实现

然后我们就来实现Cross Layer,每一步都对照着下面这个式子:

x l − 1 − x l = x 0 ∗ x l T ∗ w + b x_{l-1} - x_l = x_0 * x_l^T * w + b xl1xl=x0xlTw+b

class CrossNet(nn.Module):
    """
	: param layer_num: the number of layers in cross module
	: param input_size: the dim of input vector
	: param seed: random seed which can be ignored
	: param device: cpu or gpu ..  
	"""

	def __init__(self, layer_num, input_size, seed=1024, device='cpu'):
        super(CrossNet, self).__init__()
		
        self.layer_num = layer_num
        ## define the w in the above formula
        ## 注意这里的维度,如果不清楚的话可以看上面的计算第L+1层的图
        self.weights = nn.ParameterList(
            [nn.Parameter(nn.init.xavier_normal_(torch.empty(input_size, 1))) for _ in range(layer_num)]
        )
        ## define the b in the above formula
        ## 同样这里的dim和上面的图示中是一样的
        self.bias = nn.ParameterList(
            [nn.Parameter(nn.init.xavier_normal_(torch.empty(input_size, 1))) for _ in range(layer_num)]
        )
        ## to device标准操作,没什么好说的
        self.to(device)

接下来就是forward, 我把每个tensor的维度都写在注释里了

def forward(self, x):
        ## x [bat_s dim]
        x_0 = x.unsqueeze(2)
        ## x_0 [batch_size, dim, 1]
        x_l = x_0 
        for i in range(self.layer_num):
            ## x_l [batch_size, dim, 1]
            ## weights[i] [dim, 1]
            ## xl_w [batch_size, 1, 1]
            xl_w = torch.tensordot(x_l, self.weights[i], dims=([1], [0]))
            res_ = torch.matmul(x_0, xl_w)
            x_l = res_ + self.bias[i] + x_l
        x_l = torch.squeeze(x_l, dim=2)

        return x_l

所有的 步骤都是上面formula的转化。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值