TM20K 用「老师读全文、学生读缩写」的两阶段蒸馏范式破解超长序列的效率困境:一次性训练的 teacher 吃完整 20K token 但永不上线,学生模型用三种由注意力观测反推出来的 token merge 把 20K 压到平均 1.8K 后上线,再靠 KD 把 teacher 约 85% 的收益捞回来——最终线上 ADSS +1.036%,serving 延迟只涨 5.6%。
📄 原文:https://arxiv.org/abs/2608.07055
🔗 密切相关工作:LONGER(均匀 token merge + Perceiver)、TWIN-V1/V2(检索式压缩)、ExFM(外部大 foundation model 蒸馏)、HSTU / M-Falcon(serving 基建)、RankMixer(特征交互骨架)
① 范式:首个把「teacher 保留全 token / student 合并 token」的两阶段 KD 用于超长序列 scaling 的工业框架;
② 方法:三种极简但动机扎实的 token merge(LITM / PATM / LPTM),全部由真实注意力分数统计推导而来;
③ 取向:架构上坚持 full attention 而非轻量 target attention,效率问题从「压序列 + 蒸馏」而非「削注意力」解决;
④ 落地:字节电商广告全量上线,序列 5K → 20K,吞吐仅降 5%,ADSS +1.036%。
超长序列建模的「效果 - 效率」死结
超长用户行为序列建模已被反复证明能同时刻画长期与短期兴趣、显著提升推荐质量,是当前公认的 scaling 方向之一。但字节在自家电商广告系统里把最大序列长度从 5K 拉到 20K 时发现:即使已经上了 FlashAttention 和 M-Falcon serving,代价依然是灾难性的。
| 成本指标 | 5K | 10K | 15K | 20K | 净增 |
|---|---|---|---|---|---|
| 训练时间 | 1× | 1.9× | 3.0× | 4.5× | +3.5× |
| GPU 显存 | +0GB | +21GB | +40GB | +49GB | +49GB |
| Serving 延迟 | 1× | 1.7× | 3.1× | 7.3× | +6.3× |
注意力是二次复杂度。假设 5K 序列一层 attention 的计算量记为 1 个单位($5000^2 = 2.5\times10^7$ 量级),那么 20K 序列就是 $20000^2 = 4\times10^8$,即 16 倍。
实测只涨了 3.5× 训练时间而不是 16×,是因为:① FlashAttention 把显存墙推后、访存效率提升;② 真实用户序列长度分布极不均匀,多数用户远不到 20K(论文里 20K 配置下 AvgL 才 8.8K);③ 模型里还有大量与序列长度无关的计算(RankMixer、非序列特征)在摊薄。
但 serving 延迟涨了 6.3×——线上单请求要对几百个候选广告打分,序列侧一旦变重,延迟就被直接放大,这是最致命的一项。
现有两条路线,各有硬伤
论文把业界的 trade-off 方案归成两类,并逐一点出问题。
路线 A:序列长度压缩(Sequence Length Compression)
| 子类 | 代表工作 | 硬伤 |
|---|---|---|
| 检索式(search-based) | SIM、TWIN-V1(CP-GSU)、TWIN-V2、DIN 系 | ① 每个候选只捞相关 token,必然丢弃细粒度行为信息;② 与 M-Falcon serving 不兼容(每个候选检索结果不同,无法共享序列侧计算) |
| 聚类式(cluster-based) | TWIN-V2(HC)、HiSAC | 依赖高质量预训练 token embedding 才能稳定聚类,需要额外多模态/表征体系支撑 |
| 长度外推(LE) | STCA | 训练时随机丢 token,本质仍是丢信息 |
| 均匀 token merge | LONGER | 全序列一刀切等比压缩,把最近行为和远古行为当同等重要 |
路线 B:轻量注意力架构(Lightweight Attention)
TWIN 的 ETA、STCA 的堆叠 target-to-history cross attention、EST 的 LCA + CSA、HyTRec 的「线性注意力管长期 + softmax 注意力管近期」混合、MTFM 的 GQA + 混合 target attention、LONGER 的 Perceiver 式「底层 CA + 上层 SA」……
路线 C(论文选择的方向):两阶段框架
除了上述端到端方案,还有一类更灵活的思路:两阶段。
- 知识蒸馏路线:以 ExFM 为代表——构建一个 foundation-model 式的 teacher,同时服务多个 vertical model(学生),把构建成本摊薄。
- Foundation model 路线:通过缓存 user embedding / item embedding 来提升下游任务,以及近期的 instance-as-token 范式。
TM20K 属于第一类,但差异是:别人用 KD 解决「模型容量/特征规模」的 scaling,本文用 KD 专门解决「序列长度」的 scaling——teacher 保留全部 token,student 做高效训练与推理。作者也明确说,foundation model 的整合留作未来工作。
TM20K 在方法谱系中的位置
| 方法 | MaxLen(名义最大) | 压缩方式 | EffLen(实际计算) | 注意力架构 |
|---|---|---|---|---|
| TWIN-V1 | $10^4$ | GSU | $10^2$ | ETA |
| TWIN-V2 | $10^6$ | HC & GSU | $10^2$ | ETA |
| EST | $10^6$ | SIM | $10^3$ | LCA & CSA |
| STCA | $10^4$ | LE | $2\times10^3$ | STCA |
| HyTRec | $10^4$ | — | $10^4$ | HA |
| HiSAC | $10^4$ | HC | $2\times10^2$ | MHA |
| LONGER | $2\times10^3$ | TM | $10^3$ | CA & SA |
| TM20K-S(学生) | $2\times10^4$ | TM | $2\times10^3$ | FA |
| TM20K-T(老师) | $2\times10^4$ | — | $2\times10^4$ | FA |
方法部分的每一个设计都不是拍脑袋来的。论文先做了两组前置研究:(1)架构选型实验决定用 FA 还是 TA;(2)注意力分数统计直接反推出三种 token merge 策略。这一节是理解方法的必要前提。
3.1 FA vs TA:为什么坚持全注意力
先把两种架构写清楚。Full Attention(FA)把 target 拼到序列前面做整体自注意力:
- $e_t \in \mathbb{R}^{d}$:目标候选广告(target item)的 embedding
- $E_s \in \mathbb{R}^{L\times d}$:$L$ 个历史行为 token 的 embedding 矩阵($L$ 最大 20000)
- $E_c \in \mathbb{R}^{(L+1)\times d}$:把 target 拼进序列后的完整输入,关键:target 也是序列的一员
- $W_Q, W_K, W_V$:query / key / value 投影矩阵
- $\mathcal{M}$:causal mask(因果掩码),禁止早期 token 看到后续 token;这不只是建模选择,更是 M-Falcon serving 的硬性要求(因为 M-Falcon 要把多个候选拼成一条长序列共享前缀计算)
- $W_u, W_v, W_d$:SwiGLU FFN 的三个投影矩阵;$\odot$ 是逐元素乘
- 公式中省略了 LayerNorm、多头拆分和残差连接
而 Target Attention(TA)把注意力简化成「target 对序列的一次 cross attention」:
- $a_t \in \mathbb{R}^{d}$:只有一个向量——target 汇聚全序列后的表示(注意与 FA 的 $A_c \in \mathbb{R}^{(L+1)\times d}$ 对比)
- query 只有 $e_t$ 一个:所以计算量从 $O(L^2)$ 降到 $O(L)$
- 只有 target 的特征过 SwiGLU FFN,序列 token 本身不做任何变换
假设用户序列是:[看运动鞋 → 看篮球 → 加购篮球 → 看护腕 → 下单篮球],目标候选广告 = 篮球气筒。
TA 的视角:「篮球气筒」这个 query 分别问 5 个 token「你跟我有多像」,得到 5 个分数,加权求和结束。它不知道「加购篮球」后面紧跟着「下单篮球」这条转化链路,也不知道「护腕」是在篮球语境下才出现的。
FA 的视角:6 个 token(含 target)两两交互。「下单篮球」这个 token 可以 attend 到前面的「加购篮球」,形成「加购→下单」的强转化信号;「护腕」可以 attend 到「篮球」,被上下文重新解释为「篮球周边配件」。这些经过序列内加工的表示再和 target 交互,信号质量远高于原始 embedding。
结论:序列越长、行为链路越复杂,FA 相对 TA 的优势就越大——这也解释了下面表格里 TA 加长度几乎不涨的现象。
实验结论(基线 = 5K + TA)
| MaxLen | Full Attention ΔAUC | Target Attention ΔAUC | FA − TA 差距 |
|---|---|---|---|
| 5K | +0.20% | +0%(基线) | 0.20% |
| 10K | +0.24% | +0.03% | 0.21% |
| 15K | +0.28% | +0.04% | 0.24% |
| 20K | +0.30% | +0.05% | 0.25% |
① FA 全面碾压 TA,20K 下差距达 0.25% AUC(推荐系统里这是很大的数字);
② TA 吃不下长序列——从 5K 到 20K,TA 只从 +0% 涨到 +0.05%,几乎等于白加长度;而 FA 稳定爬升。这说明「支持长序列」的前提是注意力架构本身有足够表达力;
③ FA 的收益随训练时长持续放大:在超过半年的训练数据上,FA vs TA 的 AUC delta 从 0 单调爬升到 0.0035(Figure 2b),是典型的「越训越值」结构,而不是早期虚高。
最关键的证据:seq-seq 注意力不能丢
这一段是在回答一个非常具体的工程问题:注意力矩阵里,除了 target 那一行,其他行能不能直接砍掉?先把矩阵画出来才好理解。
行 = query(谁在提问),列 = key(问谁)。假设历史只有 5 个行为 $h_1 \sim h_5$($h_5$ 最近)加上 target $t$,矩阵是 $6\times 6$(因果掩码使右上角为空,每行 Softmax 后加起来 = 1):
| query ↓ \ key → | $h_1$ | $h_2$ | $h_3$ | $h_4$ | $h_5$ | 属于哪类 |
|---|---|---|---|---|---|---|
| $h_1$ | 1.00 | — | — | — | — | seq-seq 共 5 行 TA 完全不算 |
| $h_2$ | 0.40 | 0.60 | — | — | — | |
| $h_3$ | 0.10 | 0.20 | 0.70 | — | — | |
| $h_4$ | 0.10 | 0.10 | 0.30 | 0.50 | — | |
| $h_5$ | 0.05 | 0.05 | 0.20 | 0.30 | 0.40 | |
| $t$(target) | 0.05 | 0.30 | 0.15 | 0.20 | 0.30 | target-seq 只有这 1 行 |
• TA = 只算最后一行。它只关心「target 对每个历史行为的关注度」,前 5 行根本不计算;
• FA = 整个矩阵都算。多出来的前 5 行就是「历史 token 互相看」;
• FA 比 TA 贵的开销,几乎全部来自前 5 行——$O(L^2)$ 与 $O(L)$ 的差距就在这里。
于是最自然的省钱思路是「砍掉前 5 行只留最后一行」。这一小节就是在证明:不行,前 5 行有用。
论文的做法是把矩阵里的数值分成两堆——堆 A = 最后一行的所有数值(target-seq),堆 B = 前 5 行的所有数值(seq-seq)——各画一条概率密度曲线,看两堆数值的分布形态。结果是两条曲线基本重合。
为什么「形态重合」能算证据?因为如果 seq-seq 是纯粹浪费算力的计算,我们应该看到两种退化形态之一:
| 假如 seq-seq 无用,应该长这样 | 含义 |
|---|---|
| 分布极度均匀(全挤在 $1/L$ 附近) | 历史 token 之间「谁都不特别关注谁」,等于什么都没学到 |
| 分布极度尖锐(一个 token 吃掉几乎全部权重) | 退化成「每个 token 只看自己」,等价于恒等映射,没有交互发生 |
而实测是:seq-seq 的分布和 target-seq 一样有结构、一样有区分度。既然 target-seq 那一行公认有用(TA 就只用它),形态相同的 seq-seq 就很难说是噪声。进一步放大到「5 个 query token(1 个 target + 4 个序列 token)× 最近 50 个 key token」的局部热力图后可以看到:那 4 个序列 token 的行同样出现明显亮格子,而且亮的位置各不相同——每个历史 token 都在有选择地关注特定的其他历史 token,这种「有选择」就是在做真实的信息加工。
序列:$h_1$ 看运动鞋 → $h_2$ 看篮球 → $h_3$ 加购篮球 → $h_4$ 看护腕 → $h_5$ 下单篮球,target = 篮球气筒。
TA 的世界(只有最后一行):target 逐个去问这 5 个行为「你跟我像不像」,拿到 5 个分数、加权求和、结束。这 5 个行为始终是它们最原始的样子—— $h_4$ 就是"看了个护腕",一个孤立的、语义模糊的行为。
FA 的世界(整个矩阵):在 target 提问之前,这 5 个 token 先互相"开了个会":
• $h_4$(看护腕)那一行把注意力投给 $h_2/h_3$(篮球相关)→ $h_4$ 的表示被改写成「篮球场景下的配件浏览」,不再是"随便看了个护腕";
• $h_5$(下单篮球)那一行把注意力投给 $h_3$(加购篮球)→ 形成「加购 → 下单」这条完整转化链路的表示。
等 target 来提问时,它面对的已经不是 5 个原始行为,而是 5 个被上下文重新解释过的行为。此时「篮球气筒」与「篮球场景下的配件浏览」的匹配度,显然远高于与「看了个护腕」的匹配度。
一句话:seq-seq 不是在"回答 target 的问题",而是在"提前把材料整理好"。砍掉它,target 只能对着原始素材硬猜。
| 证据 | 类型 | 强度 |
|---|---|---|
| 分布重合 + 局部热力图(Figure 2d) | 解释性 / 间接 | 中 严格说「分布形态相似」推不出「信息量相当」——形态像也可能是冗余信息 |
| FA vs TA 在 20K 下 AUC 差 0.25%(上面那张表) | 因果 / 直接 | 强 砍掉就掉点,端到端实测结论 |
真正定案的是表,图只是在解释「为什么会掉点」。这个顺序不能反——如果只有图没有表,「seq-seq 有结构」完全可以是「有结构但对 CVR 没用」。
3.2 三组注意力分数观测 → 三种 token merge
这是全文最精彩的部分:三种 merge 策略,一一对应三组真实统计观测,不是凭直觉设计的。这一节的实验设置写得很压缩,下面拆开讲。
第一步:为什么必须先训一个 20K 的 FA 模型
注意力分数是模型学出来的,不是数据自带的属性。随机初始化的模型,注意力矩阵基本是均匀噪声,看不出任何规律。所以必须先有一个训到收敛的、吃完整 20K 序列的 FA 模型——这个模型就是后来的 teacher。
第二步:为什么只取一个局部子矩阵——因为全量存不下
完整注意力矩阵有多大?序列 20000 + 1 个 target,矩阵是 $20001 \times 20001$:
一个样本、一个 head、一层就 1.6GB,而模型有 6 层、多个 head,还要跑一批样本——根本不可能落盘。所以作者做了三刀裁剪:
| 裁剪 | 从 | 到 | 理由 |
|---|---|---|---|
| 只留 5 行($m=5$) | 20001 个 query | 5 个 query | 论文明说是 for storage saving。5 行足够看规律 |
| 保留全部列($n=L$) | — | 20000 个 key | 不能裁!要研究「不同位置的 key 被关注程度」,列必须完整 |
| 只看第 1 个 head | 多个 head | 1 个 | 各 head 并行独立,挑一个报告,避免图表爆炸 |
裁完就是 $A \in \mathbb{R}^{5\times 20000}$ = 10 万个数,轻松落盘。
第三步:这个矩阵具体长什么样
行 = query,列 = key,每行经过 Softmax 所以一行加起来 = 1。关键是每一列都挂着两个元信息标签:
| query ↓ \ key → | 列 0 | 列 1 | 列 2 | 列 3 | … | 列 19999 | 行和 |
|---|---|---|---|---|---|---|---|
| PID 标签 | A | A | B | C | … | Z | ← 分组用 |
| 位置索引 | 最近 | ↓ | ↓ | ↓ | … | 最远 | ← 分桶用 |
| $q_0$ = target | 0.30 | 0.28 | 0.05 | 0.19 | … | 0.00001 | = 1 |
| $q_1$ = seq token | 0.12 | 0.09 | 0.31 | 0.02 | … | 0.00002 | = 1 |
| $q_2$ = seq token | 0.05 | 0.40 | 0.11 | 0.07 | … | 0.00001 | = 1 |
| $q_3, q_4$ | …(同上) | = 1 | |||||
① PID 和位置索引本身不参与计算,它们纯粹是给后面分组用的标签——观测一按 PID 分组,观测二按位置分桶,用的是同一份数值、不同的标签;
② 位置索引的约定是反的:论文里 索引小 = 时间更近。所以「最近 10% 的 token」= 索引 0~2000 那一段。这个约定和直觉相反,读伪码时特别容易搞混。
第四步:三组观测 = 用三种方式切同一块数据
这是这节最优雅的地方——一次 dump,三种切法:
| 切的维度 | 具体操作 | 用到的标签 | 得出的结论 | 催生 | |
|---|---|---|---|---|---|
| 观测一 | 列,按 PID 分组 | 任取两列算差值 $\Delta_{i,j}^{(t)}$,按「PID 是否相同」分两堆画分布 | product ID | 同 PID 的两列,被关注程度几乎一样 | LITM |
| 观测二 | 列,按位置分桶 | 每 10% 位置切一桶,桶内数值求和 $M_k$ | 位置索引 | 最近 10% 占掉约 50% 权重 | PATM |
| 观测三 | 换层重新 dump | 每行算熵 $H_t$,对比不同层 | 层号 | 上层熵小(集中)、底层熵大(均匀) | LPTM |
注意观测一、二都在同一份数据的列上做文章,只是分组标签不同;只有观测三需要换一层再 dump 一次。
观测一:同 product ID 的 token,注意力分数高度接近 → LITM
对第 $t$ 个 query,计算任意两个 key token 之间的注意力分数绝对差:
- $A_{t,i}$:第 $t$ 个 query token 分配给第 $i$ 个 key token 的注意力概率(Softmax 之后,$\sum_i A_{t,i}=1$)
- $\Delta_{i,j}^{(t)}$:两个 key token 在同一 query 视角下「被关注程度」的差距
- 分组依据:$p_i = p_j$(同商品)还是 $p_i \neq p_j$(不同商品)
结果:同 product ID 的 token 对,$\Delta$ 分布明显更集中于 0。
回看 Eq. 2:$E_{s_i} = \mathrm{SumPooling}(E_{p_i},\, E_{o_i})$ ——token 不只是 PID。$p_i$ 是关键 ID 特征,$o_i$ 是其他特征(类目、交互类型、时间戳等)。所以同 PID 的两个 token,$E_{p_i}$ 那一半相同,$E_{o_i}$ 那一半不同。差异来源按影响排序:
| 差异来源 | 说明 | 举例 |
|---|---|---|
| 交互类型 | 同一商品可被曝光/点击/加购/下单 | 「看了篮球」和「下单篮球」PID 相同,语义天差地别 |
| 时间特征 | 时间戳、距今时长 | 三天前看 vs 三个月前看 |
| 位置信息 | 因果 transformer 里位置本身携带信息 | 第 3 个行为 vs 第 8000 个行为 |
| 上下文(若测的是高层) | 经过 attention 后表示已被上下文改写 | 同一商品在"篮球场景"与"办公场景"里被重新解释 |
尽管两个同 PID token 在交互类型、时间、位置、上下文上全都不同,它们最终拿到的注意力权重却几乎一样。
这等价于说:在注意力分配这件事上,product ID 是压倒性的主导因素,其他侧信息的贡献很小。这才是「可以合并」的依据。注意 Figure 3(a) 的措辞也是「更集中在 0 附近」(more concentrated near zero)而不是「等于 0」——它是一条有宽度的分布曲线,只是比 Diff PID 那条窄得多。
用前面矩阵示意里 target 那一行的数值,两两算差、按 PID 标签归堆:
| 列对 | PID | 差值计算 | 归入哪堆 |
|---|---|---|---|
| 列0 vs 列1 | A vs A | $|0.30-0.28| = $ 0.02 | Same PID |
| 列0 vs 列2 | A vs B | $|0.30-0.05| = $ 0.25 | Diff PID |
| 列2 vs 列3 | B vs C | $|0.05-0.19| = $ 0.14 | Diff PID |
把成千上万个这样的差值分成两堆、各画一条密度曲线 → 就是 Figure 3(a)。Same PID 那堆明显更挤在 0 附近。
答案就在那点没归零的残差里——它是真实携带信息的,而且间隔越远差异越大(时间特征差得越多、上下文越不同)。超参消融正好证实:
| $T$ | 压缩率 | ΔAUC | 解读 |
|---|---|---|---|
| 1 | −39% | −0.02% | 只合严格相邻 |
| 3(采用) | −43% | −0.02% | 多压 4%,AUC 无额外损失 → 这段残差确实可忽略 |
| 10 | −57% | −0.04% | 损失翻倍 → 这段残差开始有信息了 |
所以完整的结论应该是:同 PID 且位置相近时,注意力差异可忽略;位置一旦拉远,差异就恢复了。$T=3$ 正是这条曲线的拐点。「为什么 $\Delta \ne 0$」这个疑问和这个消融实验,本质是同一件事的两面。
观测二:最近 10% 的 token 占掉约一半注意力 → PATM
把序列按位置索引分桶(位置索引越小 = 越近期),对每个桶 $[i_k, i_{k+1}]$ 累加注意力质量:
- $M_k$:第 $k$ 个位置桶承载的注意力质量总和(attention mass)
- $[i_k, i_{k+1}]$:第 $k$ 个位置桶的起止索引;论文按 10% 为步长分成 10 个桶
- 约定:位置索引小 = 交互时间更近(整篇论文都遵循这个约定,读伪代码时尤其要注意)
结果:最近的 top 10% token 就贡献了接近一半的注意力总权重(Figure 3b 的累积概率曲线在 10% 处已到 ~0.5)。
| 桶 | 位置范围 | 桶内注意力总和 $M_k$ | 累积 |
|---|---|---|---|
| 1(最近) | 0 ~ 2000 | 0.50 | 0.50 |
| 2 | 2001 ~ 4000 | 0.13 | 0.63 |
| 3 | 4001 ~ 6000 | 0.08 | 0.71 |
| … | … | … | … |
| 10(最远) | 18001 ~ 20000 | 0.02 | 1.00 |
把最后一列画成曲线 → 就是 Figure 3(b),在 10% 处就已经冲到 0.5。
这个判断不需要猜,从方法本身就能反推。看 PATM 的配置 $R = [[1,1000],[1001,5000],[5001,10000],[10001,20000]]$、$K=[1,2,3,4]$ ——这是固定的绝对区间。而且更关键的是:
所以如果观测二是「每个 query 各自的相对 10%」,结论就无法落地成 PATM —— 你会需要给每个 query 准备一条不同的压缩序列,计算上完全不可行(那比不压缩还贵)。观测必须和方法在同一个坐标系里,否则推不出来。
那为什么横轴用「%」而不是绝对位置?因为要跨用户可比——用户序列长度差异极大:
| 用户 | 序列长度 | 「最近 10%」 |
|---|---|---|
| 重度用户 | 20000 | 最近 2000 个行为 |
| 轻度用户 | 3000 | 最近 300 个行为 |
如果横轴用绝对位置,两类用户的曲线没法叠在一张图上。用百分比归一化后才能画出统一的累积分布曲线。
副作用:绝对区间意味着轻度用户几乎不被压缩(序列只有 800,全落在第一段 $k=1$ 里),重度用户才被重压。这个行为本身合理,但也说明按时间窗而非位置索引分段可能更精确(重度用户的最近 1000 个行为可能只跨 3 天,轻度用户可能跨 3 个月)。
观测三:上层注意力更尖锐、底层更均匀 → LPTM
逐层计算注意力概率分布的熵:
- $H_t$:第 $t$ 个 query 的注意力分布熵。熵大 = 注意力铺得均匀(谁都看一点);熵小 = 注意力集中(只看少数几个 token)
- 统计对象:同一模型不同 transformer 层的注意力矩阵
熵的直观含义:
| 熵 | 注意力形态 | 打个比方 |
|---|---|---|
| 大 | 铺得均匀,谁都看一点 | 读者在通读全文 |
| 小 | 高度集中在少数几列 | 读者只看划线重点 |
结果:上层(upper layer)熵更小、注意力分配更尖锐;底层(bottom layer)熵更大、注意力更均匀。这与 LLM 领域的注意力分析结论一致。注意这一组观测需要换层重新 dump 一次,不像观测一、二那样共用同一份数据。
把 20K 序列想象成一本 2 万字的书,模型是读者:
观测一 → LITM(去重):书里连续 3 页都在讲同一件商品(用户反复点了 3 次同一双鞋),模型对这 3 页的关注度几乎一样 → 把它们缩写成一页,信息几乎不丢。
观测二 → PATM(分段缩写):最后一章(最近行为)是重点,逐字读;开头几章(远古行为)扫一眼就够 → 近期段落不压缩,远期段落 4 页压成 1 页。
观测三 → LPTM(逐轮精简):第一遍通读要看全文;第二遍只看划线部分;第三遍只看结论 → 每读 2 层,就把手里的材料对折一次(长度减半)。
三者叠加的实际效果:teacher 的 AvgL = 8.8K → student 的 AvgL = 1.8K,压掉约 80%,而 AUC 只掉 0.11%。
整个 3.2 节的流程串起来
(= teacher)
(存储妥协)
PID + 位置
4.1 整体框架:一个 teacher,多个 student
TM20K 的输入输出链路是这样的:原始电商行为序列(最长 20K,每个 token = 商品 ID + 侧信息)→ CPU 侧数据处理做 LITM + PATM 合并 →查 embedding 表并 sum pooling → 6 层 full attention transformer(层间做 LPTM)→ 序列表示 $x_{\text{seq}}$ 与非序列特征一起送入 RankMixer 做高阶交互 → 输出 CVR 预估。Teacher 和 student 共享这套架构,唯一区别是 teacher 不做任何 token merge。
形式化地,单个 token 的表示由各个特征 embedding 求和得到:
- $s_i = [p_i, o_i]$:序列第 $i$ 个 token,由关键 ID 特征 $p_i$(如 product ID)和其他特征 $o_i$(类目、交互类型、时间戳等)组成
- $E_{p_i}, E_{o_i}, E_{s_i} \in \mathbb{R}^{d}$:分别是 ID 特征、其他特征、以及合并后的 token embedding,都是 $d$ 维(论文中 $d = 512$)
- 所有 token embedding 堆成序列张量 $E_s \in \mathbb{R}^{L\times d}$
然后走序列建模与特征交互:
- $F_{\text{seq}}$:序列建模模块——本文选定为 full attention transformer(6 层,hidden 512,FFN 中间层 1024,SwiGLU 激活)
- $e_t$:目标候选广告 embedding;$x_{\text{seq}}$:编码了 target 与历史序列交互信息的序列表示
- $x_{\text{non-seq}}$:非序列特征(用户画像、商品属性、上下文等)
- $F_{\text{interaction}}$:RankMixer,负责异构 token 之间的高阶交互
- $h$:最终表示,接 MLP 后预测 CVR,用交叉熵损失优化
商品 ID + 侧信息
8.8K → 5K
→ 1.8K
+ SumPooling
得 token 向量
广泛注意
(GPU 张量操作)
集中注意
高阶交互
dis tower(吃 KD)
4.2.1 LITM:局部同 ID Token 合并
动机来源:观测一——同 product ID 的 token 注意力分数高度接近。
做什么:在局部窗口内把相同关键 ID(product ID)的 token 求和聚合成一个 token。注意关键词是 local-wise(局部)——不是全序列去重,而是只合并「位置间隔不超过阈值 $T$」的同 ID token。
输入:$E \in \mathbb{R}^{L\times d}$(token embedding)、$p \in \mathcal{I}^{L}$(ID 列表)、$T$(最大间隔阈值)
初始化:
p2i = 空字典(ID → 在结果列表中的下标)、$\mathcal{G}$ = 空列表遍历 $j = 0 \ldots L-1$:
• 若 $p_j$ 不在
p2i 中,或 $j - \texttt{p2i}[p_j] > T$:→ 把 $E_j$ 作为新 token 追加到 $\mathcal{G}$,并记录
p2i$[p_j] = |\mathcal{G}| - 1$• 否则:
→ $\mathcal{G}[\texttt{p2i}[p_j]] \leftarrow \mathrm{Sum}(\mathcal{G}[\texttt{p2i}[p_j]], E_j)$,即累加进已有 token
输出:$E_m \in \mathbb{R}^{L'\times d}$,$L' \le L$
- $\mathcal{I}$:所有唯一 ID 构成的离散集合
- $T$:最大位置间隔阈值,控制「多远之内的同 ID 才合并」。论文取 $T = 3$
p2i:id → index 映射,记录某 ID 最近一次落在结果列表的哪个位置- $L'$:合并后的序列长度;实测 LITM 单独可把 AvgL 从 8.8K 压到 5K(−43%)
输入序列(按 product ID 列出,位置 0 最近):
位置: 0 1 2 3 4 5 6 7
PID: A A B A C D E A
逐步执行:
• $j=0$(A):新 ID → 新建 token 0,p2i[A]=0。结果 = [A₀]
• $j=1$(A):$1 - 0 = 1 \le 3$ → 合并进 token 0。结果 = [A₀+A₁]
• $j=2$(B):新 ID → 新建 token 1。结果 = [A₀+A₁, B₂]
• $j=3$(A):p2i[A]=0,$3 - 0 = 3 \le 3$ → 合并进 token 0。结果 = [A₀+A₁+A₃, B₂]
• $j=4$(C)、$j=5$(D)、$j=6$(E):都是新 ID → 分别新建。结果 = [A₀₁₃, B₂, C₄, D₅, E₆]
• $j=7$(A):p2i[A]=0,$7 - 0 = 7 > 3$ → 间隔太远,不合并,新建 token。结果 = [A₀₁₃, B₂, C₄, D₅, E₆, A₇]
最终:8 个 token → 6 个 token。注意最后那个 A 单独成 token 是有意义的——它可能是「一周后又回来看这双鞋」,与三天前的连续三次浏览是两段不同的兴趣事件,不该混为一谈。这就是 T 的作用:区分"同一次逛店的重复点击"和"隔了很久的二次兴趣"。
① 信息浓缩:把同一商品的多次交互聚成一个更强的表示,而非重复的弱信号;
② 过滤异常行为噪声:疯狂连点、误触这类行为被自动折叠;
③ 强化用户隐私保护:合并后无法还原精确的单次交互序列(论文脚注也说明所有数据都做了 hash 处理)。
4.2.2 PATM:位置自适应 Token 合并
动机来源:观测二——最近 10% 的 token 占掉约一半注意力。
做什么:把序列切成 $B$ 个不重叠分段,每段用不同的压缩因子:近期段几乎不压,远期段狠狠压。
输入:$E \in \mathbb{R}^{L\times d}$、段数 $B$、段范围列表 $R$、压缩因子向量 $K$
遍历 $b = 0 \ldots B-1$:
• $(s, e) \leftarrow R_b$(第 $b$ 段的起止位置)
• $k \leftarrow K_b$(该段压缩因子)
• $\hat{E} = \mathrm{Sum}\bigl(\mathrm{Reshape}(E[s{:}e],\, (-1, k, d)),\ \mathrm{dim}=1\bigr)$ ← 把 $k$ 个连续 token 求和成 1 个
• $\mathcal{G}$.extend($\hat{E}$)
输出:$E_m \in \mathbb{R}^{L'\times d}$
- $R_b = (s, e)$:第 $b$ 段的起止位置索引
- $K_b = k$:第 $b$ 段的压缩因子——$k$ 个连续 token 合并成 1 个;$k=1$ 表示不压缩
- $\mathrm{Reshape}(\cdot, (-1,k,d))$ 后沿 $\mathrm{dim}=1$ 求和:这就是 LONGER 提出的 token merge 算子,本文的创新是让 $k$ 随位置变化
- 核心原则:位置索引小(近期行为)→ $k$ 小;位置索引大(远古行为)→ $k$ 大
- 实现细节:每段用全零 token 做 padding,保证段长能被 $k$ 整除
配置:$L = 20{,}000$,$B = 4$
段范围 $R = [[1,\,1000],\ [1001,\,5000],\ [5001,\,10000],\ [10001,\,20000]]$
压缩因子 $K = [1,\ 2,\ 3,\ 4]$
逐段算:
• 第 1 段(最近 1000 个行为):$k=1$ → 1000 个 token 原样保留,一个都不合
• 第 2 段(第 1001~5000):$k=2$ → 4000 / 2 = 2000 个 token
• 第 3 段(第 5001~10000):$k=3$ → 5000 / 3 ≈ 1667 个 token
• 第 4 段(第 10001~20000):$k=4$ → 10000 / 4 = 2500 个 token
合计 ≈ 7167 ≈ 7000 个 token,从 20000 压到约 7000(−65%),但最近 1000 个行为的细粒度信息完全无损。
对比 LONGER 的均匀 merge:若全序列统一 $k=3$,也能压到约 6667,长度差不多——但最近 1000 个高价值行为被三三合并,直接把 Figure 3(b) 里那「占一半注意力」的部分给糊掉了。这就是 PATM 的全部意义。
4.2.3 LPTM:层间金字塔 Token 合并
动机来源:观测三——上层注意力更集中,底层更均匀。
做什么:随着 transformer 层数上升,逐步把序列对折,形成「底层长、上层短」的金字塔。
- $\hat{E}_n \in \mathbb{R}^{L_n \times d}$:第 $n$ 层 transformer 的输出
- $E_{n+1} \in \mathbb{R}^{(L_n/2) \times d}$:第 $n+1$ 层的输入,长度减半,后续注意力计算量降为 $1/4$(二次复杂度)
- $\mathrm{Reshape} + \mathrm{Sum}(\mathrm{dim}=1)$:把相邻 2 个 token 求和成 1 个,与 PATM 用的是同一个算子
- 关键约束:只有历史序列 token 参与层间合并,target 候选 token 永不被合并(论文说伪代码里为简洁省略了这个实现)
- 执行频率可调:可以每层做,也可以每若干层做一次。本文用 6 层 transformer,每 2 层做一次
假设经过 LITM + PATM 后进入 transformer 的序列长度是 $L_0 = 2000$,每 2 层做一次 LPTM:
| 层 | 输入长度 | 注意力相对计算量 | 说明 |
|---|---|---|---|
| Layer 1 | 2000 | 1.00 | 底层:注意力均匀,需要看全貌 |
| Layer 2 | 2000 | 1.00 | |
| ↓ LPTM:相邻 2 token 求和,2000 → 1000 | |||
| Layer 3 | 1000 | 0.25 | 中层:开始聚焦 |
| Layer 4 | 1000 | 0.25 | |
| ↓ LPTM:1000 → 500 | |||
| Layer 5 | 500 | 0.0625 | 上层:注意力已高度集中,短序列足够 |
| Layer 6 | 500 | 0.0625 | |
总计算量对比:不做 LPTM 时 6 层都是 1.00,合计 6.0;做 LPTM 后合计 = 1+1+0.25+0.25+0.0625+0.0625 = 2.625,约省掉 56% 的注意力计算。而这一切只换来 0.03% 的 AUC 损失。
为什么 target token 不能合并?因为 target 是唯一的「query 主角」,最终 $x_{\text{seq}}$ 要从它的位置读出。把它和某个历史 token 求和会直接污染预测信号。
4.2.4 工程实现:CPU / GPU 的分工艺术
三种 merge 按顺序叠加:LITM → PATM → LPTM。但落地时的关键决策是「谁在哪算」。
理由一:这两个是规则型(rule-based)操作——查字典、比较位置、分段 reshape,充满分支判断和不规则内存访问,天生 CPU 友好、GPU 不友好(无法向量化)。理由二:它们属于数据预处理阶段,可以和 GPU 训练流水线并行,不占用宝贵的 GPU 时间。
这是全文最有工程含金量的一处细节。不是先查 embedding 再在 CPU 上把向量相加(那样 CPU 要处理 $L \times 512$ 的浮点矩阵,还要把结果传给 GPU),而是先在 CPU 上按 LITM / PATM 规则把 token 的原始特征 ID 分好组,然后在 GPU 侧查 embedding 表、再做 sum pooling。这样 CPU→GPU 之间传的只是整数 ID + 分组信息,通信带宽开销大幅下降。
它只需要对标准 transformer 做很小的改动,Eq. 9 就是一个 reshape + sum,是完美的规整张量操作,GPU 上几乎零成本。
方案 A(先查表再合并,朴素做法):假设一个用户 20000 个 token,$d=512$,fp32。CPU 需要处理 $20000 \times 512 \times 4\text{B} \approx 41\text{MB}$ 的浮点数据,做完合并后即使压到 1800 个 token,也要把 $1800 \times 512 \times 4\text{B} \approx 3.7\text{MB}$ 的稠密矩阵传给 GPU。batch 一大,PCIe 直接被打满。
方案 B(本文做法,先分组再查表):CPU 只处理整数 ID。假设每个 token 有 10 个特征 ID(int64),传输量约 $1800 \times 10 \times 8\text{B} \approx 144\text{KB}$,加上分组元信息也就几百 KB——比方案 A 小一个数量级以上。而且 embedding 表本来就在 GPU/参数服务器侧,查表 + sum pooling 都是 GPU 的强项。
额外好处:CPU 侧完全不涉及模型参数,预处理逻辑可以独立部署、独立扩容,与训练解耦。
4.3 Teacher 模型与知识蒸馏
Teacher 的定位非常明确:不追求效率、独立训练、缓存 logits 供所有 student 使用。
Teacher 的损失
- $g_{\mathcal{T}} = \mathrm{MLP}(h_{\mathcal{T}})$:teacher 的预测 logit,$h_{\mathcal{T}}$ 是 RankMixer 出来的最终表示
- $q_{\mathcal{T}} = \mathrm{Sigmoid}(g_{\mathcal{T}})$:teacher 预测的转化率,这个值会被缓存下来做 KD
- $y \in \{0,1\}$:真实转化标签
- 标准二分类交叉熵,没有任何特殊设计——teacher 就是一个「什么都不省」的常规模型
Student 的双塔损失
Student 设计了两个独立的预测头:main tower(只学真实标签)和 distillation tower(同时学标签和 teacher)。
- $q_{\mathcal{S},\star} = \mathrm{Sigmoid}\bigl(\mathrm{MLP}_{\star}(h_{\mathcal{S}})\bigr)$,$\star \in \{\text{main},\ \text{dis}\}$:两个塔共享同一份 $h_{\mathcal{S}}$(student 骨干输出),只是各接一个独立 MLP 头
- $\ell_{\text{main}}$:main tower 对硬标签 $y$ 的交叉熵
- $\ell_{kd}$:distillation tower 对软标签 $q_{\mathcal{T}}$(teacher 预测概率)的交叉熵——形式上就是把 $y$ 换成 $q_{\mathcal{T}}$
- $\lambda$:蒸馏损失权重,论文实验最优值 $\lambda = 50$
- 总损失 = $\ell_{\text{main}} + \ell_{\text{dis}}$(两塔的梯度都回传到共享骨干)
如果只有一个塔(把 KD loss 直接加到唯一的头上):这个头要同时拟合 0/1 硬标签和 teacher 的软概率(比如 0.037)。两个目标的最优解不同——硬标签把预测往 0 或 1 推,软标签把预测往 0.037 拉。结果是预估值分布被扭曲,而广告系统里预估值的绝对校准(calibration)直接影响出价,不能乱。
双塔的解法:main tower 只对硬标签负责,预估值分布干净、校准正确,这个才是上线用的;dis tower 负责吸收 teacher 知识。由于两塔共享骨干 $h_{\mathcal{S}}$,teacher 的知识通过梯度流进共享表示层,间接让 main tower 也变强,但不直接干扰它的输出分布。
假设数字:某样本真实标签 $y=0$,teacher 预测 $q_{\mathcal{T}} = 0.15$(它凭 20K 完整序列看出这个用户其实有一定兴趣)。dis tower 会被拉向 0.15,学到「这类样本没那么无望」这个 teacher 独有的判断;这个信息通过骨干反哺给 main tower 的特征表示,而 main tower 自己仍然老老实实往 0 学。
4.4 两个额外的工程设计
论文的基线已经用了一整套优化:User-Level Training(类似 STCA 的 RLB)、FlashAttention、混合精度、Remove-Padding、M-Falcon Serving。在此之上又加了两个。
① Stack Sequence(显存优化)
一个 batch 内用户序列长度极不均匀,传统做法把所有序列 pad 到最长,得到 $E_s \in \mathbb{R}^{B\times L_{\max}\times d}$,浪费巨大。改法:把所有有效 token 在 batch 内重新均匀分配,并记录每条样本的真实 token 数,张量变成 $E_{\text{stack},s} \in \mathbb{R}^{B\times L\times d}$,其中 $L = \lceil L_{\text{total}}/B \rceil$,之后在 GPU 上按记录的计数重建 remove-padding 张量。完整 20K 序列下省下最多 10GB 显存。
② QK Norm(训练稳定性)
加入超长序列 + KD loss 后,student 频繁训练发散。借鉴 LLM 缓解极端 attention score 的方案,在算注意力之前对 query 和 key 各加一层 normalization。虽然带来轻微的显存和计算开销(吞吐 +2% 是去掉它才有的),但彻底稳住了整个训练过程。
- $B$:batch size(论文全局 320;teacher 因显存压力降到 96)
- $L_{\text{valid},i}$:第 $i$ 条样本的真实有效 token 数
- $L_{\text{total}}$:整个 batch 的有效 token 总数,实践中远小于 $B \times L_{\max}$
- $L$:重分配后每条「虚拟样本」的长度,即把总量摊平——本质是用「总量守恒」替代「按最长对齐」
4.5 与相邻工作的核心区别
| 对比维度 | LONGER | TWIN-V2 | ExFM | TM20K |
|---|---|---|---|---|
| 压缩粒度 | 全序列均匀 TM | 检索 + 层次聚类 | 不针对序列 | ID / 位置 / 层三维差异化 |
| 是否丢 token | 否(merge) | 是(检索丢弃) | — | 否(全 merge,一个不丢) |
| 注意力架构 | CA + SA(Perceiver) | ETA | — | Full Attention |
| KD 的用途 | 无 | 无 | 解决模型容量 scaling | 解决序列长度 scaling |
| Teacher 差异点 | — | — | 更大的 foundation model | 同架构,但序列不压缩 |
| 压缩依据 | 启发式(等比) | 相关性 / 聚类 | — | 真实注意力分数统计 |
| M-Falcon 兼容 | 兼容 | 不兼容 | — | 兼容(causal mask + 无检索) |
| EffLen | $10^3$ | $10^2$ | — | $2\times10^3$(S)/ $2\times10^4$(T) |
5.1 实验设置
数据与场景
字节电商广告真实生产环境的 CVR 预估任务。序列 token 由用户历史交互商品的 ID + 侧信息构成。训练数据横跨超过半年(论文强调长周期观察)。全部数据经 hash 处理,无隐私泄露。
模型与训练
6 层 transformer,hidden 512,FFN 中间层 1024,SwiGLU。特征交互用 RankMixer。全局 batch size 320(teacher 因显存限制降到 96)。基线已包含 FlashAttention、混合精度、Remove-Padding、User-Level Training、M-Falcon Serving。
5.2 主实验:效果与效率的全景对比
| MaxL | 方法 | AvgL | P90L | AUC | ΔAUC | LogLoss | ΔLogLoss | Thr | Mem |
|---|---|---|---|---|---|---|---|---|---|
| 5K | Baseline | 1.8K | 5K | 0.8212 | — | 0.4917 | — | 88K | 52G |
| 5K | STCA | 1.8K | 5K | 0.8200 | −0.15% | 0.4931 | +0.29% | 137K | 40G |
| 5K | LONGER | 1.4K | 3.5K | 0.8215 | +0.04% | 0.4914 | −0.07% | 100K | 58G |
| 20K | LONGER | 2.7K | 7K | 0.8221 | +0.11% | 0.4907 | −0.21% | 48K | 70G |
| 20K | HyFormer | 8.8K | 20K | 0.8222 | +0.12% | 0.4906 | −0.23% | 36K | 75G |
| 20K | TM20K-T(老师) | 8.8K | 20K | 0.8233 | +0.26% | 0.4890 | −0.55% | 11K | 86G |
| 20K | TM20K-S(学生) | 1.8K | 2.6K | 0.8224 | +0.15% | 0.4903 | −0.29% | 83K | 74G |
| 20K | TM20K-S w/ KD | 1.8K | 2.6K | 0.8230 | +0.22% | 0.4896 | −0.43% | 83K | 74G |
① STCA 是唯一负收益的方法(−0.15%)。它吞吐最高(137K)、显存最低(40G),但训练时随机丢 token 的做法在这个场景直接掉点——丢信息是有代价的;
② LONGER 从 5K 到 20K 只涨 0.07%(+0.04% → +0.11%)而吞吐从 100K 掉到 48K,性价比很差。原因就是均匀 merge 把近期高价值 token 也压糊了;
③ Teacher 是天花板但完全不能上线:+0.26% AUC 是全表最高,但吞吐 11K = 基线的 1/8,显存 86G。这就是「效果上限」的定义;
④ Student 单独就已经很能打:三种 merge 把 AvgL 从 8.8K 压到 1.8K(和 5K 基线一样!),吞吐回到 83K(基线的 94%),却拿到 +0.15%——同样的计算量下,20K 压缩序列比 5K 原始序列更有信息量;
⑤ KD 把 teacher 的收益捞回约 85%:0.15% → 0.22%,而 teacher 上限是 0.26%。$0.22/0.26 \approx 85\%$ 且吞吐显存一分钱不多花(83K / 74G 完全不变)——因为 teacher logits 是离线缓存的。
5K Baseline:AvgL 1.8K,意思是平均每个用户实际有 1800 个行为 token 参与计算,这 1800 个是最近的 1800 次原始行为(因为 MaxL=5K 时大部分用户不到 5K)。
TM20K-S:AvgL 也是 1.8K,但这 1800 个 token 是从最多 20000 次原始行为压缩来的——每个 token 可能聚合了多次同商品交互、或代表远期的一段行为区间。信息覆盖面广了 4 倍多,而计算量一样。
更妙的是 P90L:Baseline 是 5K,TM20K-S 只有 2.6K。P90 决定了 padding 后的实际张量大小和长尾延迟——TM20K-S 的长尾用户比 5K 基线还要轻。这就是为什么它吞吐能做到 83K 却看得比基线更远。
类比:基线是「逐字读最近 1800 字」,TM20K-S 是「读一份 20000 字原文的 1800 字精编摘要」。摘要的信息密度更高。
5.3 三种 Token Merge 的消融
从 20K Full(= teacher)出发逐步叠加 merge:
| 配置 | AvgL | P90L | ΔAUC | Thr | 吞吐提升 |
|---|---|---|---|---|---|
| 20K Full(无压缩) | 8.8K | 20K | — | 11K | 1.0× |
| + LITM | 5K | 13K | −0.02% | 25K | 2.3× |
| + PATM | 4.5K | 9K | −0.06% | 34K | 3.1× |
| + LPTM | 8.8K | 20K | −0.03% | 19K | 1.7× |
| + LITM & PATM | 1.8K | 2.6K | −0.07% | 68K | 6.2× |
| + LITM & PATM & LPTM | 1.8K | 2.6K | −0.11% | 83K | 7.5× |
• 三者叠加换来 7.5× 吞吐,只付 0.11% AUC——这个 trade-off 比例极其漂亮;
• LITM 是性价比之王:单独用就有 2.3× 吞吐,AUC 只掉 0.02%。「合并连续同商品行为」这件事几乎是免费的;
• LPTM 那一行的 AvgL/P90L 与 20K Full 完全相同(8.8K / 20K)——不是笔误!因为 LPTM 是层间压缩,输入层长度不变,AvgL/P90L 这两个指标测的是输入长度。它的价值体现在 Thr 从 11K 涨到 19K;
• LITM + PATM 有超线性协同:单独 LITM 到 5K、单独 PATM 到 4.5K,两者叠加直接到 1.8K。因为 LITM 先把重复 token 折掉后,PATM 的分段压缩作用在更"干净"的序列上,等效压缩率被放大;
• P90L 的暴降是关键:从 20K → 2.6K(−87%),这直接决定了 serving 长尾延迟能不能扛住。
5.4 超参与蒸馏权重
LITM 的间隔阈值 $T$
| $T$ | 序列长度变化 | ΔAUC | 解读 |
|---|---|---|---|
| 1 | −39% | −0.02% | 只合并严格相邻的同 ID |
| 3(采用) | −43% | −0.02% | 最优:多压 4% 且 AUC 无额外损失 |
| 10 | −57% | −0.04% | 压得更狠但 AUC 损失翻倍 |
结论:$T=1 \to 3$ 是纯赚(−39% → −43%,AUC 不变);$T=3 \to 10$ 才开始付代价(AUC 损失从 0.02% 翻倍到 0.04%)。说明「同一次浏览会话内的重复点击」大约就在 3 个位置的间隔内,超出这个范围就是不同的兴趣事件了。
PATM 的分段配置
| 配置强度 | 序列长度变化 | ΔAUC | 解读 |
|---|---|---|---|
| 激进 | −55% | −0.09% | 压得最多,损失最大 |
| 中等(采用) | −49% | −0.06% | 平衡点 |
| 保守 | −40% | −0.05% | 多保留 9% 长度只换回 0.01% AUC,不划算 |
结论:PATM 的效果损失对压缩强度更敏感(0.05% ~ 0.09% 的区间,比 LITM 的 0.02% ~ 0.04% 大一倍)。这符合直觉——PATM 是「不管内容、按位置强制合并」,而 LITM 有语义依据(同商品)。所以 PATM 应该调得比 LITM 保守。
蒸馏权重 $\lambda$
| $\lambda$ | 30 | 50 | 75 | 100 | 150 |
|---|---|---|---|---|---|
| ΔAUC | −0.01% | +0.00% | −0.01% | −0.01% | −0.03% |
其他实现选择的消融(表 6)
| 变体 | ΔAUC | ΔThr | 结论 |
|---|---|---|---|
| merge 用 MeanPooling + LogN 而非 SumPooling | −0.01% | +0% | 差别可忽略,SumPooling 更简单 |
| PATM 只压缩增量 token(复用历史压缩结果) | +0.01% | +0% | 略有收益但工程复杂度太高,未采用 |
| 去掉 QK Norm | 前期 +0.00% / 后期 −0.45% | +2% | 训练会发散,绝不能去 |
| 训练后期去掉 KD loss | ±0% | +0% | 知识已吸收完,可以省掉缓存读取 |
5.5 线上 A/B 实验
在字节电商广告线上系统做 A/B,基线是 5K 序列的生产模型。
| 方法 | ADSS(广告主分数) | ADVV(广告主价值) | Serving 延迟 |
|---|---|---|---|
| TM20K-S | +0.881% | +0.515% | +5.6% |
| TM20K-S w/ KD(全量上线) | +1.036% | +0.780% | +5.6% |
① KD 对线上指标的提升比离线更明显:ADSS +0.881% → +1.036%(相对提升 18%),ADVV +0.515% → +0.780%(相对提升 51%)。离线 AUC 只涨 0.07pp,线上 ADVV 涨了半成——说明 teacher 教给 student 的知识,对高价值转化的判别尤其有帮助;
② 延迟只涨 5.6%,而 Figure 1 里原生 20K 的延迟是 7.3×。对比一下:+630% vs +5.6%,这就是三种 merge 的全部价值;
③ 加 KD 不增加任何 serving 成本(两行延迟完全相同 +5.6%)——蒸馏的收益是纯赚的,因为 teacher 只在训练时以缓存 logits 的形式存在。已在字节电商广告全量部署。
原始 20K FA:序列侧注意力计算量 $\propto 20000^2$。相对 5K($5000^2$)是 16×,加上 serving 阶段要对每个候选广告重复计算,实测延迟 7.3×(+630%)。
加上三种 merge 后:
• LITM + PATM:输入长度 20K → AvgL 1.8K / P90 2.6K。与 5K 基线的 AvgL 1.8K 持平,所以底层 attention 成本回到基线水平;
• LPTM:中间 4 层进一步减半再减半,注意力总计算量再省约 56%;
• M-Falcon:多候选共享序列前缀计算(causal mask 使之可行),摊薄单候选成本。
净结果:比 5K 基线只多 5.6% 延迟。多出来的这 5.6% 主要来自 CPU 侧 merge 预处理和 LPTM 的 reshape 开销,而不是 attention 本身。换来的是覆盖 4 倍历史长度的信息量 + ADSS +1.036%。
5.6 作者自陈的局限
① Token merge 是规则式的
三种 merge 的超参($T$、分段范围 $R$、压缩因子 $K$、LPTM 频率)都依赖特定业务场景的注意力统计。换到别的域(如短视频、信息流)需要重新做观测和调参。未来方向:让 merge 策略可学习,端到端优化压缩模式。
② 没引入 sparse attention
稀疏注意力理论上能进一步降本,但与本文已有的 User-Level Training / Remove-Padding / FlashAttention 这套优化组合难以兼容——需要定制 CUDA 算子。作者留作未来工作。
这篇论文最值得学的三件事
三种 merge 不是从「我觉得应该这样压」出发,而是从三个具体的注意力统计量($\Delta_{i,j}^{(t)}$ 按 PID 分组、$M_k$ 按位置分桶、$H_t$ 按层)出发。每一个观测精确对应一种压缩维度。这种「让数据告诉你哪里冗余」的做法,比堆砌复杂模块的论文有用得多——它可迁移:换个场景,重跑这三个统计,就知道该怎么调参。
训练与推理的成本结构在工业系统里是极度不对称的:一次性离线训练可以任性,在线推理一毫秒都要抠。TM20K 的核心洞察就是把这个不对称性变成杠杆——让贵的那一次去承担全部重计算,把便宜的那一亿次做到极轻,中间用 KD 搭桥。这个思路远超序列建模本身,任何「效果好但太贵」的模块都可以套用:先建一个只训一次的重量级版本,再蒸馏出轻量上线版。
表 1 里 TM20K 是唯一「一个 token 都不丢」的方法。表 2 里 STCA(随机丢 token)是唯一负收益的方法。这两个事实放在一起就是全文最有说服力的论证:信息可以浓缩,但不能删除。Sum pooling 保留了所有 token 的贡献(哪怕被稀释),而检索/丢弃是硬性的信息删除,模型无从恢复。这个原则应该成为做任何序列压缩时的第一条准则。
几个我觉得特别锐利的判断
关于 EffLen 的揭穿。表 1 那一列 EffLen 是全文最"不留情面"的设计。业界论文都爱标榜 MaxLen 支持到 $10^6$,但真正参与计算的只有 $10^2$。这等于在说:你们号称支持百万序列,实际上模型只看到了几百个 token,剩下的都在检索阶段被扔掉了。把 MaxLen 和 EffLen 并列摆出来,是一种非常有力的学术批评。以后读长序列论文,第一件事就该是问 EffLen 是多少。
关于与 EST 结论冲突的处理。面对「EST 说 seq-seq 依赖不重要」这个矛盾结论,作者没有简单说对方错了,而是指出EST 用了检索式压缩,检索本身在强化 target-seq 相关性,从而系统性压低了 seq-seq 的边际价值。这是教科书级别的「结论依赖于实验设定」辨析——同样的实验现象,在不同的数据预处理下会导向相反结论。这提醒我们:任何"某模块不重要"的消融结论,都要先检查上游预处理是否已经替它做了工作。
关于 FA 的 GPU 利用率更高。「计算量大的方案反而更快」是这篇论文最反直觉的发现。现代 GPU 的瓶颈早已从 FLOPs 转向访存带宽和算子规整度。TA 的一个 query × 长 key 是典型的 memory-bound 细碎操作;FA 的大矩阵乘法能打满 Tensor Core。所以「减少计算量」不等于「变快」,选架构时必须看实测利用率而不是理论复杂度。
可以直接借鉴的工程 checklist
- CPU 侧只搬整数,不搬浮点。规则型预处理(去重、分段、分组)放 CPU,但要合并原始特征 ID 而非 embedding,CPU↔GPU 之间只传 ID + 分组元信息。这一条能省掉一个数量级的通信量。
- KD 权重的量级校准比数值本身重要。$\lambda = 50$ 看着离谱,但它的意义只是「让 $\lambda\ell_{kd}$ 和 $\ell_{ce}$ 同量级」。换场景时先算两个 loss 的量级比,而不是照搬 50。且 30~100 都行,鲁棒性很好。
- 蒸馏一定要用独立的塔。不要把 KD loss 加到上线用的那个头上,否则预估值校准会被软标签污染。共享骨干 + 独立头,让知识走梯度而不走输出。
- 超长序列训练必须看长周期曲线。QK Norm 的消融就是血泪教训:前期 +0.00%,后期 −0.45%。任何「早期看起来无用」的稳定性组件,都要跑到后期再判断。
- 盯 P90L 而不只是 AvgL。P90L 决定 padding 张量大小和长尾延迟。TM20K-S 的 P90L 从 20K 降到 2.6K(−87%),这才是延迟能压在 +5.6% 的真正原因。
- 训练后期可以关掉 KD。知识吸收完之后 KD loss 就没用了,关掉可以省掉 teacher logits 的缓存读取和存储成本。
- Stack Sequence 值得单独抄。把 batch 内有效 token 重新均匀分配 + 记录真实计数,替代 pad-to-max,20K 场景省 10GB 显存。这是个与序列建模方法无关的通用优化。
我的疑问与可延伸的方向
- Teacher 上限就一定是天花板吗?Student 拿到 teacher 的 85%,但 teacher 自己也只有 +0.26%。如果 teacher 再往上(比如 50K 序列、更宽的模型),student 能捞回的绝对值会不会更高?论文没有探索 teacher scaling 与 student 收益之间的关系曲线,这可能是下一篇的内容。
- 三种 merge 的顺序能否交换或联合优化?现在是固定 LITM → PATM → LPTM。如果先 PATM 再 LITM,或者把 LITM 也做成层间的,效果如何?论文只给了「叠加」的消融,没给「排序」的消融。
- 可学习的 merge 会不会反而更差?作者把「让 merge 可学习」列为未来工作,但我怀疑这里有个隐藏权衡:规则式 merge 可以在 CPU 上做、可以缓存、可以和训练流水线并行;一旦变成可学习的(需要 embedding 参与决策),就必须搬到 GPU 上,那个 7.5× 吞吐提升可能就没了。这不是纯粹的效果问题,而是效果与可实现性的冲突。
- 为什么 KD 对 ADVV 的提升(+51% 相对)远大于对 AUC 的提升?ADVV +0.515% → +0.780%,而 AUC 只从 +0.15% 到 +0.22%。这暗示 teacher 教给 student 的知识在高价值样本上尤其有效——可能是因为高价值转化往往依赖更长期的兴趣线索,正是 20K 全序列的独有优势。如果这个猜想成立,那么按样本价值加权的蒸馏可能还有额外收益。
- PATM 的分段配置能否随用户自适应?现在 $R$ 和 $K$ 是全局固定的。但重度用户和轻度用户的行为密度差异巨大——重度用户最近 1000 个行为可能只跨 3 天,轻度用户可能跨 3 个月。按时间窗而不是位置索引分段,或者按用户活跃度选择配置,可能比全局固定更合理。