想象你周末走进一家商场,店员递来一瓶防晒霜。你并不会把从小到大的购物史从头翻到尾——你的目光瞬间停在大三那年海边的泳衣、上个月的遮阳帽,而羽绒服、鼠标垫这些记忆自动“沉”了下去。每个人心里都有一本无形的“购物记忆相册”,而推荐系统的任务,就是为这本相册配一位聪明的店员。 DIN(Deep Interest Network,深度兴趣网络)正是这样一位店员。它来自阿里妈妈团队 2018 年的经典论文,用于广告点击率(CTR)预估。过去的方法把所有历史行为压成一个固定向量,等于把整本相册揉成一张“模糊合影”;DIN 则先看清候选物品,再动态翻开相册里最相关的几页,按相关性加权求和,得到“此刻、此物”对应的兴趣。这套被称为“局部激活”的思路,让用户千变万化的兴趣第一次有了细腻的数学表达。
掌握 DIN,你就掌握了推荐系统里“候选驱动兴趣建模”的主流范式——它是工业界 CTR 预估的经典地基,也是面试中高频出现的注意力机制考题。
目录
可视化演示
展示DIN通过注意力机制动态激活用户历史行为兴趣,对比局部激活单元结构与多兴趣分布建模。
本节配有交互动效(进入视口后自动加载,约 3KB)。
注意力激活机制 候选物品与历史行为计算相关性 高权重行为被激活 v=Σαᵢ·eᵢ 加权求和生成自适应兴趣向量
1. 推荐系统困境:一张压扁的合影
小李是商场的老顾客,相册里躺着几百条购物记忆。旧店员从不问他想买什么,只把相册从头到尾“平均”成一张模糊合影:无论推销防晒霜还是羽绒服,都指着合影说“这位顾客大概喜欢这些”。合影里什么都有一点,又什么都很模糊——推荐自然隔靴搔痒。
在推荐系统的 CTR 预估任务里,“模糊合影”对应固定长度的用户兴趣向量:把用户历史行为通过 sum pooling 或 average pooling 压成一个定长向量。无论候选物品是什么,模型都用同一个向量喂给多层感知机判断点击概率,无法体现“候选不同、关注不同”。
用户兴趣天然是多峰的:同一用户既关注数码又关注健身。平均池化会让不同兴趣互相稀释,表达力不足。这种固定向量是“候选无关”的表示,公式如下:
合影一旦压成,细节就永久丢失。想要推荐得准,必须允许“同一本相册被不同商品翻出不同的重点”。
- 历史行为向量用户第 i 次交互物品的稠密向量,是 Embedding 层输出的记忆编码。
- 行为数量N 是用户历史行为的条数,对应相册里的照片总数。
- 逐维平均把 N 个向量每个维度取均值,得到固定向量。
- 固定表示vU 与候选物品无关,对任何商品都是同一张“合影”。
2. 局部激活思想:只翻相关的几页
新店员小李学会了关键一招:先看清顾客想买什么,再翻相册。推荐防晒霜时,他把“海边、泳衣、遮阳帽”几页高高举起、放大细看;羽绒服和鼠标垫随手翻过。同一本相册,推销不同商品时,被“点亮”的页面完全不同。
这就是 DIN 的核心思想——局部激活。用户兴趣向量不再是固定的 vU,而是候选物品 A 的函数 vU(A)。每个历史行为与候选算出一个相关性权重,权重越大,该行为对当前兴趣的贡献就越大。
每个历史行为对“此刻兴趣”的贡献并不相等。DIN 用注意力机制为每条历史行为赋予权重,再做加权求和:
候选物品像一块磁铁,吸起相册里相关的铁屑;换一块磁铁,吸起来的铁屑又不同了——这正是“动态激活”的直觉,也是 DIN 与固定向量方法最本质的区别。
- 候选物品向量当前被评估点击概率的广告或商品的嵌入向量,即“眼前推销的商品”。
- 注意力权重由激活单元算出的标量,衡量第 i 条历史行为与候选物品的相关程度。
- 缩放历史向量每条历史行为向量乘上自己的权重,相关记忆被放大,无关记忆被压暗。
- 加权求和把所有缩放后的记忆累加,得到随候选物品变化的用户兴趣向量。
3. 激活单元设计:相册的智能索引卡
店员怎么快速判断“这张照片跟防晒霜有关”?只看照片主色调会出错——沙滩照片和沙漠照片都偏黄。真正靠谱的索引卡要同时看三样东西:照片里的物件、要卖的商品、以及“它们在一起意味着什么”。
DIN 的激活单元就是一张可学习的“索引卡”:一个小型多层感知机。它的输入不是简单拼接,而是加入了候选向量与历史行为向量的逐元素乘积——捕捉“两者共同出现”才成立的相关性。论文示意图中把交叉画成外积,工业实现常用逐元素乘积(⊙)。
索引卡不是死板打分,而是“看照片、看商品、再联想关系”的三层判断。正是这层“联想”,让注意力权重真正代表相关性,而不是简单的余弦相似度。
- 拼接输入把行为向量与候选向量首尾相连,让网络同时看到双方。
- 逐元素乘积v_i ⊙ v_A 刻画“两者共同出现”的交叉信息,只有对应维度都大时响应才大。
- 三路合并拼接后的 3d 维向量作为多层感知机的输入。
- 多层感知机经过线性变换与非线性激活,把 3d 维特征映射为标量权重。
4. 网络结构:从相册到推荐的流水线
单张索引卡还不够,整条推荐链路像一条相册流水线:先给每张照片编号归档,再按当前商品动态检索,最后把检索结果与商品资料交给“评估委员会”打分。
DIN 的网络结构分三段:Embedding 层把高维稀疏特征变成稠密向量;激活单元对用户历史行为做注意力加权池化;最后把池化后的兴趣向量与候选向量、其他上下文特征拼接,送入多层全连接网络,输出点击概率。
其他特征包括用户画像(年龄、性别)、场景特征(时间、地点)等。整体输出公式如下:
编码、检索、评估三步各司其职,共同构成“懂你”的完整流水线。DIN 正是这套流水线的经典模板,也是后来众多兴趣建模模型的骨架。
- 动态兴趣向量注意力池化得到的候选相关兴趣,是“被翻出来的那几页记忆”。
- 候选向量物品自身的嵌入表示,与兴趣向量一起送审,保证“兴趣”始终围绕“商品”。
- 其他特征用户画像、上下文等辅助特征,补充相册之外的信息。
- 概率输出拼接后经多层全连接与 sigmoid,输出点击概率。
5. 训练优化:让翻阅策略越练越准
店员刚开始翻相册全凭感觉,推荐十次错七次。好在顾客会用“点一下 / 划走”给出反馈,系统据此修正翻阅策略:高相关页提亮、低相关页变暗。
DIN 用负对数似然损失(即交叉熵)作为优化目标,配合 Dice 激活函数与自适应正则化。Dice 是 ReLU 的改进版:它的拐点随数据分布自适应移动,避免了 ReLU 在负数区域梯度完全为零的问题,也更适合注意力机制中大量存在的多层小网络。
给定 N 条训练样本,模型输出的点击概率为 ŷᵢ,真实标签为 yᵢ,损失函数如下:
每一次点击都是对翻阅策略的点赞,每一次划走都是纠偏。损失函数就是这场“训练马拉松”的记分牌,Dice 和正则化则是保证选手不摔跤的护具。
- 真实标签样本 i 的点击标签,1 表示点击、0 表示未点击。
- 预测概率模型对样本 i 输出“会点击”的概率。
- 对数损失点击和未点击两条分支分别取对数损失,预测越错,损失越大。
- 批量平均对所有样本损失取平均,得到可微的优化目标。
6. 工业实践:把相册搬进真实商场
小李的“相册翻阅法”在柜台大获成功,整座商场决定全面推广。但商场面临新挑战:千万顾客、亿万商品、每秒上亿次推荐请求。相册法再聪明,也得经得住规模和口碑的双重考验。
工业界落地重点有三:其一,同一用户在不同候选下被激活不同兴趣面,这正是多兴趣分布的有效建模;其二,激活单元带来额外计算,向量维度、层数设计要权衡推理耗时;其三,评估不能只看全局 AUC,而要看GAUC。
全局 AUC 衡量整体排序质量,但推荐本质是“每个用户自己的排序”。GAUC 先把每个用户的 AUC 单独算出来,再按曝光数或点击数加权平均,更贴近业务目标:
相册法从柜台走向整座商场,靠的不是某一次灵光一现,而是“刻画多兴趣—控制成本—多维评估”的工程体系。DIN 正是这套体系的原点。
- 单用户 AUC仅用用户 u 的样本计算 AUC,衡量“发给这个用户的排序是否合理”。
- 用户权重w_u 通常取曝光数或点击数,用户体量越大,对整体指标影响越大。
- 加权分子每个用户的 AUC 乘以其权重再求和。
- 总权重归一除以所有用户权重之和,得到全局 GAUC。
AI 应用场景
展示广告 CTR 预估
阶段:模型训练与在线推理
解决的问题:传统定长向量无法区分“买过口红”和“正在看口红”的差异:无论展示什么广告,用户向量都一模一样。DIN 按候选广告动态激活历史行为,让每条历史行为在“此刻该不该被想起”上得到精确判断。
具体案例:用户曾浏览泳衣与防晒霜。平台推防晒霜广告时,DIN 重点激活“初夏出行”相关行为,点击率预估显著提升;推键盘广告时,则激活“办公装备”相关行为。同一个用户,两种场景下兴趣向量完全不同。
短视频信息流精排
阶段:召回后的精排阶段
解决的问题:精排需要候选视频与用户历史兴趣的细粒度匹配;快消内容下用户兴趣漂移快,固定兴趣向量往往“慢半拍”。DIN 把候选视频当作“唤醒钥匙”,让兴趣表达实时跟随内容切换。
具体案例:用户昨晚看美食、今早看健身。刷到健身视频时,模型激活“晨练打卡”记忆;刷到夜宵视频时,又激活“深夜食堂”记忆。DIN 让同一个用户的不同时刻都有对应的兴趣表达。
搜索排序个性化
阶段:特征工程与排序模型
解决的问题:同一个搜索词,不同用户意图差异巨大。DIN 把 query 当作“候选”,动态激活用户历史搜索与点击行为中的相关子集,实现搜索结果的个性化排序。
具体案例:搜索“面膜”时,护肤达人的历史中优先激活“面膜测评”“成分攻略”类行为,学生用户则激活“平价补水”类行为。行为序列相同,query 不同,激活出的兴趣面就不同。
Python 演示
import numpy as np def sigmoid(x): return 1.0 / (1.0 + np.exp(-x)) class SimpleDIN: """简化版 DIN: 激活单元 + 注意力加权池化 + 点击概率输出 仅用于教学演示, 真实工业训练请使用深度学习框架自动求导 """ def __init__(self, n_items, dim=8, hidden=16): rng = np.random.RandomState(42) self.dim = dim self.emb = rng.randn(n_items, dim) * 0.1 self.attn_w1 = rng.randn(dim * 3, hidden) * 0.1 self.attn_b1 = np.zeros(hidden) self.attn_w2 = rng.randn(hidden, 1) * 0.1 self.attn_b2 = np.zeros(1) self.mlp_w = rng.randn(dim * 2, hidden) * 0.1 self.mlp_b = np.zeros(hidden) self.out_w = rng.randn(hidden, 1) * 0.1 self.out_b = np.zeros(1) def attention(self, cand, hist): """候选向量与历史向量计算注意力权重""" n = hist.shape[0] cand_tile = np.tile(cand, (n, 1)) feat = np.concatenate([cand_tile, hist, cand_tile * hist], axis=1) h = np.maximum(feat @ self.attn_w1 + self.attn_b1, 0) score = (h @ self.attn_w2 + self.attn_b2).ravel() w = np.exp(score - score.max()) return w / (w.sum() + 1e-9) def forward(self, cand_id, hist_ids): cand = self.emb[cand_id] hist = self.emb[hist_ids] w = self.attention(cand, hist) interest = (w[:, None] * hist).sum(axis=0) vec = np.concatenate([cand, interest]) h = np.maximum(vec @ self.mlp_w + self.mlp_b, 0) logit = float((h @ self.out_w + self.out_b)[0]) return sigmoid(logit), w def train_step(self, cand_id, hist_ids, label, lr=0.1): """演示性梯度更新: 仅更新输出层, 便于审视学习过程""" p, w = self.forward(cand_id, hist_ids) grad = p - label vec = np.concatenate([self.emb[cand_id], (w[:, None] * self.emb[hist_ids]).sum(axis=0)]) h = np.maximum(vec @ self.mlp_w + self.mlp_b, 0) self.out_w -= lr * grad * h[:, None] self.out_b -= lr * grad return p def main(): model = SimpleDIN(n_items=8) hist_ids = np.array([0, 1, 2, 3, 4, 5, 6]) cand_id = 7 for epoch in range(300): p, _ = model.forward(cand_id, hist_ids) model.train_step(cand_id, hist_ids, 1.0) if epoch % 100 == 0: print("epoch %d p=%.3f" % (epoch, p)) p, w = model.forward(cand_id, hist_ids) print("final p=%.3f" % p) print("attn weights:", np.round(w, 3)) print("sum of weights:", round(w.sum(), 3)) if __name__ == "__main__": main()
feat = np.concatenate([cand_tile, hist, cand_tile * hist], axis=1)构造激活单元三路输入:候选、行为、逐元素乘积交叉特征,对应“看商品、看照片、再联想关系”。w = np.exp(score - score.max())对原始分数做平移再取指数,避免数值溢出,保持权重相对关系。return w / (w.sum() + 1e-9)权重归一化,让相关性转化为可比较的“点亮程度”。interest = (w[:, None] * hist).sum(axis=0)注意力加权池化:按权重累加历史行为,得到随候选变化的兴趣向量。self.out_w -= lr * grad * h[:, None]简化梯度更新示意;真实 DIN 在深度学习框架中端到端反向传播全部参数。
常见误区
误区我以为 DIN 里的注意力就是 Transformer 的自注意力,反正都是对向量加权求和,把历史行为之间两两计算注意力会更合理。
正解DIN 的注意力是“候选物品 × 历史行为”的交叉注意力:候选物品作为 query,历史行为作为 key 和 value。历史行为之间并不互相计算注意力,因此 DIN 不建模行为序列内部的关联。Transformer 自注意力是“记忆内部互相点亮”,DIN 是“外部商品去点亮记忆”,结构完全不同。
为何常见:Transformer 太普及,初学者容易把一切注意力机制都归为自注意力。
误区注意力权重一定要做 Softmax 归一化,让所有历史行为的权重加起来等于 1,这才是标准做法。
正解DIN 原文的激活单元直接输出标量权重,并不强制 Softmax。原因是:权重之和本身就携带“用户对这个候选物品的整体兴趣强度”信息,归一化会把强度差异抹掉。一些工程实现为数值稳定会做归一化,但那属于变体而非论文原意。
为何常见:Transformer 的 scaled dot-product attention 使用 Softmax,这种习惯被直接迁移到了 DIN 上。
误区摘要说 DIN 能刻画多兴趣分布,那它应该同时输出多个兴趣向量,每个向量代表一种兴趣。
正解DIN 输出的仍然是一个兴趣向量,但这个向量随候选物品而变。同一用户,候选是防晒霜时激活“夏日海边”,候选是键盘时激活“办公桌”,向量内容不同,从而体现多兴趣。真正显式输出多个兴趣向量的代表作是后来的 MIND。
为何常见:“多兴趣”字样容易让人直观理解为多向量输出。
误区既然叫注意力网络,DIN 的效果提升全靠注意力权重,激活单元的输入拼接和逐元素乘积只是锦上添花。
正解逐元素乘积(交叉特征)是激活单元能捕捉“组合意义”的关键——比如“泳衣 + 防晒霜”相关,而“泳衣 + 羽绒服”不相关。没有交叉特征,仅凭拼接很难学到这种非线性相关性。DIN 的效果来自“注意力 + 交叉特征 + 端到端训练”的整体设计。
为何常见:注意力是论文最大的传播亮点,容易被放大成唯一功臣。
面试题
Q1. DIN 的核心思想可以概括为?
- A.将全部历史行为压成固定向量
- B.按候选物品动态激活相关历史← 正确答案
- C.对历史行为做等权简单平均
- D.只取最近的几条行为做预测
答案:B。DIN 的核心是“候选驱动”:先看候选物品,再动态激活历史行为。A 和 C 仍是固定式压缩,D 只取近期行为,都不符合 DIN 的思想精髓。
Q2. 在 DIN 中,注意力权重的主要计算依据是?
- A.候选物品与历史行为的相似度← 正确答案
- B.历史行为发生的时间远近
- C.用户点击行为的统计频次
- D.物品在类别树中的位置信息
答案:A。注意力权重由激活单元根据候选物品与历史行为的相关性算出,就像店员根据“眼前商品”决定重点看相册哪几页。时间顺序、统计频次、类别树都不是 DIN 中权重的直接依据。
Q3. 相比固定向量的兴趣建模,DIN 的最大改进在于?
- A.降低模型参数量并加速在线推理
- B.刻画多兴趣并按候选动态激活子集← 正确答案
- C.用更深网络替代全部特征工程
- D.把 CTR 预估转化为检索问题
答案:B。固定向量是一张“模糊合影”,DIN 输出随候选变化的兴趣向量,精细刻画多兴趣。A 恰恰相反——引入激活单元会带来少量额外计算;C 和 D 都不是 DIN 的主要贡献。
Q4. DIN 激活单元的输入特征不包括?
- A.候选物品的嵌入向量表示
- B.历史行为物品的嵌入向量
- C.候选与行为的逐元素乘积
- D.用户基础画像的独热编码← 正确答案
答案:D。激活单元的输入为 [候选向量,行为向量,逐元素乘积],即 A、B、C 三者。用户画像的独热编码属于“其他特征”,直接拼到网络最后的 MLP 中,不进入激活单元。
Q5. 下列属于 DIN 模型组成部分的有?
- A.Embedding 层映射稀疏特征为稠密向量← 正确答案
- B.激活单元计算注意力权重并加权池化← 正确答案
- C.多层全连接网络输出点击概率估计← 正确答案
- D.循环神经网络建模行为序列时序
答案:ABC。DIN 由 Embedding 层、激活单元加权池化、MLP 输出层组成。D 的循环神经网络并不是 DIN 的组件——DIN 不做时序显式建模,后来 DIEN 才引入序列建模。
Q6. 关于 DIN 中注意力权重的归一化,下列说法正确的是?
- A.原文强制 Softmax 使权重之和为 1
- B.原文不做归一化以保留兴趣强度← 正确答案
- C.原文用最大池化对权重做归一化
- D.注意力权重不参与梯度反传更新
答案:B。原文刻意不强制 Softmax:激活单元直接输出权重,保留“兴趣强度”的量级信息。若强制权重和为 1,每条记忆的影响力会被比例化稀释。A、C、D 均与原文不符。
Q7. GAUC 相对于 AUC 的主要改进是?
- A.按用户分组计算 AUC 后加权平均← 正确答案
- B.对负样本降采样后再计算 AUC
- C.用点击率替代排序指标做评估
- D.对物品侧分层抽样加速评估
答案:A。GAUC 先按用户分组算 AUC,再按曝光数或点击数加权平均。全局 AUC 像全班总平均分,无法反映每个学生自己的排名;GAUC 更像逐人统计后的加权平均分,更贴近个性化排序目标。
Q8. DIN 在工业落地时需要注意的事项有?
- A.高维稀疏特征的嵌入维度选择← 正确答案
- B.激活单元带来的推理耗时控制← 正确答案
- C.用 GAUC 等指标做多维评估← 正确答案
- D.所有用户共享同一固定兴趣向量
答案:ABC。工业落地需要权衡 embedding 维度与表达力、控制激活单元的在线推理耗时,并用 GAUC 等多维指标评估。D 恰恰是 DIN 要推翻的固定向量做法,不属于落地注意点。
Q9. DIN 主要解决以下哪类任务?
- A.图像分类中的注意力可视化
- B.广告点击率 CTR 预估任务← 正确答案
- C.自然语言文本的机器翻译
- D.语音信号的分帧端点检测
答案:B。DIN 诞生于阿里妈妈的展示广告场景,面向 CTR 预估任务:给定用户、候选物品与上下文,预测点击概率。图像注意力、机器翻译、语音端点检测都不是它的目标场景。
Q10. Dice 激活函数与 ReLU 相比,关键特点是?
- A.根据数据分布自适应调整激活拐点← 正确答案
- B.完全移除模型的非线性表达能力
- C.只对正输入生效且函数不可微
- D.用随机失活替代批归一化方案
答案:A。Dice 利用数据的均值与方差把激活拐点自适应化,数据分布变化时拐点跟着移动,解决了 ReLU 负数区域梯度为零的问题。B 错误,Dice 保持非线性;C 错误,Dice 处处可微;D 属于张冠李戴。