DFlash: Block Diffusion for Flash Speculative Decoding
速读卡片 (TL;DR)
一句话:把 speculative decoding 里的 drafter 从"自回归"换成"block-diffusion + 5 层 target hidden 注入到每层 K/V cache",让 16 个 draft token 在一次 forward 里同时被预测出来,Qwen3-8B 上端到端 ~6× 加速,比 EAGLE-3 再快 ~2.5×。
立场:这是一篇范式分叉论文。EAGLE 系列把"AR drafter"打到了天花板(τ ≈ 3,加速 ≈ 2×);DFlash 主张唯一突破口是把 drafter 换成 block-diffusion——让 drafting 时间几乎与 γ 解耦,从而能放下 5 层的"深"模型,同时把 target 5 层 hidden 永久驻留在 draft K/V 里,使 acceptance 也跟着深度涨。见 EAGLE 演化简报。
1 · 动机:为什么 AR drafter 撞了天花板
1.1 历史脉络: Medusa → EAGLE-1/2/3 的路径与极限
过去两年 speculative decoding 的 drafter 路线基本可以画成一条单调向上的曲线,但方向只有一个: 把 draft 网络做得更小、跟 target 对齐得更紧、verification topology 做得更宽。这条线大体是这样:
- Vanilla SD (Leviathan 2023): 直接用一个独立小模型当 drafter,τ ≈ 2,代价是要再维护一个独立训练的 small LM。
- Medusa (Cai 2024): 干脆不要外部小模型,在 target 顶上长出 K 个独立 prediction head,用 tree attention 并行验证。但每个 head 看到的上下文都是同一时刻的 hidden,后面的 head 只能"猜",τ ~3.
- EAGLE-1 (Li 2024): 把 drafter 做成 1 层 transformer + autoregressive,以 target 最后一层 hidden 作为输入,共享 LM head。从"猜 token 分布"升级到"猜 hidden state 分布",数学上更优(future-token 信息显式编码在 hidden 里)。
- EAGLE-2: 引入 dynamic draft tree,每层只展开高置信度的分支,用 rejection sampling 把 draft tree 拉到 60 节点。
- EAGLE-3 (Li 2025b): "Training-time test"——用 target 的多层 hidden 拼成一个 fused feature,作为token embedding 的 input,把 τ 推到 ~3.5,加速比 ~2.0–2.2×。这是目前 AR drafter 公开 SOTA。
问题是,从 EAGLE-1 到 EAGLE-3,虽然每代都涨,但涨幅在收敛。原因可以一句话写完:
AR drafter 必然有 Tdraft = γ · tstep——γ 个 token 就要走 γ 次 forward。为了让 Tdraft 不爆炸,EAGLE-3 把 drafter 砍到只剩 1 层 transformer。但 1 层 transformer 的 capacity 上限就在那;γ 拉到 7 以后,τ 已经接近平台。
这就是 AR drafter 的天花板: 论文里说得很直接——"This imbalance restricts achievable speedups to approximately 2−3×."
1.2 别的方案为什么不够
"AR drafter 撞墙"这件事大家都看到了,过去一年里出现过至少四种突围尝试。但每一种都有自己的硬伤:
| 方案 | 核心想法 | 谁做过 | 硬伤 |
|---|---|---|---|
| Tree-AR | 一次提议一棵 draft 树, target 用 tree-attention 并行验证 | SpecInfer / EAGLE-2/3 | 每个枝干仍然是 AR; 树越大 verify cost 越高;在大 batch 下 tree 收益消失 |
| Block-AR | 在 target 上加 K 个独立 prediction head | Medusa | K 个 head 共享同一个上下文;后位置 head 没有"已生成 token" 信息,质量梯度衰减 |
| Continuous diffusion drafter | 把 token logits 看成连续向量做高斯噪声 + denoise | SpecDiff-1 | 需要离散→连续的代理表示;一般要多步 denoise (10+),drafting 反而慢 |
| Discrete (mask) diffusion 大模型当 drafter | 用 7B 的 LLaDA / Dream 当 drafter | DiffuSpec / SpecDiff-2 | drafter 太大 (7B), drafting latency 占满, 实测加速 3–4× 上不去 |
| Mimic-diffusion AR | 训一个小 AR 模型去"装"成一次出多 token | PARD (An 2025) | 小 AR 容量不够,τ 上限 ~3, speedup ceiling ≈ 3× |
| Block-diffusion 小 drafter + target hidden 注入 👈 | 5 层 mask-diffusion + 5 层 target hidden 进 K/V cache | DFlash | 本文主张这条是甜蜜点 |
看完这张表你就明白 DFlash 在选址上的位置:它同时避开了 (a) 大 drafter 的 latency 陷阱、(b) 小 AR 的 capacity 陷阱、(c) 多步 denoise 的延迟陷阱。具体怎么避的?——靠 5 层 target hidden 永久驻留在 draft K/V 里,把"小模型推理能力不足"的问题外包给了 target 自己。这正是论文那句口号 "the target knows best"。
1.3 为什么"把 diffusion 嫁接给 spec decoding"非平凡
把 diffusion 拿来做 drafter 听上去就两步: ① 训一个 mask-diffusion 模型; ② 一次 forward 出 γ 个 token。但落到具体细节上,有四个深坑:
- K/V cache 不变性: AR 模型在 spec decoding 里已经把 K/V cache 玩成艺术——每接受 m 个 token,就 commit m 行 K/V。Diffusion drafter 要 mask 一段、再解 mask,每一步 K/V 写哪儿、清哪儿,需要重新设计;否则 K/V state 会被 mask 污染。
- 训练时如何保证 inference-train 一致: 标准 block diffusion 是"把 response 切成等大块,每块 mask 一些位置"。但 spec decoding 的 inference 行为是: target 给你一个 verified token (bonus),你以这个 token 为锚点,解后面 γ−1 个 mask。两者的"上下文形状"不一样——这就是论文为什么改成 "random anchor token + 块内剩下都 mask" 的训练策略 (§4)。
- Verification 拓扑: AR drafter 提议一条线、tree drafter 提议一棵树。Diffusion drafter 一次出 γ 个并行预测的 token——它们之间是不条件依赖的(都从同一组 mask 上 denoise 出来),所以 token-i 是 sample 自 p(·|context, masks),不是 p(·|context, token_{1..i-1})。这导致 token-i+1 不能直接拼在 token-i 后头做 token-by-token rejection——需要重新审视 verification chain。论文(及 DFlash 的实现)走的是"把 γ 个 token 当作一条 sequence,顺序做 rejection"的路线; 一旦中间某位置 reject,后面整段全丢,所以早期位置 disproportionately 重要(这正是 §4 loss decay 设计的根因)。
- 训练数据质量与 target 对齐: 如果直接拿原始 Nemotron-V2 / CodeAlpaca 的 ground-truth response 训 diffusion drafter,drafter 会去对齐 ground truth, 但 inference 时它要对齐的是 target model 自己的输出分布。论文的 fix: 先用 target model 自己 generate response,把这个 response 当作训练目标 (§5 Datasets 段)。
没有这四个 fix 中任何一个,DFlash 都跑不出 6×。这才是论文真正的"系统贡献"——主结构是 block-diffusion,但能 work 的是上面这四个细节。
2 · 背景速查
2.1 关键术语
| 术语 | 含义 |
|---|---|
| Speculative Decoding | draft 提议 γ token, target 并行验证, rejection sampling 保证最终分布 = target 分布 |
| τ (acceptance length) | 每个 spec 周期平均产出的 token 数, ∈ [1, γ+1] (含 verifier 的 bonus token) |
| Block diffusion | 把 sequence 切 block, 块内 mask + 并行 denoise, 块间 AR. 是 Arriola 2025 的"interpolating between AR and diffusion" |
| Mask token | discrete diffusion 里的"未确定"占位符。forward process: clean→mask; reverse: mask→clean |
| Anchor token | DFlash 训练里, 块的第一个位置放一个 clean token, 后面 γ−1 位都 mask. 这个 clean token 模拟 inference 时 verifier bonus token |
| Target context feature | target model 5 层 hidden states concat → 一个轻量 projection → 紧凑的 fused feature, 注入 draft |
| KV injection | 把 fused feature 投影成 K, V, 直接挂到 draft 每层的 K/V cache 里, 持续可被 attend |
| EAGLE-3 fusion | 同样取多层 hidden, 但只 fuse 进 draft 的 token embedding 输入端 (input-side) |
| Flex Attention | PyTorch 提供的可编程 attention mask kernel(Dong 2024),DFlash 用它在训练时同时处理多个 block 的 sparse mask |
| SGLang Spec-v2 | SGLang 的 v2 调度,带 draft / verify overlap, 支持 block drafting |
2.2 Mask diffusion for text 简版回顾
不需要太多 ELBO 数学,记住这几个事实就够看懂 DFlash:
- Forward process: 给定 clean sequence x₀, 在时间 t ∈ [0,1], 每个位置以概率 t 被替换为
<m>(mask token), 否则保留 clean. 整个 process 仅在离散 token 空间发生 (没有连续高斯噪声). - Reverse process: 训一个网络 pθ(x₀ | xt), 即"看 mask 序列, 预测原始 token". 标准 loss 是只在 mask 位置算 cross-entropy.
- Sampling: 从全 mask 起步, 多步迭代 (T 步) 每步重新预测 + remask 部分位置. T 越大质量越高但越慢.
- Block diffusion = mask diffusion 局限到 block: 块内并行 denoise, 块间 AR (因果). 把全序列建模拆成"局部并行 + 全局自回归"折中.
DFlash 的关键工程小动作: T = 1 (一步出全 block, 不做多步迭代). 标准 block-diffusion 论文里多步 denoise 是为了高质量, 但 spec-decoding 场景下质量靠 verifier 的 rejection 兜底, 多步 denoise 反而拖慢 drafting. 这是 DFlash 与 dLLM-as-generator 路线最大的工程哲学差异.
2.3 EAGLE-3 行为简短复习
这一节是给已经熟悉 EAGLE-3 的人备查。EAGLE-3 的 drafter:
- 1 层 transformer (decoder block), 输入 = (target multi-layer fused hidden) ⊕ (token embedding).
- 共享 target 的 LM head & embedding (frozen).
- AR 地往后展开, 每步产生 top-k tokens, 用 dynamic tree (60 节点) 验证.
- "training-time test": 训练时让 drafter 也用前一步自己输出的 hidden 做下一步 input, 减少 train/inference mismatch.
记住这一点: EAGLE-3 用 hidden 时只把它"喂进 input"。DFlash 的最大反向就是: 不要喂 input, 要把它焊在 K/V cache 里, 让 draft 每一层都能 attend 到。
3 · Drafter 架构详解
3.1 Block-diffusion drafter 全景 (paper Figure 2 重画)
从最高层看,DFlash 一个 spec 周期长这样:
- target prefill prompt → 第一个 token (verified bonus) + 5 层 hidden states.
- 5 层 hidden 在 token 维上 concat → projection → fused target feature, 形状 ≈
[Lprompt, d]. - fused feature 在每个 draft 层都过一次 (WK, WV) 投影, 写进该层 K/V cache. (这一步只发生一次, 后续 reuse.)
- draft input = (bonus token) ⊕ (γ−1 个
<m>); attend 到自己 + K/V 里的 target context. - 1 次 forward 5 层 transformer → γ 个位置都 ready → LM head → top-1 (greedy) 或 sample.
- γ 个 token 当作一条 sequence 送给 target verify; rejection sampling 决定 acceptance 长度 m ∈ [0, γ]; target 顺手再吐 1 个 bonus token, 总产出 m+1 个.
- 下一步: bonus 当 anchor, 再 mask γ−1 个, 重复. 注意: target 的 K/V cache 也只增长 m+1, draft 的 K/V cache 只增长 m+1 (mask 位置不写 cache, 详见 §3.3).
Worked example #1: 跟踪一个具体 token
假设 prompt 是 "Diffusion is good", target 给 bonus token "for"。Block size γ=16。draft 输入序列(长度 16)按位置写出来:
pos: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 tok: "for"
位置 0 的 token "for" 经过 embedding → e ∈ ℝ⁴⁰⁹⁶。每个 mask 位置的 embedding 是 e_mask(共享一个特殊向量)。同时 draft 每一层的 K/V cache 已经预填好了 prompt + bonus 共 4 个时间步对应的来自 target 的 K, V 投影。Draft 第 ℓ 层的注意力计算粗略是:
attn = softmax( Qℓ [Kℓself | Kℓtgt] / √d ) · [Vℓself | Vℓtgt]
关键: Kℓtgt, Vℓtgt 是这一层独有的 target-feature 投影,不是所有层共享。也就是说每层都从 fused target context 里"自取所需"。这跟 EAGLE-3 把 target hidden 只拼在第 0 层 input 是天差地别。
反向论证 (为什么不能更简单)
"为什么不直接用 1 层 mask-diffusion?" — Table 8 给了答案: 5 层 + 没有 target hidden 注入,加速比只有 ~3×, τ ~4.6 (Math500)。少了 target hidden,小模型就成了 from-scratch 推理,质量崩。"为什么不维持 EAGLE-3 的 input 拼接?" — 见 §3.2 的层数消融, 加深没用。
3.2 5 层 target hidden 注入到每层 K/V (核心 fork 点)
这是论文的真正核心。如果只记一件事就记这个。
EAGLE-3 怎么用 multi-layer target hidden? — 拼在 token embedding 上,作为第 0 层的输入:
问题: 信息只在第 0 层"灌进去",经过 5 层 transformer 后,被 layer norm + residual + MLP 一次次稀释,深的层离 target 信号越来越远。EAGLE-3 自己的曲线: drafter 加层数 → τ 不涨(他们因此固定 1 层)。
DFlash 把同一组 hidden 投到每一层的 K/V:
每层 attention 都能直接 attend 到 target 信号,不被 residual 稀释。结果: 加 draft 层数 τ 一直涨 (Table 5: 3-L τ=5.64 → 5-L τ=5.99 → 8-L τ=6.33)。
Worked example #2: 5 层 hidden 是哪 5 层?
论文 §5 Implementation: "target hidden features are extracted from 5 layers uniformly selected between the second layer and the third-to-last layer of the target model." 对 Qwen3-8B (28 层 transformer):
- 第 2 层 (浅层语法 / 表层 token 信息)
- (28 − 3 − 2) / 4 = 5.75 步长 → 大约 layer 8 / 14 / 19 / 25
- 不是最后一层 (最后一层非常 task-specific, 信号过窄)
每层 hidden ∈ ℝL × 4096, 5 层 concat → ℝL × 20480, 经过 projection Wfuse ∈ ℝ20480 × 4096 → fused ∈ ℝL × 4096。再对每个 draft 层做 K/V 投影 WℓK/V-tgt ∈ ℝ4096 × 4096。Draft 一共 5 层 → 引入 5 × 2 × 4096 × 4096 ≈ 168M 额外参数; 加上 fusion 那个 Wfuse 还有 84M。这是 DFlash drafter 比 EAGLE-3 重不少的根源, 但因为 drafting cost 与 γ 解耦, 这点参数没拖慢推理。
反向论证: 为什么不能"只用 1 层 hidden 进每层 K/V"?
论文 Table 6: 3-hidden vs 5-hidden, 后者 τ=5.64 / 前者 τ=5.38, 差 ~5%. 同时 3-hidden 训练时 storage 减小线性比例 (offline 训练要 cache 全部 hidden). 5 层是经验甜蜜点, 不是定理. 但作者说"continues to outperform", 暗示更多 (7? 9?) 还能涨, 只是收益递减 + 训练 IO 成本顶不住.
3.3 Mask schedule 与"一步解 16 个"的微观过程
这是 DFlash 与"标准 block diffusion"最大的简化: 推理时denoise 步数 T = 1。看时间轴:
Worked example #3: 一个具体 mask 的 denoise
设 anchor = "for", target context 已被注入到每层 K/V (5 层 hidden 投影了 prompt + bonus 共 N 个时间步)。block size 16, 所以 input 长度 16. 看位置 1 (第一个 mask):
- embedding: em (mask token 的 embedding) + pos_emb(1)
- Layer 1 attention: Q 来自 em, K/V = (其他 15 个位置的当前 hidden) ∪ (5 层 hidden 的 layer-1 K, V slot, 长度 = N)
- Layer 1 输出 → MLP → Layer 2 (再次 attend, 这次 K/V 包含 Layer 2 的 target slot)...
- Layer 5 输出 hfinal ∈ ℝ⁴⁰⁹⁶
- LM head (target 的, frozen): logits = Wlm hfinal ∈ ℝ|V|
- greedy: argmax → 比如
"speculative"; 或 sample (但 spec decoding 中 draft 的采样温度通常等于 target 的)
注意位置 1 的输出能"看到"位置 2 (是个 mask) 的 hidden, 也能看到位置 15 的 mask hidden, 因为是双向 attention. 这与 AR drafter 的 causal mask 完全相反, 但因为后面位置都是 mask token, 信息量很低, 主要还是从 target K/V 拿信息.
"为什么不做多步 denoise?"
标准 dLLM (LLaDA, LLaDA-V, MMaDA) 推理时跑 T=10–20 步多步 denoise, 每步预测 + remask 低置信度位置, 显著提升 generation quality. DFlash 反其道行之,坚持 T=1, 论证如下:
- spec-decoding 场景质量靠 verifier 兜底,draft 不必尽善尽美
- 每多一步 denoise, drafting cost 翻倍, 削弱 spec decoding 的本来意义
- 实证 5 层 + 1 步 + target hidden 注入足够把 τ 推到 7+, 已经远超 EAGLE-3 的 3.5
这其实是论文的隐藏哲学: "diffusion 的多步 denoise 是为了独立生成时质量, 但放到 spec decoding 里, verifier 已经在做"质量保险", 所以可以激进地砍 denoise 步数."
4 · 训练程序
DFlash 的训练直接抓住了"inference 时是什么样, 训练时就照搬"原则。但相比标准 block-diffusion, 改了 5 处:
| 设计 | 标准 block diffusion | DFlash |
|---|---|---|
| K/V 注入 | 无 | 每层 K/V 接 5-层 fused target hidden |
| Block 划分 | 等宽切, 每块 mask 随机一些位置 | 从 response 随机抽 anchor 位置, 每个 anchor 起头一块, 块内剩下全 mask |
| 同时训练多块 | 单块或几个固定块 | 同一 sequence 取 ~512 anchors → 512 块, Flex Attention 一次跑完 |
| Loss | 在 mask 位置 uniform CE | 位置 k 加权 wk = exp(−(k−1)/γ_decay) |
| Embedding / LM head | 独立训 | 共享 target 的, frozen |
4.1 Random-anchor 数据增强 (Figure 4 重画)
为什么这种构造比"等宽块 + 随机 mask"更好
Inference 时, draft 总是看到 1 个 verifier 给的 clean token + 后面全 mask。等宽块 + 随机 mask 训出来的模型, 看到的格式是 "块内偶尔有 clean、偶尔有 mask, 顺序随机", 与推理分布偏离。Random-anchor 训练把"块第 0 位 = clean, 后面 = mask"这个固定 pattern 焊在数据里, 和推理对齐。Table 9: 这一改进让 Math500 τ 从 4.94 → 5.64, +14%。
4.2 Loss decay (Equation 4)
这里的 γ 是个 decay 超参 (注意它跟 block size 不是同一个 γ; 论文 Appendix A.1: block 16 用 γ_decay=7, block 10 用 5, block 8 用 4)。每个 mask 位置 k 的 loss 权重 = wk。位置 1 (第一个 mask) 权重 = 1.0; 位置 16 (最后一个 mask) 权重 = exp(−15/7) ≈ 0.117。早期位置的损失约是后期位置的 8.5×。
| k (位置) | wk (block 16, γ=7) | wk (block 10, γ=5) | wk (block 8, γ=4) |
|---|---|---|---|
| 1 | 1.000 | 1.000 | 1.000 |
| 2 | 0.867 | 0.819 | 0.779 |
| 4 | 0.651 | 0.549 | 0.472 |
| 8 | 0.368 | 0.247 | 0.174 |
| 16 | 0.117 | 0.050 | 0.024 |
物理直觉: spec decoding 一旦中间 reject, 后面 token 全废, 所以早期 token 的正确率"决定整段长度"。但训练时简单 uniform CE 会让网络平均地分配容量, 把后期低重要性的 token 也练得准。Loss decay 让网络把容量集中在"有可能被接受的早期位置", 加速收敛 (Figure 5 显示同样 epoch 数下 acceptance length 高 ~0.4 个 token)。
4.3 共享 frozen embedding & LM head
Draft 的 token embedding 和 LM head 直接复用 target 的 frozen 副本。这有两个好处:
- 表征空间对齐: draft 的输出 logits 与 target 在同一向量空间下, 减少 distribution mismatch (类似 EAGLE 系列的设计选择)。
- 参数量少: Qwen3-8B 的 embedding 矩阵就 ~600M 参数, 不训省一大块。
4.4 训练数据 & 长上下文友好
800K 样本来自 Nemotron Post-Training v2 + CodeAlpaca, 但 response 不直接用 ground-truth, 而是用target model 自己 generate 的 response。这是 self-distillation 风格, 和 EAGLE-3 一致, 但放在 diffusion 设定下重要性更突出: diffusion drafter 学的不是"语言模型分布", 而是"target 在每个位置的下一步是什么", 必须用 target 自产数据。
长上下文支持: 标准 EAGLE-3 在长上下文下做"training-time test"——drafter 自回归地展开一段, 然后在最后位置算 loss——这个递归非常昂贵 (深度 ∝ steps)。DFlash 不需要这种递归, 因为它在一次 forward 里就把所有 mask 解了, 训练时直接对每个 anchor block 算 CE 即可。论文 §4.2 说这让"long-context training 几乎免费"。
5 · 推理与验证拓扑
5.1 为什么 DFlash 不用 tree
EAGLE-2/3 的胜负手是 dynamic draft tree (60 节点)——一棵树同时提议 60 个候选 token, 用 tree-attention 一次 verify, 把 acceptance 拉到 3.5。但 tree 有自己的代价:
- verification 计算量 ∝ tree size, 60 节点是 16-block 的 ~4×
- 大 batch 下计算 saturate, tree 的边际收益消失 (Table 4 证实: EAGLE-3 (60) 在 concurrency=32 时 speedup ≤ 1×, 反而比 EAGLE-3 (10) 慢)
- tree 实现复杂, SGLang Spec-v2 不支持
DFlash 选了"一条直线"路线: 提议 16 个连续 token, target 1 次 verify, sequence-level rejection sampling。简单, 但因为 acceptance 本身高 (τ=7+), 总产出比 tree 还高。论文 §5.1 直接秒杀: "DFlash also surpasses EAGLE-3 with tree size 60, achieving higher acceptance length while incurring substantially lower verification overhead."
5.2 Sequence rejection sampling 在 diffusion drafter 下的细节
Leviathan 2023 的标准 rejection sampling 是为 AR drafter 设计的: token-i 由 pdraft(·|t1..i-1) 采样, 用 min(1, ptgt(ti|·)/pdraft(ti|·)) 接受。Diffusion drafter 的 token 不是 AR 采样的, 而是 marginal — token-i 的概率分布是 pdraft(ti|context, all_masks), 不依赖 t1..i-1。这看上去会破坏 rejection sampling 的等价性。
DFlash 怎么处理? 论文没有展开, 但从"6× lossless"可推断它仍然走标准 rejection。一个合理解释:
- 把 draft 的 16 个 token 当作一条 sequence, 顺序对每个位置做 rejection。
- 每次 rejection 用的 qdraft(ti) 是 draft 在那个位置的边缘分布 (因为 draft 一次就预测了)。
- 这其实仍然给出 "samples from ptgt"——条件是 qdraft 在每个位置都对 ptgt 有支撑 (绝对连续), 这一点 mask-diffusion 的 softmax 输出天然满足。
核心数学不变: 只要 reject 的 fallback 分布是 (ptgt − qdraft)+, 接受 / 拒绝混合后的边缘就是 ptgt。所以 DFlash 是 lossless 的, 与 EAGLE-3 同地位。
Worked example #4: 一段具体 rejection 跟踪
设 draft 输出 16 个 token: t = ["speculative", "decoding", ".", "It", "achieves", "lossless", "speedup", "by", ...]; greedy 模式 (温度 0)。target 1 次 forward 给出每个位置的 logits。greedy 验证退化为等价比较: 接受当 tidraft = argmax ptgt(·|t1..i-1) 时, 否则 reject。设比较结果是 ✓ ✓ ✓ ✓ ✗ — 接受 4 个, 第 5 位置被替换为 target argmax (比如 "without"), 第 6+ 全丢, target 顺手再吐 1 个 bonus。本周期产出 = 4 (accepted) + 1 (replacement) + 1 (bonus) = 6 个 token。
这就是为什么 τ ∈ [1, γ+1]; γ=16 的话 τ 上限 17。Qwen3-8B 实测 τ ≈ 7.87 → 平均每周期产 7.87 个 token, 即接受了 ~6.87 个 draft + 1 个 bonus, 接受比 6.87/16 ≈ 43%。听起来不高, 但因为 drafting cost 接近 0, 这个比例已经够推到 6×。
5.3 KV cache 在每次周期间的演化
Draft 的 K/V cache 每周期增长 m+1 行 (m = accepted 数)。Mask 位置不写 cache, 因为它们的预测下个周期就过期了 (会重新 mask)。这点跟 AR drafter 完全一样, 但实现要小心: 当 draft forward 完, 只 commit 前 m+1 个位置的 K/V, 后面 γ−1−m 个位置的 K/V 丢弃。SGLang 的 Spec-v2 支持这种 "partial commit"。
Target 的 K/V 也只增长 m+1 行 (verifier 验证后 commit)。两个 cache 在 prompt 阶段已经"对齐"过一次 (target 给 draft 提供 fused K/V), 之后两边各走各的。
6 · 公式与数值理解
6.1 加速比的解析模型
从 Equation 1 出发:
对 EAGLE-3 (16) on Qwen3-8B / Math500: 假设 tstepdraft ≈ 0.5 ms (1 层), γ=7 → Tdraft ≈ 3.5 ms; Tverify ≈ 5 ms; τ ≈ 3.49; Ltarget ≈ 12 ms (B200 Qwen3-8B 单 token); L_eagle = (3.5+5)/3.49 ≈ 2.43 ms; η = 12/2.43 ≈ 4.9× — 但实际只有 2.05× (per Table 1) 因为 verify 还有 tree-attention 的额外开销 + 调度损耗。
对 DFlash: tparalleldraft ≈ 5 ms (5 层一次性, Figure 3 实测); γ=16; Tverify ≈ 8 ms (target 一次过 16 位); τ ≈ 7.87; L_dflash = (5+8)/7.87 ≈ 1.65 ms; η = 12/1.65 ≈ 7.3× — 实测 6.08× 与之吻合。
| 变量 | EAGLE-3 (16) | DFlash (16) |
|---|---|---|
| γ (draft tokens) | 16 (tree) | 16 (block) |
| Tdraft | ~7×0.5 = 3.5 ms (7 个 AR step) | ~5 ms (1 forward, 5 层) |
| Tverify | ~5 ms (tree) | ~8 ms (sequence) |
| τ | ~3.49 | ~7.87 |
| L | (3.5+5)/3.49 ≈ 2.43 ms | (5+8)/7.87 ≈ 1.65 ms |
| η (vs ~12 ms) | ~4.9× (理论) / 2.05× (实测) | ~7.3× (理论) / 6.08× (实测) |
6.2 Loss decay 的灵敏度
给一个直觉表: 假设各位置接受概率 pk 单调减 (因为后位置错的可能性大), 整段被全部接受的概率是 ∏ pk。期望接受长度:
| p1 | p2 | p3 | ... (decay 0.95) | γ=16, E[m] |
|---|---|---|---|---|
| 0.95 | 0.90 | 0.85 | ... | ≈ 5.6 |
| 0.85 | 0.85 | 0.85 | 0.85 | ≈ 4.7 |
| 0.99 | 0.95 | 0.90 | ... | ≈ 7.4 |
读法: 提升 p1 0.05 (从 0.95→0.99) 比同样幅度提升 p10 价值大几个量级——所以 loss decay 把训练 budget 偏向 p1..3 是数学上正确的。
6.3 Drafting cost vs γ 的标度律 (Figure 3 重画)
7 · 实验关键结果
7.1 Qwen3-8B / Transformers backend (Table 1 精读)
| Bench | EAGLE-3 (16) | EAGLE-3 (60) | DFlash (16) | 提升 vs E3-60 |
|---|---|---|---|---|
| GSM8K (T=0) | 1.94× / τ=3.23 | 2.23× / τ=3.71 | 5.15× / τ=6.54 | ×2.31 |
| Math500 | 1.81× / 3.02 | 2.05× / 3.49 | 6.08× / 7.87 | ×2.97 |
| AIME25 | 1.79× / 3.00 | 2.05× / 3.44 | 5.62× / 7.08 | ×2.74 |
| HumanEval | 1.89× / 3.17 | 2.17× / 3.65 | 5.14× / 6.50 | ×2.37 |
| MBPP | 1.69× / 2.82 | 1.93× / 3.25 | 4.65× / 5.95 | ×2.41 |
| LiveCodeBench | 1.57× / 2.65 | 1.81× / 3.03 | 5.51× / 7.27 | ×3.04 |
| MT-Bench | 1.63× / 2.83 | 1.90× / 3.26 | 2.75× / 4.24 | ×1.45 |
| 平均 | 1.76× | 2.02× | 4.86× | ×2.41 |
读法:
- 结构化任务 (Math, Code) → DFlash 优势最大, 因为 token-level entropy 低, draft 更容易高接受率
- 开放对话 (MT-Bench) → DFlash 优势缩到 1.45×, 因为 chat 文本多样性高, draft 错的频率高
- EAGLE-3 (60) 比 EAGLE-3 (16) 提升 ~15%, 但 DFlash 比 EAGLE-3 (60) 还快 2.4×, 说明 tree 不是终极方案
7.2 Reasoning mode (Table 2 精读)
Q3-8B + thinking mode (long CoT 数据训练). Math500 / GPQA / AIME25:
- T=0: speedup 4.17–4.64× (略低于 non-thinking, 因为 reasoning trace 多样性更高)
- T=1: 仍维持 3.7–4×
关键: reasoning model 的生成长度大 (上千 token), spec decoding 加速直接乘到端到端 latency, 实际收益绝对值最大。
7.3 SGLang on B200 + FA4 (Table 3 精读)
| Model + bench | concurrency=1 | =8 | =32 | τ |
|---|---|---|---|---|
| Q3-8B / Math500 | 5.1× | 4.5× | 2.8× | 8.01 |
| Q3-8B / HumanEval | 4.2× | 3.6× | 2.4× | 6.50 |
| Q3-Coder-30B / HumanEval | 3.5× | 3.2× | 3.1× | 8.09 |
| Q3-Coder-30B / LCB | 2.6× | 2.3× | 2.3× | 6.42 |
有趣观察: concurrency 上升, speedup 下降, 但比起 EAGLE-3 在大 batch 跌到 0.6× 已经好很多。30B-A3B (MoE) 的 speedup 反而在大 batch 更稳, 因为 MoE 在小 batch 下 GPU 浪费率高, draft 节省的 verification 占比相对大。
7.4 LLaMA-3.1-8B head-to-head (Table 4 精读)
这是与 EAGLE-3 在相同训练数据 (UltraChat + ShareGPT) 下的公平对比。block size 用 10 (不是 16) 是因为 LLaMA-3.1 与 Qwen3 字典 / 模型结构不同, 经验最优。
| Bench / conc | EAGLE-3 (10) | EAGLE-3 (60) | DFlash (10) |
|---|---|---|---|
| GSM8K conc=1 | 1.6× | 1.9× | 2.4× |
| GSM8K conc=32 | 1.0× | 0.6× | 1.6× |
| HumanEval conc=1 | 2.0× | 2.0× | 2.8× |
| HumanEval conc=32 | 1.2× | 0.6× | 1.8× |
| Alpaca conc=32 | 0.9× | 0.5× | 1.4× |
注意 conc=32 下 EAGLE-3 (60) 跌到 0.5×(比 baseline 慢 2 倍!)。tree 越大, verification 越占满, 在大 batch 下 spec decoding 的"draft 成本免费"假设破产。DFlash 因为没有 tree 这个负担, 即使 conc=32 仍维持 1.4–1.8×。
8 · 消融实验
8.1 Draft 层数 (Table 5)
8.2 Target hidden 层数 (Table 6)
| Setting | Math500 speedup / τ | HumanEval | MT-Bench |
|---|---|---|---|
| 3 hidden | 4.49× / 5.38 | 3.80× / 4.47 | 2.32× / 3.07 |
| 5 hidden | 4.69× / 5.64 | 3.90× / 4.61 | 2.38× / 3.18 |
5 hidden 一致好于 3。但代价: offline training 要 cache 5 层 hidden, IO 翻 5/3 倍。论文没试 7+ 层, 估计是工程上 unlocking 收益不够 cover 训练成本。
8.3 Block-size mismatch (Table 7)
| train BS | test BS | Math500 speedup / τ |
|---|---|---|
| 16 | 16 | 4.64× / 6.33 |
| 16 | 8 | 3.87× / 5.09 |
| 8 | 16 | 3.78× / 5.02 |
| 8 | 8 | 3.97× / 5.21 |
清晰的不对称性: 训大用小 (16→8) 不太掉, 训小用大 (8→16) 掉得明显。原因: 大 block 训出来的 attention 已经学会"看远处的 mask 信号", 缩小到 8 没有 gap; 反过来训 8 的从来没 attend 过 8 个以上 mask, 推理时 16 直接 OOD。这条性质支持动态 block-size 调度: 训一次 BS=16, 推理时根据负载动态在 8/16 之间切换 (大 batch 走 8 节省 verify cost, 小 batch 走 16 拉 acceptance)。
8.4 Loss decay (Figure 5) 与 random anchor (Table 9)
| 消融项 | 关掉后 vs 开 | Math500 τ 提升 |
|---|---|---|
| Loss decay (Eq 4) | uniform vs decay (γ=7) | +0.4 (≈ epoch 收敛快 2×) |
| Random-anchor masking | standard block split vs anchor | +0.7 (从 4.94 → 5.64) |
这两条配合: random-anchor 让训练分布对齐推理 (块结构正确), loss decay 让训练目标对齐 spec decoding 的"早 token 重要"(损失权重正确)。两者各贡献 ~10% 加速, 缺一不可。
8.5 没有 target hidden (Table 8) — 严重退化
| Bench | 5L diffusion (no target hidden) | 5L DFlash (with hidden) |
|---|---|---|
| GSM8K (T=0) | 2.83× / τ=3.38 | 5.15× / τ=6.54 |
| Math500 | 3.73× / 4.61 | 6.08× / 7.87 |
| AIME25 | 3.35× / 4.07 | 5.62× / 7.08 |
剥离 target hidden 注入后, 模型退化到与 PARD / 一般 small diffusion drafter 同档 (3× 上限)。这条消融 = "DFlash 的全部魔法在 K/V 注入"的实证。
9 · 与 EAGLE-3 / Medusa / DiffuSpec / PARD 的逐项对比
| 维度 | EAGLE-3 | Medusa | DiffuSpec / SpecDiff-2 | PARD | DFlash |
|---|---|---|---|---|---|
| Drafter 类型 | 1 层 AR | K 个独立 head | 7B mask diffusion | 小 AR mimic-diffusion | 5 层 mask diffusion |
| 每周期 draft 步数 | γ (序列) | 1 (并行) | 多步 denoise (10+) | γ (序列) | 1 (并行) |
| Target hidden 用法 | 融入 input layer 0 | 无 (head 直接接 hidden) | 无 (drafter 自己强) | 无 | 注入每层 K/V |
| Verification topology | Tree (60 节点) | Tree | Sequence | Sequence | Sequence (16) |
| 典型 τ | 3.5 | ~3 | 5–6 但 latency 高 | ~3 | 7–8 |
| End-to-end speedup | 2.0× | ~2× | 3–4× | ~3× | 5–6× |
| Drafter 参数量 | ~1.5B (1 层 80% target) | ~K × small head | 7B | ~1B | ~1.5B (5 层 + 注入) |
| 大 batch 表现 | tree-60 跌到 0.5× | 退化 | drafter 占满 | OK | 仍维持 ≥ 1.4× |
| 训练 data 需要 | self-distill | self-distill | 大规模 web text | self-distill | self-distill (target generated) |
| 训练 cost | training-time test 贵 | 便宜 | 独立预训 | 便宜 | 便宜 (无 recursive expand) |
关键解读 1 — drafter 容量是不是免费的 lunch? EAGLE-3 砍到 1 层是因为 AR 加层数 ∝ 时间。DFlash 5 层在 GPU 上由于 batch=16 一次过, 实际 latency ≈ 1 层 + 4 层并行计算的 epsilon, 不算"免费"但近似免费。所以"drafter 加深"这条在 diffusion-drafter 路线下重新打开了。
关键解读 2 — 为什么 DiffuSpec 7B drafter 会输给 1.5B DFlash? 因为 7B drafter 单步 forward ≈ 几十 ms, 即使每步出 16 token, 摊到每 token 仍贵。DFlash 1.5B + target hidden 注入相当于"借了 target 的脑子但只跑 1.5B 的腿"。这是论文那句 "diffusion adapter that efficiently leverages the deep context features modeled by the large target model" 的精确表达。
10 · 局限 / 个人 take / 待验证问题
10.1 已知 / 推测的局限
- Chat 任务收益缩水: MT-Bench 只有 2.75×, 远低于数学 / 代码任务的 5–6×。Chat 输出 entropy 高, draft 难以一次出对 16 个连续 token。开放任务的 ceiling 可能就在 3× 左右。
- 采样温度 T=1 时下降: T=0 → 4.86×, T=1 → 4.03× (Q3-8B 平均). 高温下 sampling 多样性大, draft 命中率掉, 但仍优于 EAGLE-3。
- 大 concurrency 下退化: SGLang conc=32 时 speedup 缩到 ~2.5–3×。Verifier 在大 batch 已计算 saturate, draft 节省的"计算空泡"消失。
- 训练 IO 成本随 hidden 数线性: 5-hidden offline 训练每条样本 cache 5 × 4096 维 hidden, 800K 样本 × 3072 长度 ≈ 50TB hidden cache. 论文用 online 模式 (训时 fly compute) 也行但每 step 多一次 target forward, 成本约 2×。
- Block-size 训-推不对称: 训 BS=8 推 BS=16 掉 ~20% (Table 7). 想做"训一次模型部署多种 block-size"得用大 BS 训, 增加训练 GPU 内存 (Flex Attention 单 sequence ~512 anchors × BS=16 = 8K tokens, 加 prompt 后总 sequence 上万)。
- 对 verifier 改动敏感: 5-hidden 是从 target 特定层抽的, target 微调 / 量化后这些层的语义可能漂移, draft 可能要重训。论文没做 verifier 量化下的 robustness 实验。
- 不支持非 transformer target: 抽 hidden 这件事强依赖 transformer 的层结构, 对 Mamba / RWKV-style verifier 不直接可用。
10.2 个人 take
这篇论文的真正贡献不在"用 diffusion 做 drafter"——这条路 PARD / DiffuSpec / SpecDiff-2 都试过——而是在把 5 层 target hidden 焊到每层 K/V cache这个具体工程决策。它一次性解决了:
- "加 draft 层数 τ 不涨"(EAGLE-3 痛点, 通过每层 inject 解决)
- "小 drafter 智商不够"(通过把 target 知识打在 K/V 里解决)
- "diffusion 多步太慢"(因为质量靠 target hidden 兜底, T=1 即可)
- "tree verification 大 batch 不 work"(取消 tree, 用 sequence)
之后想继续加速, 突破口可能在: (a) 让 K/V 注入也针对 query 自适应 (e.g. attention over hidden layers); (b) 做 dynamic block-size 调度; (c) 在 reasoning model 上挖更多 routing 信息 (因为 long CoT 局部高度可预测)。我个人觉得 DFlash 的设计已经把"AR drafter 范式 → 单层 + tree"和"大 dLLM drafter 范式 → 7B 多步"的中间地带占满了, 后续真正的下一步可能是非 spec decoding 的, 比如 lookahead-decoding 风格 / latent-space decoding。
10.3 待验证问题
- 5 层选择是 fixed uniform; 如果用 attention 学一个 layer-routing weights, 是否更好?
- Block size 16 是 Qwen3-8B 上的甜蜜点。30B 模型 / MoE 是不是仍然 16 最优? 论文 Coder-30B 用 8 层 + BS 16, 可能 BS 还能更大。
- Sequence rejection sampling 在 diffusion drafter 下的 lossless 性, 论文断言"lossless"但没正式证明。理论上需要 qdraft(ti) ≪ ptgt(ti) (绝对连续), mask diffusion softmax 输出能保证, 但温度 T → 0 时的 argmax 行为可能违反, 严格证明缺。
- 训练时若改用 random 长度 block (而不是固定 16), 会不会让模型同时支持多 block-size 而不掉点?
- 能否把 K/V 注入与 LoRA 复用——同一个 LoRA-adapter target model 上, 是否需要重训 drafter?
- Reasoning model thinking-mode 下 τ=5–6, 比 Math500 (τ=7+) 低, 为什么? 是 long CoT 的中段 reasoning step 内在熵更高, 还是数据 coverage 问题?
- 对超大模型 (Qwen3-Coder-30B-A3B = 30B MoE active 3B), DFlash 用 8 层 drafter, drafter 参数量已经 ~3B 接近 active expert 大小, 还能不能再扁平化到 5 层?
- 比较 baseline 缺: TiDAR / Samragh-LoRA 这两个最相关方案没开源, 论文没对比。如果这俩开源后, DFlash 优势 margin 会缩小到哪里?
11 · 速记盒 (memory points)
arXiv:2602.06036 · DFlash · UC San Diego · 精读笔记 · 2026-05-07