EAGLE 演化史 (1 → 2 → 3) 与 DFlash 的回答

Yuhui Li 等 · 2024.01–2026.02 · arXiv:2401.15077 / 2406.16858 / 2503.01840 / 2602.06036
关键词: speculative decoding · feature autoregression · dynamic draft tree · training-time test · block diffusion drafter

速读卡片 (TL;DR)

EAGLE-1: 把 draft 从 token 级搬到 second-to-top-layer feature 级,再用 shifted token 解 sampling 不确定性 → 70B 上 ~3× speedup。 EAGLE-2: 发现 draft confidence 是 acceptance rate 的良好近似,把静态 binary 树换成 context-aware dynamic draft tree → +20–40% over v1。 EAGLE-3: 拆掉 feature regression loss + 多层特征融合 + training-time test 模拟自身误差 → 在 ShareGPT/UltraChat 上首次出现 draft data scaling law,~6.5× speedup。 DFlash: 直接换掉 draft 范式——用 block diffusion 一次并行画出 γ 个 token,再把 target hidden 注入到 draft 的 KV cache;Qwen3-8B 上 ~6× ,比 EAGLE-3 再快 2.5×。

3.0×
EAGLE-1 / LLaMA2-Chat 70B
5.5×
EAGLE-3 / Vicuna 13B 平均
~2.5×
DFlash 相对 EAGLE-3 再加速

立场:EAGLE 三代是同一架构在四个维度上的逐步松绑(feature 级 → 动态树 → 多层融合 + 端到端 token 目标);DFlash 把 draft 的"自回归"维度本身砍掉,代表 draft 范式的下一步分叉。


1 · EAGLE-1 (2401.15077): 把 draft 抬到 feature 层

1.1 动机:before EAGLE,draft 模型卡在哪

2023 年的 speculative decoding 已经被 Leviathan 和 Chen 证明是 lossless 的,但工程上很尴尬:

EAGLE 的两个核心 observation:

  1. Feature 级序列比 token 级序列更"规则"。Feature 是连续高维向量,从 f₁ 推 f₂ 的轨迹比从 t₁ 推 t₂ 的离散跳变更平滑,小模型更容易拟合。
  2. 但 feature autoregression 自带 sampling 不确定性。同一个 fI 后面,sample 出 "am" 和 "always" 会得到完全不同的下一个 feature——这是分布而不是函数

第二点是 EAGLE 论文里最锋利的洞察。它的解法很便宜:把"领先一个时间步的 token 序列"(即已经采样的 tokens)和 feature 序列一起喂给 draft model,把"未观测到的随机性"显式注入,从而把"由 fI 预测下一个 feature"这件事从 ill-posed 变成 well-posed。

1.2 核心方法

EAGLE 的 drafting:feature + shifted token Target LLM (frozen) "How can" f_how f_can + sampled tokens t_can t_I (token shifted by +1) Draft Model concat → 2k-dim FC: 2k → k 1× decoder layer → next feature f̂_I (reuse target's LM head) → sample t_do Static binary tree do it that depth m, >m tokens 由 m 次 forward 生成 tree attention 验证
EAGLE 的 draft 子图: target LLM 跑过一遍后留下 f₁ … fj;draft model 拿到 (f, tshifted) 一起 concat,过一个 1-layer decoder,再走 target 的 LM head,得到下一个 token 分布。注意 LM head 和 embedding 共享 target 权重,真正训练的只有那个 FC + 1 个 decoder layer(<1B params)。

Worked example: "How can" → 一次 draft 步

张量 / 量形状含义
f_how, f_can4096 × 2target LLM 第 L−1 层 hidden(LLaMA2-7B)
e_can, e_I4096 × 2embedding,token 已经领先 1 步
concat 后(1, 2, 8192)(bs, seq_len, 2·hidden)
FC → decoder layer(1, 2, 4096)~0.3B param,output 即 f̂_I
LM head(共享)(1, 2, |V|)取 top-k = 4 → 4 个候选 t_I⁽¹⁾ … t_I⁽⁴⁾
Tree depthm=55 次 draft forward → 26-token 静态树

1.3 关键结果

训练只用 ShareGPT(≤70k 对话),4×A100 1–2 天就可以训完 70B 的那一份 draft 头。MT-bench T=0:

1.4 局限(为后两代埋的坑)


2 · EAGLE-2 (2406.16858): tree 结构本身要 context-aware

2.1 动机:静态树的两个 cherry-picked 假设

Sequoia / Medusa / EAGLE-1 都显式或隐式假设:draft token 的 acceptance rate 只依赖它在树里的位置。所以"上左多放、下右少放"就是最优 layout。

EAGLE-2 做了一个简单实验:在 Alpaca 上对 Vicuna 7B 跑 EAGLE-1,把每个位置 P1–P6 的 acceptance rate 按 query 画散点。结果是:

这就让"动态调整 tree 结构"成为必要。但有个鸡生蛋问题:要知道某个 draft token 的 acceptance,得让 target LLM 跑一遍,而 spec decoding 的目标恰恰是少跑 target。

EAGLE-2 的关键发现:EAGLE 的 draft model 是 well-calibrated 的。draft model 输出的 confidence(softmax 概率)与真实 acceptance rate 几乎落在 y=x 的对角线上(confidence 0.05 → accept 0.04;confidence 0.95 → accept 0.98)。所以可以用 confidence 当 acceptance 的代理。

2.2 核心方法:全局 value 排序 + expand/rerank 两阶段

定义节点 ti全局 value:

Vi = ∏tj ∈ Path(root, ti) pj ≈ ∏tj ∈ Path cj

这是从根到 ti 路径上所有 confidence 的乘积,直觉是"只有 ti 的所有祖先全部被 verify 接受,ti 才有机会被检查"。所以局部 confidence 高但深度处于劣势分支的 token,V 自然会变小。

EAGLE-1 静态树 EAGLE-2 动态扩展 (Expand top-2) It is has a the to a 每个非叶节点都强制扩 2 个孩子, 无论它本身被接受的概率有多低。 浪费在低 V 的分支上 It V=1.0 is .6 has .2 a .48 good .34 the to 只展开 V 最大的两个 ("is" 和 "is→a"),"has" 不再深挖。 最后再 rerank 全树取 top-m flatten
EAGLE-2 的两阶段流程: Expand——在当前最深一层选 top-k 个 V 最大的节点喂给 draft 模型,生成下一层;Rerank——在所有节点(含未扩展的浅节点)里按 V 选 top-m,flatten + 改 attention mask 一次性丢给 target。注意 reranking 选出的 m 个节点天然是连通子树(因为 V 单调递减且同 V 选浅节点)。

Worked example: "10+2=" vs "10+2"

Query下一 token 顶 confidenceEAGLE-1 行为EAGLE-2 行为
"10+2=""1" → 0.99仍然加 2 个候选,第 2 个浪费只扩 1 个候选 "1"
"10+2""=" → 0.55, " " → 0.30同样加 2 个加 2 个,且都深挖

2.3 关键结果

2.4 与 v1 的差异

关键在于 EAGLE-2 不动 draft model 训练、不动 verification,只重写"怎么从 draft model 多次 forward 的输出里挑出最值得 verify 的 token 集合"。所以一份 EAGLE-1 的 draft checkpoint 直接套上 v2 的 search 逻辑就能拿到收益——这也是 v2 论文反复强调"out-of-the-box"的原因。

实操要点:静态树的 layout 隐藏了一个常被忽略的成本——verification 的 attention 长度。EAGLE-1 26-token 树意味着每个 verify forward 都要算 ~26-len 的 tree-attn;EAGLE-2 通过 rerank 选 top-m 后,m 通常更小(8–16),但 acceptance length 反而高,verify forward 更便宜。

§ Tree Verification 详解 — 从 chain 到 tree,再到动态树

这是一节穿插在 EAGLE-2 与 EAGLE-3 之间的"机制深读"。EAGLE-2 把 dynamic tree 推向主流之后,tree verification 已经成为整个 spec decoding 生态(SpecInfer / Medusa / EAGLE / Sequoia / DDTree / Mirror-SD)的共享原语。本节抽出来单独讲清三件事:它是什么、它为什么有用、它怎么设计。后面 EAGLE-3 / DFlash 都会反复引用本节。

A · 什么是 tree verification(对比 chain)

朴素的 speculative decoding 是单链(chain):draft model 串行生成 t̂₁ → t̂₂ → … → t̂_d,然后 target 一次 forward 把这条链 verify 一遍。问题是 acceptance 在深度上是乘性的——令 α 表示 per-token acceptance,d 步链全部通过的概率是 α^d。α=0.7、d=4 已经只剩 0.24,d=8 是 0.058。哪怕你 draft model 训得再好,链越长,"白干"概率指数级上升。

Tree 的思路:既然单条链的"赌注"很容易输,那就同时下多条注,而且让它们共享前缀。在 tree 里,每个 draft 步可以扩出 2、3 或 k 个候选;深度 d 的二叉树有 2^(d+1) − 1 个节点(d=4 是 31),它们的 KV 在共享前缀上是同一份。target 仍然只跑一次 forward,通过精心设计的 attention mask 一次性把整棵树都 verify 出每个节点的"假设我接受了我所有祖先,我自己被接受的概率是多少"。

Chain (左) vs Binary Tree (右) — 同样 4 步深度 Chain: 4 个候选 token root t₁ t₂ t₃ t₄ P(全接受) = α⁴ α=0.7 → 0.24 期望接受长度 ≈ α/(1−α) = 2.33 cap 为 d=4 Binary tree: 1+2+4+8+16=31 候选 r P(≥1 路径全过) = 1−(1−α^d)^w α=0.7, w=16 → 0.999 期望接受长度更高,且 verify 成本 仍是 1 次 target forward
同样深度 4 的两种结构。链上输了一步整条作废;tree 里只要有一条路径全程通过,就拿到 d 个 token——而且即使没全过,也能拿到"最长前缀"。这就是 tree verification 的杠杆。

注意一个常见误解:tree 并不要求 target 跑 31 次。target 永远是一次 forward,只是 input 长度从 4 变成 31。GPU 的瓶颈是 memory-bound decode,从 4 → 31 token 的 self-attention 在 H100 上几乎不增加 wall-clock(因为 KV 已经 cached,只需要算 query × 31 个 key 的点积),代价主要是 31 次 LM head 的 softmax。这正是 spec decoding 把"算力换 latency"的核心交易。

B · Tree attention mask 的具体形态

实现层面,tree verification 把整棵树flatten 成一个序列送入 target,然后用一个特制的 attention mask 强制每个节点只看到自己在树里的祖先(不能看兄弟、不能看堂表亲)。这样每个节点的 hidden state 都等价于"假设这条路径就是真实续写,我应该长成什么样"。

看一个具体的小树。flatten 顺序按 BFS,序列长度 7:

7 节点 tree → 7×7 attention mask(causal-on-ancestors) Tree(节点编号 = flatten 索引) 0 1 2 3 4 5 6 flatten: [0, 1, 2, 3, 4, 5, 6] parent: [-, 0, 0, 1, 1, 2, 2] ancestors(5) = {0, 2} attention(5) → 0, 2, 5(自己) 7×7 mask (v=可看, ·=屏蔽) k= 0 1 2 3 4 5 6 q=0 v · · · · · · q=1 v v · · · · · q=2 v · v · · · · q=3 v v · v · · · q=4 v v · · v · · q=5 v · v · · v · q=6 v · v · · · v 每行非零项数 = 该节点深度 + 1 非 strictly lower-triangular(节点 2 不能看节点 1) 这就是和 causal mask 唯一的区别
对比 causal mask 是 strictly lower-triangular(q=2 能看 k=0,1);tree mask 里 q=2 看不到 k=1,因为节点 1 不是节点 2 的祖先。每行的"v"个数等于该节点在树里的深度+1。整张 mask 是 sparse 的,实现上常用 flash-attn 的 variable-length 接口或自定义 block-sparse kernel。前缀 prompt 那部分仍然是 full causal,只在 tree 这 7 个 token 上启用 ancestor-only mask。

正确性论证:每个 tree 节点 ti 经过 self-attention 之后得到的 hidden state hi,实际上等价于把"prompt + Path(root, ti)"作为一个普通 causal 序列单独跑出来的结果——因为它能且只能 attend 到自己的祖先。这意味着 target 给出的 logit p_target(· | ti) 在数学上和"如果只 verify 这一条路径"得到的 logit 完全一致。所以 tree 没有引入任何额外近似,后面的 rejection sampling 可以照搬。

C · Tree 下的 lossless 保证

spec decoding 是 lossless 的(target 的 marginal token 分布和它单独 decode 一致),这一点在 chain 上由 rejection sampling 教程 给出严格证明。Tree 的版本只需要把"沿着唯一一条路径做 rejection"换成"沿着当前选中的路径做 rejection,reject 时切到对应 fallback":

accept t̂i w.p. min(1, ptarget(t̂i) / pdraft(t̂i))

这里关键点是每个 tree 节点的"draft 分布"是它父节点位置上的那次 draft forward 给出的(因为兄弟节点共享父亲)。验证算法:

  1. 从 root 的孩子里挑出 draft 概率最高的一个,运行 rejection 测试。如果通过,推进到这个孩子,继续向下。
  2. 如果这一层的某个孩子 reject 了,对照同层其它兄弟:把已 reject 节点的 draft 概率从父位置的 target 分布里"扣掉"(得到 residual),再用 residual 对剩下的兄弟做一次试探。这就是 SpecInfer 的 multi-candidate rejection。
  3. 若整层兄弟都 reject,则在父位置从 residual 分布里 sample 一个 token 作为 bonus,中止。

"longest accepted prefix" 输出规则:对每条 root → leaf 路径都跑这个 sequential rejection,沿着 tree 的连接逐级深入,直到第一次 reject 或到达 leaf。最终 commit 的就是第一次 reject 之前那段路径。注意这条 commit 路径在 tree 里是唯一的,所以输出是良定义的。

为什么这不破坏 marginal?——因为 rejection 在每一层都是独立进行的,而每一层"成功 sample 出的 token"的分布严格等于 ptarget。tree 只是降低了某层全部 reject 的概率(因为同一位置有多个候选,任意一个被接受就不需要 fallback),但 fallback 一旦被触发,它仍是从 residual 分布精确 sample 的。所以 marginal 一致。

这点和 Mirror-SD 的 branch-complete tree 关联紧密(参见 09 Mirror-SD):Mirror-SD 要求每层把 vocabulary 的 top-k 都补齐成"完整"分支,这样 rejection 算法的 residual 几乎总能被某个兄弟吸收,fallback 概率几乎为 0,等效 acceptance 暴涨。

D · 效率分析:加速从哪里来,代价是什么

D.1 Acceptance 概率的数学

令 α 为 per-token acceptance(独立同分布近似),d 为深度,w 为最深一层的"路径数"。

下表用 α = 0.7 计算:

结构d=2d=4d=6d=8
Chain α^d0.490.240.1180.058
Binary tree (1−(1−α^d)^(2^d))0.840.980.999~1
节点数 (2^(d+1)−1)731127511
期望接受长度(实测,Vicuna-7B)~1.7~3.5~4.8~5.2

看到关键转折:从 chain 到 binary tree,d=4 时全程通过概率从 0.24 跳到 0.98——但 verify 的输入长度从 4 涨到 31,大约 8× 个 LM head softmax。这交易在memory-bound 的 decode 阶段是赚的(GPU 闲着也是闲着),所以才有 EAGLE-1 的 ~3× speedup。

D.2 成本分解

tree verification 的实际开销有三块:

D.3 Speedup 分解公式

speedup = E[L] / (1 + C_tree(N) / t_target)

其中 E[L] 是期望接受长度,t_target 是 target 单步 forward 时间,C_tree(N) 是 N 节点 tree 的额外开销(主要是 LM head 多算 N−1 次)。所以加大 N → E[L] 涨,但 C_tree(N) 也线性涨,直到某个 N* 后边际收益跌破 1。

EAGLE-1 论文的 ablation 显示:N=26(深度 5 的 binary tree)是 7B/13B 上的甜蜜点;EAGLE-2 通过 dynamic rerank 把有效 N 压到 8–16 同时 E[L] 反而提高。N=60 之后 throughput 普遍掉头向下(LM head 已经吃满,带宽打满)。

全程接受概率 vs 深度: chain 指数衰减,binary tree 几乎不衰减 depth d P 1.0 0.75 0.50 0.25 0 2 3 4 5 6 7 8 chain binary tree w=3 (ref) α = 0.7,理想假设;实测因 confidence 非独立会略低,但形状一致
Chain 在 d=4 后已经掉到 0.24 以下,继续加深几乎无意义;binary tree 在 d=3 已经 0.95+,d=4 后基本饱和。这解释了为什么实践中 tree 深度通常 4–6 就够,继续加深的边际收益被 verify 成本反吃。Mirror-SD 这类 branch-complete tree 等价于 w → |V|,曲线整体上推。

E · 怎么设计一棵 tree

设计的本质是给定 N(节点预算),怎么放才能最大化 E[L]。N 通常受 verify 的 GPU 显存与 LM head 带宽约束(典型 16–64)。

E.1 Static tree(EAGLE-1 / Medusa / SpecInfer 早期)

固定拓扑,常见的两种:

静态树的根本问题已经在 EAGLE-2 被指出:同一个位置的 acceptance 在不同 query 上跨度很大(0.1–1.0)。静态最优解只是边缘分布意义上的最优,在任何具体 query 上都不会真正最优。

E.2 Dynamic tree(EAGLE-2): expand & rerank

把 tree 的设计拆成两步,关键是用 draft confidence 当 acceptance 的 proxy(2.1 节里讨论过 well-calibrated 性质)。给每个节点定义全局 value:

Vi = ∏j ∈ Path(root, ti) cj

其中 cj 是 draft model 在节点 j 输出 token 时的 softmax 概率。

Expand 阶段(m 次迭代,m = 树深度):

  1. 初始化:tree = {root}。
  2. 循环 m 次:从 frontier(当前最深一层)选 V 最大的 top-k 个节点,送给 draft 模型 forward 一次,生成它们各自的 top-k 子节点;把这些子节点加入 tree。
  3. 结束时 tree 大概有 1 + k + k² + … + k^m 个节点;但因为 top-k 的剪枝,实际节点数远小于满二叉。

Rerank 阶段:把 tree 里所有节点(含未扩展的浅节点)按 V 排序,取 top-N 作为最终送 verify 的子树。一个关键引理: "按 V 取 top-N 得到的节点集合天然是连通子树"——因为 V 沿着路径单调下降,所以任何被选中的节点的祖先 V 都更大、必然也被选中。

E.3 Worked example: dynamic 扩展一步

假设当前 frontier 有 4 个节点,V 分别为 {0.95, 0.6, 0.3, 0.05}。budget k=2:

  1. 选 V=0.95 和 V=0.6 两个 expand,丢弃 V=0.3 和 V=0.05(它们的 path 太弱,继续挖也会很快掉到 0.1 以下)。
  2. 对前者 draft forward,假设 top-2 子 confidence = {0.9, 0.4} → 子节点 V 分别 = {0.95×0.9, 0.95×0.4} = {0.855, 0.38}。
  3. 对后者 draft forward,top-2 = {0.7, 0.2} → 子 V = {0.42, 0.12}。
  4. 新 frontier = {0.855, 0.42, 0.38, 0.12}。继续下一轮。

注意 0.42 > 0.38 — 更弱父亲的强孩子 反超 强父亲的弱孩子。这种跨支比较正是静态树做不到的地方。

E.4 Best-first heap(DDTree)

EAGLE-2 是 layer-synchronous 的(一层一层扩);DDTree(参见 16)进一步指出 layer 同步浪费:某些路径明显比其他路径强,应该它们继续往下挖。DDTree 把 frontier 用 max-heap 维护,每次只 pop V 最大那一个 expand,不管它在哪一层。这相当于一个 best-first search,在 block diffusion drafter 上能拿到比 EAGLE-2 更高的 E[L](因为 diffusion drafter 一次出一整 block,best-first 能跨 block 比较 V)。

E.5 Node-budget 怎么调

实操经验:

F · 跨论文对比

方法 Tree topology Expansion 策略 Drafter 类型 核心 trade-off
SpecInfer (Miao 23) 静态 token tree 多个独立 SSM,各产一条 chain → 拼成 tree 多个小 AR draft model 多模型成本高;tree 不共享前缀
Medusa (Cai 24) 静态笛卡尔积 tree K 个独立 head 各 top-k,笛卡尔积 多 head,无 AR head 之间独立 → acceptance 卡 0.6
EAGLE-1 静态二叉,深度 5,~26 节点 每节点强制扩 2 子 1 层 AR drafter on feature 结构 context-blind
EAGLE-2 动态子树,N=8–16 经 rerank Layer-synchronous expand top-k by V 同 v1,只改 search 逐层同步,深路径浪费 budget
Sequoia (Chen 24) 静态优化拓扑 Offline DP 对边缘 acceptance 独立 small AR 静态,但优化粒度细
DDTree (2604.12989) 动态,heap-driven Best-first by global V Block diffusion drafter 需要 frontier heap 实现;diffusion-aware
Mirror-SD (2510.13161) Branch-complete tree 每层 top-|V'| 全展(V' ≪ V) Mirror drafter 显存 / 带宽换 acceptance,extreme
DFlash (2602.06036) 无 tree,平面 block Block diffusion 一次出 16 token(平行不分支) 5-layer block diffusion 放弃 tree 的"多假设"换并行性

G · 完整 worked example: 一棵深度 2 的二叉 tree 全流程

假设 prompt = "积分等于",vocab = {一, 二, 三, 五},target 模型 LLaMA-7B-zh,draft 用 EAGLE-1 head。要求构造一棵深度 2、宽度 2 的完整二叉 tree(7 个节点),走完一轮 verify。

Step 1: Draft 第一层

Draft model 拿到 hidden state h_等于 + token "等于",输出 logit;softmax 后 top-2:

(其余 vocab confidence 太低,忽略)

Step 2: Draft 第二层(2 次 forward,batched)

对 node 1("一"),draft model 输入 h_一(由 EAGLE 的特征自回归算出来) + token "一",输出 top-2:

对 node 2("五"),输出:

Step 3: Flatten + 构 mask

Tree(BFS 顺序):[root, 一, 五, 百₁, 千, 百₂, 十],节点编号 0..6。Mask 与本节 B 部分给出的 7×7 矩阵相同(只是 token 内容不同)。

Per-node 全局 V: [1.0, 0.7, 0.2, 0.42, 0.21, 0.08, 0.10]。

Step 4: Target 一次 forward

Target 在 prompt + 7 个 tree token 上跑一次,得到每个节点位置的 next-token 分布 p_target(· | path)。具体数值假设:

节点tokenp_draftp_target(this token | parent path)
10.70.85
20.20.05
30.60.55
40.30.25
50.40.30
60.50.20

Step 5: Sequential rejection,跟随最优路径

Layer 1:在 root 这一层,先比较 node 1 和 node 2(它们都对应 root 的 child)。

Layer 2:在 node 1 这一层,看它的 children(node 3, node 4)。

Step 6: 收尾

到达 node 3(leaf),tree 走完。Commit 的 token 序列 = ["一", "百"](沿 root → 1 → 3 的路径)。再加上 target 在 node 3 位置上 sample 出的bonus token(就是它在 node 3 hidden 上的 next-token 分布 sample)——假设 bonus = "万",最终输出三个 token。

对照:同样深度的 chain 只能尝试 ["一", "百"] 这一条;如果 chain 选错(比如 chain 第一步 sample 了 "五"),就会在第一步直接 reject、commit 0 个 token。Tree 通过同时下两个一层注 + 两个二层注,把"全程通过"概率从 α² ≈ 0.49 推到 ~0.84。一次 verify forward,3 个 commit token,wall-clock 约等于 1 次普通 decode + 30% 的 LM head + tree-attn overhead。

这个 7 节点小例子里,V=0.08 的 node 5 是明显该被剪掉的:它需要 root→五→百 这条路径全过才有意义,但 p_target(五 | root)=0.05 已经几乎注定 reject。EAGLE-2 的 dynamic 版本会在 expand 阶段就发现 V=0.2 远小于 V=0.7,直接放弃 expand node 2,把那部分 budget(2 个节点)挪到去 expand "一→百" 的 grandchild。这就是"动态"相比"静态"的真正杠杆。

3 · EAGLE-3 (2503.01840): 拆掉 feature loss,引入 training-time test

3.1 动机:为什么 EAGLE 不能"加数据就更快"

到 2024 年下半年,LLaMA 系列每代训练数据都翻倍(LLaMA1: 1T → LLaMA3: 15T)。Yuhui 想:把 EAGLE 的训练数据也从 ShareGPT(~68K)扩到 ShareGPT + UltraChat(~530K),acceptance 应该会涨。

实测结果是个 anti-scaling 曲线:数据从 1× 加到 8×,EAGLE 的 speedup 几乎不动,acceptance 微涨然后饱和。问题出在 EAGLE 的 loss 本质上是两项 lockstep:

L = l_fea ‖ f̂t+1 − ft+1 ‖ + l_token CE(t̂t+1, tt+1)

l_fea 强行让 draft model 的中间表示逼近 target 的 top-layer feature。这有两个隐性问题:

  1. top-layer feature 只承载"下一个 token"的信息(LM head 是满秩,所以 logit 对 feature 是单射);它不天然包含"下下个 token"的信息,因此哪怕 l_fea 训得很好,multi-step generation 时也不会变得更好。
  2. l_fea 这个约束剥夺了 draft model 的内部表达自由——加大数据后,模型本来可以学到更聪明的内部 routing,但被 l_fea 拽着不让走。

第一刀就是砍掉 l_fea。但这又引出第二个问题:Step 2 的输入需要 ft+1,而 train 时给的是 ground-truth f,test 时只有 draft 自己的输出 ât+1——分布不一致,所以 1-α(input 含 1 个估计值时的 acceptance)崩盘到 ~0.2。

解法是training-time test:训练时就让 Step 1 的 draft model 输出 â,然后把 â 而不是 f 喂给 Step 2 训练,模拟推理路径。这是标准的 scheduled sampling 思路在 spec decoding 上的具体化。HASS 论文同期也做了类似改动,但目的不同(HASS 是修 EAGLE 的误差累积,仍保留 l_fea)。

3.2 核心方法:三件套

EAGLE-3 三件套: 多层融合 → token-only loss → training-time test (a) 多层特征融合 low-layer feature l mid-layer feature m high-layer feature h concat → 3k FC: 3k → k → g 不再只用 top layer (b) loss 变化 EAGLE-1/2: L = l_fea + l_token feature 拟合约束 → 限表达力 EAGLE-3: L = l_token only draft model 输出 a 不必逼近 f → 输入也不再被 f 形状绑架 → 可以喂多层融合的 g (c) training-time test Step 1 (training): [g₁..g_t] → â_{t+1} supervise on t̂_{t+1} Step 2 (training): [g₁..g_t, â_{t+1}] → â_{t+2} supervise on t̂_{t+2} (â 是 Step 1 自己的输出, 不是 ground-truth f) → 训练分布 = 推理分布 → 1-α 不再崩
EAGLE-3 的三件套互相耦合:loss 砍掉 l_fea(b)是前提,因为只有这样 (a) 多层融合 g 才能取代 top-layer f;(c) 又是为了让砍掉 l_fea 后的 multi-step 不至于因 train/test mismatch 崩盘。注意推理时仍然兼容 EAGLE-2 的 dynamic tree。

Worked example: "How can" → "How can I do" 的 3 步 draft

StepDraft inputDraft outputSample
1g_how, g_can(target 给的多层融合) + e_can, e_Ia_I ∈ ℝ⁴⁰⁹⁶LM head(a_I) → "do"
2g_how, g_can, a_I(注意:不是 g_I,target 还没验) + e_I, e_doa_doLM head(a_do) → "it"
3... + a_do + e_ita_it"."

训练时 attention mask 要做"仿造"——同一行 ground-truth 序列要分别和 Step 1 的 a、Step 2 的 a 配对,但跨 step 之间不能互相穿越(否则模型会偷看后面的真值)。Figure 6 的稀疏 mask 用 vector dot 而不是矩阵乘可以省算力。

3.3 关键结果

3.4 与 v2 的差异

v2 是推理时的 search 优化(不动训练);v3 是训练目标 + 输入侧的根本重构。一句话总结:v2 教会"怎么挑 token",v3 教会"怎么生成更好的 candidate token"。两者正交,v3 的代码里 dynamic tree 仍照常用。

为什么这是"training-time test"而不是普通 scheduled sampling?——测试时的输入分布在 EAGLE-3 里是明确知道的(就是 draft model 自己输出的 a),所以可以在训练里"穷举"地模拟。这跟一般序列模型 teacher forcing 抽象不同,后者的"测试分布"无法事先采样。

4 · DFlash (2602.06036): 把 drafter 本身换成 block diffusion

4.1 动机:autoregressive drafting 的天花板

EAGLE-3 已经把 acceptance 推到 ~6 token / cycle,但 DFlash 作者(Zhijian Liu et al. @ UCSD)指出一个被忽视的事实:即使 acceptance 再涨,autoregressive draft 的 T_draft 是线性增长的:

T_draft = γ · t_step

每多猜一个 token,draft 模型就多一次 forward。所以 EAGLE-3 不得不把 draft 模型限制成"1 个 transformer decoder layer",哪怕这意味着模型容量不够;一旦想加深,latency 立刻吃掉收益。整个 spec decoding 的实际 ceiling 卡在 2–3×(reasoning 模型上 EAGLE-3 平均 ~4× 已经是 outlier)。

另一边,2025 年的 dLLM(LLaDA / SDAR / Block Diffusion)展示了一种不同的生成方式:一次 forward 把一个 block 内所有 mask 位置并行解码。问题是 dLLM 端到端 quality 输给 AR 模型,且需要多步去噪。但作为 drafter——只要 verifier 把关,quality 不达标的 token 会被 reject,所以 lossless 仍然成立。

DFlash 的核心赌注:drafting 不需要去和 AR 模型卷质量,只要能在并行性上拿到工程红利就赢。

4.2 核心方法

DFlash 推理: target hidden 注入 draft KV cache + 一次性 unmask 整个 block Target Model "Diffusion is good" (prefill + 上一轮 verify) layer 4 hidden h₄ layer 12 hidden h₁₂ layer 20 hidden h₂₀ layer 28 hidden h₂₈ layer 36 hidden h₃₆ concat + MLP → target context feature + token "for"(bonus) inject K/V DFlash Draft (3–8 layers, block diffusion) for ⟨m⟩ ⟨m⟩ ⟨m⟩ ⟨m⟩ ⟨m⟩ block size = 16 ↕ bidirectional attention(每 token 看到所有 mask 位)↕ 1 forward for spec- ulative decod- ing ⟨eos⟩ 每个 draft layer 的 K/V cache 里都持续存着 target context feature → 加深 draft 不会"稀释"target 的指引 送给 target verify(所有 16 token 一次性 verify)
DFlash 把 5 层(均匀采样自 layer 4/12/20/28/36)target hidden 拼接 + MLP 投影成"target context feature",然后把它作为持续的 K/V 注入 每一层 draft 的 attention 缓存——这与 EAGLE-3 把多层 feature 仅作输入 prepend 形成对比,后者随 draft 加深信号会被"稀释"。Draft 本身用 block diffusion(bidirectional attn,一次 forward unmask 全部 16 个 mask 位置)。

Worked example: 一轮 draft–verify

组件形状 / 数说明
Target hidden(5 层)5 × ℝ4096(per-token)从 layer {4,12,20,28,36} 抽
fused context feature4096(per-token)concat → MLP 投影
Draft layers5 layers(消融最优)EAGLE-3 是 1 layer
Block size16(Qwen3),10(LLaMA3.1-8B)训练 16 推理可降到 8
Draft forward1 次EAGLE-3 要 5–8 次 sequential
Acceptance length τ~6.5 (Q3-8B GSM8K)EAGLE-3 在同模型 ~3.2
End-to-end speedup5.15×(GSM8K)EAGLE-3 同条件 1.99×

4.3 训练设计的两个细节

  1. Random anchor sampling:不是均匀切 block,而是从 response 里随机选 anchor token 作为 block 的第一位(对应推理时 verify 通过的 bonus token),其余位置 mask。这样训练的 block 起点分布 ≈ 推理时的 block 起点分布。
  2. Loss 指数衰减加权:w_k = exp(−(k−1)/γ)。block 内第 k 位的权重逐位下降,因为只要前面位置 reject,后面就被 discard——前面错的代价高,所以早位置 weight 大。

4.4 关键结果

4.5 与 EAGLE-3 的差异

维度EAGLE-3DFlash
Drafter 类型autoregressive,1 层 decoderblock diffusion,3–8 层 bidirectional
Draft cost vs γ线性 γ·t_step近似常数 t_parallel
Target hidden 注入位置仅作 input concat注入每层的 K/V cache
训练稳定性需要 training-time test 模拟用 anchor sampling 直接对齐
Tree?dynamic tree(继承自 v2)纯 block,没有 tree
DFlash 的"draft model 加深不再使 target 信号稀释"是关键论点。EAGLE-3 把 g 直接拼到 token embedding 后,信号经过几层 attention 后会被 dilute;DFlash 把它放在 K/V 里,每一层 attention 都能直接 query,不被深度抹平。这是一个非常巧妙的注入位置选择。

5 · 演化轨迹: 一根线索 + 一次范式分叉

EAGLE-1 2024.01 feature 级 + shifted token ~3.0× EAGLE-2 2024.06 dynamic tree (confidence 校准) ~4.2× EAGLE-3 2025.03 无 l_fea + 多层融合 + training-time test ~5.5× DFlash 2026.02 block diffusion + KV 注入 ~6.0×+ 动 search (不动 train) 动 loss + input (同架构内重构) 范式分叉 (换 drafter 类型) EAGLE 家族 → DFlash: 速度 / 设计变化点
横轴时间。三代 EAGLE 都在"AR drafter + tree verify"框架内逐步松绑;DFlash 跳出 AR drafter,但仍然沿用了 target hidden 注入这条遗产线。

5.1 横向对比

维度EAGLE-1EAGLE-2EAGLE-3DFlash
Feature 输入粒度top-layer feature f同 v1低/中/高 多层融合 g5 层 target hidden 通过 K/V 注入
Draft tree topology静态 binary tree (~26 token)context-aware dynamic + rerank继承 v2 dynamic tree无树,block diffusion 平面 16 token
Lossl_fea + l_token无改动(只动 search)仅 l_tokenl_token,带位置衰减加权
训练时模拟测试training-time test(scheduled sampling 风格)random anchor + bidirectional mask
Drafter 架构1 decoder + FC同 v11 decoder + 3k→k FC3–8 bidirectional layers
Drafter forward 数 / cyclem 次 (m=5)m 次 + rerank 后 m 减小m 次1 次 / block
是否 lossless是(保证 verifier 分布)
典型 speedup~3.0×~4.2×~5.5×~6.0×(再 ÷ EAGLE-3 ≈ 2.5×)
生态位置开 feature-level autoregression 先河tree search 最佳实践data scaling 路径draft 范式分叉(non-AR drafter)

5.2 一句话总结每代

5.3 趋势解读

EAGLE 三代是同一根线索的逐步松绑。v1 把 draft 抬到 feature 层用 shifted token 解决了"sampling 随机性引入的输入歧义";v2 注意到"verify 的搜索空间也应该 context-aware";v3 终于回头审视"我们当初为什么用 l_fea"并决定把它砍掉。每一代都解决了上一代的某个被掩盖的瓶颈,但结构上都属于"AR drafter + tree verify"这个家族。

DFlash 不在这条线上。它做的是范式分叉:既然 drafter 的核心问题是"AR 限制了 γ 和 model depth 之间的非耦合空间",那么换一个一次性并行解码 block 的生成模型(block diffusion),就能让 draft 模型变深(5 层而不是 1 层)而不付 latency 代价。注意 DFlash 仍然沿用了 EAGLE 系列的核心遗产——target hidden 注入(EAGLE-3 多层融合的演化版本)、共享 LM head、verifier 端 lossless rejection——它只换了"如何并行画出 γ 个候选 token"。

从工程角度看,接下来几个月可能的分叉点:


关键记忆点

EAGLE-1 洞察:feature 自回归比 token 简单,但要把 shifted token 注入解决 sampling 不确定性。Loss = l_fea + l_token。
EAGLE-2 洞察:draft confidence ≈ acceptance rate;用全局 V = ∏c_j 做 expand+rerank,把静态树变成 context-aware 动态树。不动训练。
EAGLE-3 洞察:l_fea 是隐性约束;砍掉它 + 多层 feature 融合 g + training-time test = 第一次出现 draft data scaling law。
DFlash 洞察:AR drafter 的 T_draft = γ·t_step 是天花板;block diffusion 一次 forward 出 16 个 token,target hidden 通过 K/V 注入每一层。
数字 1→2→3→DFlash 在 chat 任务上的 speedup 大致是 3 → 4.2 → 5.5 → 6.0+(模型不同,趋势一致)。
线索 三代 EAGLE 都松绑(粒度→搜索→loss);DFlash 是范式分叉,但仍然沿用 target hidden 注入这一遗产。
立场 把 EAGLE 系列读成"逐步把 draft 模型从设计假设里解放";DFlash 读成"draft 不必和 verifier 同范式"。下一步可能是把 training-time test 思路移植到 DFlash,或者做 batch 大场景下的 dynamic block size 调度。