DFlash2 用投机解码给 Qwen 提速
Qwen3.8-27B 开源短短十天,Hugging Face 下载量就破了 260 万,配套的加速生态也几乎同步成熟。其中最具讨论度的一件事,是 Inco AI 开源的 Qwen3.8-27B-DFlash2 投机解码(speculative decoding)草稿模型:它只有 1.92B 参数、约 3.85GB,配合主模型在 SGLang 上跑,官方模型卡给出的单并发输出吞吐最高达到自回归基准的 3.43 倍。网上随之出现“提速明显”“4–5 倍”的说法。作为长期使用大模型做服务的工程师,我的第一反应不是看峰值倍数,而是追问:这笔加速到底从哪来、在什么工况下成立、又会在哪里缩水。把投机解码的原理、DFlash2 的架构选择与实测数据叠在一起看,答案其实相当清晰,也远比标题里的倍数更有信息量。
要理解 DFlash2 为什么能提速,得先回到自回归解码的成本结构。标准 LLM 推理是逐 token 生成的:每产出一个 token,都要把整张权重从显存搬一遍、跑一次完整前向。模型越大,单次前向越贵,而每个 token 的生成都受限于这次前向的延迟,与批量无关——单请求场景下,GPU 的大量算力被浪费在“等下一个 token”的串行节奏里。投机解码的核心直觉非常朴素:能不能让一个小模型先“猜”一长串后续 token,再由大模型一次性并行验证这一串猜得对不对?猜对的就直接采纳,猜错的从第一个分歧点之后重来。只要草稿模型的接受率够高,大模型每步就不再只产出 1 个 token,而是产出 k 个(k 为接受长度),而验证 k 个 token 的成本近似等于验证 1 个(一次并行前向),于是有效吞吐就近似放大了 k 倍。代价是每步多跑一次小草稿模型的前向——但 1.92B 相对 27B 几乎可忽略。这套机制的正确性有严格保证:验证时用大模型的分布对草稿 token 做拒绝采样(rejection sampling),输出分布与纯自回归完全一致,所以加速是“免费的”,不损失任何质量。
把这套机制落成代码,最直观的是草稿-验证循环。下面是一段概念性伪代码,剥离了框架细节,只保留投机解码的骨架:
# 投机解码:草稿模型并行预测 + 目标模型一次性验证
def speculative_decode(target, drafter, prompt, k=7, max_new=4096):
seq = prompt
cache = {} # 目标模型 KV cache
generated = 0
while generated < max_new:
# 1) 草稿模型自回归产出 k 个候选 token(廉价)
draft_tokens = drafter.greedy(seq, steps=k) # O(k) 小模型前向
# 2) 目标模型对 [原序列 + k 草稿] 做一次并行前向,拿到整段分布
logits = target.forward(seq + draft_tokens, cache) # 一次大模型前向
# 3) 用拒绝采样逐个判定接受 / 拒绝
accepted = []
for i, dt in enumerate(draft_tokens):
if sample_accept(logits[i], dt): # 分布一致则接受
accepted.append(dt)
else:
# 从目标分布重采样一个,终止本轮
accepted.append(resample(logits[i]))
break
seq += accepted
generated += len(accepted)
return seq
注意第 2 步:无论草稿多长,目标模型只跑一次前向(借助 KV cache 复用前缀),这正是加速的来源。DFlash2 的特别之处,在于它把“草稿模型自回归产出 k 个候选”这一步也做了改造——它不走标准投机解码那种“草稿模型自己递归 k 步”的串行路径,而是用一次前向并行预测整块 draft token(block-level drafting),配合 SGLang 的 speculation block size 机制(每步约 7 个 draft token)。这种设计减少了草稿阶段自身的串行延迟,也让草稿与目标模型的步调更对齐,是其能在单并发下把接受长度和有效吞吐推到较高的原因之一。从技术脉络看,DFlash2 是 DFlash 系列的二代:一代已经验证了“块级并行草稿 + 严格拒绝采样”在国产大模型上的可行性,二代则把草稿模型从通用小模型换成针对 Qwen3.8 蒸馏对齐的专用 1.92B 草稿,使草稿分布更贴近主模型,从而抬高接受率这个决定加速上限的核心变量。换句话说,DFlash2 的工程增量不在算法框架,而在“草稿质量”这一项的专精——而这恰恰是投机解码收益的最高杠杆点。
官方模型卡(H200 单卡、SGLang、block size 8、temperature 1.0 / top-p 0.95 / top-k 20)给出了最干净的对比,因为它把 DFlash2 和同引擎下的自回归、Qwen3.8 内置 7-token MTP 放在同一张表里。单并发(Concurrency 1)的输出吞吐:
任务 自回归 MTP DFlash2 DFlash2 加速
GSM8K 68.9 178.5 (2.59×) 236.1 (3.43×) ▲ 最高
MATH-500 69.0 172.8 (2.51×) 230.7 (3.34×)
HumanEval 69.0 151.9 (2.20×) 214.6 (3.11×)
MBPP 69.0 153.1 (2.22×) 226.9 (3.29×)
MT-Bench 68.9 134.9 (1.96×) 184.0 (2.67×)
这组数据的价值不只是“3.43× 很猛”,更在于它暴露了加速的工况依赖性。把并发拉到 8 和 32,画面立刻变化:并发 8 时 DFlash2 落在 2.27×–2.85×;并发 32 时进一步降到 1.01×–1.45×,而 MTP 在并发 32 的多个任务上已经出现 0.77×–0.94× 的负加速。为什么会这样?因为高并发下,GPU 算力已经被多请求填满,投机解码“用草稿模型的小开销换并行验证收益”的空间被压缩;同时草稿接受率会随负载和采样温度漂移而下降,当接受长度趋近于 1,投机解码反而因为多跑了草稿前向而变慢。DFlash2 相比 MTP 仍保持正增益,说明其独立草稿模型的接受率在高并发下更稳——这正是它相对内置 MTP 的底层优势:MTP 复用主模型自身的层做草稿,省参数但受主模型状态牵制;DFlash2 用独立小草稿模型,草稿质量与主模型解耦,高压下更不容易崩。
在解读这些数字前,有必要把“加速倍数”还原成它真正的决定式。设草稿步数为 k、草稿被大模型接受的平均长度为 a(1 ≤ a ≤ k),则单步有效产出约 a 个 token,而成本为“1 次草稿前向 + 1 次目标模型前向”。当 a 越接近 k,有效吞吐就越逼近 k 倍;当 a 跌到 1,就退化成“跑了两次前向只多产 1 个 token”,反而可能变慢。所以加速上限由 k 决定,实际收益由 a(接受率)决定,而 a 强依赖于任务类型:GSM8K 这类有确定推理链、next-token 分布尖锐的任务,草稿容易猜中,a 高;自由闲聊、创意写作这类分布平坦的任务,草稿频繁在第一个分歧点被拒,a 低。这也是为什么同一份 DFlash2,在 GSM8K 上能跑出 3.43×,在 MT-Bench(含开放生成)上只剩 2.67×——不是模型变了,而是任务的可预测性变了。任何部署前的收益评估,都应拿真实业务 prompt 的分布去测 a,而不是盯着“好猜”基准的峰值。
光看官方卡还不够,因为那是 H200 数据中心卡的理想工况。两份独立实测把边界说得更实在。其一是 8×RTX 3090(CSDN 可复跑测试,2026-08-22):同主模型权重,一侧 vLLM(TP=4/FP16)普通解码,一侧 SGLang+DFlash2(TP=4/BF16)。单请求端到端生成速率 45.60 → 196.86 tok/s(4.32×),4 并发总吞吐 3.01×;且两端 20 题正确率均 90%、输出完全一致。这份测试很诚实地点出一个方法论陷阱:4.32× 是“vLLM 部署路径 vs SGLang+DFlash2 部署路径”的整体差距,引擎、数据类型、CUDA Graph 配置都不一样,不能全算给 DFlash2。真正公平的是“同引擎自回归 vs 投机解码”——那才接近官方卡的 2.67–3.43× 区间。其二是 48GB M4 Pro 端侧(MLX,block size 4):官方 4-bit 普通解码 15.4 tok/s,加 DFlash2 后 26.96 tok/s(1.75×);GSM8K 上达 31.49 tok/s(2.08×),峰值显存多占约 4GB,首 token 延迟几乎不变。这组数据对“消费级硬件能不能捡到加速”给出了肯定答案:能,但倍数比数据中心卡低,因为端侧本来就受内存带宽而非算力主导,投机解码对带宽瓶颈的缓解有限。
把三方数据合起来,可以给“DFlash2 提速到底值不值”一个工程化的判断。第一,它几乎是无代价的正收益:草稿模型 1.92B、多几 GB 显存,正确性经多份实测确认无损,SGLang 集成成本极低——属于“上了不亏”的加速件,尤其适合单卡、端侧、低并发的交互式场景。第二,别把标题倍数当承诺:单并发 3.43× 是峰值,生产多并发下更可能是 2× 上下;选型的预期应建立在“同引擎、目标并发”的对比上,而非跨引擎的端到端倍数。第三,它真正的差异化价值在于高并发稳定性,而非峰值更高——当内置 MTP 在并发 32 已经负加速时,DFlash2 仍正增益,这对要上生产的服务比纸面峰值更关键。第四,草稿接受率即一切:接受长度直接决定有效加速,而它随任务类型剧烈波动(推理/数学类高、自由生成类低),部署前应先用真实业务 prompt 跑一轮接受率,而不是只看 GSM8K 这类“好猜”基准。
落到实操,如果你要在 SGLang 上把 Qwen3.8-27B 配成 DFlash2 推理,核心就是告诉引擎用哪个草稿模型、块大小多少。一个最小化的启动形态大致如下(参数为示意,实际以 SGLang 版本文档为准):
# SGLang 启用 DFlash2 投机解码(示意)
python -m sglang.launch_server \
--model-path Qwen/Qwen3.8-27B \
--speculative-algorithm DFlash2 \
--draft-model-path incoai/Qwen3.8-27B-DFlash2 \
--speculative-num-steps 7 \
--trust-remote-code
这里 --speculative-num-steps 对应每步并行预测的草稿 token 数(官方用 7,对应 block size 8);草稿模型路径指向 1.92B 的 DFlash2 权重。调优时真正要盯的不是步数本身,而是在线接受长度监控——若发现平均接受 token 数远低于设定步数,说明草稿与主模型分布偏移(常见于温度偏高、或业务域与训练域差异大),此时要么降温度、要么换更贴合的草稿模型,否则投机解码会从“加速”退化成“白跑草稿”。
回到开头那个问题:网上说 DFlash2 在 Qwen3.8-27B 上 token 速度提升明显,这件事属实,且有官方卡与多份独立实测三重印证;但它不是“换个引擎凭空快四五倍”的魔法,而是“同引擎投机解码在合适工况下的稳健加速”——单并发 2.7–3.4×、端侧 1.75×、高并发下仍优于会负加速的内置 MTP。对工程师而言,最有用的结论其实很简单:把它当作一个低成本、可验证、正确无损的加速件,按真实并发和业务 prompt 的接受率来预期收益,而不是被峰值倍数牵着走。在 27B 这一档模型越来越成为中小团队主力推理负载的当下,DFlash2 这类“小模型给大模型当 accelerator”的思路,注定会比单次的倍数字节更长久地留在我们的部署清单里。