Datawhale第23期组队学习—深度学习推荐系统—task1—DeepCrossing

学习资料来源:Datawhale

这次的深度学习任务相对来说还是比较有挑战的,原因是自己的基础理论并没有掌握很好,对于这次学习中遇到的基础理论知识,会在博文中进行说明。

1. DeepCrossing引言

参考来源:https://zhuanlan.zhihu.com/p/130455031

对于web规模的应用程序来说,特性的多样性和数量使得这些人工合成的特征的创建、维护和部署变得非常昂贵。DeepCrossing提出了一种深度交叉模型,该模型是一种深度神经网络,它能自动地将特征组合在一起,生成更优的模型。深度交叉的输入可以是一组单独的特征,可以是密集的,也可以是稀疏的。重要的交叉特征由网络隐含地发现。

原始特征需要改造
传统的机器学习算法充分利用所有的输入特征来预测和对新实例进行分类。但是,仅使用原始的特征很少会提供最佳的结果。因此,无论是在工业界还是学术界,都存在着大量的工程工作来对原始特征进行改造。特征改造一种主要方式是基于多种特征的组合来构造函数并将函数的输出当作后续学习器的输入。这些组合特征有时称为cross features或者multi-way features.

特征组合成本高昂
将特征进行组合能发挥强大的功能,但是与此同时将特征进行组合却需要高昂的成本代价。随着特征数量的增加,管理,维护变得充满挑战。在网络规模的应用程序中,由于庞大的搜索空间以及给定数十亿个样本的训练和评估周期中的缓慢转换,寻找额外的组合特征来改进现有模型是一项艰巨的任务。

深度学习与DeepCrossing
深度学习可以从单个特征中进行学习,而无需人工干预。在计算机视觉以及自然语言处理中已经发挥了它的功能。

Deep Crossing将深度学习的成功扩展到更普遍的环境中,其中各个特征具有不同的性质。更具体地说,它采用了诸如文本,分类,ID和数字特征之类的单个特征,并根据特定任务自动搜索最佳组合。此外,Deep Crossing旨在处理Web规模的应用程序和数据大小。

尽管Deep Crossing的输出是一个没有针对这些特征的明确表示的模型,但Deep Crossing在学习过程中确实以某种方式生成了组合特征。

DeepCrossing应用
Deep Crossing模型的应用场景是微软搜索引擎Bing中的搜索广告推荐场景。用户在搜索引擎中输入搜索词之后,搜索引擎除了会返回相关结果,还会返回与搜索词相关的广告。尽可能地增加搜索广告的点击率,准确地预测广告点击率,并以此作为广告排序的指标之一,是非常重要的工作,也是Deep Crossing模型的优化目标。

2. DeepCrossing模型结构及原理

为了完成端到端的训练, DeepCrossing模型要在内部网络结构中解决如下问题:

  1. 离散类特征编码后过于稀疏, 不利于直接输入神经网络训练, 需要解决稀疏特征向量稠密化的问题。
  2. 如何解决特征自动交叉组合的问题
  3. 如何在输出层中达成问题设定的优化目标

DeepCrossing分别设置了不同神经网络层解决上述问题,模型结构如下:
DeepCrossing整体模型结构图1 DeepCrossing整体模型结构

2.1 Embedding Layer

由于数据的特征有类别型(离散型)和数值型(连续型)之分,所以在特征处理的时候要区分对待。对于数值型特征,可以之际放入Stacking中处理,但是对于类别型特征,一般是是用one-hot1 的形式表示,这时需要使用Embedding 2 将其转换成稠密向量。

将稀疏的类别型特征转成稠密的Embedding向量,Embedding的维度会远小于原始的稀疏特征向量。

1. one-hot
one-hot中文直译为“独热”,又称为一位有效编码,主要是采用N位状态寄存器来对N个状态进行编码,每个状态都由他独立的寄存器位,并且在任意时候只有一位有效。
如,将“深度学习推荐系统”转化成one-hot就是:
在这里插入图片描述
每一行就表示该字的one-hot编码。

2. Embedding
Embedding中文译为“嵌入”,是NLP里面常用的一种技术,作用是把高维空间的向量压缩到低维空间。这里的Feature #1表示的类别特征(one-hot编码后的稀疏特征向量), Feature #2是数值型特征,不用embedding, 直接到了Stacking Layer。

关于Embedding Layer的实现, 往往一个全连接层即可,Tensorflow中有实现好的层可以直接用。 和NLP里面的embedding技术异曲同工, 比如Word2Vec, 语言模型等。

2.2 Stacking Layer

这个层是把不同的Embedding特征和数值型特征拼接在一起,形成新的包含全部特征的特征向量,该层通常也称为连接层, 具体的实现如下:
① 先将所有的数值特征拼接起来
② 然后将所有的Embedding转换过的特征拼接起来
③ 最后将数值特征和Embedding转换过的特征拼接起来作为DNN的输入,这里Tensorflow是通过Concatnate层进行拼接。

# 将所有的dense(数值型)特征拼接到一起
dense_dnn_list = list(dense_input_dict.values())
dense_dnn_inputs = Concatenate(axis=1)(dense_dnn_list) # B x n (n表示数值特征的数量)

# 将所有的sparse(类别型)特征拼接到一起
sparse_dnn_list = concat_embedding_list(dnn_feature_columns, sparse_input_dict, embedding_layer_dict, flatten=True) 
sparse_dnn_inputs = Concatenate(axis=1)(sparse_dnn_list) # B x n x dim (n表示类别特征的数量,dim表示embedding的维度)

# 将dense特征和Sparse特征拼接到一起,作为Stacking Layer的输入
dnn_inputs = Concatenate(axis=1)([dense_dnn_inputs, sparse_dnn_inputs]) 

DeepCrossing的完整结构
图2 DeepCrossing的完整结构

通过该图可以较好理解Embedding Layer和Stacking Layer的关系。

2.3 Multiple Residual Units Layer

该层的主要结构是MLP3, 但DeepCrossing采用了残差网络进行的连接。通过多层残差网络对特征向量各个维度充分的交叉组合, 使得模型能够抓取更多的非线性特征和组合特征信息, 增加模型的表达能力。残差网络结构如下图所示:
在这里插入图片描述
Deep Crossing模型使用稍微修改过的残差单元,它不使用卷积内核,改为了两层神经网络。残差单元是通过两层ReLU4变换再将原输入特征相加回来实现的。具体代码实现如下:

# DNN残差块的定义
class ResidualBlock(Layer):
    def __init__(self, units): # units表示的是DNN隐藏层神经元数量
        super(ResidualBlock, self).__init__()
        self.units = units

    def build(self, input_shape):
        out_dim = input_shape[-1]
        self.dnn1 = Dense(self.units, activation='relu')
        self.dnn2 = Dense(out_dim, activation='relu') # 保证输入的维度和输出的维度一致才能进行残差连接
    
    def call(self, inputs):
        x = inputs
        x = self.dnn1(x)
        x = self.dnn2(x)
        x = Activation('relu')(x + inputs) # 残差操作
        return x
  1. MLP
    MLP(Multi-Layer Perception,多层感知机),主要分为三层:输入层,隐层和输出层,与普通的神经网络(ANN)相比,多出了隐层。而隐层可能又包含多层。MLP主要是为了解决ANN无法处理非线性可分离的问题。
  1. ReLU
    线性整流函数(Rectified Linear Unit, ReLU),又称修正线性单元,MLP中常用的一种激活函数,通常指代以斜坡函数及其变种为代表的非线性函数。当输入信号小于0时,输出为0;当输入信号大于0时,输出等于输入。

2.4 Scoring Layer

这个作为输出层,为了拟合优化目标存在。 对于CTR预估二分类问题, Scoring往往采用逻辑回归,模型通过叠加多个残差块加深网络的深度,最后将结果转换成一个概率值输出。

# block_nums表示DNN残差块的数量
def get_dnn_logits(dnn_inputs, block_nums=3):
    dnn_out = dnn_inputs
    for i in range(block_nums):
        dnn_out = ResidualBlock(64)(dnn_out)
    
    # 将dnn的输出转化成logits
    dnn_logits = Dense(1, activation='sigmoid')(dnn_out)

    return dnn_logits

3. 学习心得

本次学习对于DeepCrossing有了一个大概的了解,但是由于自己在专业知识上的缺失和对tf经验较少,理解代码相对比较困难,在后续过程中会逐渐加强自己在代码方面的训练,争取做到复现。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值