ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

DIN与DIEN:从注意力机制到用户兴趣演化建模

DIN与DIEN:从注意力机制到用户兴趣演化建模 1. DIN出现之前电商推荐模型差在哪2018年前后阿里妈妈团队放出了DINDeep Interest Network论文随后在2019年又推出了DIENDeep Interest Evolution Network这两篇论文在工业界推荐系统圈子里几乎是人手一份的必读材料。当时我在做电商场景的CTR预估看完DIN的感受是这个模型的思路其实非常简单但它精准地捅破了一层窗户纸——用户行为序列并非一个固定长度的稠密向量而是一堆五花八门的兴趣碎片直接把它们压平成定长向量信息损耗实在太大。要理解DIN和DIEN的价值先得回到它们出现之前的基线模型究竟是怎么处理用户行为的。主流方案是EmbeddingMLP的塔式结构用户历史行为点击过的商品、浏览过的店铺、搜过的关键词被打平成固定长度的向量拼上用户画像、商品特征、上下文特征一起喂进全连接网络。这套方案看起来没什么问题但一旦落到真实的电商场景很快就会暴露几个痛点。第一个痛点是行为序列的异构性。用户的历史行为并不是同质的。有人上午看了MacBook下午给娃买奶粉晚上又顺手点开一双跑鞋。这些行为在“预测用户是否点击某款新MacBook”这件事上的重要性完全不同。但EmbeddingMLP的结构在池化层把所有行为等权相加跑鞋和奶粉的embedding一平均MacBook的兴趣信号就被稀释得不成样子。我见过有些团队为了缓解这个问题直接把行为序列拉长到几百个结果模型参数量爆炸线上延迟也扛不住。第二个痛点是候选商品与行为的交互缺失。用户是否点击某个商品本质上取决于这个商品和他过往兴趣的匹配程度。静态池化把行为序列变成一个与候选商品完全无关的用户向量等于让模型“闭眼”判断候选商品与用户兴趣的匹配度这个信息瓶颈是致命伤。DIN最核心的贡献就是用候选商品去激活用户行为序列中相关的部分相当于在判断之前先“对焦”。第三个痛点是行为顺序与兴趣演化被忽略。用户今天的兴趣和昨天的兴趣其实是有连续性的。上个月频繁浏览婴儿用品说明家里有新生儿最近一周开始搜索儿童绘本说明孩子长大了。这种演化趋势里藏着很强的购买意图信号但在DIN出现之前几乎没有人把行为序列按时间顺序建模更没有人去刻画“兴趣从哪里来、往哪里去”的过程。DIN和DIEN分别针对前两个和第三个痛点给出了解法。DIN解决的是“兴趣是多样的”这一事实DIEN在此基础上再进一步处理的是“兴趣是演化的”这一事实。两者不是替代关系而是递进关系。要真正理解它们得从模型结构背后的业务逻辑和社会观察说起而不是只看几篇论文的结构图。2. DIN模型拆解注意力机制怎么被用到用户兴趣建模上DIN全称Deep Interest Network核心思想一句话就能讲清楚用户的兴趣是多样的预测不同商品时历史行为中只有一部分值得重点关注。它用候选商品作为query对用户行为序列中的每个行为计算一个权重再做加权求和得到与当前候选商品相关的兴趣向量。这个机制现在看起来像极了Transformer里的self-attention但在2018年把这种“相关性加权”思路直接用MLP实现并大规模落地到工业级CTR模型里DIN是第一批。2.1 Activation Unit一个用MLP算出来的“注意力分数”DIN的注意力权重结构非常朴素没有用点积、没有缩放、没有softmax先归一化。它把候选商品embedding和每个行为商品的embedding拼起来再算它们的差和逐元素乘积得到一个拼接向量喂入一个两到三层的MLP输出一个标量作为注意力分数。这个设计的核心在“差和乘积”的拼接上。拼接本身保留了两个向量各自的完整信息逐元素乘积捕捉了两个向量在每一维上的交互强度差值则捕捉了它们之间的“距离”。用这个四路拼接作为MLP的输入MLP就能学到比简单的点积更丰富的匹配信号。我曾在离线实验里试过把差值去掉只用concatenate和element-wise productAUC掉了将近0.3个百分点说明距离信息确实在传参时起到作用。整个加权求和的公式可以写成兴趣向量 Σ (attention_score_i × 行为embedding_i)这里有个常被初学者忽略的细节DIN没有在注意力分数上做softmax归一化。为什么不归一化论文作者的解释是加权求和的输出最终会经过全连接层和最后的softmax层完成归一化所以中间层不需要额外的归一化操作而且不限制权重范围可以让模型的拟合空间更大。我在实际训练中也验证过如果在Activation Unit输出后强行加一个softmax模型收敛速度反而变慢效果没有明显提升。这个设计看起来反直觉但它是经过业务验证的不要随手“修正”它。2.2 GAUC为什么要用分组AUC评估DIN论文里还有一个常被引用但容易被忽略的细节就是评估指标从AUC改成了GAUCGroup AUC。传统AUC把所有用户的预测结果混在一起计算这在电商场景是有失真的。不同用户的行为模式差异太大有的用户只点击过5次商品有的用户点击过500次这两类用户混在一起算AUC模型的排序能力会被整体平均掩盖。GAUC的具体做法是先按用户分组在每个用户的样本上分别计算AUC再把所有用户的AUC按该用户的曝光量加权平均。这个指标对“用户级排序能力”更敏感。我自己的经验是模型离线AUC提升0.5%可能在线效果平平但GAUC提升0.5%往往能在线上带来明显的CTR涨幅。所以后来我跟同行交流时凡是做电商推荐的人我都会建议报表上同时放AUC和GAUC两个指标并且以GAUC为主要调参依据。2.3 从“独立行为”到“加权行为”DIN到底改变了什么把DIN和之前的模型放在一起对比可以看得更清楚。之前的模型把用户行为序列视为一组互不相关的信号无论候选商品是什么用户的表示向量是同一个DIN则让用户表示向量变成候选商品的函数。同一个用户在预测MacBook和跑鞋时得到的用户兴趣向量是不同的。但这并不意味着DIN已经完美解决了建模问题。它依然假设行为之间是相互独立的没有利用行为之间的时间顺序和依赖关系。一个用户在一小时内连续点击了五款手机之后紧接着点击了一款手机壳这个序列里藏着“换新手机”的强意图。DIN只会把这六个行为当成无序集合来处理它在第1次点击和最后1次点击之间的转移关系中能够学习到的信息非常有限。这就引出了DIEN的定位。3. 被很多人忽略的工程细节Dice激活与正则化DIN论文里除了模型结构的创新还搞定了两个非常实际的工程问题一个是激活函数在训练初期的分布偏移另一个是L2正则化在Embedding参数上的超高计算开销。这两个问题如果没有处理好DIN的复现效果会大打折扣而且很多人在复现时效果不好往往就死在这两个点上。3.1 Dice激活函数让网络自己决定闸门开在哪推荐模型里的特征大多是稀疏的但经过Embedding查表后送入神经网络的实际上是稠密的embedding向量。神经网络的隐藏层在训练初期输入分布是剧烈变化的。PReLU可以看作带一个可学习斜率的ReLU但它的阈值依然是固定的0。Dice激活函数的核心改动是让“阈值”也变成数据依赖的即根据当前batch的输入均值和方差做归一化再用一个sigmoid控制左右两边的平滑过渡。这个思路在特征分布漂移严重的大规模稀疏场景下特别有效。我在复现时对比过PReLU和Dice的效果在同样的学习率、同样的训练步数下用Dice的模型在AUC上比PReLU高出0.2到0.3个百分点而且前期loss下降更平稳。原因也很简单稀疏场景下很多特征在实际样本中出现的频率非常低固定阈值的激活函数在处理这些低频特征的embedding时更容易产生梯度方向震荡Dice的归一化机制在一定程度上自适应的缓解了这个问题。3.2 Mini-batch Aware正则化与自适应学习率CTR模型的Embedding表往往非常大几亿甚至几十亿的参数都有可能。如果对这些参数做标准的L2正则化每个batch都要更新所有Embedding向量的梯度这个计算量完全不可接受。DIN的解决方案是Mini-batch Aware正则化只对当前batch中实际出现过的特征ID对应的Embedding做L2更新没出现的特征ID就跳过。这篇文章里还对不同频率特征的Embedding做了自适应学习率调整频繁出现的特征更新步长小一点稀疏特征更新步长大一点。这个思路和Adagrad有些相似。如果缺了这个修正高频特征的Embedding会学得非常“油滑”对真实兴趣的表征能力反而下降低频特征的Embedding又学不到位训练速度慢得令人抓狂。很多复现DIN的人只关注Activation Unit的结构对激活函数和正则化一带而过结果离线效果始终差论文一截。我自己的经验是这两处工程优化在大规模数据上的增益甚至超过了Activation Unit本身带来的提升。4. DIEN的新问题意识从“兴趣多样”到“兴趣演化”DIN上线后效果提升明显但做推荐系统的人马上又碰到了新的问题。DIN把行为序列当作无序集合处理可用户的行为是有时间顺序的。用户的兴趣不是静态的标签集合而是会随时间演化的过程。今天看手机是因为旧手机坏了明天看手机壳是因为新手机到了。这些连续行为背后的兴趣转移和演化趋势如果能被显式建模就能捕捉到更强的购买意图。DIENDeep Interest Evolution Network就是从这个角度切入的。它的核心问题从“哪些行为重要”变成了“兴趣是怎么从一个状态演化到另一个状态的”。这个转变表面上只是多了个时序建模实际上是把模型的假设从“用户兴趣是多样且静态的”升级为“用户兴趣是多样且动态演化的”。4.1 兴趣抽取层与辅助损失逼GRU学出真正的“兴趣”DIEN的第一层是一个双向或单向的GRU网络把行为序列按时间顺序输入得到每个时间步的隐状态。但这里有个关键问题直接用行为embedding训练GRU隐状态学到的是“行为特征”而非“兴趣状态”。用户在t时刻点击了商品A这个行为本身是商品A的特征而不是用户t时刻完整的兴趣。打个比方用户在晚上看到了一条连衣裙的广告并点击了它第二天早上又在搜索平底鞋。如果GRU只是建模“点击了连衣裙”这个事件它对“用户兴趣在向通勤穿搭演化”的理解就远不够深入。为了逼GRU的隐状态表达“兴趣”而非“行为”DIEN设计了一个辅助损失。这个辅助损失的做法是用t时刻的隐状态去预测t1时刻的真实行为。也就是说要求第t步的隐状态不仅能解释当前点击的商品还能为下一步点击做铺垫。这个辅助损失通过一个额外的二分类网络把输出和真实行为embedding做内积计算然后和负采样行为做交叉熵。这就像把“预测下一个行为”这个任务劈开作为GRU训练时的强约束。我在复现DIEN时特意做过开启和关闭辅助损失的对比实验。关闭辅助损失后模型效果跌到和DIN差不多甚至略差——因为GRU如果不加约束很容易退化成“记忆点击序列”而不是“提取兴趣演化”。开启辅助损失后GAUC有明显提升。这说明辅助损失在DIEN里不是锦上添花而是灵魂之一。4.2 兴趣演化层从GRU到AUGRU的跨越有了兴趣抽取层我们得到了每个时间步的兴趣状态序列。但并非所有兴趣都与当前候选商品相关。用户过去一周的兴趣演变可能是“童装→绘本→积木”现在候选商品是“乐高机械组”整条演化路径中“积木”这个方向显然更值得关注。兴趣演化层的作用就是在大量兴趣状态里找到与候选商品相关的那条演化路径。DIEN论文里首先尝试了将注意力得分直接乘以GRU的输入称为AIGRUAttention-based input GRU。实际效果不理想因为如果第一层有些无关的兴趣状态被赋予接近0的权重GRU就会丢失这部分信息而且这个衰减可能在后续时间步被逐层放大。接着又尝试了将注意力得分直接与隐状态相乘的AGRUAttention-based GRU这比AIGRU好但它直接把门控值替换成注意力分数丢失了GRU门控机制本身学到的自适应记忆控制能力。最后DIEN选定了AUGRUAttention-based Update Gate GRU方案用注意力分数作为GRU更新门的修正因子。更新门控制的是“保留多少旧记忆”和“吸收多少新信息”这个位置刚好把“与候选商品相关的兴趣才值得演化”的意图精准地嵌入了GRU的记忆更新机制中。更新门输出 注意力分数 × GRU更新门原始输出这样即使在注意力权重较低的时间步GRU仍能靠原始门的自适应能力决定记忆的保留程度。5. DIN与DIEN全方位对比论文不会明说的差异DIN与DIEN的关系很多初学者容易搞混。有人觉得DIEN比DIN高一个档次直接做DIEN就行也有人觉得两者差不多随便选一个就行。这两种说法都不准确。从业务适配的角度看DIN和DIEN解决的是不同层次的问题适用条件的宽窄也不一样。5.1 核心假设对比维度DINDIEN核心问题用户兴趣是多样的需要根据候选商品选择相关行为用户兴趣是演化的需要在演化路径中提取与候选商品相关的片段行为序列处理无序集合加权求和有序序列GRU逐步建模兴趣表达与候选商品相关的加权行为向量与候选商品相关的演化路径末态时间依赖不依赖行为顺序依赖行为顺序训练复杂度低MLP为主高GRU辅助损失在线推断速度快相对较慢GRU串行计算适用场景行为丰富但短期意图不强的场景行为序列具有明显递进关系的场景这个表格的意义在于DIEN并不在任何场景下都优于DIN。我见过一些团队在数据稀疏的冷启动场景下强行上DIEN结果GRU因样本不足很难收敛效果反而不如DIN。反过来在用户行为序列长且具有明显递进性的场景比如电商大促前的浏览→收藏→加购DIEN捕捉演化路径的优势就能充分释放。5.2 为什么说AUGRU是DIEN最容易踩坑的组件AUGRU的实现看起来只是把更新门做了一次乘法但里面的细节如果不注意复现的效果会天差地别。先是注意力分数的来源DIEN中的注意力得分与DIN类似也是由候选商品embedding与当前时间步的兴趣状态即GRU隐状态共同计算出来的而不是与原始行为embedding计算。门上乘法实现时是在计算新候选状态之前用注意力分数乘更新门再参与下一个隐状态的更新。如果把注意力分数乘到输入上注意力分数乘到隐状态上或者乘到了重置门上效果都会明显变差这不是“差不多”级别的差异而是GAUC下降0.5个百分点的级别。我踩过的一个坑是注意力分数的数值范围。AUGRU中的注意力分数来自sigmoid输出0到1之间理论上可以直接乘更新门。但如果在实现时用了softmax归一化或者手动缩放过得分分布就会完全变形AUGRU的更新门会被压缩到特别小的范围记忆几乎无法更新模型的表达能力就会严重受限。这一点论文里没有专门强调但复现时非常关键。5.3 训练技巧负采样是辅助损失的生命线DIEN的辅助损失需要一个关键设计负采样。在每个时间步用当前GRU隐状态去预测下一个行为时正样本下一时刻真实点击的商品只有一个如果直接和一个正样本算交叉熵训练信号太稀疏模型很难收敛。因此负采样的做法是给每个正样本随机抽取若干个未被用户点击过的商品作为负样本然后计算一个多分类或二分类的损失。这里负采样的数目直接影响模型效果。采样太少模型学不到足够的判别信息采样太多训练时间暴增。我实测下来负采样数量取2到4个时性价比最高再多对GAUC的提升就非常有限了。还有一个细节负样本要避免与当前正样本来自同一商品的重复曝光否则负样本的实际语义变模糊模型学出来的兴趣状态会被带偏。这些细节论文里不会有但每次复现都会遇上。6. 复现与上线踩坑记录最后分享一些我在复现和上线DIN、DIEN时的实际经验包括数据处理、训参、部署时的一些细节和踩坑希望你能少走些弯路。6.1 行为序列长度怎么截断用户的真实行为序列长短差异巨大有人近30天点击了3000个商品有人只点了3个。直接全部输入模型序列长度不一训练时padding太浪费截断又会丢失尾部兴趣信号。正常做法是截取最近50到100个行为因为通常在推荐场景里最近的行为权重远高于很久之前的行为。如果业务上季节性因素很强可以适当把窗口拉长到200但不要更长否则GRU的时间步变长训练速度和显存开销都会吃紧。DIN对序列长度没那么敏感因为它是无序集合DIEN则需要考虑行为的时间连续性截断时尽量保留连续的一段不要采样式截断。6.2 Embedding维度与初始化DIN和DIEN的Embedding维度业界常见的是16到32维而非很多论文里写的64或128维。原因是推荐场景的特征空间很大用户数、商品数动辄上千万Embedding维度越高参数总量越大过拟合风险越高训练速度和内存开销也随之上升。我自己的经验是特征数量多且稀疏时16维起步逐步往上调在验证集上看GAUC的增益是否值得额外的资源开销。Embedding的初始化建议用均值为0、方差很小的正态分布不要用全0初始化。全0初始化会让所有行为embedding在训练初期完全相同Attention得分退化成均匀分布DIN的动态加权能力在第一轮更新里完全体现不出来。6.3 训练时的学习率与batch sizeDIN和DIEN这类模型用Adam优化器时学习率一般设在0.001附近需要配合warmup或者逐步衰减。我在实际训练中发现学习率过大0.01以上时模型的前期训练波动非常剧烈尤其是DIEN的GRU部分很容易出现梯度爆炸学习率过小0.0001以下时低频特征的Embedding更新太慢训练步数不够时效果明显偏差。batch size建议在1024到4096之间。batch size太小时梯度估计的方差大Dice激活函数里的batch统计数据也更容易抖动batch size太大时训练速度快但模型的AUC可能会略微下降需要根据数据量做折中。6.4 特征体系的搭配技巧DIN和DIEN的模型结构主要解决用户行为序列的建模问题但推荐系统的整体效果很大程度上还依赖整个特征体系的完整度。用户静态特征性别、年龄、消费水平、商品特征类目、价格带、品牌、上下文特征时间、位置、渠道这些基础特征必须和行为序列特征配合使用。我自己做实验时的体会是行为序列建模做得好能把CTR预估的上限提高但下限还是由整个特征体系撑住的。只堆行为序列、其他特征一塌糊涂的模型上线后效果不一定比特征工程扎实的简单模型好。6.5 从离线指标到线上AB测试绝对不要把离线AUC的提升直接等同于线上CTR的提升。离线AUC反映的是排序能力的一种度量但线上的展示位置、竞价环境、商品池变化都会影响最终的真实点击率。我在一次实验中离线GAUC提升了0.4个百分点上线的CTR却几乎没有变化后来排查发现是推荐列表中商品池与训练样本的商品池分布不一致部分新商品缺乏足够的历史行为数据模型在它们身上的预测能力非常弱。所以上线前一定要检查候选商品池的分布偏移并且对新商品做好保底策略比如对行为缺失的候选直接用用户静态特征商品特征做打分兜底。DIN与DIEN的整体脉络是DIN把用户行为序列从“无序等权加和”变成了“参考候选商品的加权聚合”解决了兴趣的多样性问题DIEN在这个基础上把行为序列视作时间上有序的信号通过GRU捕捉兴趣从“状态”到“状态”的演化过程再通过AUGRU把候选商品相关的演化路径单独提取出来。对推荐系统的从业者而言我个人的实际经验是如果你的数据规模不大、行为序列较短从DIN入手把基础打牢比直接上手DIEN更有效率如果行为序列长、而且用户行为有明显的节奏变化那DIEN在GAUC上的优势值得你付出额外的调参和训练时间。
返回列表