(七)一字一字蹦太慢?MTP 让主模型一次确认多个字

三道墙拆完了,但生成还是一个字一个字蹦
上一篇我们用 MoE 拆了墙 3(推不动),753B 的模型现在能用一小撮激活专家跑起来。算不动、放不下、推不动都松动了。
但墙 4(蹦得慢)还在。 它不在参数,也不在注意力,而在”生成方式”本身。
进度感:本篇破墙 4(蹦得慢 · 自回归)
墙 1(算不动)→ 第 5 篇 DSA 已破
墙 2(放不下)→ 第 4 篇 MLA 已破
墙 3(推不动)→ 第 6 篇 MoE 已破
墙 4(蹦得慢)→ 本篇 MTP 在破 ★ 最后一道
墙 4 量化:自回归,每蹦一个字都要跑一遍 78 层
地基篇讲过,模型是”自回归”的:用已生成的 token 预测下一个,循环往复。这意味着:
生成 "你好世界":
跑 78 层 → 出 "你"
跑 78 层 → 出 "好"
跑 78 层 → 出 "世"
跑 78 层 → 出 "界"
→ 4 个字 = 4 次完整前向传播
哪怕 DSA、MLA、MoE 让每次前向更快,瓶颈还是”每次只蹦一个字”。生成 1000 个字,就是跑 1000 次完整的前向传播。这就是墙 4——不是哪一环慢,是”一蹦一个”这个节奏本身慢。

这对你用 AI 意味着什么: 为什么 AI 回复是”流式”一个字一个字蹦出来,而不是瞬间蹦整句?因为它真的在”一个字一个字想”——每蹦一个,都要把整个模型从头跑一遍。你看到的打字动画,本质是 1000 次 78 层前向传播在实时发生。 MTP 要解的就是这个节奏。
能不能一次蹦多个?能。答案就是 MTP(Multi-Token Prediction,多 token 预测),也叫投机解码。
核心思想:考试蒙题
MTP 的思路,用”考试蒙题”比喻最直观。
传统做题是串行的:做一题、等老师批、再做下一题、再等批……每题都得等。MTP 的玩法不一样:
MTP 蒙题:
快速蒙完 5 题(MTP 头,便宜)
一次性提交 5 题给老师(主模型)批改
如果前 3 题对 → 3 题一起通过(省了 3 次"做题+等批")
如果第 4 题错 → 第 4 题重做,后面丢弃
(这里说”对/错”是为了好懂。严格讲,老师批改也不是非黑即白——后面会看到,主模型其实是用概率决定”认领”还是”自己来”,不是判对错。)
关键分工:MTP 头是”便宜的蒙题器”,主模型是”批改老师”。 蒙题快但可能错,批改慢但权威。

两个角色:主模型 vs MTP 头
先把两个角色的地位说清楚:
| 角色 | 是什么 | 速度 | 权威性 |
|---|---|---|---|
| 主模型(78 层) | 完整模型 | 慢(一次算 1 个) | 权威(最终决定) |
| MTP 头(第 79 层) | 单层 transformer block(结构同构) | 快(猜一串草稿) | 草稿(可能错) |
MTP 头猜的 token 一律是”草稿”,主模型必须自己确认才算数。 怎么确认,是这篇最难也最精彩的部分,下面专门讲。
MTP 头长什么样、在哪
GLM-5.2 的主体是 78 层(索引 0–77),第 79 层(layer 78)就是 MTP 头。拆 config:
num_nextn_predict_layers: 1 # 1 个 MTP 预测层(NextN prediction)
这里要澄清一个容易误解的点:MTP 头只有”一层”(num_nextn_predict_layers: 1),不是一堆头并行。那它怎么”猜多个”?靠迭代——单层 MTP 头每跑一次预测一个 token,然后把这个草稿当输入再跑一次预测下一个,像接龙一样猜出一条草稿链 [t1, t2, t3, …]。所以”一次猜多个”是单层头迭代式地猜出一串,不是一个头同时吐出多个。
从权重清单看,这个 MTP 头结构不简单——它不是个轻量小预测头,而是一个和主模型同构的完整 transformer block(有完整的 attention + MoE),外加几个 MTP 专属组件(eh_proj、hnorm、enorm)。它是一层结构同构的 transformer block(不是缩小版,而是单层复用主模型的 block 结构),这样才有足够表达能力,猜出高质量草稿。

这对你用 AI 意味着什么: MTP 头猜的草稿,质量直接决定能省多少。草稿越准,主模型一次确认的就越多、越快;草稿老猜错,主模型光验证和重算就够忙的,反而拖慢。这就是为什么 GLM-5.2 花大力气提升”接受长度”——它直接等于你的等待时间变短。
怎么判断草稿对错:这篇最反直觉的地方
这是整个 MTP 最微妙、也最容易讲错的部分。我必须先纠正一个常见误解:
“验证”不是”主模型知道标准答案,再对比 MTP 头的猜测”。
真相是:主模型也不知道正确答案——它自己也是个概率机器。 生成下一个 token 时,没有任何”标准答案”可以拿来对比。那它凭什么判断 MTP 头猜得对不对?
一句话:主模型自己重新算一遍,看 MTP 头猜的那个 token,主模型自己算出的概率够不够高。(注意,这里的”重新算”不是逐个串行——主模型是把整串草稿一次性喂进去并行算的,后面”为什么能加速”专门讲。)
完整流程:以猜 3 个字为例
假设已生成到”苹果”,要预测后面 3 个字。
第 1 步:MTP 头迭代猜出草稿链
苹果 → MTP 头(快,迭代) → 草稿 [t1=也, t2=喜, t3=欢]
第 2 步:主模型重新算第 1 个字
主模型拿”苹果”,自己跑一遍 78 层,算出词表概率:
苹果 → 78 层 → 词表概率:
「也」 → 0.45 ← 主模型认为最可能
「真」 → 0.20
「了」 → 0.15
第 3 步:概率比较(不是非黑即白)
主模型不会说”t1 对”或”t1 错”,而是比较两个概率:
主模型对「也」的概率: 0.45
MTP 头对「也」的概率: 0.40(它草稿时算的)
如果 主模型概率 ≥ MTP 头概率 → 主模型"至少和 MTP 头一样认可" → 接受 t1=也 ✓
如果 主模型概率 < MTP 头概率 → 主模型"不如 MTP 头认可" → 拒绝,改用主模型自己的选择
为什么是”概率比较”而不是”取概率最高”
这是最反直觉的点。用两个极端例子说清楚:
极端 A:MTP 头很自信地猜「苹果」(概率 0.9)
主模型算出来「苹果」只有 0.1
→ 主模型"不认可"(0.1 < 0.9) → 拒绝,改用主模型自己的预测
极端 B:MTP 头弱弱地猜「香蕉」(概率 0.3)
主模型算出来「香蕉」0.5
→ 主模型"挺认可"(0.5 > 0.3) → 接受 t1=香蕉 ✓(哪怕不是主模型概率最高)
核心洞察:验证不是对错判断,而是”主模型愿不愿认领 MTP 头的草稿”。 主模型拿自己重算的概率,和 MTP 头的概率比一比,决定”认领”还是”拒绝、我自己来”。
严格讲:上面”≥ 就认领、< 就拒绝”是贪心解码下好懂的简化说法。标准投机解码的真实规则更精细——当主模型概率低于 MTP 头时,并不是必然拒绝,而是按
主模型概率 / MTP 头概率的比例概率性地接受(比如 0.5 对 0.7,就以约 71% 的概率接受),实在不接受才从残差分布里重新采样一个 token。这套”概率性接受 + 残差重采样”(正是后面”拒绝采样”那个改进项名字的来历)是为了保证一件事:MTP 加速后的输出分布,和主模型自己一步步采样数学上完全一致,也就是无损。我们先用好懂的”认领/拒绝”建立直觉,知道严格规则还多这么一层就行。

接受一个,就接着验证下一个;拒绝一个,后面全丢
假设 t1=“也”被接受。序列变成”苹果 也”,主模型继续算”也”之后的下一字,和 t2=“喜”比……如果接受,再验证 t3。
但只要有一个草稿被拒,它和它后面的所有草稿全部丢弃。 因为草稿链是接龙的——t3 错了,MTP 头基于”t3=欢”猜的 t4 就建立在错误基础上,不可信。所以从被拒的位置重新算。
草稿: [也✓, 喜✓, 欢✗]
结果: 确认 [也, 喜],从「欢」的位置重算,后面草稿全丢
为什么能加速:主模型验证可以并行
你可能要问:“主模型还是一个一个验证,这不还是 N 次前向吗?快在哪?”
关键:主模型验证时,可以把一串草稿一次性纳入序列,并行算它们的概率——一次前向,验证多个。
传统逐字生成:
字1 → 主模型 → 字2 → 主模型 → 字3 → 主模型 → ...
(每次主模型只算 1 个,串行)
MTP 验证:
MTP 头快速猜 [t1, t2, t3]
主模型一次性把 [t1, t2, t3] 都纳入序列,并行算它们的概率
(一次主模型前向 = 验证多个 token!)
如果 3 个都接受 → 3 个字一次确认!
所以加速来自:主模型验证一串草稿时,是一次并行的前向传播,而不是 N 次串行。 就像老师一次批改 5 份试卷,比逐份批改快得多。MTP 头那点”蒙题”成本很便宜,主模型省下来的前向次数才是大头。

这对你用 AI 意味着什么: 为什么同样是流式输出,有的模型”蹦字飞快”、有的慢吞吞?背后可能就是有没有用投机解码、接受长度有多高。MTP 让主模型一次确认多个字,直接缩短你的等待——这是”蹦字快慢”在工程上的真相。
GLM-5.2 的改进:接受长度 4.56 → 5.47
接受长度 = 平均每次能”猜对”几个 token。 这是衡量 MTP 效果的核心指标:接受长度 1 等于没用 MTP,接受长度 5.47 就是每次平均确认 5.47 个字,速度大幅提升。
GLM-5.2 官方博客公布了一组消融(编码场景,基于 GLM-5.1 骨干):
| 改进 | 接受长度 |
|---|---|
| 基线 | 4.56 |
| + IndexShare + KVShare | 5.10 |
| + 拒绝采样 | 5.29 |
| + 端到端 TV 损失 | 5.47 |
注意归因:5.47 是四项改进叠加的总效果(4.56 → 5.47,约 +20%),不是单一改进的功劳。 其中 IndexShare + KVShare 这一项把接受长度从 4.56 拉到 5.10(单项约 +12%),后面拒绝采样(让验证阶段的采样更稳)和端到端 TV 损失(缩小 MTP 头和主模型输出分布的差异)又各加一点。
IndexShare + KVShare 为什么能提升接受长度
这是 GLM-5.2 在 MTP 上的独到之处。简化讲:
问题:MTP 头猜的 token,在主模型验证时,用的 KV Cache 会混入”MTP 头自己算的 K/V”。但训练时 MTP 头没见过这种混合,导致训练和推理的环境不一致,接受长度上不去。
解法:GLM-5.2 让 MTP 头通过 IndexShare(复用主模型的 top-2048 索引)+ KVShare(复用主模型的 KV),消除这种不一致,接受长度从 4.56 提到 5.10。拆 config 能印证这个联动:
index_share_for_mtp_iteration: true # MTP 迭代时复用主模型的索引
精妙之处在于:第 5 篇讲的 DSA 的 IndexShare,本来是为注意力省算设计的,但在这里意外地也帮了 MTP 的忙——共享索引让 MTP 头和主模型”看到的世界”一致了,训练推理不一致的毛病被治好。
这是 GLM-5.2 架构的一个”协同效应”:IndexShare 不仅省了注意力计算,还顺手提升了 MTP 的接受长度。一个设计,两处收益。(最终接受长度 5.47 是叠加拒绝采样 + TV loss 后的总效果。)

MTP 不是免费的午餐
诚实地说,MTP 也有代价:
- 多了一个完整的 transformer block(layer 78 的 MTP 头),模型体积略增。
- 草稿错了要重算——MTP 头猜得烂的话,验证开销反而拖慢。
- 实现复杂——并行验证、概率比较、截断重算,工程上不简单。
但综合收益远大于代价,所以 GLM-5.2 和 DeepSeek 系列都用 MTP(DeepSeek 称 NextN prediction,据其公开资料)。
这对你用 AI 意味着什么: MTP 的”先猜后验”其实是个很通用的加速套路——用便宜的估算换掉昂贵的精算,再花一点成本验证。这思路不只在大模型里:编译器 speculate-then-check、数据库乐观锁、CPU 分支预测,都是同一招。GLM 把它用到了 token 生成上。
四道墙,全部拆完
到这里,长上下文的四道墙我们拆完了:
- 墙 1 算不动 → DSA + IndexShare(第 5 篇)
- 墙 2 放不下 → MLA(第 4 篇)
- 墙 3 推不动 → MoE(第 6 篇)
- 墙 4 蹦得慢 → MTP(本篇)
但这里有个关键问题:这四个机制,能单靠一个就搞定 1M 上下文吗?
答案是不能。单靠任何一个都不够——只有 DSA 算得动但 KV Cache 几 TB 放不下;只有 MLA 放得下但 N² 点积算不动;只有 MoE 省参数但不解决注意力瓶颈;只有 MTP 加速生成但不解决长上下文本身。
必须四管齐下。 下一篇是收官,我们把四个机制串起来,回答整个连载最核心的问题:为什么 GLM-5.2 能做到开源 1M,而这条路别的玩家走不通?
下篇预告:《四管齐下:GLM-5.2 怎么把 1M 变可能》
本篇涉及的 config 字段——num_nextn_predict_layers: 1、index_share_for_mtp_iteration: true、num_hidden_layers: 78——均来自 GLM-5.2 公开的 config.json。MTP 头为 layer 78(主体 78 层之外的第 79 层),结构为完整 transformer block + eh_proj/hnorm/enorm,据权重清单。接受长度 4.56 → 5.47 及四项消融(IndexShare+KVShare / 拒绝采样 / 端到端 TV 损失)引自 GLM-5.2 官方博客(编码场景、基于 GLM-5.1 骨干),+20% 为四项叠加总效果、非单一改进。MTP / 投机解码 / NextN prediction 为业界通用方案,DeepSeek 系列亦用,据其公开资料。概率比较验证机制(P主 ≥ P_MTP 则认领)为投机解码标准做法。无任何闭源或未公开信息。