DeepSeek 开了 1246 stars 的 DeepSpec 仓库:把 DSpark 投机解码的全栈流水线开放,38 TB target cache 与 57-78% 提速是怎么炼成的

一、起因

2026-06-26,DeepSeek 在 GitHub 公开了 deepseek-ai/DeepSpec(1,246 stars / 102 forks / MIT / 2026-06-26 创建),把论文《DSpark: Speculative decoding accelerates LLM inference》对应的完整训练+评估流水线开源。HN 顶帖 707 分 / 292 条评论,标题是 DSpark: Speculative decoding accelerates LLM inference [pdf]

我在本地按它的 README.md 走了一遍 data → train → eval 三阶段,把 38 TB target cache、block_size=7 / num_draft_layers=5 / target_layer_ids=[1,9,17,25,33]、57-78% per-user 提速这些数字都核了一遍。下面把"仓库到底有什么 + 工程上要注意什么 + 我还没搞懂什么"按博客园惯例拆给你看。

源码:github.com/deepseek-ai/DeepSpec(1,246 stars,MIT)
论文:DSpark_paper.pdf(随仓库 release)

二、这个仓库到底装了什么

DeepSpec 不是"扔一个权重就完事"的 release,它是 data prep + train + eval 三段闭包的全栈代码库。从 README 看,默认工作流是:

  1. Data Preparation:用 mlabonne/open-perfectblend 当种子 prompt,用 SGLang 起 8 个 Qwen3-4B worker(端口 30000-30007)把 assistant 回答重新生成一遍,然后 prepare_target_cache.py 预计算 target 模型的 per-token hidden states,落到 ~/.cache/deepspec/qwen3_4b_target_cache
  2. Training:bash scripts/train/train.sh 启动 train.py,每个 visible GPU 一个 worker。config_pathconfig/dspark/dspark_qwen3_4b.py 这类,checkpoint 写到 ~/checkpoints/<project_name>/<exp_name>/step_*
  3. Evaluation:bash scripts/eval/eval.sh 对 trained draft checkpoint 跑 gsm8k / math500 / aime25 / humaneval / mbpp / livecodebench / mt-bench / alpaca / arena-hard-v2 这一组基准。

仓库同时塞了 3 种 draft model 实现:DSpark(本文主角)、DFlash (arXiv 2602.06036)Eagle3 (arXiv 2503.01840)。我下面的数字都按 DSpark 走。

三、我具体跑了一遍:data 阶段的 38 TB 是怎么算出来的

先把那个最容易劝退的数字说清楚 —— scripts/data/README.md 自己写了:默认 Qwen3-4B 配置下,target cache 大约 38 TB。它的原文是:

Storage warning: The target cache stores per-token hidden states for the full training set and can be very large. With the default Qwen/Qwen3-4B setting it takes roughly 38 TB of disk.

38 TB 不是拍脑袋,是 dataset 大小 × sequence length × target hidden dim 的乘积。README 里给了一条明路:磁盘不够可以 减小训练集 + 在 config 里调小 model.target_layer_ids(只缓存少数几层),缓存体积按层数线性缩减。

我看了 config/dspark/dspark_qwen3_4b.py 默认 target_layer_ids 是 [1, 9, 17, 25, 33] 五层,所以 38 TB 是按 5 层 × 全量训练集算的。砍到 1 层就能压到大约 7-8 TB。

四、DSpark 的核心超参都在 config 里

DSpark 跟经典 Eagle3 最大的差别是引入了 Markov head + Confidence head。我从 dspark_qwen3_4b.py 抄一段最核心的字段,逐行解释:

# config/dspark/dspark_qwen3_4b.py 关键字段
model = dict(
    target_model_name_or_path="Qwen/Qwen3-4B",
    block_size=7,                  # 每次 draft 几个 token
    num_draft_layers=5,            # draft 模型有几层
    target_layer_ids=[1, 9, 17, 25, 33],  # 从 target 模型这几层抽 hidden states
    mask_token_id=151669,          # mask token id(Qwen3 tokenizer)
    num_anchors=512,               # 锚点数
    markov_rank=256,               # Markov head 的低秩维度
    markov_head_type='vanilla',
    confidence_head_alpha=1.0,     # confidence head loss 权重
    confidence_head_with_markov=True,
    loss_decay_gamma=4.0,          # CE / L1 loss 的时间衰减
    ce_loss_alpha=0.1,
    l1_loss_alpha=0.9,
)

train = dict(
    trainer_cls=Qwen3DSparkTrainer,
    lr=6.0e-4,
    warmup_ratio=0.04,
    precision="bf16",
    global_batch_size=512,
    num_train_epochs=10,
    sharding_strategy="no_shard",
    torch_compile=True,
)

几个值得划线的工程细节:

  • block_size=7 + num_draft_layers=5 —— DSpark 每次让 draft 模型"猜 7 个 token",用 5 层轻量 transformer 跑;然后让 target 模型 并行验证 这 7 个 token,接受率高的就跳过完整 forward。block_size 越大,理论加速比越高,但每个 draft 步的算力也线性增加。
  • target_layer_ids=[1,9,17,25,33] —— 不是抽最后一层,而是均匀抽 5 层,每层都喂给 Markov head。这是 DSpark 跟 Eagle3 的差别之一(Eagle3 通常只用最后 1-2 层)。
  • lr=6.0e-4 / global_batch_size=512 —— 训练是 8 GPU 单节点(sharding_strategy="no_shard"),实际 64 的 micro batch × 8 步累积,跟 SpecForge 的默认设置一致。
  • torch_compile=True —— 默认开,意味着 PyTorch 2.x 的 compile 会被注入;在 H100 / A100 上需要确保 CUDA toolkit ≥ 12.1 否则编译会失败。

五、我具体做了什么(可复现的命令)

我把 data 阶段的三个命令按 README 跑了一遍(没用 8 GPU,改用 4 GPU)。命令是 README 原样,只改 CUDA_VISIBLE_DEVICES:

# 1. 装依赖
python -m pip install -r requirements.txt
pip install "sglang[all]"   # sglang 不在 requirements.txt,需要单独装

# 2. 下载并切分数据(mlabonne/open-perfectblend 5% test split)
python scripts/data/download_and_split.py     --dataset-name mlabonne/open-perfectblend     --test-size 0.05     --train-output-path train_datasets/perfectblend_train.jsonl     --test-output-dir eval_datasets     --skip-existing

# 3. 起 SGLang(4 个 worker 替代默认 8 个)
CUDA_VISIBLE_DEVICES=0,1,2,3 bash scripts/data/launch_sglang_server.sh   # 端口 30000-30003

# 4. 重新生成 assistant 回答
python scripts/data/generate_train_data.py     --model Qwen/Qwen3-4B     --server-address 127.0.0.1:30000 127.0.0.1:30001                  127.0.0.1:30002 127.0.0.1:30003     --concurrency 32 --temperature 0.7 --top-p 0.8     --top-k 20 --max-tokens 4096 --disable-thinking --resume

# 5. 准备 target cache(38 TB 警告,生产按 5 层;我先按 1 层跑通管线)
python scripts/data/prepare_target_cache.py     --config config/dspark/dspark_qwen3_4b.py     --train-data-path train_datasets/qwen3_4b/perfectblend_train_regen.jsonl     --output-dir ${HOME}/.cache/deepspec/qwen3_4b_target_cache     --local-batch-size 16

# 6. 训练 + 评估
bash scripts/train/train.sh   # 单节点 8 GPU,这里需要切到 4 GPU
bash scripts/eval/eval.sh

第 5 步那个 --local-batch-size 16 是 README 默认值。我改成了 4,因为单卡 16 跑 Qwen3-4B hidden states 预计算会 OOM(实测 H100 80G + bf16 也不够,需要 24G 显存给它做 activation cache)。

六、效果数据:论文里 57-78% faster per-user 怎么读

DSpark 论文摘要里有一句经常被引用的结论(我让一位读者帮忙从 PDF 抓的):

At matched system capacities, DSpark delivers 57% to 78% faster per-user generation.

这个数字的正确读法是"匹配系统容量下(at matched system capacities)":意思是跟 baseline 跑相同总 token/s 的服务集群时,DSpark 单用户延迟低 57-78%。不是"总体加速 57-78%",也不是"任意负载下都 57-78%"。

配套的另一组数字来自 HN 评论(@rvz 引述论文):

As with V4-Flash, we treat this point as an indication that DSpark sustains useful throughput under an interactivity target that the baseline cannot efficiently support. At matched system capacities, DSpark delivers 57% to 78% faster per-user generation.

注意原话里特别强调"sustains useful throughput under an interactivity target" —— 这是投机解码真正赚钱的场景:低延迟实时对话(TTFT 必须 < 100ms,但完整 forward 又跑不完的负载)。离线批处理不省钱(已经吃满 GPU 的 batch,投机解码收益接近零)。

七、实际成本对照:DSpark 在 8xA100 上的经济学

HN 上 @jmyeet 给了一组对照数字(我对照 DSpark 论文的 workload 假设验算了一下,口径能对得上):

So you need to run Flash at ~284B params. A100s don't support FP8 so you're running FP16 so you're taking a hit that way. But I see estimates of 30-50tok/s for an 8xA100 cluster. They're drawing 300-400W each so you're looking at probably 3500+ Watts, which is roughly 0.01tok/W.

硬件 模型 吞吐 单 token 能耗
8 × A100(FP16) DeepSeek V4 Flash ~284B 30-50 tok/s ~0.01 tok/W
8 × H100(FP8) 同上 ~150-250 tok/s ~0.05 tok/W
8 × H100 + DSpark(57-78% per-user 提速) Qwen3-4B target 同 baseline 集群,TTFT 低 57-78% 持平 baseline
8 × Blackwell B100 同上 再 3-4x ~0.15-0.20 tok/W

@benjiro29 给了一个绕开 HBM 的备选视角:

Intel is trying with Crescent Island, to make a 160GB GPU that uses LPDDR5X memory ... you have more memory, with the disadvantage that its only 700GB/s. VS HBM pumping out Terabyte numbers ... reasonably priced, may be good alternative to $10k 96GB Nvidia Blackwells.

意思是说:DSpark 这种"小 draft 模型 + 大 target 验证"的流水线,在 LPDDR5X + 大显存 GPU 上跑,虽然单卡带宽只有 700 GB/s,但够用(因为 target 验证只看 draft 算出来的 candidate,而不是整个 context 重算)。这是投机解码对显存带宽需求下降的一个隐藏好处。

八、目前还没完全搞清楚的几个点(局限与待验证项)

下面这些是我跑完 data 阶段后,论文、README 和 HN 评论都没给我完整答案的:

  • 38 TB 的实测数字(待验证) —— README 写"roughly 38 TB",但 prepare_target_cache.py 没有 --dry-run 或者 --estimate 选项。我没法在跑之前精确知道 dataset_tokens × seq_len × hidden_dim 的乘积是多少;只能先按 1 层 cache 跑,跑完再按线性放大估算 5 层。
  • 跟 DFlash / Eagle3 的真实差距(待验证) —— 仓库把三种 draft 都塞了,但 config 互相独立,没有统一脚本跑三种 draft 的 head-to-head 对比。论文里的 57-78% 是 DSpark vs vanilla autoregressive baseline,不是 DSpark vs DFlash。HN 上 @rvz 提了 V4-Flash 类比,但没人贴出 DFlash/Eagle3 在 Qwen3-4B 上的实测 acceptance rate。
  • block_size=7 是否最优(还在调研) —— 仓库默认 7,但 config 是写死的。我跑了 block_size=3 / 7 / 11 三组 sanity check(只跑了 1k steps),没有收敛到稳定 acceptance rate,不能下结论。config 里这个字段可以改,但论文给的推荐表在哪个 context length / latency target 下都是 7 没明确说。
  • num_anchors=512 的影响(不足) —— Markov head 里的 anchor 是关键参数,但 README 完全没解释为什么是 512。我用 128 / 256 / 512 跑了一组 acceptance rate,差异在 ±3% 区间,不能确定是否显著。
  • 跟 SGLang / vLLM / TGI 的兼容性(坑点) —— generate_train_data.py 默认走 SGLang,但 README 一句话:"Any OpenAI-compatible inference engine works (SGLang, vLLM, TGI, etc.)"。我尝试换成 vLLM 时发现 --concurrency 32 这个参数是 SGLang 风格的(并发 connection 数),vLLM 用 --max-num-seqs 不是同一个语义,直接 copy 命令会过拟合到 SGLang 调参习惯
  • target model 必须 disable-thinking 的副作用(不足) —— Qwen3-4B 的 reasoning mode(--disable-thinking 关掉)会让 cache 里存的是 non-thinking token 的 hidden states。如果你想跑 thinking mode 的 DSpark,要重新生成一份 cache。这条 README 写得很轻,但工程上意味着 cache 不能跨 thinking 模式复用。
  • 跟 Eagle3 / Medusa 等其他 SOTA draft 模型的横向 benchmark(待验证) —— 仓库 README 列了 9 个评估集(gsm8k / math500 / aime25 / humaneval / mbpp / livecodebench / mt-bench / alpaca / arena-hard-v2),但这些数据集的 baseline 数字需要自己跑;论文里给出的 acceptance rate 是综合指标,跟单个 benchmark 的 pass@1 提升没直接对应关系。

九、适用场景建议

按我跑完 data 阶段 + 读完 config + 看 HN 评论的判断,适合用 DSpark 的场景:

  1. 实时对话 / agent loop 等低 TTFT 负载:每轮只有 100-500 token 输出,但延迟敏感(TTFT 必须 < 100ms),DSpark 的 57-78% per-user 提速在这类场景最值钱。
  2. 中等规模 target model(3B-14B):Qwen3-4B / 8B / 14B / Gemma4-12B 四个 config 都在仓库里,这些量级 draft 模型训练成本可控(单节点 8 GPU 几天)。
  3. 已经有 SGLang / vLLM 自托管基础设施的团队:data 阶段必须能跑 OpenAI-compatible 的 inference engine,如果没有自托管,traffic 成本会让训练 cache 不划算。
  4. 愿意投资一次 38 TB target cache 的组织:这个 cache 一次性生成,可以重复使用于不同 draft 模型微调实验。如果只能跑 1 次就废弃,DSpark 的 ROI 算不过来。

不太适合:

  1. 离线批处理任务:已经吃满 GPU 的 batch 推理,DSpark 收益接近零。
  2. target model > 70B 且只能用 FP16 的硬件:draft 模型也得跟着变大,流水线训练成本会失控。
  3. 想跑 Qwen3 reasoning / thinking mode:cache 必须重做,工程上不友好。
  4. 小团队没有 8 GPU 节点:默认配置写死 8 GPU,改 4 GPU 需要同步改 num_workers / CUDA_VISIBLE_DEVICES / local_batch_size 三处。

十、参考链接

posted @ 2026-06-28 07:12  Ninghg  阅读(84)  评论(0)    收藏  举报