Rec - Ads Recommendation in a Collapsed and Entangled World

1.想要解决的问题
- 表示的先验知识:现实世界的系统包含来自不同来源的各种类型的特征,包括序列特征(例如,用户点击/转换历史),数字特征(例如,保留语义的广告ID),以及嵌入来自预先训练的外部模型的特征(例如,GNN或LLM)。在推荐系统中对这些特征进行编码时,保留这些特征的固有先验是至关重要的。
- 维度折叠:编码过程将所有特征映射到嵌入中,通常表示为多维向量,并在模型训练期间学习。然而,我们观察到,许多字段的嵌入往往占据一个低维的子空间,而不是充分利用可用的二维空间。这种维度压缩不仅导致了参数的浪费,而且限制了推荐模型的可扩展性。
- 兴趣纠缠:广告推荐系统中的用户响应由复杂的潜在因素决定,特别是当同时学习多个任务或场景时。现有的共享嵌入方法可能无法充分解决这些因素,因为它们依赖于每个特征的单个纠缠嵌入。通俗的讲,一个用户(或广告)在所有任务/场景下,都被强行塞进同一条 embedding 向量里,导致不同任务所需的兴趣信号互相打架。
2.方法
2.1 Feature Encoding
特征编码在工业广告推荐系统中,特征是从许多来源生成的,并且属于不同的类型,例如序列特征、数字特征和嵌入特征。在对这些特征进行编码时,我们希望尽可能地保留其固有的时间、顺序或距离(相似性)先验。
2.1.1 序列特征

| 原文 | 直译 | 真实含义(举例) |
|---|---|---|
| quadruple semantic-temporal correlation | 四元语义-时间相关性 | 同时刻画 4 个维度的匹配度: 1. 历史行为本身的语义(点了什么品类) 2. 候选广告的语义(推的是什么品类) 3. 历史行为发生的时间点 4. 候选广告曝光的时间点 |
| behavior semantic | 行为语义 | 用户 3 天前点击的「传奇手游」这条行为的「品类 ID → Embedding」 |
| target semantic | 目标语义 | 候选广告「原神手游」的「品类 ID → Embedding」 |
| behavior temporal | 行为时间 | 行为时间戳离散化后得到的「时间间隔 id → Temporal Embedding」 |
| target temporal | 目标时间 | 候选广告曝光时间戳离散化后得到的「相对位置 id → Temporal Embedding」 |
| Target-aware Temporal Encoding (TTE) | 目标感知时间编码 | 把“行为发生时间”与“广告曝光时间”之差 Δt 映射成可学习的向量 |
| Target-aware Attention (TA) | 目标感知注意力 | 用候选广告向量作为 Query,去计算每条历史行为的权重 α_i |
| Target-aware Representation (TR) | 目标感知表示 | 把每条历史行为向量与候选广告向量做元素级乘法 ⊙,得到交互向量 |
| explicit 4-way interaction | 显式四路交互 | 在注意力权重 α_i 与交互向量 ⊙ 结果之间再乘一次, 把 4 个维度全部显式揉进最终输出 |
Target-aware Attention 用“候选广告本身”去给用户历史行为打权重,筛出与这条广告最相关的行为,从而生成“针对这条广告”的用户兴趣向量。
与self-attention对比
| Self-Attention | Target-aware Attention (TIM) | |
|---|---|---|
| Query 来源 | 行为自身 | 候选广告 |
| 输出含义 | 行为序列内部的依赖 | 针对当前广告的用户兴趣 |
| 适用场景 | 序列模型(SASRec, BERT4Rec) | 广告 CTR/CVR 预测 |
TIM 把「点过什么、什么时候点的」与「推的是什么、什么时候推的」全部量化成向量,然后用“目标感知的注意力”挑出最相关的行为,再用“目标感知的表示”把这些行为的四元信息压缩成一条用户兴趣向量。
Temporal Interest Module(TIM) 的核心表达式,它把“用户历史行为序列”压缩成一个定长向量,用于预测对当前候选广告的兴趣。逐元素拆解如下:
[ \mathbf{A}{\text{TIM}} = \sum{\mathbf{b}_i \in \mathcal{H}} \underbrace{\alpha(\tilde{\mathbf{b}}i, \tilde{\mathbf{t}})}{\text{① 权重}} \cdot \underbrace{(\tilde{\mathbf{b}}i \odot \tilde{\mathbf{t}})}{\text{② 交互}} ]
| 符号 | 含义 | 维度 | 具体示例 |
|---|---|---|---|
| (\mathcal{H}) | 用户历史行为序列 | 长度 (L) | 最近 50 次点击/转化行为 |
| (\mathbf{b}_i) | 第 (i) 条行为的原始语义向量(品类/商品 embedding) | (d) | 传奇手游品类向量 |
| (\tilde{\mathbf{b}}_i) | 加时间信息后的行为向量: (\mathbf{b}i \oplus \mathbf{p}\text{temp}(t_i)) | (d+d_t) | 语义向量 + 3 天前时间向量 |
| (\tilde{\mathbf{t}}) | 候选广告的“目标向量”: (\mathbf{t} \oplus \mathbf{p}\text{temp}(t\text{target})) | (d+d_t) | 原神广告向量 + 此刻时间向量 |
| (\alpha(\cdot)) | Target-aware Attention Score | 标量 | 用广告向量做 Query, 计算行为与广告的相关度 |
| (\odot) | 元素级乘法(Hadamard Product) | (d+d_t) | 语义-语义、时间-时间全部逐位相乘 |
| (\mathbf{A}_{\text{TIM}}) | 最终输出的用户兴趣向量 | (d+d_t) | 压缩了 50 条行为后的定长表示 |
把每一条历史行为与候选广告做“语义×时间”的四元匹配,
用广告本身做 Query 给行为打分,再把所有行为按权重融合,
得到一条“此刻对该广告最相关的用户兴趣”向量。
- 时间衰减:通过时间 embedding 把“3 天前点击”与“此刻曝光”的差距量化。
- 语义匹配:用 ⊙ 把“传奇手游”与“原神手游”的语义相似度显式相乘。
- 注意力筛选:用广告自身向量做 Query,自动聚焦最相关的行为。
!!!有个疑问,“此刻”这个概念是怎么得到的?仅仅是通过时间向量逐位相乘,时间近的权重大就能得出此刻最想点击的这个结论吗? KIMI:不能直接推出“此刻最想点”,它只是把“时间近”转成可学习的信号;真正的“此刻最想点”是由整个 TIM + 上层网络一起学出来的。时间向量把“时间近”变成可学习的偏置信号; “此刻最想点”是整个 TIM + 上层网络在亿万样本里用梯度一起调出来的,时间向量只是帮它省了一道“重新发现时间衰减规律”的力气。
输入侧
只有 2 个时间戳:- 行为发生时间
t_i(例如 3 天前) - 广告曝光时间
t_target(例如此刻 2024-07-20 10:00)
差值Δt = t_target - t_i被离散化成 bucket-id,再查表得到p_temp(Δt)。
所以它并不神秘,就是系统日志里现成的两个时间戳。
- 行为发生时间
模型侧
时间向量p_temp的权重(embedding 值)是随机初始化后由梯度反传学出来的。
如果数据里“Δt 越小→最终转化率越高”,反向传播就会把靠近 0 的 bucket 学得更大,远离 0 的 bucket 学得更小——数据驱动而非人工写死。
!!!有个疑问,如果代表一个候选广告的新向量是由一个历史交互序列上的所有广告和目标广告乘积权重相加,那么1.会不会很消耗时间、资源,2.会不会丧失目标广告本身的意义,因为都是乘积相加,本身的embedding可能会被掩盖? KIMI:1.线上通常只取最近 30~50 条,不是无限制回溯,资源消耗比传统 attention 少,比纯 MLP 略多,但仍在可接受范围,另候选集在工业上可以剪枝,同一用户在同一请求里的行为序列 只算一次;把几百条候选广告拼成一个 batch × seq_len × dim 的大张量,一次 GPU kernel 并行完成所有注意力 → 计算密度高,耗时与一条广告几乎同一量级。2.不会,因为目标广告向量以“Query”身份出现两次:① 计算 注意力权重(决定哪些历史行为更重要);② 参与 交互向量(逐元素乘后再加权相加)。所以它的信息既当裁判又当选手,不会被淹没。 !!!有个疑问,TIM与position embedding比? KIMI: 目的不同 Position Embedding(PE):让模型知道“这是用户第几次点击”。 TIM(Target-aware Interest Module):让模型知道“用户第 3 次点击的【手机壳】对当前要推的【iPhone 15】有多重要”。
| 维度 | Position Embedding | TIM |
|---|---|---|
| 位置本身 | ✅ 绝对/相对位置序号 | ✅ 相对位置/时间间隔 |
| 行为语义 | ❌ 不管 | ✅ 行为类目/商品向量 |
| 目标语义 | ❌ 不管 | ✅ 目标广告类目/向量 |
| 交叉关系 | ❌ 没有 | ✅ 4 维交叉(行为×目标 × 位置×时间) |
2.1.2 数值特征
与独立的ID特征不同,数字/序数特征之间存在固有的偏序关系,例如年龄 20<30。为了保留这些有序先验,我们采用了NaryDis编码的简化变体[9],即多数字系统编码(MNSE)。它通过根据多个数字系统(即,二进制、三进制、十进制),然后将可学习的嵌入分配给这些代码,如图2(B)所示。
“多数字系统编码(MNSE)”怎么做
• 选一个整数,例如 51。
• 同时用三种进制拆它:
– 二进制 → 110011
– 三进制 → 1220
– 十进制 → 51
• 把每一位数字当成一个新的“小 id”,再去查三张可学习的嵌入表,得到多条小向量。
• 把这些小向量加总,就得到 51 的最终表示。
这样 51 与 50 的二进制只差最后两位,三进制也只在低位不同,它们的最终向量也会接近,于是顺序信息被保留下来。
“简化变体”省掉了什么
原论文 NaryDis 还带“位间注意力”和“位内注意力”,既慢又占显存;
MNSE 直接拿掉注意力,只保留**“拆数字 → 查表 → sum pooling”**,省算力又省内存。
步骤 2 的 3 个子步骤
1️⃣ 把十进制整数 A 转换成 多套 进制下的 位序列
2️⃣ 把每一位数字当作离散 ID,去查 该进制专属的小嵌入表
3️⃣ 同一进制内的所有位向量做 sum-pooling;不同进制结果再相加
拿 A = 51 做 2 进制 + 3 进制的完整例子
1️⃣ 进制转换
• 二进制:51 → 110011₂ → 位序列 [1,1,0,0,1,1]
• 三进制:51 → 01220₃ → 位序列 [0,1,2,2,0]
2️⃣ 查表(假设嵌入维度 d = 4,随机初始化)
二进制表 E₂:
E₂[0] = [0.1,0.2,0.3,0.4]
E₂[1] = [0.5,0.6,0.7,0.8]
三进制表 E₃:
E₃[0] = [0.01,0.02,0.03,0.04]
E₃[1] = [0.05,0.06,0.07,0.08]
E₃[2] = [0.09,0.10,0.11,0.12]
把位序列变成向量列表:
• 二进制:E₂[1], E₂[1], E₂[0], E₂[0], E₂[1], E₂[1]
• 三进制:E₃[0], E₃[1], E₃[2], E₃[2], E₃[0]
3️⃣ sum-pooling
二进制和:
[0.5+0.5+0.1+0.1+0.5+0.5, …] = [2.2, 2.4, 2.6, 2.8]
三进制和:
[0.01+0.05+0.09+0.09+0.01, …] = [0.25, 0.28, 0.31, 0.34]
最后相加得 MNS(51) = [2.45, 2.68, 2.91, 3.14]
Deployment Details 分两部分:
(1) HashID 工程落地(把无意义的自增 Ad ID 换成携带视觉语义的离散 ID)
(2) MNS 编码落地(把 HashID 当成数值特征,用 MNS 训练)
2.1.3 Embedding Features
Embedding Features —— 如何把「外部预训练好的嵌入」(LLM、GNN、CV 模型产出的向量)无缝接入广告推荐主模型,同时解决两大难题:
- 语义鸿沟(semantic gap)——外部嵌入与推荐 ID 嵌入的语义/距离度量不一致;
- 训练协同 —— 既要保留外部知识,又不能让外部向量喧宾夺主。
一、场景与动机
• 外部模型:
– GraphSage 在用户-广告二部图上预训练,产出 user & ad 的 64-d 图嵌入;
– LLM 对文本侧(标题、描述)产出 768-d 语言嵌入;
– CV 模型对创意图产出 512-d 视觉嵌入。
• 问题:这些嵌入用 cosine / L2 距离度量,而推荐内积更常用 dot-product;直接拼接会冲突、负迁移。
二、两阶段「降维 + 编码」框架
Step-1 距离蒸馏
计算外部空间中的相似度分数(cosine 或 L2)→ 得到一个标量 s ∈ [-1,1]。
例:GraphSage 得到 user_u 与 ad_i 的 cosine 相似度 s_ui。
Step-2 MNS 数值编码
把 s_ui 先线性归一化到 [0, M],再用 3.2 节的 Multiple Numeral System(多进制查表求和)转成 d 维向量 e_ext。
公式化:
e_ext = MNS(round(s_ui × scale))
• 该向量与主模型里的 ID 嵌入共享后续所有层,从而把外部知识“翻译”到推荐语义空间。
3.3 节把任何外部高维嵌入先“降维”成一个相似度标量,再用 3.2 的 MNS 编码进主模型,既保留外部先验,又避免语义/距离冲突,实现低成本、高收益的跨模态融合。 #@ 应对维度崩溃 核心使命:解释「为什么把 embedding 维度从 64 → 192 反而掉点」,并提出 可落地的工业级解决方案,让广告模型真正“吃得下”更大参数。
1 维度崩溃现象(§4.1) • 观察:用 SVD 分析各字段的 embedding 矩阵,发现大量奇异值≈0 ⇒ 有效维度 ≪ 设定维度。
• 根因:显式特征交互(FM/DCN/FFM 等)里,低基数字段(如性别只有 2 类)会把高维空间“拉”到低维子空间,导致 参数浪费 + 扩展困难。
2 多嵌入范式(Multi-Embedding Paradigm, §4.2) 思路:不再“把单张 embedding 表做大”,而是 增加多张独立表,每张表内部做特征交互 + ReLU。
• 实现:一个特征在 K 张表里分别查 K 个向量;同一表内的向量做交互,不同表互不影响。
• 效果:奇异值分布明显“撑开”,参数量可继续放大;Moments pCTR 切到 2 表 3 专家架构 → +3.9 % GMV。
- 多嵌入查表(Multi-Embedding Lookup)
对于任意一个特征 f,传统单嵌入做法只查一张表
e = E(id_f) ∈ ℝ^d。
Multi-Embedding 把它扩展成查 K 张独立的表(K 是超参,线上常用 K = 2 或 3):
e_k = E_k(id_f) ∈ ℝ^d , k = 1 … K。
于是同一个特征得到 K 个 d 维向量 {e_1, …, e_K},而不是一个。
like: 把同一张身份证复印几份,分别放到几本不同的词典里,各写各的解释,互不干扰。
通俗的讲: 把 4.2 想象成「把原来一口大锅里的面条,分成了几口小锅,每口锅只炒自己锅里的面条」
1️⃣ 原来(单嵌入)
• 只有一个大查找表 E
• 所有字段(用户 id、广告 id、性别、城市…)都挤在这一张表里拿向量
• 结果:维度低的字段(性别只有 2 个取值)把整张表拉成 2 维子空间 → 其他字段白学
2️⃣ 4.2 的做法(多嵌入)
• 把一张大表拆成 K 张小表
表 1 专管「用户侧字段」
表 2 专管「广告侧字段」
表 3 专管「上下文字段」
… 想拆几张就几张,线上常用 K=2~4
• 查表阶段就分开
同一个特征值,现在要从 K 张小表里各拿一次向量
例:用户 id = Alice
→ 从表 1 拿 e₁(Alice) ∈ ℝ^64
→ 从表 2 拿 e₂(Alice) ∈ ℝ^64
→ 从表 3 拿 e₃(Alice) ∈ ℝ^64
于是 Alice 有了 3 份 64 维向量,互不干扰
• 交互阶段也分开
表 1 的所有向量只在「表 1 的专家网络」里做交叉
表 2 的所有向量只在「表 2 的专家网络」里做交叉
不同表之间不做直接交互 → 低维字段再也拖不垮高维字段
部署细节:具体地,我们学习多个不同的特征交互专家,GwPFM(FFM的变体,将在下面描述)、IPNN、DCN V2或FlatDNN以及多个嵌入表。一个或多个专家共享这些嵌入表中的一个。我们将这种架构命名为具有多嵌入的异构混合专家架构,它与DHEN [75]的不同之处在于[75]使用一个共享嵌入表,而我们部署了多个嵌入表。例如,Moments pCTR模型由GwPFM、IPNN [51]、FlatDNN和两个嵌入表组成。GwPFM和FlatDNN共享第一个表,而IPNN使用第二个表。从单一嵌入式切换到上述架构可使Moments pCTR的GMV提升3.9%,这是过去十年中最大的性能提升之一。
表内交互 + 非线性投影(Table-wise Interaction & Non-linear Projection)
同一张表里所有特征的嵌入先送到该表专属的交互模块 φ_k(·)。
以 Moments pCTR 为例,φ_1 是 GwPFM,φ_2 是 IPNN,φ_3 是 FlatDNN。
用符号记:
z_k = φ_k( {e_k(f_i) | 所有特征 i} ) ∈ ℝ^m。每个 φ_k 后面必须接一个非线性 MLP(ReLU),否则线性交互会导致多嵌入退化成单嵌入。
h_k = ReLU(W_k z_k + b_k)。最后把 K 个塔的输出做 gate 加权求和,送进各自的任务 tower:
h = Σ_k g_k · h_k , 其中 g_k 通过 gate 网络学习。
- GwPFM:轻量版多嵌入(§4.3)
原始 FFM 的痛点 如果有 F 个字段(field),FFM 给每个特征学 F-1 个向量。 例:100 个字段 → 每个特征要学 99 个向量 → 存储爆炸。 计算一次二阶交互要 O(F²) 的时间,工业系统无法接受。
GwPFM 的核心思想 把字段先分组(group),每个特征只在组粒度上保留一份向量,再让“组对组”共享一个权重;这样参数量从 O(F²) 降到 O(G²),G≪F。
- 先把全部 F 个字段划分成 G 个 field group(G 通常几十)。 例:G = 3 组 {用户侧字段, 上下文字段, 广告侧字段}。
- 每个特征 x_i 不再拥有 F-1 个向量,而是只学 G 个向量v_{i,g} ∈ ℝ^d , g = 1…G
- 交互项写成 Φ = Σ_{g=1}^{G} Σ_{h=g+1}^{G} w_{g,h}Σ_{i∈group(g)} Σ_{j∈group(h)} ⟨v_{i,h}, v_{j,g}⟩
解释: – 只有不同组之间才做内积交互; – w_{g,h} 是一个标量权重,整组对整组共享; – 参数量 = n_feature×G×d + G(G-1)/2,远小于 FFM 的 n_feature×F×d + F(F-1)/2。
用一句话总结:“先在每个特征向量前乘一个‘专属滤镜’,再做内积,就不会把维度挤扁了。” 1️⃣ 传统做法(FM / 内积交互) 对两个特征向量 eᵢ , eⱼ ,直接 score = ⟨eᵢ , eⱼ⟩ = ∑ₗ eᵢₗ · eⱼₗ 也就是把两个向量“裸着”点对点相乘后求和。 问题:如果 eᵢ 本身只有 k 个维度有信号(k≪d),那么 eⱼ 在剩下的 d-k 个维度上的数值就会被“挤”成 0,导致整个空间的秩被锁死——这就叫 维度崩溃。 2️⃣ 4.4 的“滤镜”做法(Collapse-Resilient) 给每个“字段”配一个可学习的投影矩阵 P_f ∈ ℝ^{d×d}, 交互前先把向量过一次滤镜,再做内积: score = ⟨ P_{f(i)} eᵢ , P_{f(j)} eⱼ ⟩ f(i) 表示特征 i 属于哪个字段(field)。 每个字段各学一个 P_f,参数量 = (#field) × d²,很小。 因为 P_f 是满秩矩阵,可以把原本塌掉的维度重新“撑开”,从而避免崩溃。 3️⃣ 与 DCN-V2 的关系 DCN-V2 的 Cross Layer 正好就是这种“字段级投影 + 内积”的实现: X_{l+1} = X₀ ⊙ (W_l X_l + b_l) + X_l 其中 W_l 其实就是把每个字段的投影拼在一起, 所以 4.4 的结论可以概括为: “DCN-V2 中的字段级投影不仅提升表达力,还能缓解维度崩溃。”
兴趣纠缠
在腾讯广告投放系统里,同一位用户可能既刷朋友圈,又看腾讯视频,还在小程序里下单。 如果把所有行为塞进同一份用户向量里,就会出现:
- 游戏兴趣把购物兴趣“淹没”——结果给他推了游戏皮肤,错过了高客单价的耳机;
- 不同转化类型(下载、注册、付费)互相拉扯——模型学到最后什么都不精。
这就是论文里说的 Interest Entanglement(兴趣纠缠)。

方案一:STEM(Shared & Task-Specific Embedding)
口号:一公一私,互不打扰
- 每个任务除了共享向量(shared emb),还有任务私有向量(task-specific emb)。
- 专家(Expert)也被分成两类:
– 只看共享向量(shared expert)
– 只看私有向量(task expert) - 门控(gate)决定最终融合比例。
图示理解
| |
任务 B 同理。这样游戏兴趣留在 taskA emb,购物兴趣留在 taskB emb,不打架。
方案二:AME(Asymmetric Multi-Embedding)
口号:大任务用大表,小任务用小表
现实里腾讯一次要预测 100+ 种转化类型,不可能给每个类型一张大表。
做法:
- 把 100+ 任务聚成 32 个塔。
- 准备 3 张 不同尺寸 的嵌入表:16 维 / 32 维 / 64 维。
- Gate 根据任务数据量自动路由:
– 数据少的“付费”任务主要走 16 维表;
– 数据多的“下载”任务主要走 64 维表。
实验结果(线上 A/B):
- Moments / 公众号 / 新闻 三大场景平均 AUC ↑0.32%、0.24%、0.48%
- 换算 GMV 提升 4.2%、3.9%、7.1%
方案三:STEM-AL(Auxiliary Learning 版)
口号:主任务最大,辅任务只帮忙不抢戏
场景:把“朋友圈 CTR”作为辅助任务,去提升“小程序 CTR”主任务。
实现:
- 主任务塔接收 所有专家 的输出;
- 辅助任务塔只接收 对应专家 的输出,并在 推理阶段直接砍掉。
效果:
- 仅用朋友圈做辅助 → 小程序 CTR ↑1.16%
- 朋友圈 + 视频双辅助 → 小程序 CTR ↑2.93%
Model Training
CTR/CVR 大模型在腾讯千亿级流量场景下“怎么学得又快又稳”最核心的 6 个实操技巧
🕒 时间线:从“样本进管线”到“模型出预测”的全过程
1️⃣ 样本进管线 → 在线学习(§6.3)
• 点击样本秒级回传;转化样本有延迟 → 用“方差门控”动态决定等多久再喂模型,既新鲜又抗波动。
• 新广告 3 天内 GMV 多涨 2~4%,老广告 bias 从 10% 降到 1%。
2️⃣ 训练目标 → BCE + Ranking Loss(§6.1)
• 纯 BCE 会让负样本梯度消失(0.1% 正样本场景)。
• 额外加一条 Pairwise Ranking Loss,负样本梯度立刻变大,线下 AUC 涨 0.3~0.5 个点,线上 Moments GMV +0.57%。
3️⃣ 样本权重 → 重复曝光降权 REW(§6.2)
• 同广告 1 天内反复出现 → 用户烦。
• 给重复曝光样本乘 ≥1 的权重(等价于降模型分),再对正样本全局校准。
• 重复曝光率下降 7~15%,用户体验分上涨。
4️⃣ 探索 → 不确定度 + Thompson Sampling(§6.4)
• 给每条广告预测一个“置信区间”,而非点估计。
• 用 Thompson Sampling 在区间内随机采样做 eCPM,冷启动 GMV +1.92%。
5️⃣ 训练框架 → STEM / AME / STEM-AL(§5 已讲)
• 多任务、多场景共用一套样本流,但私有塔各自回传梯度,互不干扰。
6️⃣ 工程细节 → 异构专家 + 多嵌入(§4 已讲)
• GwPFM / DCN-V2 / FlatDNN 并行跑,Embedding 按表分片,GPU 通信量可控。
📊 一张对照表:6 个技巧与线上收益
| 技巧 | 解决痛点 | 关键参数 | 典型收益 |
|---|---|---|---|
| BCE+Ranking Loss | 负样本梯度消失 | ranking loss 权重 λ=1~2 | GMV +0.5~1% |
| REW | 重复曝光疲劳 | 权重公式 w_rep | 重复曝光 ↓10% |
| 在线学习-方差门控 | 转化延迟 & bias | 方差阈值 τ | 新广告 GMV +2~4% |
| Thompson Sampling | 冷启动探索 | 高斯过程后验 | GMV +1.9% |
| STEM/AME | 任务互斥 | 私有表维度 16/32/64 | GMV +3~7% |
| 多嵌入+异构专家 | 维度崩溃 | 表数 K=2~3 | GMV +3.9% |
第 7 节
把平时藏在黑盒里的 Embedding、特征相关性、任务纠缠一次性变成可观测、可度量的仪表盘。
🧰 工具 1:Feature Correlation(特征相关性 X 光机)
目的:看“哪些行为/特征真的跟转化有关”。
方法:互信息 MI
- 先框定两个变量
① 历史行为集合 B(可再细分为“同类目+第 k 个位置”或“间隔 t 天”)
② 用户对 Target 的反馈 Y(点击 or 转化) - 算 MI(B; Y),数值越大越相关。
- 直接产出热力图(论文图 5):
– 同色类目 + 最近 1 天 → MI 0.6+
– 跨类目 + 30 天前 → MI 0.05
一句话:把“拍脑袋”选特征变成“算 MI”选特征。
🧰 工具 2:Embedding Dimensional Collapse(塌陷探测器)
目的:量化“我的 Embedding 到底有没有白学”。
方法:奇异值分解 SVD + 自定义指标 IA
步骤:
- 抽某一 field 的全部 Embedding 矩阵 E ∈ ℝ^{N×d}
- SVD:E = U Σ Vᵀ,得到奇异值 σ₁ ≥ σ₂ ≥ … ≥ σ_d
- 计算 Information Abundance
IA = (Σ σ_i) / σ₁- IA ≈ 1 → 几乎全部能量挤在第 1 维,塌陷严重
- IA ≈ d → 能量均匀分布,没有塌陷
实操:
- 线上每周例行跑脚本,IA<5 的字段自动告警 → 触发多嵌入扩容或重训。
🧰 工具 3:Interest Entanglement(任务纠缠显微镜)
目的:看“多任务共享向量是否真的在打架”。
方法:矛盾样本距离分布
操作 3 步:
- 挑一批“矛盾对”:在任务 A 里距离小、任务 B 里距离大的 (u,i)。
- 画 3 条距离分布曲线:
a) 单任务 A(红色)
b) 单任务 B(蓝色)
c) 共享向量 MT(灰色) - 如果灰色曲线把红蓝“中和”成一条中间鼓包 → 纠缠严重;
STEM/AME 的私有向量能让红蓝双峰重新分开 → 解耦成功。
🎯 一张速查卡
| 工具 | 输入 | 输出 | 线上用法 |
|---|---|---|---|
| Feature Correlation | 行为序列+标签 | MI 热力图 | 筛特征、调 TIM 窗口 |
| Collapse Detector | 某 field 的 Embedding | IA 值 | IA<5 触发扩容 |
| Entanglement Scope | 矛盾 (u,i) 列表 | 三条距离曲线 | 选 STEM 还是 AME |
STEM
STEM = Shared & Task-Specific Embedding
一句话:把“所有任务共用一份向量”升级成“公共客厅 + 每间卧室”结构——客厅(共享)保留通用信息,卧室(私有)存放任务独有兴趣,彻底避免多任务之间的「兴趣打架」。
下面从 原理 → 公式 → 网络结构 → 训练细节 → 落地经验 五步彻底拆开。
1️⃣ 原理:为什么需要 STEM?
| 现象 | 原因 | STEM 解法 |
|---|---|---|
| 多任务共享向量导致负迁移 | 任务 A 的高权重把任务 B 需要的维度挤掉 | 给每个任务单独开一份私有向量 |
| 参数量爆炸 | 100 个任务就 100 份表? | 共享 + 私有混合,参数量可控 |
| 冷启动任务学不动 | 数据少,学不出好向量 | 先用共享向量保底,私有向量慢慢微调 |
2️⃣ 公式:STEM 的数学表达
设任务 τ ∈ {1,…,T}
对任意特征 x,生成两份向量
• 共享向量:eˢ = Eˢ(x)
• 任务私有向量:eᵗ = Eᵗ(x)下游专家(Expert)分成两类:
• 共享专家 φˢ 只看 eˢ
• 任务专家 φᵗ 只看 eᵗ门控融合(gate)
g = softmax(W·[eˢ || eᵗ])
h = g₁·φˢ(eˢ) + g₂·φᵗ(eᵗ)最终损失
L = Σ_τ L_τ(task_τ)
反向传播时,共享参数被所有任务同时更新,私有参数只被对应任务更新。
3️⃣ 网络结构:一张图即可描述
| |
• 共享表:所有任务共用 1 张
• 私有表:每个任务 1 张(或 AME 里按组共用)
4️⃣ 训练细节:别让共享/私有互相干扰
- Stop-gradient trick
在私有专家回传梯度时,给共享向量加 stop-gradient,防止私有任务把共享空间带偏。 - 初始化
共享表用全局预训练;私有表随机小值,避免一开始就主导。 - 容量配比
共享维度 : 私有维度 ≈ 2:1(腾讯线上经验值)。 - 正则化
对私有向量加 L2 正则,防止过拟合小任务。
5️⃣ 落地经验:腾讯线上长这样
| 场景 | 任务数 | 表设置 | 效果 |
|---|---|---|---|
| 多转化 CVR | 100+ 转化类型 | 1 张共享 64d + 32 张私有 32d(聚类到 32 塔) | AUC↑0.3 |
| 小程序 CTR | 主任务:小程序 CTR 辅任务:朋友圈 CTR | 共享 64d + 私有 32d(主) 共享 64d + 私有 32d(辅) | 主任务 CTR↑2.93% |
AME
AME = Asymmetric Multi-Embedding
一句话:把 STEM 的「一个任务一张私有表」再升级成「少数几张不同尺寸的表 + 智能路由」,既保留解耦能力,又把参数量从 O(T·V) 压回 O(G·V),真正能在“100+ 任务”场景落地。
下面从「背景 → 设计思路 → 公式 → 路由机制 → 工程落地 → 效果」六步拆开。
1️⃣ 背景:STEM 在超大规模任务面前的痛点
- 任务 T = 100+(每个转化类型算一个任务)
- STEM 需要 T 张私有表 → 存储爆炸,GPU 显存放不下。
- AME 核心诉求:用 <5 张表,服务 100+ 任务,还不打架。
2️⃣ 设计思路:三件事
- 分桶:把 T 个任务聚成 G 个桶(G≪T,线上 G=3 或 4)。
- 非对称维度:桶越大,表越大;桶越小,表越小。
例:
– 大桶(下载、付费)→ 64 维
– 中桶(注册、加购)→ 32 维
– 小桶(留资、关注)→ 16 维 - 路由 Gate:每个样本动态决定“这次我主要靠哪张表”。
3️⃣ 公式化描述
- 设 G 张表 {E₁,E₂,…,E_G},对应维度 {d₁,d₂,…,d_G}。
- 对任务 τ 的样本 x:
e_g(x) = E_g(x) g = 1…G (查表)
s_g(x) = gate_τ(concat(e_g(x))) (路由权重)
h(x) = Σ_{g=1}^G s_g(x) · φ_g(e_g(x)) (门控融合)
其中
- gate_τ 是一个轻量 MLP,只跟任务 ID 有关,不跟特征维度挂钩;
- φ_g 是第 g 张表对应的专家网络;
- 反向传播时,只有 s_g>0 的表和专家才会收到梯度 → 稀疏更新、省显存。
4️⃣ 路由机制:两阶段门控
| 阶段 | 作用 | 实现 |
|---|---|---|
| 任务级静态门 | 根据任务历史样本量先分桶 | 离线聚类+人工微调 |
| 样本级动态门 | 实时决定“这次更信哪张表” | gate MLP + softmax |
伪代码
| |
5️⃣ 工程落地:腾讯线上长什么样
| 线上系统 | 参数 |
|---|---|
| 任务数 | 100+ 转化类型 |
| 桶数 G | 3 |
| 维度 | 16 / 32 / 64 |
| 表大小 | 16d 表≈1 GB,64d 表≈4 GB,单卡可放下 |
| 专家共享 | 每张表配 1 个 DCN-V2 expert |
| 训练 | 在线学习 + stop-gradient 防大桶抢梯度 |
显存对比
- STEM 100 私有表 ≈ 100×1 GB = 100 GB → 放不进单卡
- AME 3 张表 ≈ 7 GB → 单卡 A100 轻松跑
6️⃣ 实验效果(线上 A/B)
| 场景 | 基线 | AME | 提升 |
|---|---|---|---|
| 朋友圈转化 | PLE | AME | AUC +0.32% → GMV +4.2% |
| 公众号转化 | PLE | AME | AUC +0.24% → GMV +3.9% |
| 新闻转化 | PLE | AME | AUC +0.48% → GMV +7.1% |
小任务(如“付费”)AUC 涨幅更高,达到 0.78%,验证了“小桶小维”策略有效。
🎯 一张记忆卡片
| 对比点 | STEM | AME |
|---|---|---|
| 表数量 | T(任务数) | G(桶数,常数) |
| 维度策略 | 统一 | 非对称 |
| 路由 | 任务 gate | 任务+样本两级 gate |
| 存储 | O(T·V) | O(G·V) |
| 适用规模 | T<30 | T=100+ |
一句话总结
AME 用“分桶 + 非对称维度 + 动态门”三板斧,把 STEM 的思想从实验室搬到千亿级线上系统:
表只留几张,大小按需求分配,任务再多也不炸显存,兴趣照样解耦。
STEM-AL
STEM-AL = STEM for Auxiliary Learning
一句话:主任务独享大客厅,辅任务只当临时客人——训练时来帮忙,上线时悄悄走人。
它是 STEM 范式的“偏斜版”,专为 主任务 + 若干辅助任务 设计,解决“辅助信号怎样助攻又不抢戏”的难题。
下面按“动机 → 结构 → 公式 → 训练/推理差异 → 线上案例”彻底拆解。
1️⃣ 动机:主辅任务打架现场
| 场景 | 主任务 | 辅助任务 | 传统做法痛点 |
|---|---|---|---|
| 小程序 CTR | 小程序点击 | 朋友圈 CTR、频道 CTR | 直接多任务共享向量 → 主任务被侧路数据带偏,推理期还得跑全部塔,浪费算力 |
STEM-AL 的诉求:让主任务 100% 掌控最终预测,辅助任务只在训练时提供额外梯度。
2️⃣ 结构:一条单向支路 + 可裁剪塔
| |
关键细节
- Stop-Gradient:辅助塔 → 主塔的连线只传梯度,不传激活(灰色虚线)。
- 推理时直接砍掉辅助塔,主塔独享所有特征,零额外开销。
3️⃣ 公式化描述
设
- 主任务损失 L_main
- 第 k 个辅助任务损失 L_aux,k
总体训练目标
| |
其中 α_k 是人工系数,通常 0.1~0.3,防止辅助任务喧宾夺主。
反向传播时
- 主塔参数接收 L_main + Σ L_aux,k 的总梯度。
- 辅助塔参数只接收 α_k L_aux,k 的梯度。
- 辅助塔到主塔方向 stop_gradient,保证主塔权重不被辅助塔直接“拖走”。
4️⃣ 训练 vs 推理差异
| 阶段 | 网络形态 | 计算图 | 显存占用 |
|---|---|---|---|
| 训练期 | 主塔 + 辅塔 | 全连接 | 正常 |
| 推理期 | 只剩主塔 | 砍掉辅塔 | 降低 20~30% |
5️⃣ 线上落地案例:腾讯小程序 CTR
| 配置 | 主任务 | 辅助任务 | 效果 |
|---|---|---|---|
| 单任务 | 小程序 CTR | 无 | baseline |
| STEM-AL | 小程序 CTR | 朋友圈 CTR | 小程序 CTR ↑1.16% |
| STEM-AL | 小程序 CTR | 朋友圈 CTR + 频道 CTR | 小程序 CTR ↑2.93% |
- 辅助样本量 ≈ 主任务 3 倍,带来丰富用户兴趣信号。
- 推理期只保留主塔,QPS 无压力。
🎯 记忆口诀
主客厅全开,辅卧室只帮工;
训练带梯度,上线不留痕。
一句话总结
STEM-AL 用「主塔全接收、辅塔单向助攻、推理一键裁剪」三板斧,
把辅助任务的信号榨干,却把计算和干扰全部留在训练期,
真正做到**“辅助不抢戏,上线零负担”**。
