科普解读,带你理解 DeepSeek 团队提出的投机解码新框架 DSpark。
一、先说一个烦恼:大模型为什么"慢"?
你跟 ChatGPT、DeepSeek 聊天时,有没有好奇过:它是怎么把回答一个字一个字"吐"出来的?
实际上,目前几乎所有大语言模型(LLM)都在用同一种"笨办法"生成文字------自回归(Autoregressive) 生成。意思是:
每生成一个新字,模型都要把"前面所有的字"重新读一遍,做一次完整的计算(一次 forward pass),才能决定下一个字是什么。
打个比方:就像一个人写文章,每写一个字都要从头把已经写的内容重新默念一遍,才敢落下一个字。这显然很慢------输出越长,等待越久,显卡(GPU)也常常处于"吃不饱"的状态。
在实时对话、多轮 Agent 这类对延迟敏感的场景里,这种"逐字生成"的慢,是用户体验的头号杀手。
二、投机解码:请个"助理"先打草稿
为了解决这个问题,研究者提出了一个聪明办法------投机解码(Speculative Decoding)。它的核心思路可以用一句话概括:
请一个又小又快的"助理模型"先打草稿,再让"老板模型"(目标大模型)一次性审核。
具体流程是这样的:
- 草稿阶段 :小模型(叫 draft model)快速"猜"出接下来 γ 个候选字(比如 7 个)。
- 审核阶段 :大模型(叫 target model)把这 7 个字一起读进来,只做一次计算,就能判断哪些猜对了、哪些猜错了。
- 接受规则 :从左到右,保留最长的、连续猜对的前缀;一旦遇到第一个猜错的字,后面所有字(不管对错)全部丢弃。作为"安慰奖",大模型会额外补一个正确的字。
这里有两个关键点让这个方法"白嫖"了速度:
- 审核是并行的:大模型一次就能审完一整批草稿字,不用一个一个审。
- 质量零损失 :通过一种叫"拒绝采样"(rejection sampling)的数学技巧,最终输出的分布和大模型自己一个个字写完全一致------也就是说,加速但不降质。
一个核心公式
论文里给出了每个字平均生成时间的公式:
L=τTdraft+Tverify
- Tdraft:助理打草稿花的时间
- Tverify:老板审核花的时间
- τ:每轮被接受(采纳)的字数
这个公式很简单但很关键------它告诉我们,想让生成变快,只有三个抓手:
- 打草稿更快 (降低 Tdraft)
- 草稿质量更高 (提高 τ,让更多字被采纳)
- 审核更聪明 (降低有效的 Tverify)
DSpark 的所有创新,都是围绕这三个抓手展开的。
三、两条老路,各有各的坑
"助理模型"该怎么设计?过去主要有两派,各有优劣。
派别一:自回归助理(Autoregressive Drafter)
代表:Eagle3。
它的做法和小模型逐字生成一样------每猜一个字,都要看前面已经猜出来的字。
- 优点:质量高,前后连贯,因为每一步都"看着上文"在猜。
- 缺点 :慢。草稿时间和草稿长度成正比( Tdraft∝γ)。要想快,就只能猜很短的一小段(比如 γ 很小),而且模型层不能太深。
派别二:并行助理(Parallel Drafter)
代表:DFlash。
它的做法更激进------一次性、一个前向过程,把所有 γ 个字全部猜出来。
- 优点 :快。打草稿的时间和草稿长度几乎无关,所以可以猜很长一段(比如 γ=16)。
- 缺点 :每个位置都是"独立"猜的,看不到同一批里其他位置猜了什么 。这会导致一个叫 "多模态碰撞"(multi-modal collision) 的问题。
什么是"多模态碰撞"?
举个论文里的例子。假设上下文后面可能接两种合理说法:"of course" 或 "no problem"。
- 并行助理猜第 1 个位置时,它不知道第 2 个位置会接什么,只能在"of"和"no"之间平均下注。
- 猜第 2 个位置时同样如此。
- 结果它可能拼出 "of problem" 或 "no course" 这种前后矛盾的组合!
这就是"多模态碰撞"------每个位置都把多种合理可能"平均"了,最终拼出来的反而谁都不像。后果是:越靠后的字,被采纳的概率衰减得越快(论文称之为 "suffix decay",后缀衰减)。
还有一个被忽视的系统级问题
除了"草稿质量",还有一个"系统效率"问题:到底该审核几个草稿字?
这事儿没那么简单,因为它随两个轴变化:
- 数据侧:结构化文本(如代码)采纳率高,开放闲聊采纳率低。
- 系统侧 :系统空闲时,多审几个字几乎不花成本;但高并发时,每多审一个低把握的字,就挤占了原本可以服务其他用户的"批次容量"(batch capacity)。
过去的方法常常"一刀切"地审核所有草稿字,结果在高并发下反而拖慢了整体吞吐------这就是论文要解决的第二个痛点。
四、DSpark 登场:两招破两局
DSpark 的核心是用两个互补的机制分别解决上面两个问题。
第一招:半自回归生成(Semi-Autoregressive Generation)
目标:又快又连贯地打草稿。
DSpark 把草稿生成拆成两阶段:
① 并行阶段(重活儿):用一个深的并行骨架(论文里直接用了 DFlash)一次算出所有位置的基础预测。这保证了速度------和长度几乎无关。
② 序列阶段(轻活儿) :在并行预测之上,加一个轻量的串行小模块 ,从左到右扫一遍,给每个位置补一个"依赖修正项" Bk,让每个字能看到"同一批里前面已经定下来的字"。
用公式说话(别怕,我翻译)
最终每个位置 k 的预测概率是:
pk(xk∣x0,x<k)=∑uexp(Uk(u)+Bk(x0,x<k,u))exp(Uk(xk)+Bk(x0,x<k,xk))
翻译成人话:
- Uk 是并行骨架给出的"基础分数"(每个字都有一个)。
- Bk 是串行小模块给出的"修正分数",它依赖前面的字 x<k。
- 两者相加,再做一次 softmax(归一化成概率)。
关键在于:因为 Bk 依赖前面的字,所以一旦第 1 个位置定了"of",串行模块就会在第 2 个位置抬高"course"、压低"problem",从而避免了"of problem"这种笑话。
串行模块怎么实现?两种"头"
论文给了两种轻量实现:
1. Markov 头(马尔可夫头,默认方案)
只看"上一个字"。它本质上是一个"转移偏置" B(xk−1,xk),用低秩分解 B=W1W2 来近似( r=256):
B(xk−1,⋅)=W1xk−1W2∈RV
- W1 是一张"词嵌入查找表", W2 是一个"打分投影"。
- 低秩分解让存储和计算都很省,词表再大也扛得住。
- "Markov"这个名字来自马尔可夫假设------只依赖上一步状态。
补充小知识:什么是"马尔可夫"? 马尔可夫性质说的是"未来只取决于现在,不依赖过去"。一阶马尔可夫就是"只看上一步"。这里 Markov 头只看上一个 token,简单但有效。
2. RNN 头(循环神经网络头,可选方案)
用一个循环状态 sk 累积整个前缀的记忆,能看更远的历史:
sk=σ(Wgzk)⊙sk−1+(1−σ(Wgzk))⊙tanh(Wczk)
Bk(x<k,⋅)=W2⊤tanh(Wozk)
其中 zk 把"当前状态 + 上一个字嵌入 + 骨架隐状态"拼在一起。 σ 是 sigmoid 门控, ⊙ 是逐元素相乘------这就是经典的 GRU/LSTM 风格的"门控循环"。
补充小知识:RNN 与门控 RNN(循环神经网络)通过一个"记忆状态"在时间步之间传递信息。门控(gate)就像水龙头,决定"记忆里保留多少旧的、写入多少新的"。LSTM 和 GRU 都是这个思路。DSpark 的 RNN 头只有一层门控,非常轻。
效果对比 :论文发现 RNN 头比 Markov 头提升有限 (主要在更长的草稿块上),但实现复杂、部署不友好,所以默认用 Markov 头。这印证了一个朴素道理:"一点点自回归"就能带来巨大收益(论文原话:"A Little Autoregression Goes a Long Way")。
第二招:置信度调度验证(Confidence-Scheduled Verification)
目标:别盲目审核,看人下菜碟。
这一招又分两部分:一个"置信度头" + 一个"硬件感知调度器"。
4.1 置信度头(Confidence Head)
给每个草稿位置 k 输出一个分数 ck∈(0,1),表示**"在前面的字都被采纳的前提下,这个字能活下来的概率"**。
ck=σ(w⊤hk;W1\[xk−1])
就是一个简单的线性投影 + sigmoid。它用"分析性采纳率"作为监督信号:
ck∗=1−21∥pkd−pkt∥1
这个公式什么意思? pkd 是助理模型在每个词上的概率分布, pkt 是大模型在每个词上的概率分布。 ∥⋅∥1 是两个分布差异的"总变差距离"(Total Variation distance)。
直觉理解:两个分布越像,采纳率越高 。如果两者完全一致, ck∗=1(必然采纳);如果完全不同, ck∗=0(必然拒绝)。这正符合直觉------助理越像老板,老板越买账。
4.2 校准:别让模型"过度自信"
神经网络的置信度常常"虚高"------它说"我有 90% 把握",实际可能只有 70%。如果直接拿这个虚高的数去调度,就会高估收益、做出错误决策。
论文提出 序列温度缩放(Sequential Temperature Scaling, STS):
- 因为每个 ci 是"条件概率",整段前缀被采纳的概率是它们连乘 : ∏i≤kci(概率链式法则)。
- STS 在验证集上,从左到右逐位置做一维网格搜索,找一个温度系数让"累积乘积"的预测值和真实采纳率对齐。
- 温度缩放是"保序"的------只校准绝对数值,不改变"哪个字更靠谱"的相对排序。
补充小知识:什么是"温度缩放"? 这是神经网络校准的经典方法(Guo et al., 2017)。"温度" T 是个正数,把 logits 除以 T 再做 softmax: T>1 让概率更"软"(更不确定), T<1 让概率更"硬"(更自信)。调到合适温度,就能让模型的自信度和真实准确率对上号。
ECE(Expected Calibration Error,期望校准误差) 是衡量"自信度 vs 准确率"是否吻合的指标,越小越好。论文里把 ECE 从 3%~8% 降到了约 1%。
4.3 硬件感知前缀调度器(Hardware-Aware Prefix Scheduler)
这是 DSpark 最有"系统工程味"的部分。
要解决的问题 :一批里有 R 个请求,每个请求有一串草稿字和置信度。该给每个请求审几个字?
建模思路:
- 对请求 r,审到第 j 个字的"存活概率"是前面所有置信度的连乘: ar,j=∏i≤jcr,i(因为投机解码只接受连续前缀)。
- 这一批总共要审 B=∑r(1+ℓr) 个字( ℓr 是请求 r 的审核长度)。
- 期望被采纳的字数 τ=∑r(1+∑j=1ℓrar,j)。
- 设 SPS(B) 是"batch 大小为 B 时引擎每秒能跑几步"(这个曲线事先测量好,存成一张表)。
- 目标:最大化系统总吞吐 Θ=τ⋅SPS(B)。
巧妙之处 :因为 ar,j 随 j 单调不增(越往后越难活),所以可以贪心 地全局排序所有候选字、按存活概率从高到低加入,每加一个就查表算一次 Θ,直到吞吐开始下降就停。
为什么这个贪心是对的? 因为"存活概率单调"保证了:如果固定总审核字数 B,最优分配就是从全局池子里挑存活概率最高的那些字 。而 B 多大最好,可以沿着这条贪心路径边走边查表。这就把一个看似组合爆炸的搜索问题,变成了高效的贪心。
4.4 一个不能踩的雷:无损性
投机解码有个铁律------"非预测性"(non-anticipating) :决定要不要审某个字时,不能偷看它后面还没生成的字,否则会破坏"输出分布和大模型完全一致"这一无损保证。
DSpark 的置信度头依赖"上一个实际采样的字",所以计算下一个存活概率时需要具体的 xr,k。如果回顾式地全局搜索,就会把这个字的信息"泄漏"到当前决策里,造成选择偏差(论文在附录 A 给了反例)。
为保证严格因果性,调度器用了一个早停机制:一旦吞吐下降就立刻 break,决策只依赖当前已处理的前缀,绝不看未来。这样才保住了"无损"这块招牌。
五、一个反直觉的发现:并行居然能赢自回归?
按常理,"一步步看上文"的自回归模型,质量应该比"独立猜"的并行模型好。但实验里,并行(DFlash)和半自回归(DSpark)的采纳长度反而超过了自回归(Eagle3)。为什么?
论文做了一个非常漂亮的"逐位置条件采纳率"分析:
- 第 1 个位置 :两种架构都只基于目标上下文预测。差距来自模型容量 ------自回归模型受限于 O(γ) 延迟,只能做得很浅;并行模型 O(1) 延迟,可以堆得很深。所以并行在第 1 个位置就明显更准(比如数学上 0.88 vs 0.81)。
- 第 1 个位置的杠杆效应 :投机解码是"严格前缀匹配",第 1 个字错了,整段全废。所以第 1 个位置的优势会"放大"到最终采纳长度上。
- 后续位置:自回归模型越往后越准(条件越来越确定,比如闲聊从 0.53 涨到 0.74);并行模型则"后缀衰减"(闲聊从 0.72 跌到 0.63),因为独立预测拼不出连贯后缀。
DSpark 的设计哲学正是取两者之长:
- 用深的并行骨架,保住第 1 个位置的"高容量优势";
- 用轻量序列头,补上后续位置的"依赖建模",缓解后缀衰减。
最终 DSpark 在整段草稿上都保持高而稳的采纳率------既不像并行那样"高开低走",也不像自回归那样"低开高走",而是"全程高走"。
六、训练:三个目标,缺一不可
DSpark 训练时,大模型冻结,只训练草稿骨架、序列头、置信度头。损失函数由三项加权组成(默认 αce=0.1,αtv=0.9,αconf=1.0):
- 交叉熵损失 Lce:让助理预测对正确答案。
Lce=−∑k=1γwklogpkd(xk∗)
- 分布匹配损失 Ltv :让助理的概率分布整体逼近大模型的分布(用总变差距离)。这一项直接最大化采纳率。
Ltv=∑k=1γwk∥pkd−pkt∥1
- 置信度损失 Lconf :用二元交叉熵训练置信度头去预测 ck∗。
Lconf=−∑k=1γwkck∗logck+(1−ck∗)log(1−ck)
所有项都用位置权重 wk=exp(−(k−1)/γ) 加权------越靠前的位置权重越大,因为前缀验证下,前面的字贡献更大。
七、实验:离线和线上都赢麻了
离线基准
在 Qwen3-4B/8B/14B 和 Gemma4-12B 上,覆盖数学、代码、闲聊三大领域:
- 相比自回归的 Eagle3 ,DSpark 平均采纳长度提升 26.7%~30.9%。
- 相比并行的 DFlash ,提升 16.3%~18.4%。
- 跨模型家族(Qwen、Gemma)一致有效。
几个有意思的细节
- "2 层 DSpark 胜过 5 层 DFlash":说明轻量序列头的"性价比"远高于单纯堆并行层数。
- 草稿块越长,DSpark 优势越大 :在 γ=15 时,数学提升 30%、代码 26%、闲聊 22%。因为 DFlash 衰减快、长块边际效用递减,而 DSpark 把衰减按住了。
- 序列头延迟几乎可忽略:草稿长度从 4 加到 16,整体延迟只比 DFlash 多 0.2%~1.3%,却换来高达 30% 的采纳长度提升。
- 置信度头真的会"挑字":闲聊场景下,调高阈值能把采纳率从 45.7% 拉到 95.7%(剪掉了大量本来就会被拒的字);结构化任务(数学/代码)则剪得较少。
八、线上部署:工程不是请客吃饭
把 DSpark 装进 DeepSeek-V4 的真实服务系统,又会撞上理论与现实的差距。论文讲了几处精彩的工程适配。
8.1 可扩展训练的两个优化
- 隐状态通信 :大模型全词表 logits( V≈105)跨 worker 传输是带宽噩梦。改为只传"LM head 前一层的隐状态",到草稿模型这边再本地做投影,通信复杂度从词表量级降到隐维度 O(d)。
- 锚点定界序列打包:把长上下文的计算成本和草稿训练解耦------从训练序列里采若干"锚点",把孤立的小预测块密集打包成 batch,用 token 级注意力索引代替 2D mask,既省内存又保因果。
8.2 调度器的"异步化"
理论算法假设硬件容量曲线平滑,但真实硬件是阶梯式、锯齿状的 ;而且现代推理引擎用 CUDA Graph 回放和"零开销调度(ZOS)",要求下一步的 batch 大小必须在当前步结束前就定好------同步调度会让 GPU 干等。
DSpark 的解法是异步近似:
- 用"两步之前的置信度预测"来估计当前的容量上限 K;
- 但当前步的候选字仍然按最新的真实累计置信度严格排序 ,做"动态 top- K 选择"。
- 因为 K 来自历史信息,当前字 xr,k 不会泄漏到决策里------异步设计反而成了一道"因果屏障",既保住了无损性,又把调度延迟完全藏了起来。
8.3 变长批次的内核改造
调度器会给不同请求分配不同审核长度,但标准 decode 内核是为"定长查询"优化的,直接处理变长会因 padding 严重浪费 GPU。
解法:把物理执行和逻辑序列追踪解耦------所有请求的所有 token 在 kernel 里被"拍平"成一维,当作独立元素同等处理;序列内的依赖关系通过一个"marker tensor"在稀疏注意力里表达。在 DeepSeek-V4 架构上,只需改 index-attention 和 compress 两个 kernel。
九、线上真实流量:搬动了"帕累托前沿"
最终在 DeepSeek-V4-Flash 和 V4-Pro 的真实用户流量上对比旧的生产基线 MTP-1:
- 在同等吞吐水平下 ,DSpark 把单用户生成速度提升了 60%~85%(Flash) 和 57%~78%(Pro)。
- 在严格的交互性 SLA 下 (比如 Flash 120 tok/s/user、Pro 50 tok/s/user),旧基线 MTP-1 接近"崩盘",而 DSpark 仍能稳住吞吐------相对优势放大到 406%~661%。这说明 DSpark 搬动了系统的"吞吐---交互性"帕累托前沿,解锁了以前根本达不到的"严格低延迟"服务档位。
什么是"帕累托前沿"? 简单说,就是"鱼与熊掌不可兼得"时所有最优权衡点连成的边界。前沿往外扩,意味着同样的资源能同时获得更多吞吐和更低延迟------这是系统性能的"硬指标"提升。
负载自适应也很有意思:并发低时(<200 请求),调度器把每请求审核预算从 MTP-1 的固定 2 个字扩到 4~6 个字,多吃多占;并发高时,自动平滑收缩预算,把低置信度的草稿字提前剪掉,保护关键批次容量。
十、局限与展望
论文也坦诚了不足:
- 即便调度器把"审核浪费"降到最低,DSpark 仍要为"生成初始草稿块"付一笔固定开销。
- 对于本身就极难猜对的复杂请求(采纳率天然低),这笔草稿开销是"沉没成本"。
- 未来方向:在草稿模型内部引入"难度感知的提前退出(early exit)",让这类请求干脆跳过整块生成。
十一、一句话总结
DSpark 用**"并行骨架 + 轻量序列头"让草稿又快又连贯,用"置信度头 + 硬件感知调度器"**让审核又准又省。它把"加速但不降质"的投机解码,从实验室搬到了高并发生产线,并真正搬动了大模型服务的性能边界。
论文核心三句话:
- 草稿要"半自回归"------并行保速度,串行保连贯。
- 审核要"看负载下菜碟"------闲时多吃,忙时精审。
- 全程"无损"------输出分布和大模型完全一致,质量不打折。
附:关键术语速查表
| 术语 | 通俗解释 |
|---|---|
| 投机解码(Speculative Decoding) | 小模型先草拟,大模型一次性审核,加速但不降质 |
| 自回归(Autoregressive) | 一个字一个字生成,每步都看上文 |
| 并行生成(Parallel Generation) | 一次算出所有字,快但位置间无依赖 |
| 半自回归(Semi-Autoregressive) | DSpark 的核心:并行骨架 + 串行修正头 |
| 多模态碰撞(Multi-modal Collision) | 并行模型把多种合理可能"平均"掉,拼出矛盾组合 |
| 后缀衰减(Suffix Decay) | 越靠后的草稿字采纳率越低 |
| 拒绝采样(Rejection Sampling) | 保证输出分布无损的接受规则 |
| 总变差距离(Total Variation) | 衡量两个概率分布差异,直接对应采纳率 |
| 置信度头(Confidence Head) | 预测每个草稿字"能活下来"的概率 |
| 硬件感知调度器 | 根据系统负载动态决定每请求审几个字 |
| 温度缩放(Temperature Scaling) | 校准神经网络过度自信的经典方法 |
| 帕累托前沿(Pareto Frontier) | 多目标下最优权衡点连成的边界 |
| MTP(Multi-Token Prediction) | DeepSeek 旧的生产基线,一次预测 1 个字 |
本文是对 DeepSeek-AI 论文《DSpark: Confidence-Scheduled Speculative Decoding with Semi-Autoregressive Generation》的科普解读,旨在帮助非专业读者理解其核心思想。