LLaDA 8B Instruct 在 GSM8K 上的分数,是每次前向只落下 1 个 token 测出来的:答案长 512,就走 512 步(LLaDA 附录 B.6)。第三方在生成长度 128、块大小 32 的设置下,把同一个模型改成每步固定落 4 个 token,GSM8K 从 73.6 掉到 61.7(Kim 等,2025-10)。扩散模型能快多少,看两个数:平均每步能放心落下几个 token(记作 $\tau$),以及每一步要重算多少个位置(记作 $G$)。并发低时,decode 被显存带宽卡住、算力闲着,速度最多提高约 $\tau$ 倍;并发高到算力用满以后,每个 token 要多付约 $G/\tau$ 倍的计算,优势会消失,甚至反过来。

待审核草稿。 这一篇还没有经过站主审阅,事实、取舍和措辞都可能修改;引用前请回到文中链接的一手资料核对。

本篇接着掩码扩散的训练目标,算账用 roofline 一篇的记号和 H100 数字。

一步在做什么:预测所有空位,只留下有把握的

LLaDA §2.4 的采样从全空的回答开始,生成长度和步数都是超参数。从时刻 $t$ 走到 $s$ 的一步:把提示词(prompt)和部分被遮的回答一起送进模型,一次前向预测所有空位,再把其中约 $s/t$ 的预测重新遮住。默认的“低置信度重遮”(low-confidence remasking)留下最有把握的预测,遮回其余的;EOS 之后的内容最后丢掉。

拿 the tea is cold 走一遍:生成长度 4,分 2 步,每步留 2 个。置信度是教学数字。

步 输入 每个空位最可能的词和置信度 留下 输出
1 [M] [M] [M] [M] the 0.9,tea 0.3,is 0.6,cold 0.4 the、is the [M] is [M]
2 the [M] is [M] tea 0.7,cold 0.8 全部 the tea is cold

第 1 步 tea 只有 0.3,被遮回去;第 2 步有了 the 和 is 作上下文,升到 0.7。这里的“重遮”只针对本步的新预测:已经留下的 the 和 is 以后不会再改。写成伪代码:

def sample(model, prompt, gen_len, steps):
    x = prompt + [MASK] * gen_len
    for k in range(steps):
        probs = model(x)                          # 一次完整的双向前向
        masked = [i for i in range(len(x)) if x[i] == MASK]
        n_keep = len(masked) // (steps - k)       # 剩下的空位平摊到剩下的步数
        conf = {i: probs[i].max() for i in masked}
        for i in sorted(masked, key=conf.get, reverse=True)[:n_keep]:
            x[i] = probs[i].argmax()              # 落下,之后不再改
    return x

能改已经落下的 token 吗? 掩码扩散默认不能,这是它和下面几种方法的区别。Mask-Predict(Ghazvininejad 等,2019-04,EMNLP 2019)在机器翻译里会反复遮住所有位置中最没把握的词,重新预测。ReMDM(Wang 等,2025-03,NeurIPS 2025)给预训练(pre-training)好的掩码扩散模型加上重遮已解码 token 的采样器,步数越多质量越接近自回归(AR)。LLaDA2.1(2026-02)在“把空位填成词”之外加了“把词改成另一个词”的编辑。DiffusionGemma 的模型卡写,每步没被选中的 token 会被完全重新加噪;开发者指南也说,置信度下降的 token 可以重新加噪、换掉。

一步落几个:并行解码为什么会写出 high house

一步里同时落下的几个 token,是各自按自己的边缘分布选出来的,没有看到彼此。Fast-dLLM(Wu 等,2025-05)用扑克牌型举例。设答案一半是 full house、一半是 high card(教学分布)。第 1 位的边缘分布是 full 0.5、high 0.5,第 2 位是 house 0.5、card 0.5。一步同时采两个位置,拼出合法牌型的概率只有 $0.5\times0.5+0.5\times0.5=0.5$,另一半是 full card 或 high house;分两步,先落一个,第二个就确定了,合法率回到 1。上一篇的 hot tea 也一样:一步落两个,生成它的概率是 $0.2\times0.1=0.02$,一个一个填是 0.105。

Fast-dLLM 的办法是按置信度决定落几个:置信度超过阈值(默认 0.9)的位置都落下,一个都没有就只落最高的那个。它的定理 1 说:若 $n$ 个位置的边缘置信度都高于 $1-\epsilon$,且 $(n+1)\epsilon\le1$,那么各自取最大值,和对联合分布取最大值,选出的是同一个序列。3 个位置都在 0.95 以上时,$(3+1)\times0.05=0.2\le1$,可以一起落;扑克的例子里 $\epsilon=0.5$、$n=2$,$3\times0.5=1.5>1$,没有保证,而且阈值规则也只会先落一个。于是 $\tau$ 会随内容变化:容易确定的片段可以一步落很多,难的地方一次一个;DiffusionGemma 的模型卡也写,简单的提示和代码这类结构化任务需要的去噪步数更少。

固定 $\tau$ 的代价有第三方测量。Kim 等(2025-10)用 LLaDA-8B-Instruct,生成长度 128、块大小 32,并开着 Fast-dLLM 的近似缓存:

每步固定落下 1 2 4 8 32
步数 128 64 32 16 4
GSM8K(4-shot) 73.6 70.6 61.7 29.7 6.1
HumanEval(pass@1) 35.4 32.3 17.7 9.1 3.7

73.6 是这套设置下每步落 1 个的基线(baseline),和 LLaDA 自报的 69.4(生成长度 512、不分块)不是同一套设置,两者不能直接比;表里能比的是同一行从左到右的下降。

按置信度自适应要好得多,但数字来自方法作者自己:Fast-dLLM 报告 LLaDA 在 GSM8K(5-shot,生成长度 256,A100 80GB)上从 79.3 到 78.5,吞吐从 6.7 升到 54.4 tokens/s,即 8.1 倍,这是缓存和并行解码合起来的效果。Google 的模型卡自报 DiffusionGemma 每次前向生成 15–20 个 token,最多 48 个去噪步。

Feng 等(2025-02)的定理 4.2–4.4讨论的范围更具体:目标分布和误差指标不同,所需步数会怎样变。对于 n-gram 语言,定理 4.2 在固定 n-gram 阶数和精度、满足学习误差与长度条件时,给出了不随序列长度增长的步数界。定理 4.4 则构造了一个词表(vocabulary)大小为 16 的隐马尔可夫模型(HMM)作为最坏情况:对论文研究的逐位置因子化掩码反向过程,在假设 4.1、逐 token 反向分布的 KL 误差 $\epsilon_{\rm learning}<1/128$ 下,要把序列错误率降下来,至少需要随长度线性增长的步数。这里的“序列错误”指生成了 HMM 支持集之外的序列,不是对任意推理任务测出的错误率。

它提醒我们:困惑度(perplexity)不错,不代表多个位置一起选就可靠。但这不是说所有推理任务、所有采样器都不可能加速。 真正选模型时,仍要在相同任务准确率下比较延迟,不能只凭一个最坏情况定理,也不能只凭 tokens/s。

KV cache:双向注意力为什么缓存不了

AR 里,位置 $i$ 的 K、V 只依赖 $x_{\le i}$,这些 token 不会再变,缓存是精确的(见 KV cache 篇和缓存必须等价)。双向注意力下,从第 2 层起,每个位置的隐藏状态(hidden state)都读了所有位置,包括每步都在变的空位,连提示词的 K、V 也跟着变。LLaDA §2.2 直接写明它和 KV cache 不兼容,每一步都要把提示词和整段回答重算一遍。

有两种补法:

  • 近似缓存。 Fast-dLLM 观察到同一块内相邻两步的 KV 非常相似,于是在一个块内复用前缀(PrefixCache)甚至后缀(DualCache)的 KV,每写完一个块再整体刷新。它是近似,作者报告准确率保持在基线 1–2 分之内。
  • 改结构:分块扩散。 Block Diffusion(BD3-LM)让块与块之间从左到右,块内做扩散;前面的块不看后面的块,所以已完成块的 KV 能精确缓存。块大小为 1 就退回 AR。OpenWebText 上,块越小困惑度越接近 AR:AR 17.54,块大小 4、8、16 分别是 ≤20.73、≤21.68、≤22.27,整段的 MDLM ≤22.98。LLaDA2.0 评测时块大小是 32;DiffusionGemma 每次去噪一块 256 个 token,块写完后用一次因果注意力的前向把它写进 KV cache(开发者指南)。SGLang 在 2025-12-19 的博客里说,它把分块扩散接在已有的 chunked prefill 路径上。

分块还顺带提高质量:Kim 等测到,不分块时 GSM8K 63.2,块大小 32 时 73.6,16 时 75.7(生成长度 128)。代价是块间又变回串行,块越小越像 AR。

手算一次账(教学模型):同一张卡上各花多少时间

这一节是教学模型,不是实测。 它只用 roofline 一篇的三个数:7B 模型的 BF16 权重约 $1.4\times10^{10}$ 字节,H100 SXM5 带宽 3.352 TB/s,BF16 dense 峰值 989.4 TFLOPS。读一遍权重至少 $1.4\times10^{10}/3.352\times10^{12}=4.18$ ms;每处理一个位置的计算约 $2N=1.4\times10^{10}$ FLOPs,按峰值是 0.01415 ms。忽略 attention 的计算、KV 的读取和各种开销,一次前向处理 $n$ 个位置的时间下限是

$$ T_{\text{step}}(n)=\max\big(4.18\ \text{ms},\;n\times0.01415\ \text{ms}\big) $$

$n$ 小于约 295 时,读权重说了算,多算几个位置几乎不花时间;超过 295,计算说了算。下面是单条请求、提示词 512、生成 256 的教学估算:

方案 每步处理的位置 每步下限 步数 总时间 相对 AR
AR + KV cache 1(另有一次 512 的 prefill,7.24 ms) 4.18 ms 256 1,076 ms 1×
整段扩散,无缓存,每步落 1 个 768 10.87 ms 256 2,782 ms 0.39×
同上,每步落 4 个 768 10.87 ms 64 696 ms 1.55×
分块 $G=32$ + 前缀缓存,每步落 1 个 32 4.18 ms 256 1,076 ms 1.0×
同上,每步落 4 个 32 4.18 ms 64 275 ms 3.9×

无缓存时每步都要重算 768 个位置,越过了 295,一步的时间就是 AR 的 2.6 倍;每步只落 1 个 token 时,总时间也是 AR 的 2.6 倍。分块加缓存后,每步只算 32 个位置,仍在读权重的阴影里,所以每步落 4 个,就差不多快 4 倍。若每完成一块再做一次写缓存的前向(DiffusionGemma 就是这样做的),8 块多出 $8\times4.18=33$ ms,总时间 308 ms,约 3.5 倍。

再看多条请求并发(仍是教学模型,只算 decode 阶段,分块扩散 $G=32$、$\tau=4$):

并发请求数 AR 每步位置 AR 吞吐上限 扩散每步位置 扩散吞吐上限
1 1 239 tok/s 32 958 tok/s
8 8 1,915 tok/s 256 7,662 tok/s
64 64 15,323 tok/s 2,048 8,834 tok/s
295 295 70,631 tok/s 9,440 8,834 tok/s

扩散在约 9 条并发时就把算力用满($9\times32=288$ 个位置),此后封顶在 8,834 tok/s,正好是 AR 封顶值 70,671 的 1/8:每落下 1 个 token,要算 $G/\tau=8$ 个位置。约 37 条并发时 AR 追平,之后 AR 更快。两张表都能用下面几行复算:

W = 1.4e10 / 3.352e12 * 1e3      # 读一遍权重:4.18 ms
C = 1.4e10 / 989.4e12 * 1e3      # 每个位置的计算:0.01415 ms
step = lambda n: max(W, n * C)   # 一次前向处理 n 个位置的下限
prefill = step(512)              # 7.24 ms
print(prefill + 256 * step(1), 256 * step(768), 64 * step(768))           # 1076 2782 696
print(prefill + 64 * step(32), prefill + 72 * step(32))                   # 275 308(后者含 8 次写缓存)
for b in (1, 8, 64, 295):
    print(b, round(b / step(b) * 1e3), round(4 * b / step(32 * b) * 1e3))  # 并发 b 时 AR、扩散的 tok/s

两种情形合起来:

$$ \frac{T_{\mathrm{AR}}}{T_{\mathrm{diff}}}\Big|_{\text{low batch}}\approx\tau,\qquad \frac{\Theta_{\mathrm{diff}}}{\Theta_{\mathrm{AR}}}\Big|_{\text{compute-bound}}\approx\frac{\tau}{G} $$

$\Theta$ 是吞吐。这个账忽略了 attention 和 KV。roofline 一篇的第二张表把 KV 算进来后,上下文 4096、batch 64 的 AR 上限只剩 4,440 tok/s,所以真实的交叉点要另外量。定性地看,扩散读 KV 的开销同样按 $\tau$ 摊薄(每步读一次、落下 $\tau$ 个),但 attention 的计算也要多付 $G/\tau$ 倍。

实测方向和这个账一致。 Kim 等(A100 80GB,提示词和生成都是 128,块大小 32)测到 LLaMA-3-8B-Instruct 的吞吐能随 batch 增长到 16,LLaDA 在 8 左右就不涨了;提示词 2k、batch 1、不分块时,即使生成很短,LLaDA 的延迟也更高。Fast-dLLM 附录(A100,prefill 256,batch 1–32)发现小 batch 时带前缀缓存的 LLaDA 吞吐不低于 LLaMA,batch 变大后跟不上,因为 LLaMA 从带宽受限走向算力受限。Google 对 DiffusionGemma 的发布文章(2026-06-10)也写:优势在单卡、中低 batch 时最明显,高 QPS 的云端服务里收益递减,还可能抬高服务成本;Apple Silicon 这类统一内存设备未必有同样的加速。

厂商数字怎么读

下面都是公司或方法作者自报,条件各不相同,不能互相比较:

日期 系统 自报的数字 没说清的
2025-05-20 Gemini Diffusion 各评测平均采样速度 1479 tokens/s,不计 0.84 s 的固定开销 模型大小、硬件、batch
2025-06 Mercury Coder Mini / Small H100 上 1109 / 737 tokens/s,报告说来自 Artificial Analysis 对 Inception API 的独立测评 模型大小、batch;推理引擎(inference engine)只说是自研
2025-12 LLaDA2.0-flash-CAP 535 TPS,两个 AR 基线 256 和 237 TPS,“最多 2.1 倍” 硬件和 batch;扩散跑 dInfer、基线跑 SGLang
2026-02-24 Mercury 2 Blackwell GPU 上 1009 tokens/s,“快 5 倍以上” 基线、负载、谁测的
2026-06-10 DiffusionGemma 26B A4B 发布文章:最多快 4 倍,单张 H100 上 1000+ tokens/s;模型卡:低 batch、H100、FP8 时 1100+ 4 倍的基线和 batch
2026-09-08 Mercury 2.5 1107 tokens/s,“广泛可得的 NVIDIA GPU” GPU 型号、基准分数、参数量

几个具体的坑。Mercury 报告里,对照模型的速度是 Artificial Analysis 在各家云服务商上测得的中位数,硬件、引擎和模型大小都不同;负载是约 1000 token 输入、1000 token 输出的编程提示。LLaDA2.0 论文没说 256 和 237 分别对应 Ling-flash-2.0 和 Qwen3-30B-A3B 中的哪一个,而且两边引擎不同;SGLang 的博客把两边都放在 SGLang 上(H20、TP8、小 batch),同一个 CAP 模型是 500 TPS 对 258 和 237,约 1.9 倍。LLaDA 作者自己在附录 B.7 报告,A100、batch 1、输出 256 时,基座模型在 GSM8K 和 MATH 上达到相当准确率时,吞吐是带 KV cache 的 LLaMA3 8B 的 1.5 倍和 1.8 倍。质量也要一起看:Gemini Diffusion 自己的表里,GPQA Diamond 40.4% 对 Gemini 2.0 Flash-Lite 的 56.5%,HumanEval 89.6% 对 90.2%。

读到“N 倍快”时先问四件事:多少并发;基线是不是同一张卡、同一个引擎;这个速度下质量是多少、用的什么阈值;时间里算没算 prefill、每块的提交前向和固定开销。

和 DFlash 的关系:扩散只管写草稿

DFlash(2026-02,ICML 2026)走的是另一条路:用一个小的分块扩散模型,读目标模型的特征,一次前向写出一块草稿;最终由 AR 的目标模型验证,只留下连续接受的前缀。目标模型的输出分布不变,质量风险就不在扩散一侧。作者自报在多种模型和任务上无损加速 6 倍以上,比 EAGLE-3 的加速高最多 2.5 倍。它的账和上面同构:草稿和验证都要算一整块,接受得越多越划算。

路线 谁决定最终 token 质量风险 速度从哪里来 高并发时
原生扩散 LM(LLaDA、DiffusionGemma) 扩散模型自己 并行落下的 token 不一致;同族对比质量更低 每步落 $\tau$ 个 每个 token 多付约 $G/\tau$ 倍计算
扩散草稿 + AR 验证(DFlash) AR 目标模型 不改变目标模型的分布 每轮接受多个草稿 token 草稿和验证都占算力,收益同样缩小
纯自回归 AR 模型 无额外风险 无并行 吞吐随 batch 涨到算力饱和

动手时怎么检查

先试什么 应该观察什么 不能据此推出什么
固定一个质量目标,扫阈值或步数,画“质量–平均 $\tau$”曲线 $\tau$ 增大到哪里质量开始掉 某一个点上的速度代表这个模型
同一张卡、同一个引擎,并发从 1 扫到 64 AR 和扩散吞吐曲线的交点 batch 1 的加速代表整台服务器的收益
打开近似缓存前后,逐题对比准确率 差距是否在 1–2 分以内 KV 相似度接近 1,就说明结果等价
计时包括 prefill、每块的提交前向和固定开销 端到端延迟和首 token 时间 只看“采样速度”就能估出用户等多久
记录每一步落下几个 token 的分布 难题和简单片段的 $\tau$ 差多少 平均 $\tau$ 能代表每一道题

下一篇:复习题。

本页术语 7
提示词 prompt
提供给模型的任务说明、上下文和示例
预训练 pre-training
先用大量数据学习通用表示和能力,再适配具体任务
基线 baseline
用来比较新方法的参考方法或配置
词表 vocabulary
模型能输出的所有 token 的集合
困惑度 perplexity
exp(交叉熵),语言模型的常用指标
隐藏状态 hidden state
递归模型在时间步之间传递的压缩表示
推理引擎 inference engine
负责高吞吐生成或模型服务的执行系统