手搭深度推荐模型(一) DeepCrossing

本文是笔者参与datawhale组织的深度推荐模型组队学习的分享,学习内容见本链接 ,本文中所指的教程即该链接中的相应文件。

传统推荐系统模型有协同过滤、矩阵分解、FM算法等,随着算力的提升以及层出不穷的算法,深度学习技术逐渐在推荐系统中展露手脚,因为深度学习有更强的表达能力,有更灵活的网络结构。DeepCrossing是深度学习开始在推荐系统领域大显身手的标杆,本篇文章从论文总结、模型实现两个方面入手,深入学习Deep Crossing。

论文总结

本章基于5W1H法,对论文整理总结。

(what) Deep Crossing模型的结构是怎样的?

Deep Crossing模型是一个典型的Embedding + MLP的模型,模型的输入分为了稀疏特征和稠密特征,对于稀疏的特征(论文中为维度大于256维的特征,实际应根据应用而定),先采用embedding技术将其稠密化,再与稠密特征和数值特征等一起作为MLP的输入。MLP采用多个残差模块组成。最后将MLP的输出进行整合打分,打分方式根据实际应用而定,论文中所关注的问题是CTR预估问题,所以使用了sigmoid估计其概率。
模型如下:
在这里插入图片描述

(when&how) 基于什么背景,作者提出了这样的模型?这个模型是怎样在CTR预估中发挥作用的?

  1. 类别特征是推荐系统中最为重要的一类特征,而在工业级推荐系统中,很多类别特征的基数都是非常大的,如果进行one-hot编码将会非常稀疏。在本文出现之前,就已有了一些embedding技术,可以将稀疏的特征稠密化,同时,稠密的特征比稀疏特征更能挖掘冷门信息。因此作者将embedding引入了推荐系统。
  2. 特征交叉是构造特征非常有效的方式,尤其当交叉的是类别特征的时候。传统的FM只能进行自动二阶交叉,可以使用LR+ 手工构造特征,单手工构造组合特征是低效且不充分的,因此引入MLP进行特征交叉。MLP进行特征交叉可以进行任意维度交叉并自动发现有效的交叉组合。
  3. 残差网络在本文发表之前在CV领域取得巨大成功,本文首次将残差网络用在了CV之外的领域,使特征交叉更充分。

(where) 这篇文章解决了推荐系统中的什么问题,它在推荐系统中处于哪个环节?

Deep Crossing主要的贡献是使用了MLP来进行特征交叉,证明了深度学习在特征交叉中能够起到非常有效的作用。文中提出首次在不用卷积的情况下使用了多层残差网络,不过使用什么构造MLP都是可以的,我认为应当根据具体应用做出实践来选择构造方式。
下图是王喆老师对深度推荐模型的总结。
在这里插入图片描述

模型实现

  1. 构造MLP的残差模块
    每个残差模块使用了两个全连接层,每层使用relu激活函数。要注意的是由于残差的定义,即目标函数是h(x),要通过x + [h(x) - x]这样的形式去拟合,因此[h(x) - x]这一部分(也即第二个全连接层的输出)的尺寸要和x保持一致,因此第二个全连接层的尺寸是等于输入的特征的尺寸的。
    由于这个尺寸是变化的,因此在tensorflow中实现的时候要用build函数来自动识别输入的尺寸,这个方法的详解可以见这个链接中的build部分。
class RisidualBlock(Layer):
    def __init__(self, units=32):
        super(RisidualBlock, self).__init__()
        self.units = units

    def build(self, input_shape):
        self.relu1 = Dense(self.units, activation='relu')
        self.relu2 = Dense(input_shape[-1], activation='relu')

    def call(self, inputs):
        x = self.relu1(inputs)
        x = self.relu2(x)
        return Activation('relu')(x + inputs)

2.构建模型
这里相对于datawhale教程中的模型我做了以下改动:
1)使用论文中的方法,将embedding层放入整个网络中随着整个网络的bp进行更新,embedding层按照论文里的做法用一个relu的全连接层实现而没有用keras的embedding层。
2)原文是针对CTR预估问题作出的模型,因此最后的scoring用的是sigmoid,我这里也用了sigmoid
3)整合了一下参数放在了函数行参中,更容易调整网络结构。
另外,这里这个函数的输入我仍使用了教程中的输入。

def DeepCrossing(feature_columns,
                 residual_blocks=3,
                 residual_units=32,
                 embedding_dim=4):
    sparse_input_layers = []
    dense_input_layers = []
    for fc in feature_columns:
        if isinstance(fc, SparseFeat):
            sparse_input_layers.append((Input(shape=(1, ), name=fc.name)))
        elif isinstance(fc, DenseFeat):
            dense_input_layers.append(Input(shape=(fc.dimension, ), name=fc.name))
    input_layers = sparse_input_layers + dense_input_layers
    embedded = [Dense(activation='relu', units=embedding_dim, name=f'embedding_{i}')(layer)
                for i, layer in enumerate(sparse_input_layers)]
    x = Concatenate(axis=1)(dense_input_layers + embedded)
    for block in range(residual_blocks):
        x = RisidualBlock(residual_units)(x)
    output = Dense(1, activation='sigmoid')(x)
    return Model(input_layers, output)

一些收获

  1. 正儿八经动手实现的第一个模型!发现不实现一个网络的时候很多细节就不关注,一直没弄懂残差网络的原理,现在终于理顺了,再也不愁怎么实现残差网络了
  2. 同样,如果不动手实现真的没想到embedding的一种简单实现方式就是一层全连接…看着书里的论文里的Embedding只会想他们是embedding不会想他们也是全连接。
  3. 如意大佬用了具名元组这个类型构造输入层,非常涨见识。具名元组的好处是每个稀疏特征的维度可以单另算,每个稀疏特征的embedding之后降到多少维度也可以独立决定。《流畅的python》中有对namedTuple的详解,以前只看过,没想到能用在这里。
  4. 终于弄懂了tf里多个输入层怎么实现,原来输入层的name和输入的字典数据的key一致就可以

参考文献

1.Shan, Y. et al. Deep Crossing: Web-Scale Modeling without Manually Crafted Combinatorial Features. in Proceedings of the 22nd ACM SIGKDD International Conference on Knowledge Discovery and Data Mining 255–262 (ACM, 2016). doi:10/gf245q.
2.Datawhale FunRec
3.王喆《深度学习推荐系统》

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值