基准测试 · DeepSeek-V4.1-Flash-1017 · 8×B300

超过 60 万 tokens/s:DeepSeek 4.1 Flash 在 8×B300 上,vLLM 对比 DeepInfer

DeepSeek 开源了 DeepInfer,也就是支撑其自家服务的推理引擎。我们在一台 8×B300 节点上,用 DeepSeek-V4.1-Flash-1017 把它和 vLLM 正面对比:模型如何放进显存,两个引擎在输出和预填充上分别能跑多快,以及为什么 DeepInfer 在单节点上落后。

10 月 21 日更新。本文第一版用默认设置运行 DeepInfer。我们当天按 DeepSeek 为 V4.1 推荐的设置(包括 bounded replay)重新运行;表格同时列出两次结果,所有对比都取其中较好的一次。
658K单节点预填充 tokens/s,vLLM,8K 提示
55.0K1K → 1K 输出 tokens/s;短提示 65.0K
2–4×vLLM 解码领先 DeepInfer,预填充领先 8×
88 秒warmctl up,冷启动需 930 秒
DeepSeek-V4.1-Flash-1017 · 单台 8×B300 · 2,048 并发(32K 为 512)vLLM 对比 DeepInfer
vLLM DeepInfer decode · 128 → 1K 65.0K output tok/s 36.4K 1.8× decode · 1K → 1K 55.0K output tok/s 27.9K 2.0× decode · 8K → 1K 29.5K output tok/s 7.3K 4.0× prefill · 8K prompts 658K input tok/s 72K 9.2× prefill · 32K prompts 590K input tok/s 72K 8.2×

01 · 为什么新的推理引擎:DeepInfer

10 月,DeepSeek 开源了 DeepInfer,按官方的说法,它是“支撑 DeepSeek 大规模生产服务的高性能推理框架”。它自带 DeepSeek 也单独发布的内核(FlashMLA、DeepGEMM、DeepEP、DeepSelect),支持数据并行注意力加专家并行 MoE,以及 DSpark 投机解码。DeepInfer 最初基于 vLLM 构建,而 vLLM 也有一份针对该模型在 B300 上的 recipe,用的内核大多相同。

于是问题很直接:在一台 8×B300 上,也就是大多数团队能租到的最大单元,两者差距有多大?我们在两个引擎上运行 DeepSeek-V4.1-Flash-1017,把输出和预填充都推到节点极限。

02 · 两个引擎vLLM 与 DeepInfer:区别在哪

两个引擎运行同一个模型,内核也大多相同,扩展方式也一样:每张 GPU 复制一份注意力,专家分布在各 GPU 上。区别在于定位和形态。vLLM 是装上就能对外服务的通用引擎;DeepInfer 是 DeepSeek 自家服务的核心,但开源时没有带上周边的服务系统。

vLLMDeepInfer
定位通用开源推理引擎和服务端DeepSeek 的生产引擎,为单一模型开源
模型数百个开源模型,包括本模型仅 DeepSeek-V4.1-Flash
硬件NVIDIA、AMD、TPU 等NVIDIA SM100(B200、B300、GB200)和华为昇腾 950
接口兼容 OpenAI 的 HTTP 服务,支持工具调用和推理解析Python API,离线批处理(LLM.generate),没有服务端
安装Docker 镜像或 pip wheel从源码构建:GCC 13、CUDA 13,NVCC 13.1 或更新
亮点前缀缓存、结构化输出、LoRA、通过 KV connector 的 PD 分离DSpark 与置信度调度验证、批次不变推理、确定性采样
未包含—KV 缓存系统、预填充/解码分离、负载均衡
设计目标任意规模,从单卡开始一个 NVLink 域内:预填充每组 4 卡,解码每组 64 卡

03 · 配置8×B300,一个模型,两个引擎

系统配置
GPU8× NVIDIA B300 SXM6 AC,每卡 275 GB HBM3e,NVLink 5 经 NVSwitch 互联
主机192 vCPU、2.7 TB 内存、6 块本地 NVMe 组成 RAID 0(21 TB)
模型deepseek-ai/DeepSeek-V4.1-Flash-1017,476 GB:专家为 FP4,其余为 FP8,两张 3.84 亿行的 Engram 表
vLLM0.31.1rc1,vLLM B300 recipe 的镜像,NVIDIA 驱动 610.57.04;DEP8,每个 rank 256 条序列、每步 8K token,DSpark 5 个草稿 token
DeepInferdeepseek-ai/DeepInfer 8b16149(10 月 20 日),用 CUDA 13.2 从源码构建;EP8 × DP8,DSpark 5 个草稿 token,离线 API;B300 SXM6 PC,驱动 580
warmctlv2.0.0-beta.10,快照 deepseek-v41-flash-1017:8xb300ac-275gb-610.57.04,851 GiB
负载通过 OpenAI API 运行 vllm bench serve:随机 token 提示,固定输出长度(--ignore-eos),提示数为并发数的两倍;DeepInfer 通过 LLM.generate 在进程内接收同样的提示

vLLM 的数据来自 warmctl 恢复的引擎,并与前一天在另一台节点(B300 SXM6 PC)上原生启动的同一 recipe 对比。随机提示是投机解码的最坏情况:DSpark 在 1K 时接受了 19% 的草稿,8K 时 12%。真实文本的接受率更高,因此这里的解码数据都是下限。

04 · 布局DEP8 如何把模型放到八张 GPU 上

这是一个混合专家模型:每层 384 个路由专家加 1 个共享专家,每个 token 激活 6 个路由专家。注意力是 MLA 的稀疏变体:128 token 的滑动窗口,加上一个从更早的 token 中挑出最相关 512 个的索引器,因此每步开销几乎不随上下文增长。两张 Engram 表是模型查表而非计算得到的 n-gram 嵌入,占检查点的 40%。

vLLM 的 recipe 以 DEP8 运行:数据并行注意力、专家并行 MoE。每张 GPU 运行自己的一份注意力,处理自己的请求和 KV 缓存,并持有 384 个专家中的 48 个。在每个 MoE 层,GPU 之间通过 NVSwitch 交换 token,让每个 token 到达它被路由到的 6 个专家,再把结果交换回来。

8×B300 上的 DEP88 个副本 · 每卡 1/8 的专家
GPU 0 attention KV cache 160 GiB 48 experts GPU 1 attention KV cache 160 GiB 48 experts GPU 2 attention KV cache 160 GiB 48 experts GPU 3 attention KV cache 160 GiB 48 experts GPU 4 attention KV cache 160 GiB 48 experts GPU 5 attention KV cache 160 GiB 48 experts GPU 6 attention KV cache 160 GiB 48 experts GPU 7 attention KV cache 160 GiB 48 experts NVLink · NVSwitch: tokens to their experts and back (all-to-all), every MoE layer Engram 1/8 Engram 1/8 Engram 1/8 Engram 1/8 Engram 1/8 Engram 1/8 Engram 1/8 Engram 1/8 host RAM, pinned: each rank keeps 1/8 of the Engram rows (23.6 GiB) and gathers the rows it needs from the others every step

每张 GPU 还剩很多空间。一个 rank 需要的权重是 46 GiB;profile 固定预留 160 GiB 给 KV 缓存,使用 DeepSeek 的 NVFP4 MLA 格式,vLLM 统计每个 rank 能容纳 52 百万个 token,相当于 264 个满 196K 上下文的请求。限制这台节点的不是显存,而是每个 rank 256 条运行中的序列,整节点 2,048 条。

一张 B300 · 268.6 GiBDEP8 rank
weights: 45.8 GiB 46 GiB KV cache: 160.0 GiB 160 GiB CUDA graphs: 8.0 GiB buffers and headroom: 54.7 GiB 55 GiB weights · 45.8 GiB KV cache · 160.0 GiB CUDA graphs · 8.0 GiB buffers and headroom · 54.7 GiB

05 · vLLM 满负载输入 65.8 万 tokens/s,输出 6.5 万

先说预填充,因为大数字在这里。我们发送只输出一个 token 的提示,节点只做读取。2,048 个并发 8K 提示下,vLLM recipe 每秒处理 658,259 个 token,每张 GPU 约 8.2 万;512 个并发 32K 提示时为 589,924。提示越长,每个 token 越便宜:同样并发的 1K 提示是 462,366。

每个请求输出 1 个 token · 8K 与 32K:原生 recipe,1K:恢复的引擎预填充 tok/s
8K prompts · 2,048 concurrent 658K tok/s 32K prompts · 512 concurrent 590K tok/s 1K prompts · 2,048 concurrent 462K tok/s

解码方面,2,048 个并发请求在短提示时得到 每秒 64,990 个输出 token,1K → 1K 时为 54,985,每张 GPU 约 6,900,每个 token 29 毫秒。8K 提示时输出降到 29,500,但节点同时还在每秒读取 235,996 个提示 token。2,048 也是上限:每个 rank 256 条序列。4,096 个请求时,多出的请求在队列中等待,输出保持在 55,506。

恢复的引擎 · 2,048 并发输出 tok/s
128 → 1K 65.0K tok/s 1K → 1K 55.0K tok/s 8K → 1K 29.5K tok/s 2K → 128 19.8K tok/s
输入 → 输出并发输出 tok/s总 tok/s原生,输出TPOT
128 → 1K2,04864,99073,114—24.8 ms
1K → 1K2,04854,985109,96953,89228.8 ms
1K → 1K4,096——55,50632.8 ms
8K → 1K2,04829,500265,49629,58052.8 ms
2K → 1282,04819,753335,801—74.4 ms

解码数据来自 warmctl 恢复的引擎;预填充峰值来自前一天在 B300 SXM6 PC 上原生启动的 recipe。在两边都测过的点上,差异在 2% 以内:1K → 1K 为 54,985 对 53,892,8K → 1K 为 29,500 对 29,580。恢复会把引擎原样带回,包括 CUDA graph 和自动调优过的内核。在一半并发下,恢复的引擎预填充分别为 554K 和 557K。

我们第一次恢复的引擎在 1K → 1K 只跑出 37.2K 输出 tokens/s。它只为最多 1,536 个 token 的批次捕获了 CUDA graph,而 recipe 是 8,190。满负载时大多数步骤混合了解码和一段提示,而在数据并行模式下每个 rank 都会补齐到最大的那一个,于是这些步骤都没有用上 graph。把 graph 扩展到 8,192 个 token 后提升到 55.0K(profile 修改)。

06 · DEEPINFER为机柜而生,却跑在单节点上

让 DeepInfer 跑起来比测它花的时间更长。它需要从源码构建,要求 NVCC 13.1 或更新,我们用了 NVIDIA 的 CUDA 13.2 wheel。它通过 NCCL 的 GPU 发起通信在 GPU 之间搬运 Engram 行,即使在单节点上也需要 RDMA 设备:在一台没有可用 RDMA 的 8×B200 虚拟机上它根本启动不了(DeepEP#789),在这台 B300 上,驱动 580 可以运行,610 不行。

开源版本只支持离线:没有 HTTP 服务,请求通过 LLM.generate 提交。我们在进程内给它同样的随机 token 负载,这让它省掉了 vLLM 数据里包含的 API 服务、分词和网络开销。我们运行了两次:一次用默认设置,一次按 DeepSeek 的 README 和示例脚本为 V4.1 调优。

DeepInfer 设置调优运行(10 月 21 日)原因
并行EP8 × DP8:8 个引擎,专家分布在全部 8 张 GPU 上与 DeepSeek 一致
Bounded replayYOCO_PREFILL_TRUNCATION_MODE=compact,140 个 tokenREADME:V4.1 的默认设置
DSpark5 个草稿 token,按置信度调度验证(ENABLE_MTP_VARLEN=1)README
专家32 个冗余专家,每 30 步做一次 EPLBDeepSeek 的示例脚本
Engram表放在 GPU 显存中(ENGRAM_FORCE_GPU_STORAGE=1)B300 显存充足,省去 190 GiB 锁页主机内存
批处理每个 rank 256 条序列、每步预填充 32K token与 vLLM 限制相同;DeepSeek 基准的默认步长
主机驱动 580、CUDA 13.2、锁页内存不限、RDMA 网卡DeepInfer 在驱动 610 上无法启动

纸面上最重要的是 bounded replay。V4.1 的第 21 到 39 层复用前面四层的 KV 缓存,并通过 128 token 的窗口做注意力,所以提示中较早的 token 不需要经过这些层;开启后,DeepInfer 只让每个提示的最后 140 个 token 经过它们。

8×B300 · 2,048 并发输出 tok/s
vLLM DeepInfer 128 → 1K 65.0K out tok/s 36.4K out tok/s 1K → 1K 55.0K out tok/s 27.9K out tok/s 8K → 1K 29.5K out tok/s 7.3K out tok/s

解码上 vLLM 全面领先:短提示 1.8 倍,1K → 1K 2.0 倍,8K → 1K 4.0 倍(每个请求要先预填充 8K token)。DeepInfer 在 1K → 1K 的最好成绩 27,906 来自默认运行;调优运行为 21,161,很可能是因为 EPLB 每 30 步移动一次专家,而随机 token 本来就均匀分布在各专家上,这种移动得不到回报。

每个请求输出 1 个 token预填充 tok/s
vLLM DeepInfer 8K prompts 658K tok/s 72K tok/s 32K prompts 590K tok/s 72K tok/s

预填充差距更大。调优后,DeepInfer 处理 8K 提示 71,632 tokens/s,32K 提示 71,875,每张 GPU 约 9K;vLLM 分别为 658,259 和 589,924。Bounded replay 让 DeepInfer 的 32K 成绩从 64,847 提高了 11%,而不是跳过的层所暗示的两倍,所以时间花在了别处。

负载并发vLLMDeepInfer 调优DeepInfer 默认vLLM ÷ 最佳
128 → 1K2,04864,99036,381—1.8×
1K → 1K2,04854,98521,16127,9062.0×
1K → 1K4,09655,506—26,2942.1×
8K → 1K2,04829,5007,2976,9334.0×
预填充 8K2,048658,25971,632—9.2×
预填充 32K512589,92471,87564,8478.2×

DeepSeek 自己的预填充曲线是每张 GPU 8.2–8.9 万 tokens/s,约为我们测到的九倍。它来自不同的配置:每组预填充 4 张 GPU,强制专家负载均衡(其基准脚本中的 DEEPINFER_FORCE_LOAD_BALANCE=1),以及在已缓存上下文之上预填充 4K token 的后缀。我们的节点也缺少 MLOPart——DeepGEMM 用它把 MoE 缓冲区放在 B300 正确的那一半芯片上,而驱动 580 不提供它。我们无法在单节点上复现 DeepSeek 的数字,也没有对 DeepInfer 的预填充做性能剖析。

README 说明了 DeepInfer 的设计目标:解码用 64 张 GPU、预填充用 4 张,“各自位于一个 scale-up 域内”,预填充和解码在不同机器上。把这种部署串起来的部分——KV 缓存系统、预填充/解码分离和负载均衡——不在开源版本里。在我们的节点上,DeepInfer 必须在同样的八个引擎里同时做所有事,而它的调度器每一步要么全做预填充、要么全做解码,从不混合。这正是 vLLM recipe 针对的场景,而不是 DeepInfer 的设计场景。

07 · 启动15.5 分钟,还是 88 秒

8×B300 · 从启动到可服务 · 同一刻度秒
vLLM cold start start and load weights: 184.6 s 185 compile and JIT: 227 s 227 FlashInfer autotune: 319 s 319 CUDA graph capture: 199 s 199 930 s warmctl up processes (CRIU): 48.6 s GPU state: 27.3 s weights and canary: 12.5 s 88.4 s
start and load weights · 185 scompile and JIT · 227 sFlashInfer autotune · 319 sCUDA graph capture · 199 sprocesses (CRIU) · 49 sGPU state · 27 sweights and canary · 12 s

引擎日志显示了 930 秒冷启动的去向,这是在全新磁盘、缓存为空的情况下。加载权重只占一小部分:96 秒,包括 Engram 表。其余都在让 GPU 就绪:84 秒 torch.compile 和 KV 初始化,110 秒 JIT 内核预热,319 秒 FlashInfer 自动调优(21 个 token 档位),以及 199 秒捕获 67 个 CUDA graph。前一天在另一台节点上原生启动的 vLLM recipe 用了 24 分钟才就绪。DeepInfer 在 JIT 缓存已热时加载用了 298 秒,缓存为空时 748 秒。

warmctl 把慢的部分只做一次:构建引擎、预热,然后整体做快照:全部 27 个进程的内存(CRIU)、每张 GPU 的 CUDA 状态(cuda-checkpoint)、编译好的内核、自动调优结果和 CUDA graph,以及引擎布局好的 372 GiB 权重,总共 851 GiB。warmctl up 从页缓存 88.4 秒恢复:43 秒恢复进程,22 秒恢复 GPU 状态,12 秒重新加载权重,然后用一个 canary 提示与原引擎比对,再开放端口。节点以 155 GiB/s 从页缓存读取快照。恢复后我们用贪心解码检查的每个回答都正确。

快照已在 warmctl 目录中。在装有 NVIDIA 驱动 610.57.04 的 8×B300 主机上:

DeepSeekMIT
DeepSeek-V4.1-Flash-1017

MoE · Engram · DSpark · Oct 17 update · DEP8

  • 8×B300·88 s·851 GiB·610
restore88 s cold start930 s
deepseek-v41-flash-1017Run
$ curl -fsSL https://warmctl.io/install.sh | sh
$ warmctl up deepseek-v41-flash-1017

up 会根据主机的 GPU 和驱动选择快照,并在 8000 端口提供兼容 OpenAI 的 API:

$ curl -s localhost:8000/v1/completions -H 'Content-Type: application/json' -d '{
    "model": "deepseek-v41-flash-1017", "prompt": "The capital of France is", "max_tokens": 8, "temperature": 0}' | jq -r '.choices[0].text'
 Paris.

profile 中包含 vLLM 参数、graph 尺寸和预热网格。同一模型在目录中还有 8×B200(DEP8,驱动 615)、4×B200(TP4)和 8×B300 驱动 580(TP8)的版本。

08 · 如何选择什么时候用 vLLM,什么时候用 DeepInfer

基准测试回答的是单节点上谁更快。选哪一个,取决于你要做什么。

对大多数只有一两台节点的团队来说,答案是 vLLM。DeepInfer 值得关注,它展示了 DeepSeek 自己如何运行这个模型,也值得在确定性离线任务上一试。在单节点上、按 DeepSeek 推荐的设置运行时,它不是更快的那个。