DSpark 深度解读:DeepSeek-V4 如何用「半自回归」把推理速度提升 85%

从数学原理到生产部署,一次讲透投机解码的核心思想与最佳实践。


你有没有想过,为什么 ChatGPT 生成回复时是一个字一个字蹦出来的?明明 GPU 有几千个核心,为什么不能并行输出?

答案藏在自回归解码的机制里。想象一条高速公路,所有车辆必须通过同一个收费站,一次只能放行一辆。大语言模型的推理就像这条公路:每个 token 的生成必须等前一个完全结束,GPU 算力再强也只能排队等待。

随着模型规模膨胀到数千亿参数,这个串行瓶颈已经从"有点烦人"变成"难以忍受"。DeepSeek-V4 的线上服务曾经受此拖累,直到一套新机制的引入彻底改变了局面。

这套机制叫 DSpark。在同样的服务等级协议(SLA)下,它将引擎吞吐量提升了 51%,每位用户的实际响应速度加快了 60% 到 85%。在高交互场景下,吞吐量甚至可以提升 661%。

它的核心是投机解码(Speculative Decoding)。本文将从直觉到公式,逐步拆解这项技术,并解释 DSpark 为什么选择了第三条路。


一、投机解码的数学本质

1.1 大模型推理为什么慢

大模型推理的本质是串行自回归(Autoregressive Generation)。给定前 k 个 token,模型计算第 k+1 个 token 的概率分布,采样后再作为下一步的输入。

这个过程无法并行,因为第 k+1 个 token 的输入依赖于第 k 个 token 的输出。模型参数量越大(如 DeepSeek-V4),单次前向计算的延迟越高,串行瓶颈就越严重。

(图注:每个 token 必须等待前一个完成,形成串行依赖链,GPU 利用率受限。)

1.2 投机解码的核心直觉

投机解码的核心思想可以用一个职场类比概括:让实习生(Draft Model)快速写出草稿,老板(Target Model)只做批量审核和签字。

具体来说,一个轻量级的小模型先一次性猜测接下来的若干个 token。然后大模型将候选 token 打包验证,用拒绝采样(Rejection Sampling)保证输出分布与直接自回归完全一致。

只要小模型猜得够准,大模型就能一次性"批准"多个 token,原本串行的多步压缩成一步。更重要的是,这种加速是数学上无损的,输出质量不会下降。

1.3 加速比公式与两个维度

加速比由以下公式严格定义:

\eta = \frac{T_{\text{target}}}{(T_{\text{draft}} + T_{\text{verify}}) / \tau

其中各符号含义如下:

符号 含义
\et \et \et 加速比
T_{\text{target} target model 自回归单 token 延迟
T_{\text{draft} draft model 生成候选的延迟
T_{\text{verify} target model 验证候选的延迟
\ta \ta \ta 期望接受的 token 数(含 bonus token)

从公式可以清晰看出,加速比取决于两个独立维度。第一是算法层面的接受率, \ta \ta \ta 越大越好;第二是系统层面的延迟比,T_{\text{draft} 与 T_{\text{verify} 的比值越小越好。

不同 draft 策略在这两个维度上的表现截然不同。因此选择什么样的 draft 生成方式,直接决定了投机解码方案的理论天花板和实际落地效果。


二、Draft 策略的三种范式

目前学术界和工业界的 draft 策略可以归纳为三大范式。它们在延迟和接受率之间做着不同的权衡,没有一种能在所有场景下通吃。

理解这三种范式的差异,是理解 DSpark 设计选择的前提。

2.1 自回归 Draft:以 EAGLE-3 为代表

自回归 draft(Autoregressive Draft)沿用与 target model 相同的生成方式:逐个 token 顺序预测。EAGLE-3 是该路线的代表方法。

它的延迟随 draft 长度线性增长,公式为 T_{\text{draft}} = \gamma \times t_{\text{step}。为了控制总延迟,自回归 draft 通常只能使用极浅的网络(EAGLE-3 往往只有 1 层)。

因为每一层 draft 网络都必须等待前一层的输出,计算图是严格串行的。这是自回归范式的结构性代价。

这种策略的优点是保持了 token 间的自然依赖,接受率较高。缺点是 draft 长度和模型深度都被延迟严格限制,难以扩展到更长的候选序列。

2.2 并行 Draft:以 DFlash 为代表

并行 draft(Parallel Draft)采用完全不同的思路:用单次前向传播同时预测整个 block 内的所有 token。DFlash 是该范式的典型代表。

它的最大优势是延迟近似常数,T_{\text{draft}} \approx t_{\text{parallel},与 block 长度基本无关。这使得 draft 模型可以做得更深、预测得更远,而不必担心延迟线性膨胀。

但纯并行预测存在一个致命缺陷------后缀衰减(Suffix Decay)。越靠后的位置,预测质量越差,因为每个位置的预测条件独立,没有利用到已经生成的左侧 token 信息。

当 block 长度增加到 5 个以上时,DFlash 的远端 token 接受率会急剧下滑,这直接限制了它能带来的实际加速。

(图注:三种策略在延迟-接受率平面上的分布示意。)

2.3 半自回归 Draft:DSpark 的答案

DSpark 的答案是半自回归(Semi-Autoregressive)draft。它在并行 backbone 的基础上,叠加极低开销的顺序校正,试图兼得低延迟与高接受率。

具体而言,DSpark 先用一个 5 层的小型 Transformer 并行预测整个 block,再通过轻量的 Markov 顺序校正头在相邻 token 之间引入依赖。总延迟仍近似常数,仅增加一个极小的 \epsilo \epsilo \epsilo。

实验表明,DSpark 在延迟与接受率的二维平面上处于帕累托前沿(Pareto Frontier)。它既享有并行 draft 的低延迟,又接近自回归 draft 的高接受率,从而在生产环境中取得了显著优势。

这种"先并行、后校正"的混合思路,正是 DSpark 区别于现有方案的核心创新。下一部分将深入其架构细节。

(图注:DSpark 位于帕累托前沿,打破了"低延迟 vs 高接受率"的权衡困境。)


三、DSpark 架构深度解析

3.1 架构总览

DSpark 的 draft 模型由三个组件精密协作而成。

第一个是 Parallel Backbone,负责一次性并行预测整个 token block 的独立分布。

第二个是 Markov 顺序校正头,在并行预测结果上叠加 token 间依赖,实现半自回归效果。

第三个是信心头,预估每个 draft token 被目标模型接受的概率,为调度器提供决策依据。

三者协同的核心公式可概括为:

\text{Draft}(x_k | x_

Backbone 提供上下文相关的先验分布,Markov 头注入序列依赖的修正量,信心头则量化预测可信度。

这条公式揭示了 DSpark 的半自回归本质:backbone 负责"并行猜",Markov 头负责"顺序修",两者叠加后既保留了并行速度,又获得了接近自回归的质量。

3.2 并行 Backbone

并行 Backbone 的核心任务是用一次前向传播预测整个 block。

为了告诉模型"这些位置有待预测",DSpark 借用了 Qwen3 预训练中的 Fill-in-the-Middle 特殊 token <|fim_middle|>(token_id=151669)。

它的 embedding 天然编码了"此处内容未知,需要推断"的语义,比普通 mask 更具表达力。

这里有一个关键直觉:普通的 mask token 在预训练中很少出现,模型看到它时未必知道该做什么。而 FIM token 在 Qwen3 的代码补全场景中被大量使用,其向量空间中已经形成了稳定的"待填充"语义。

具体构造方式非常简洁:选取一个真实锚点 token,后面紧跟 7 个 <|fim_middle|> mask token,组成 8 长度的预测窗口。

训练时,每份样本从 response 部分随机采样 512 个锚点位置,相当于做了大规模数据增强。

锚点的选择不是均匀的,而是限定在 response 区域内,确保 draft 模型学习的是真实生成分布,而非前缀提示的分布。

Backbone 本身是一个 5 层的小型 Transformer,参数量远小于目标模型。

这 5 层网络是可训练参数的主体,其余部分如 embedding 和 lm_head 均从目标模型拷贝并冻结。

它的 attention 设计尤为关键:Q 只来自 draft token 自身,K/V 则拼接了目标模型的上下文 hidden states 与 draft block 内部的 hidden states。

双源 attention 的巧妙之处在于分工明确:draft token 通过 Q 查询自己需要什么信息,而通过 K/V 从两个信息源中获取答案。

一个源是目标模型深层抽取的上下文语义,另一个源是 draft block 内部的横向交互。两者拼接后供给 attention 计算。

这种设计让 draft 模型无需重新编码长上下文,直接复用目标模型已计算好的深层特征。

目标 hidden 从 Qwen3 的第 1, 9, 17, 25, 33 层提取,融合后通过 RMSNorm 和线性投影注入 attention 的 K/V 路径。

既省计算又保精度,这是 DSpark 能在生产环境立足的工程基础。

5 层的深度是经过消融实验验证的:再深一层带来的质量增益有限,但延迟显著上升;再浅一层则无法充分提取 block 内的复杂模式。

3.3 Markov 顺序校正头

并行预测有一个根本缺陷:block 内每个位置的输出彼此条件独立。

数学上,backbone 给出的是 P(xk∣context P(x_k | \text{context} P(xk∣context,每个 $$$$ 互不影响。

这导致越靠后的 token 预测质量越差,也就是上文提到的后缀衰减问题。

实验数据显示,纯并行方案在位置 5 到 7 的接受率会急剧下跌,因为模型完全不知道前面已经生成了什么。

真实文本中,相邻 token 之间存在强依赖。DSpark 的核心假设是:x_ 的分布主要由前一个 token x_{k-1 决定。

这一假设被称为 Markov 性质,它让极轻量的顺序校正成为可能。

校正操作非常直接:在 backbone 输出的独立 logits 上,叠加一个基于前序 token 的偏差项。

logitscorrectedk=logitsbackbonek+bias( xk−1 \text{logits}{\text{corrected}}k = \text{logits}{\text{backbone}}k + \text{bias}(x_{k-1} logitscorrectedk=logitsbackbonek+bias(xk−1

论文探索了三种 Markov 头的实现变体:

类型 公式 参数量 特点
VanillaMarkov W2(W1( xk−1 ) W_2(W_1(x_{k-1}) W2(W1(xk−1) \appro \appro \appro 78M 低秩分解,仅看前一个 token
GatedMarkovHead W2(σ(gate)⊙W1( xk−1 ) W_2(\sigma(gate) \odot W_1(x_{k-1}) W2(σ(gate)⊙W1(xk−1) + d×d \times 用 backbone hidden 做门控调制
RNNHead GRU(state, W_1(x_{k-1}), h_) + 3r(2r+d) 累积全部历史信息

GatedMarkovHead 在 Vanilla 基础上增加了门控机制,允许 backbone 的当前 hidden state 调制偏差强度。

RNNHead 则更为复杂,它在 block 内部维护一个循环状态,理论上能捕获更长距离的依赖,但延迟也相应增加。

实际部署中,VanillaMarkov 以极简的结构和极低的延迟成为默认选择。78M 的参数量对整体吞吐影响极小。

训练时采用 teacher forcing:Markov 头总是看到真实的前序 token,而非自己上一轮的预测结果。

这意味着训练过程中梯度传递稳定,模型学习的是最理想的条件分布。

推理时则改为自回归采样:每步用上一时刻采样的 token 作为下一步的输入,循环 8 次完成整个 block。

整个过程没有 attention,没有 MLP,只有两次矩阵乘法,生成 8 个 token 仅需约 50μs。

相比 backbone 的前向传播,这个开销可以忽略不计,却显著提升了远端 token 的预测质量。

实验表明,加入 Markov 校正后,位置 5 到 7 的接受率明显优于纯并行方案,接近自回归 draft 的水平。

这正是半自回归范式的核心价值:用极小的顺序开销,换取显著的质量提升。

3.4 信心头

信心头是 DSpark 中最轻量的组件,仅由一个线性层构成。

它接收 backbone 的 hidden states,输出每个 draft token 被目标模型接受的预估概率 a_。

这个概率是硬件感知调度器的核心输入。调度器需要依据 a_ 动态决定每轮验证多少 token。

验证太少浪费并行度,验证太多则拖慢 throughput,这是一个精细的权衡。

如果信心估计不准,调度器就会做出错误决策。因此,校准质量直接决定系统收益。

DSpark 使用 BCE(Binary Cross Entropy)损失训练信心头,让预测分数与实际观察到的接受率尽可能一致。

BCE 损失比较预测概率与实际二值标签(接受为 1,拒绝为 0),通过梯度下降强迫模型输出经过 Sigmoid 后落入合理区间。

未经校准的信心估计常常过于乐观或悲观,导致调度器系统性地高估或低估验证收益。

上图是可靠性图(Reliability Diagram),横轴为预测信心分桶,纵轴为对应桶内的真实接受率。

理想情况下,所有点应落在对角线上。经过 BCE 校准后,信心头的输出与实际接受率高度吻合。

离对角线越远的点,意味着模型在该信心区间内的估计越不靠谱,调度器据此做决策就会犯错。

论文还扫描了不同信心阈值对系统的影响。

校准后的信心头让调度器能在「激进」与「保守」之间找到最优平衡点------阈值设太低混入低质量 draft,设太高则浪费并行预测能力。


4. 训练策略

4.1 损失函数设计

训练 draft 模型的目标,是尽可能模仿目标模型(Target Model)的输出分布。DSpark 没有使用单一的交叉熵(Cross Entropy, CE),而是设计了一个三项加权复合损失。

公式如下:

\mathcal{L}{\text{DSpark}} = \alpha{\text{CE}} \cdot \mathcal{L}{\text{CE}} + \alpha{\text{L1}} \cdot \mathcal{L}{\text{L1}} + \alpha{\text{conf}} \cdot \mathcal{L}_{\text{BCE}

三项损失各司其职:

损失项 含义 权重 作用
\mathcal{L}_{\text{CE} 交叉熵 token 预测 0.1 预测正确 token
\mathcal{L}_{\text{L1} \sum\|\text{softmax(draft)} - \text{softmax(target)}\ 0.9 分布对齐(核心)
\mathcal{L}_{\text{BCE} 信心头校准 1.0 准确估计接受率

最反直觉的是:L1 权重为 0.9,是 CE 的九倍。为什么?

投机解码的接受率取决于 draft 分布与 target 分布之间的 TV 距离,而不是 token 是否精确匹配。即使 draft 猜错了具体 token,只要两个分布足够接近,验证时依然大概率通过。

L1 损失直接优化的是分布距离而非 token 匹配精度,因此权重远高于 CE。

为了让模型更关注近期预测,DSpark 对位置 $$$$ 施加指数衰减权重:

w_k = e^{-k/\gamma

其中 γ=4.\gamma = 4. γ=4.。越靠后的位置权重越低------远处的 token 本来就难预测,不必分配同等监督强度。

训练时,每个样本随机采样 512 个锚点位置。锚点必须落在 response 区域内,确保模型只学习生成答案,而非模仿用户提问。

4.2 训练流程

DSpark 的训练依赖一个关键前提:目标模型的隐藏状态需要提前算好并缓存下来。

它被称为 Target Cache。以 Qwen3-4B 为例,完整缓存约 38TB。尽管存储开销巨大,它省去了训练时反复运行目标模型前向,显著提升迭代效率。

整个训练流程分为三步:数据准备、模型训练、效果评估。

在数据准备阶段,系统先用目标模型重新生成答案,再提取第 1、9、17、25、33 层的隐藏状态写入缓存。训练阶段直接读取缓存,配合锚点采样策略进行迭代。

关键超参数如下:

参数 说明
学习率 6.0 \times 10^{-4 AdamW
Warmup 比例 0.04 线性 warmup
全局 batch size 512 8 卡数据并行
训练轮数 10 覆盖充分
Block size 7 Draft 长度
Draft 层数 5 Backbone 深度
Markov rank 256 低秩维度
精度 bf16 混合精度
最大长度 4096 序列截断

所有配置均已开源在 DeepSpec 仓库中。修改 config/dspark/dspark_qwen3_4b.py 即可复现或调整实验。


5. 硬件感知前缀调度器

5.1 调度核心:应该验证多少 token?

投机解码每轮都要回答一个问题:这次验证几个 draft token?

静态长度显然不够聪明。验证太少,浪费并行能力;验证太多,可能拖垮系统吞吐。

DSpark 的调度器将这个问题转化为一个优化目标:

Θℓ= (1+ ∑k=1ℓ ak) ×SPS(ℓ+1 \Theta_\ell = \left(1 + \sum_{k=1}^{\ell} a_k\right) \times \text{SPS}(\ell + 1 Θℓ=(1+∑k=1ℓak)×SPS(ℓ+1

左边 Θ\el \Theta_\el Θ\el 是期望吞吐。右边第一项是预期接受的 token 数,第二项 \text{SPS(Steps Per Second) (ℓ+1(\ell+1 (ℓ+1 是目标模型在验证 ℓ+\ell+ ℓ+ 个 token 时的实际硬件步频。

注意 SPS(ℓ\text{SPS}(\ell SPS(ℓ 不是平滑曲线。它在 ℓ=\ell= ℓ= 附近会出现一个硬件悬崖

这是因为 GPU kernel 会在序列长度超过阈值时切换实现,比如从 FlashAttention 降级到标准 attention。吞吐量瞬间腰斩。

例如,设信心头给出 a1=0.8,a2=0.7,a3=0. a_1=0.8, a_2=0.7, a_3=0. a1=0.8,a2=0.7,a3=0.,而 SPS 剖面为 [1.0,0.95,0.52,0.48,...[1.0, 0.95, 0.52, 0.48, \ldots [1.0,0.95,0.52,0.48,...。

逐项计算结果:

Θ0=1.00,Θ1=1.71,Θ2=1.23,Θ3=1.1 \Theta_0 = 1.00, \quad \Theta_1 = 1.71, \quad \Theta_2 = 1.23, \quad \Theta_3 = 1.1 Θ0=1.00,Θ1=1.71,Θ2=1.23,Θ3=1.1

最优解是 ℓ=\ell= ℓ=。即使后面还有可用的 draft token,验证它们反而降低整体效率。没有硬件感知就会错选 ℓ=\ell= ℓ=。

搜索策略采用因果贪心:从 ℓ=\ell= ℓ= 开始递增,一旦发现 \Theta_\ell < \Theta_{\ell-1 立刻终止。

这个 early-stop 不是工程偷懒,而是数学必需。Appendix A 的证明指出,如果去掉 early-stop 做全局最优搜索,调度器会向后窥视未来 token 的取值,引入选择偏差,破坏无损解码的理论保证。

此外,调度器还会根据当前负载自适应调整:

低并发时延长验证长度到 4-6 个 token,充分利用闲置算力。高并发时自动缩回至 2 个 token 左右,防止 batch 被低质量候选撑爆。

5.2 零开销调度 (ZOS)

调度器本身的计算极其轻量:不到 1μs,仅十次浮点运算。

它藏在哪儿?GPU 从 backbone forward 切换到 target verify 时,kernel launch gap 约 10μs。调度器就在这 10μs 内完成全部决策。

信心分数 a_ 并非额外计算,而是 backbone forward 的副产品。对 backbone 的最后一个隐藏状态做一次 sigmoid 即可得到,甚至不用等 Markov 采样结束。

数据从 GPU 拷贝到 CPU 也是异步的,non_blocking=True 让传输与后续计算重叠。

更大的并发发生在 target verify 阶段:target model 的验证过程是 memory-bound,GPU 计算单元大量空闲。

此时 CPU 可并行准备下一轮:确定新的锚点、构造 noise embedding、预取 target hidden states。

这样一来,调度完全没有占用额外的时间片,故称为 Zero-Overhead Scheduling。


6. 实验结果

6.1 离线 benchmark 与生产部署

在离线评测中,DSpark 相比 EAGLE-3 的 macro-average accepted length 提升了 30.9% (Qwen3-4B)、26.7%(8B)和 30.0%(14B)。

相比 DFlash,提升幅度为 16.3% (4B)、18.4%(8B)和 18.3%(14B)。

从位置维度看,DSpark 在 position 5-7 的远端位置依然维持高接受率。纯并行方案(DFlash)在这些位置急剧衰减,而 DSpark 的 Markov 头有效抑制了后缀衰减。

论文中的 fig02、fig03、fig04 分别展示了按位置接受率、drafter 深度影响以及 proposal length 的影响,读者可对照原文查看细节。

在生产环境 DeepSeek-V4 上,DSpark 已完成全量替换。以下是线上实测数据:

引擎 SLA 锚点 吞吐量增益 每用户速度提升
V4-Flash 80 tok/s/user +51% +60%~85%
V4-Flash 120 tok/s/user(高交互) +661% ---
V4-Pro 35 tok/s/user +52% +57%~78%
V4-Pro 50 tok/s/user(高交互) +406% ---

高 SLA 点的增益看起来惊人,原因是基线 MTP-1 在这些位置已接近操作极限。DSpark 的实际意义是扩展了可行交互性前沿。

这里需要解释一个常见疑问:为什么生产对比的是 MTP-1,而不是论文离线实验里的 DFlash?

因为 MTP(Multi-Token Prediction)-1 才是 DeepSeek-V4 发布前的生产基线。它是一个附着在目标模型上的单 token 预测头。在高并发下,MTP-3/5 的静态多 token 验证会严格降低吞吐,所以 MTP-1 长期是唯一不会崩的选择。

DFlash 则没有跑在 DeepSeek-V4 的自研推理引擎上。V4 使用 index-attention 和 compress kernel,与标准 Transformer 不同。因此生产部署只能对比同引擎内可替换的基线。

6.2 方法对比总结

把 DSpark 与 EAGLE-3、DFlash 放在一起比较,差异一目了然:

维度 EAGLE-3 DFlash DSpark
生成方式 自回归 块扩散(并行) 半自回归(并行+顺序)
Draft 延迟 随长度线性增长 近似常数 近似常数
顺序校正 有(串行) 有(Markov 低秩)
信心头
硬件感知调度
生产部署 仅开源 仅开源 DeepSeek-V4 线上
适用场景 离线实验 离线实验 生产服务

EAGLE-3 的接受率不低,但自回归 draft 的延迟随 block size 线性增长,限制了它在高并发下的扩展性。DFlash 的并行延迟极低,但没有顺序校正,远端位置质量衰减严重。

DSpark 同时解决了这两个痛点:用并行 backbone 保证低延迟,用 Markov 头恢复 token 依赖,再用信心头和硬件感知调度器把整套系统推进到生产环境。


结论

回顾全文,DSpark 的核心贡献可以总结为三点。

第一,算法层面提出了半自回归范式。它打破了"并行低质量"与"自回归高延迟"之间的传统权衡,在延迟-接受率的二维平面上达到了 Pareto 更优。

第二,系统层面引入了硬件感知前缀调度器。它将投机解码的目标从"加速单个请求"提升为"优化整个服务的吞吐量-交互性帕累托前沿"。SPS 悬崖的发现和 early-stop 的理论保证,让调度器既快又正确。

第三,工程层面完成了从论文到生产的闭环。DSpark 在论文发表后两周内即完成 DeepSeek-V4 的线上全量替换,覆盖 Flash 和 Pro 两条产品线。

如果你想复现或改进这套方案,欢迎访问 DeepSpec 开源仓库。所有训练配置、损失实现和调度逻辑均已开放。

如果这篇文章帮你理清了投机解码的思路,欢迎点赞收藏,下次回顾更方便。


参考资料

  1. DSpark 论文: DeepSpec 仓库同级 DSpark_paper.pdf
  2. DFlash 论文: arXiv:2602.06036 (ICML 2026)
  3. EAGLE-3 论文: arXiv:2503.01840
  4. DeepSpec 代码仓库: GitHub
  5. SpecForge (训练框架基础): GitHub
相关推荐
统计实现局1 小时前
SVD 的三步走:双对角化、Givens 收敛、排序
算法
躬行见万象1 小时前
《VLA 系列》UniLab 强化训练 | G1 机器人 |复现
算法
统计实现局1 小时前
对称不定分解(Bunch-Kaufman):为什么 Cholesky 不够用
算法
统计实现局1 小时前
dqrsl 拆解:拿着 QR 结果能算出哪 5 种东西
算法
统计实现局1 小时前
为什么 Cholesky 求逆比 Gauss-Jordan 快一倍——行列式溢出防护详
算法
To_OC13 小时前
LC 994 腐烂的橘子:人人都说是 BFS 入门题,我却写了三遍才过
javascript·算法·leetcode
金銀銅鐵16 小时前
[Python] 扩展欧几里得算法
python·数学·算法
To_OC19 小时前
LC 200 岛屿数量:经典 DFS 入门题,我第一次写居然连方向都搞错了
javascript·算法·leetcode
To_OC1 天前
LC 128 最长连续序列:别上来就排序,O (n) 解法才是这题的灵魂
javascript·算法·leetcode