DIN

  • 1. 背景
  • 2. 模型原理
    • 2.1 特征表示
    • 2.2 模型原理
  • 3. 代码实现

参考来源:

  1. https://github.com/datawhalechina/team-learning-rs/blob/master/DeepRecommendationModel/DIN.md
  2. https://blog.csdn.net/friyal/article/details/83063948
  3. https://zhuanlan.zhihu.com/p/78365283

1. 背景

阿里巴巴一直致力于思考和寻找“真正能够发挥阿里巴巴电商体系下大量沉淀的互联网个性化行为数据”的算法模型,在这样的思路下,在过去的三、四年中,创造性地提出、研发及生产化了DIN、DIEN、MIMN、ESMM等一系列个性化预估模型,为阿里广告业务带来了百亿级收入增量。以电商场景为代表的这类互联网个性化行为模式,用何种深度模型结构来捕捉其内在规律。他们将Attention式结构(反向激活用户兴趣表达,如DIN模型)、GRU式结构(兴趣随时间演化规律,如DIEN模型)、Memory式结构(兴趣记忆与归纳,如MIMN模型)等引入模型设计中。

Deep Interest Network(DIN)是2018年阿里巴巴提出来的模型,该模型的提出是对现实业务问题的思考,从实际应用的角度进行改进,与纯理论的推荐模型不同,该模型有更高的使用价值,更好地应用在工业领域。

与其他深度学习推荐模型的区别

该模型的应用场景是阿里巴巴的电商广告推荐业务, 这样的场景下一般会有大量的用户历史行为信息, DIN模型的创新点或者解决的问题就是使用了注意力机制来对用户的兴趣动态模拟, 而这个模拟过程存在的前提就是用户之前有大量的历史行为,这样在预测某个商品广告用户是否点击的时候,就可以参考他之前购买过或者查看过的商品,这样就能猜测出用户的大致兴趣来,推荐才能做的更加到位,这个模型的使用场景是非常注重用户的历史行为特征。

在个性化的电商广告推荐业务场景中,也正是由于用户留下了大量的历史交互行为,才更加看出了之前的深度学习模型(作者统称Embeding&MLP模型)的不足之处。如果学习了前面的各种深度学习模型,就会发现Embeding&MLP模型对于这种推荐任务一般有着差不多的固定处理套路,就是大量稀疏特征先经过embedding层, 转成低维稠密的,然后进行拼接,最后放入到多层神经网络中去。

这些模型在这种个性化广告点击预测任务中存在的问题就是无法表达用户广泛的兴趣,因为这些模型在得到各个特征的embedding之后,就蛮力拼接了,然后就各种交叉等。这时候根本没有考虑之前用户历史行为商品具体是什么,究竟用户历史行为中的哪个会对当前的点击预测带来积极的作用。 而实际上,对于用户点不点击当前的商品广告,很大程度上是依赖于他的历史行为。

广告特征和用户特征的关联程度是非常强的,假设广告中的商品是键盘,用户的点击商品序列中有几个不同的商品id,分别是鼠标、T恤和洗面奶。从常识出发,“鼠标”这个历史商品id对预测“键盘”广告的点击率的重要程度应大于后两者。(来源:《深度学习推荐系统》王喆 电子工业出版社)

所以之前的深度学习模型(embedding+mlp),是没法很好的去表达出用户这广泛多样的兴趣的,如果想表达的准确些, 那么就得加大隐向量的维度,让每个特征的信息更加丰富, 那这样带来的问题就是计算量上去了,毕竟真实情景尤其是电商广告推荐的场景,特征维度的规模是非常大的。 并且根据上面的例子, 也并不是用户所有的历史行为特征都会对某个商品广告点击预测起到作用。所以对于当前某个商品广告的点击预测任务,没必要考虑之前所有的用户历史行为。

为什么embedding层的收敛速度往往很慢
在深度学习网络中,Embedding层的作用是将稀疏输入向量转换成稠密向量,但Embedding层的存在往往会拖慢整个神经网络党的收敛速度,原因有两个:
①Embedding层的参数数量巨大。这里可以做一个简单的计算。假设输入层的维度是100,000,embedding层输出维度是32,上层再加5层32维的全连接层,最后输出层维度是10,那么输出层到embedding层的参数数量是32x100,000=3,200,000,其余所有层的参数总数是(32x32)x4+32x10=4461.那么,embedding层的权重总数占比是3,200,000/(3,200,000+4416)=99.86%。
也就是说,embedding层的权重占了整个网络权重的绝大部分。那么,训练过程可想而知,大部分的训练时间和计算开销都被embedding层占据。
②由于输入向量过于稀疏,再随机梯度下降的过程中,只有与非零特征相连的embedding层权重会被更新,这进一步降低了embedding层的额收敛速度。
(来源:《深度学习推荐系统》王喆 电子工业出版社)

2. 模型原理

在业务的角度,需要自适应的去捕捉用户的兴趣变化,这样才能较为准确的实施广告推荐;从模型的角度,应当考虑到用户的历史行为商品与当前商品广告的关联性,如果用户历史商品中很多与当前商品关联,那么说明该商品可能符合用户的品味,就把该广告推荐给他。而谈到关联性,就容易想到“attention”的思想了, 所以为了更好的从用户的历史行为中学习到与当前商品广告的关联性,学习到用户的兴趣变化, 作者把注意力引入到了模型,设计了一个"local activation unit"结构,利用候选商品和历史问题商品之间的相关性计算出权重,这个就代表了对于当前商品广告的预测,用户历史行为的各个商品的重要程度大小, 而加入了注意力权重的深度学习网络,就是DIN。

2.1 特征表示

因为DIN的提出就是为了适应在工业领域推荐算法的应用问题,所以,其输入的数据大多是multi-group categorial form,它们被one-hot或者multi-hot形式表示出来,这种数据集一般长这样:

而在User Behavior中,就包含着丰富的用户兴趣数据,对于特征编码,作者举了个例子:[weekday=Friday, gender=Female, visited_cate_ids={Bag,Book}, ad_cate_id=Book], 这种情况一般是通过one-hot的形式对其编码。但是visted_cate_ids属性值,表示的是用户的历史商品列表,显然,用户购买的商品数量肯定是不一样的,那么这个属性的值的多少也就是是不确定的,是一个多值型的特征。将其进行编码的话,就不是一个1和一堆0了,可能是很多1和一堆0,这就要用到multi-hot编码,有哪个商品,对应位置就是1, 所以经过编码后的数据:

2.2 模型原理

DIN的base model仍然是Embedding&MLP的形式(我为什么要说仍然?之前那些模型好像都是,hhh)。而DIN在此基础上添加了attention机制来学习当前候选广告与用户历史行为特征的相关性,从而动态捕捉用户的兴趣。

attention
由于在DIN中,需要通过用户的历史行为来推荐广告,而每个广告的侧重点不一样。如上例中,若广告中的商品是键盘,用户的点击商品序列中有几个不同的商品id,分别是鼠标、T恤和洗面奶。从常识出发,“鼠标”这个历史商品id对预测“键盘”广告的点击率的重要程度应大于后两者。这时就需要attention"鼠标",增加鼠标在广告推荐上的权重。


Embedding Layer
与之前的Embedding相同,这个层的作用是把高维稀疏的输入转成低维稠密向量, 每个离散特征下面都会对应着一个embedding词典, 维度是D×KD\times KD×K, 这里的DDD表示的是隐向量的维度, 而KKK表示的是当前离散特征的唯一取值个数。

embedding过程:
举个例子说明,就比如上面的weekday特征:
假设某个用户的weekday特征就是周五,化成one-hot编码的时候,就是[0,0,0,0,1,0,0]表示,这里如果再假设隐向量维度是D, 那么这个特征对应的embedding词典是一个D×7D\times7D×7的一个矩阵(每一列代表一个embedding,7列正好7个embedding向量,对应周一到周日),那么该用户这个one-hot向量经过embedding层之后会得到一个D×1D\times1D×1的向量,也就是周五对应的那个embedding,怎么算的,其实就是embedding矩阵∗[0,0,0,0,1,0,0]Tembedding矩阵* [0,0,0,0,1,0,0]^Tembedding[0,0,0,0,1,0,0]T 。其实也就是直接把embedding矩阵中one-hot向量为1的那个位置的embedding向量拿出来。 这样就得到了稀疏特征的稠密向量了。(来源:datawhale)

但是对于multi-hot编码的特征,会得到一个embedding向量的列表,因为开始的multi-hot向量不止有一个是1,这样乘embedding矩阵,就会得到一个列表。通过这个层,上面的输入特征都可以拿到相应的稠密embedding向量了。

Pooling layer and Concat layer

在base model中,Pooling层的作用是将用户的历史行为embedding这个最终变成一个定长的向量,就像之前说的,不同的用户有不同的行为,我们需要把不同数量的embedding向量组合成固定维数的输入向量输入到MLP中去,所以我们需要一个pooling来结合它们ei=pooling(ei1,ei2,...eik)e_i=pooling(e_{i1}, e_{i2}, ...e_{ik}) ei=pooling(ei1,ei2,...eik) sum-pooling和average pooling都很常用。

这时eie_iei就变成了定长的向量, 这里的iii表示第iii个历史特征组(是历史行为,比如历史的商品id,历史的商品类别id等), 这里的kkk表示对应历史特种组里面用户购买过的商品数量,也就是历史embedding的数量,看上面图里面的user behaviors系列,就是那个过程了。

经过embedding之后,每个用户的multi-hot会转换成数量不同,但维度相同的多个向量。在pooling的时候,我们想要推荐的商品就是candidate,与candidate相关的商品权重大一些,与candidate不相关的商品权重小一些,这是一种attention的思想。将candidate Ad与点击序列中的每个商品发生交互来计算attention分数。具体计算方法如下图右上角的小网络所示,输入包括user behaviors和candidate Ad,以及两者的外积。对于不同的candidate,得到的用户表示向量也不同,具有更大的灵活性。具体方法如下:
vU(A)=f(vA,e1,e2,…,eH)=∑j=1Ha(ej,vA)ej=∑j=1Hwjej\boldsymbol{v}_{U}(A)=f\left(\boldsymbol{v}_{A}, \boldsymbol{e}_{1}, \boldsymbol{e}_{2}, \ldots, \boldsymbol{e}_{H}\right)=\sum_{j=1}^{H} a\left(\boldsymbol{e}_{j}, \boldsymbol{v}_{A}\right) \boldsymbol{e}_{j}=\sum{j=1}^{H} \boldsymbol{w}_{j} \boldsymbol{e}_{j} vU(A)=f(vA,e1,e2,,eH)=j=1Ha(ej,vA)ej=j=1Hwjej 这里的e1,e2,…,eH{ \boldsymbol{e}_{1}, \boldsymbol{e}_{2}, \ldots, \boldsymbol{e}_{H}}e1,e2,,eH是用户UUU的历史行为特征embedding, vAv_{A}vA表示的是候选广告AAA的embedding向量, a(ej,vA)=wja(e_j, v_A)=w_ja(ej,vA)=wj表示的权重或者历史行为商品与当前广告AAA的相关性程度。a(⋅)a(\cdot)a()表示注意力机制, 当然,看图里的话,输入除了历史行为向量和候选广告向量外,还加了一个它俩的外积操作,作者说这里是有利于模型相关性建模的显性知识。

一般来说,做attention的时候,需要对所有的分数通过softmax做归一化,这样做有两个好处,一是保证权重非负,二是保证权重之和为1。但是在DIN的论文中强调,不对点击序列的attention分数做归一化,直接将分数与对应商品的embedding向量做加权和,目的在于保留用户的兴趣强度。

经过pooling的不同种类的向量会在concat&flatten layer组合起来作为MLP的输入。

MLP
将pooling和concat的数据以全连接的方式输入MLP

Loss
由于这里是点击率预测任务, 二分类的问题,所以这里的损失函数用的负的log对数似然: L=−1N∑(x,y)∈S(ylog⁡p(x)+(1−y)log⁡(1−p(x)))L=-\frac{1}{N} \sum_{(\boldsymbol{x}, y) \in \mathcal{S}}(y \log p(\boldsymbol{x})+(1-y) \log (1-p(\boldsymbol{x}))) L=N1(x,y)S(ylogp(x)+(1y)log(1p(x)))

3. 代码实现

DIN模型的输入特征大致上分为了三类: Dense(连续型), Sparse(离散型), VarlenSparse(变长离散型),也就是指的上面的历史行为数据。而不同的类型特征也就决定了后面处理的方式会不同:

Dense型特征:由于是数值型了,这里为每个这样的特征建立Input层接收这种输入, 然后拼接起来先放着,等离散的那边处理好之后,和离散的拼接起来进DNN
Sparse型特征,为离散型特征建立Input层接收输入,然后需要先通过embedding层转成低维稠密向量,然后拼接起来放着,等变长离散那边处理好之后, 一块拼起来进DNN, 但是这里面要注意有个特征的embedding向量还得拿出来用,就是候选商品的embedding向量,这个还得和后面的计算相关性,对历史行为序列加权。
VarlenSparse型特征:这个一般指的用户的历史行为特征,变长数据, 首先会进行padding操作成等长, 然后建立Input层接收输入,然后通过embedding层得到各自历史行为的embedding向量, 拿着这些向量与上面的候选商品embedding向量进入Attention Pooling Layer去对这些历史行为特征加权合并,最后得到输出。
通过上面的三种处理, 就得到了处理好的连续特征,离散特征和变长离散特征, 接下来把这三种特征拼接,进DNN网络,得到最后的输出结果即可:

# DIN网络搭建
def DIN(feature_columns, behavior_feature_list, behavior_seq_feature_list):"""这里搭建DIN网络,有了上面的各个模块,这里直接拼起来:param feature_columns: A list. 里面的每个元素是namedtuple(元组的一种扩展类型,同时支持序号和属性名访问组件)类型,表示的是数据的特征封装版:param behavior_feature_list: A list. 用户的候选行为列表:param behavior_seq_feature_list: A list. 用户的历史行为列表"""# 构建Input层并将Input层转成列表作为模型的输入input_layer_dict = build_input_layers(feature_columns)input_layers = list(input_layer_dict.values())# 筛选出特征中的sparse和Dense特征, 后面要单独处理sparse_feature_columns = list(filter(lambda x: isinstance(x, SparseFeat), feature_columns))dense_feature_columns = list(filter(lambda x: isinstance(x, DenseFeat), feature_columns))# 获取Dense Inputdnn_dense_input = []for fc in dense_feature_columns:dnn_dense_input.append(input_layer_dict[fc.name])# 将所有的dense特征拼接dnn_dense_input = concat_input_list(dnn_dense_input)   # (None, dense_fea_nums)# 构建embedding字典embedding_layer_dict = build_embedding_layers(feature_columns, input_layer_dict)# 离散的这些特特征embedding之后,然后拼接,然后直接作为全连接层Dnn的输入,所以需要进行Flattendnn_sparse_embed_input = concat_embedding_list(sparse_feature_columns, input_layer_dict, embedding_layer_dict, flatten=True)# 将所有的sparse特征embedding特征拼接dnn_sparse_input = concat_input_list(dnn_sparse_embed_input)   # (None, sparse_fea_nums*embed_dim)# 获取当前行为特征的embedding, 这里有可能有多个行为产生了行为列表,所以需要列表将其放在一起query_embed_list = embedding_lookup(behavior_feature_list, input_layer_dict, embedding_layer_dict)# 获取历史行为的embedding, 这里有可能有多个行为产生了行为列表,所以需要列表将其放在一起keys_embed_list = embedding_lookup(behavior_seq_feature_list, input_layer_dict, embedding_layer_dict)# 使用注意力机制将历史行为的序列池化,得到用户的兴趣dnn_seq_input_list = []for i in range(len(keys_embed_list)):seq_embed = AttentionPoolingLayer()([query_embed_list[i], keys_embed_list[i]])  # (None, embed_dim)dnn_seq_input_list.append(seq_embed)# 将多个行为序列的embedding进行拼接dnn_seq_input = concat_input_list(dnn_seq_input_list)  # (None, hist_len*embed_dim)# 将dense特征,sparse特征, 即通过注意力机制加权的序列特征拼接起来dnn_input = Concatenate(axis=1)([dnn_dense_input, dnn_sparse_input, dnn_seq_input]) # (None, dense_fea_num+sparse_fea_nums*embed_dim+hist_len*embed_dim)# 获取最终的DNN的预测值dnn_logits = get_dnn_logits(dnn_input, activation='prelu')model = Model(inputs=input_layers, outputs=dnn_logits)return model

Datawhale第23期组队学习—深度学习推荐系统—task5 DIN相关推荐

  1. 深度学习 免费课程_深入学习深度学习,提供15项免费在线课程

    深度学习 免费课程 by David Venturi 大卫·文图里(David Venturi) 深入学习深度学习,提供15项免费在线课程 (Dive into Deep Learning with ...

  2. 【杂谈】如何在言有三本人的随时答疑下, 长期而系统地学习深度学习和计算机视觉,这是有三AI的完整计划...

    对深度学习从业者要说的话 深度学习的前身是神经网络,属于机器学习技术中的一种,诞生于半个多世纪以前,随着计算硬件水平的提升,工业大数据的积累以及相关理论的完善,如今得以在各行各业大展拳脚.从应用领域来 ...

  3. 【杂谈】2020年如何长期、系统,全面地学习深度学习和计算机视觉,这是有三AI的完整计划...

    对深度学习从业者要说的话 深度学习的前身是神经网络,属于机器学习技术中的一种,诞生于半个多世纪以前,随着计算硬件水平的提升,工业大数据的积累以及相关理论的完善,如今得以在各行各业大展拳脚.从应用领域来 ...

  4. 深度学习——深度学习基础概念

    摘要 本文将针对与深度学习的平台的这样的一个理解和实战这样的一个理解.这是一个系列的课程.我将一直更新有关于的paddle的开发和学习.Paddle包括众多方面.目标检测.文字识别.图像分类.图像分割 ...

  5. 动手学习深度学习-环境配置

    文章目录 前言 一.anacoda的安装 二.搭建环境 1.安装miniconda 2.修改下载源 三.安装mxnet 四.验证安装成功 参考资料 前言 小白入门深度学习,学习<手动学习深度学习 ...

  6. 如何系统型地学习深度学习?| 文末送书

    链接:https://www.zhihu.com/question/305745486 编辑:深度学习与计算机视觉 声明:仅做学术分享,侵删 如何系统型的学习深度学习? 不知小伙伴们遇到没遇到这样的情 ...

  7. 最新《动手学习深度学习》配套课程视频、笔记、ppt等资源整理分享

    <动手学习深度学习>是李沐老师(AWS 资深首席科学家,美国卡内基梅隆大学计算机系博士)主讲的一系列深度学习视频.本项目收集了我们在寒假期间学习<动手学习深度学习>过程中详细的 ...

  8. 系统学习深度学习(博客转载地址)

    转载深度学习学习系列的一些文章 1. 系统学习深度学习(一) --深度学习与神经网络关系 https://blog.csdn.net/app_12062011/article/details/5431 ...

  9. 最新版动手学习深度学习和GAN电子书免费下载!

    今天给大家推荐一个GAN方面的优质公众号---机器学习与生成对抗网络.该公众号里分享了几本深度学习.GAN等好的电子书资源! 强烈推荐李沐等人的<动手学习深度学习>最新版!完整中文版 PD ...

最新文章

  1. 听研二师兄师姐报告收获
  2. 解决了一个小问题 好像把逻辑有点复杂
  3. pc显示器分辨率 前端_五款高性价比PC显示器推荐 499元起
  4. 配置多个git账号_在Windows下配置多个git账号
  5. Calendar Game POJ - 1082(关于日历的博弈问题)
  6. 启动oracle数据库工具,Oracle数据库常用工具
  7. [vue] vue的is这个特性你有用过吗?主要用在哪些方面?
  8. html 设置两个标签的相对距离_如何准确计算一div相对另一div的相对距离?
  9. Vmware报错:此主机支持IntelVTx 但IntelVTx处于禁用状态
  10. linux上pybind11编辑python库
  11. python期权价格计算器_使用Python自带GUI tkinter编写一个期权价格计算器
  12. html5 css 字体加粗,HTML和CSS实现字体加粗的三种方法
  13. f2fs系列文章gc
  14. 配置ip地址常用命令及解释
  15. 【C++OJ多重继承与虚拟继承】商旅信用卡(多重继承)
  16. 深入理解JVM - 类文件的结构
  17. vue实现用户登录验证 + 权限验证 + 动态路由(左侧菜单栏)
  18. 金山 WPS 2016 春季实习校招笔试面试回忆
  19. 网络设备升级破解密码
  20. PHOTOSHOP CS打造素描MM

热门文章

  1. 计算机毕业设计Java家乡旅游文化推广网站(源码+系统+mysql数据库+lw文档)
  2. 用Python实现定时自动化收取蚂蚁森林能量,再也不用担心忘记收取了
  3. Excel 做相关性分析
  4. Minecraft 服务器显示旧版进不去,【开服求助】自己建立的服务器进不去
  5. 古月居ROS 入门21讲--PA5-PA8笔记
  6. 文件批量重命名神器:Bulk Rename Utility
  7. A Game of Thrones(62)
  8. 开放式WEP和共享式WEP的区别
  9. Windows 和 Linux 查看和关闭端口常用命令解析
  10. HTML和CSS整合笔记