GPUStack 单机 8 卡部署与五组实测

8 张 A100-SXM4-80GB,单卡占用 78.47 / 80.00 GiB,其中含分配器未归还的空闲池。
10 月 17 日,DeepSeek-V4.1-Flash-1017 上传至 ModelScope。五天后,我在一台 8 卡 A100 服务器上完成了部署和压测。期间调整了五版启动参数,也遇到过两次 OOM。
这次适配的难点很明确:模型权重使用 FP8,专家层使用 FP4,最大上下文达到 100 万 token;A100 属于 Ampere 架构,并不具备原生 FP8 或 FP4 Tensor Core。要让它运行,不能依赖硬件原生支持,只能由软件完成权重格式转换和计算路径适配。
最终结果比预期好一些:单流输出约为 129 token/s,1K 输入、2K 输出场景的总输出吞吐达到 1,537 token/s,100 万 token 的上下文也能够正常启用。不过,在高并发场景下,延迟上升得很明显:平均并发为 458 时,平均首 token 延迟达到 36.4 秒。
下面记录完整的部署方式、兼容路径、显存分配和压测结果。重点不只是证明“能跑”,也包括这套方案付出的性能代价。
一、测试环境与模型配置
本次实测使用单机 8 卡,软硬件环境如下。
| 类别 | 配置 |
|---|---|
| GPU | 8 × NVIDIA A100-SXM4-80GB,Compute Capability 8.0 |
| CPU 与内存 | 96 核 CPU,1 TB 内存 |
| 操作系统 | Ubuntu 24.04 |
| 驱动与 CUDA | NVIDIA Driver 595.91.07,CUDA 13.2 |
| 部署平台 | GPUStack |
| 推理镜像 | lazymio/vllm-backport:latest-sm80 |
| 并行配置 | TP=8,PP=1,DP=1,单实例 |
模型的主要参数如下。
| 项目 | 数据 |
|---|---|
| 骨干参数 | 552B |
| Engram 条件记忆 | 196B 参数,通过 token 查表稀疏访问 |
| 激活参数 | Prefill 约 8B,Decode 约 16B |
| Checkpoint | 475.25 GiB / 48 个分片 |
| 结构 | 40 层,384 routed + 1 shared,top-6 |
| 权重精度 | FP8,block 32×32,ue8m0 |
| 专家精度 | FP4 |
| 上下文 | 1,048,576 tokens |
| 模态 | 图文输入,32 层 ViT |
| License | MIT |
模型参数口径来自 DeepSeek-V4.1-Flash 官方模型卡片,结构细节来自 config.json。
部署采用 vLLM 单实例,未开启专家并行,也没有跨节点。八张 GPU 通过张量并行共同承载一个模型。
从 checkpoint 体积看,这个模型很难直接放进 8 张 80GB A100;同时还要为 100 万 token 上下文预留 KV cache。最终能够装下,主要依赖 Engram 表的 CPU offload,以及模型对 KV cache 的压缩与复用机制,第三节会展开说明。
二、A100 如何处理 FP4 与 FP8 权重
FP8 Tensor Core 从 Hopper 架构开始提供,FP4 Tensor Core 则属于 Blackwell。A100 能够原生加速的主要是 TF32、FP16、INT8 和 INT4,无法直接执行该模型使用的 FP8、FP4 权重格式。
本次使用社区维护的 wtdcode/vllm-backport。在加载阶段,它会按计算 kernel 的要求重新排布 FP4 和 FP8 权重;执行前向计算时,再将权重反量化到 BF16,并交给 A100 的 Tensor Core 处理。也就是说,A100 上运行 FP4 权重,依靠的是兼容层提供的反量化和模拟路径,而非硬件原生 FP4 计算。
该项目面向 A100、A6000、RTX 3090 等较早架构的 GPU,DeepSeek-V4.1-Flash 自 v0.13.0 起在其支持列表中标记为完整支持。
文档中的 Native FP4 是指模型以 FP4 形式保存权重,并不表示 A100 可以直接执行 FP4 运算。实际执行仍由 Marlin 完成反量化。启动日志也明确记录了对应的 kernel:
Using MarlinMxfp8LinearKernel for MXFP8 GEMM
Using 'MARLIN' Mxfp4 MoE backend
Using EmulationMxfp8LinearKernel for MXFP8 GEMM
日志中的 EmulationMxfp8LinearKernel 表明部分 MXFP8 计算走的是模拟路径。Marlin 则通过线程 tile 重排,把低比特权重的反量化与 GEMM 尽量融合,减少中间数据读写。
这种兼容方式仍有成本。A100 的显存带宽约为 2 TB/s,BF16 峰值算力为 312 TFLOPS;低比特权重在参与 BF16 计算前需要反量化,会额外消耗带宽和计算资源。vLLM 在加载阶段也给出了相关提示:
Marlin requires thread-tile padding for some weight shapes in this model.
Activations and/or outputs of the padded layers are padded/sliced on every forward; performance may be degraded.
部分权重形状不满足 Marlin 的线程 tile 要求,需要先做 padding,计算结束后再 slicing。这个过程不影响结果正确性,但会增加每次前向计算的开销。
三、显存分配与百万上下文
最终配置的启动日志给出了各项显存占用:
| 项目 | 数据 |
|---|---|
| 权重 + 非 torch 常驻 | 56.15 GiB |
| 峰值激活 | 3.36 GiB |
| CUDA graph 捕获 | 5.64 GiB |
| KV cache | 7.86 GiB |
| 合计 | 73.01 GiB / 77.64 GiB 可用 |
| 单卡显存 | 79.25 GiB |
gpu-memory-utilization=0.85 对应 67.36 GiB 预算。图捕获未设限界,占用了 5.64 GiB。
475.25 GiB 是 checkpoint 文件体积,日志中的 GPU 模型常驻占用则为 50.19 × 8,约 401.5 GiB。这两个数字包含的序列化、元数据与运行时内容不同,不能直接用差值对账。不过,日志明确显示了一项关键的主机内存卸载。
Engram table offloaded to pinned host memory:
48000217 rows x 256, 11.80 GiB per rank
模型包含 n-gram 查表。开启 cpu_offload=true 后,每个 rank 有 11.80 GiB 的 Engram 表被卸载到主机 pinned memory,八个 rank 合计约 94.4 GiB。这是模型能够装入 8 张 A100 的重要条件之一。
另一项关键因素是 KV cache 的设计。
KV head 只有 1 个,head_dim 为 512,加上 64 维 RoPE,每层为 576 维。40 层中,config.json 的 kv_source_layer_ids 只列出了 2、8、14、20 四个数。
这四层是配置中明确指定的 KV source layer,其余层会复用或通过压缩路径获取相关信息,并非每一层都按照传统注意力结构独立保存一份完整 KV。

橙色为 config.json 中列出的 4 个 KV source layer。
按本次 fp8_ds_mla 的缓存格式简化计算,576 × 4 × 1 字节 = 2,304 字节,约为单卡每 token 2.25 KiB。实测 7.86 GiB 除以 3,068,566 token,约为 2.75 KiB,考虑 block 对齐及其他缓存开销后,量级能够对上。
如果仅用于量级比较,并假设 40 层都按同样方式独立保存,单卡每 token 的占用约为 23 KB,是上述四层简化估算的 10 倍。
不过,这个估算只能用于解释本次日志中的显存量级,不能概括模型完整的 KV 压缩机制。官方技术报告还涉及 Causal Encoder-Decoder、Compressed Sparse Attention 2、索引复用和 FP4 主 KV 等设计。更准确的说法是:多种压缩与复用机制共同降低了 KV cache 占用,使 100 万 token 上下文能够在这套 8 卡配置上启用。
四、A100 上的三项兼容性回退
显存能够容纳模型,只解决了容量问题。A100 上实际运行时,还会触发三项兼容性回退。
| 限制 | 回退路径 | 主要影响 |
|---|---|---|
| 对称内存不支持 Compute Capability 8.0 | CUSTOM + PYNCCL all-reduce | 无法使用 FlashInfer 的对称内存优化 |
| DeepGEMM 不支持 A100 | Triton sparse attention indexer | 首次命中新 shape 时可能现场编译并产生延迟尖峰 |
| Marlin 需要 thread-tile padding | 每次前向做 padding 或 slicing | 不影响正确性,但增加持续的计算开销 |
对称内存不可用
SymmMemCommunicator: Device capability 8.0 not supported, communicator is not available.
FlashInfer All Reduce is disabled because it is not supported for world_size=8.
八张卡均出现了这条提示,all-reduce 最终回退到 CUSTOM + PYNCCL。功能不受影响,但无法使用对称内存相关的通信优化。
DeepGEMM 不可用
DeepGEMM not supported on this platform; using Triton fallback for sparse attention indexer.
DeepGEMM 面向支持相应 FP8 能力的新架构,A100 无法使用,因此稀疏注意力 indexer 回退到 Triton。Triton kernel 会在首次遇到特定 shape 时即时编译,所以推理开始后仍可能出现编译告警:
Triton kernel JIT compilation during inference: _block_scores_kernel.
This causes a latency spike; consider extending warmup to cover this shape/config.
首次命中未预热的 shape 时,编译过程可能造成一次明显的延迟尖峰。这也是压测开始阶段数据波动较大的原因之一。
Marlin 的 padding 代价
这对应上一节的 warning。padding 与 slicing 不影响结果正确性,但会持续增加相关层的前向计算开销。
三项回退分别影响通信、稀疏注意力和低比特矩阵计算。它们共同构成了 A100 兼容运行这类新模型的主要性能成本。
五、五组压测结果
压测使用 GPUStack 内置 Benchmark,覆盖 5 个 profile,共完成 2,400 个正式请求,未出现失败或截断。
| 场景 | 并发 | TTFT | TPOT | 输出 tok/s |
|---|---|---|---|---|
| 单流 128/128 | 1 | 121 ms | 0.94 ms | 129 |
| 长输出 1K/2K | 64 | 442 ms | 38.6 ms | 1,537 |
| 长文本 32K/100 | 54 | 118 s | 1.18 s | 31 |
| 高并发 1K/128 | 458 | 36.4 s | 332 ms | 871 |
| ShareGPT 真实分布 | 413 | 29.7 s | 144 ms | 1,842 |
TTFT 表示首 token 延迟,TPOT 表示首 token 之后的平均单 token 时间。除单流 TPOT 取 P50 外,表中 TTFT 和 TPOT 均取均值;并发数为全程平均值,峰值为 512。各指标按 GPUStack Benchmark 的统计口径分别读取,不宜直接互相换算。
单流场景的平均 TTFT 为 121 毫秒,P50 TPOT 为 0.94 毫秒,输出吞吐为 129 token/s。对于依赖兼容层执行 FP4、FP8 权重的 A100 来说,这一结果具备实用性。
在 1K 输入、2K 输出的长输出场景中,64 并发下总输出吞吐为 1,537 token/s,平均 TTFT 为 442 毫秒。这类负载可作为长代码或长报告生成场景的参考。ShareGPT 测试采用长短不一的请求分布,平均输入 350 token、输出 273 token,总输出吞吐达到 1,842 token/s,是五组测试中的最高值。
高并发下的表现则需要谨慎看待。平均并发为 458 时,平均 TTFT 上升到 36.4 秒;在平均并发 413 的 ShareGPT 测试中,TTFT 也达到 29.7 秒。现有 profile 不足以确定延迟开始快速上升的精确拐点,但可以确认:并发进入 400 量级后,排队等待已经成为主要问题。
投机解码使用 DSpark,配置为 3 个 draft token。平均接受长度为 2.4–2.7,整体接受率约为 50%;三个位置的接受率分别为 0.59、0.41 和 0.24。越靠后的 draft token,收益越低。

前五行为最终版结果,后续行为调参过程中的对照结果。
六、推荐参数并不等于最优参数
vllm-backport 的 README 给出了该模型的一组推荐配置。与初始参数相比,主要差异在 batch tokens、显存水位、draft tokens 和 capture sizes。为了验证这组参数是否更适合 A100,我先将四项同时调整,再与原配置进行对照。
参数对照
| 参数 | 原版 | 全改后 |
|---|---|---|
batch tokens | 4,096 | 16,384 |
gpu-memory-utilization | 0.85 | 0.90 |
draft tokens | 3 | 5 |
capture sizes | 未限制 | 最大 384 |
性能结果
| 场景 | 原版 | 全改后 | 变化 |
|---|---|---|---|
| 单流 TPOT | 0.95 ms | 1.90 ms | +100% |
| 长输出 tok/s | 1,529 | 1,420 | -7% |
| ShareGPT tok/s | 1,798 | 1,605 | -11% |
| 高并发 TTFT | 48.4 s | 39.7 s | -18% |
结果并不理想:四项指标中有三项变差,只有高并发 TTFT 改善了 18%。
进一步拆分后发现,draft tokens 的影响最明显。从 3 增加到 5 后,单流 TPOT 由 0.95 毫秒上升到 1.90 毫秒。第五、第六个 draft 位置的接受率只有 14.8% 和 6.2%,额外计算大多未能转化为有效输出。README 提到,Ampere 上超出原生块的 draft 位置接受率很低;本次测试进一步表明,提高 draft 数量还可能直接拖慢单流生成。
最终配置只保留一项改动:将 batch tokens 从 4,096 提高到 16,384,其余三项回退。与初始配置相比,高并发 TTFT 从 48.4 秒降至 36.4 秒,ShareGPT 输出吞吐从 1,798 token/s 提高到 1,842 token/s,单流和长输出性能基本回到原有水平。对这台机器而言,这是五版配置中整体取舍最好的一版。
七、长上下文测试中的缓存干扰
第一轮长文本测试使用 32K 输入,平均 TTFT 只有 304 毫秒。这个结果明显偏离 A100 的正常预填充能力:如果直接用 32,030 token 除以 0.304 秒,会得到超过 10 万 token/s 的 Prefill 速度。
检查测试数据后发现,低延迟主要来自 prefix cache。由于测试集使用固定 seed,100 个请求的输入完全相同;从第二个请求开始,完整的 32K 前缀可以命中缓存,实际只需计算增量部分。因此,304 毫秒不能代表真实的 32K Prefill 性能。
最终配置中,KV cache 为 7.86 GiB,可容纳约 306 万 token;而 100 个 32K 请求对应约 320 万 token 的工作集。工作集超过缓存容量后,前缀会持续被淘汰。这组测试的 prefix cache 命中率只有 0.0%–1.3%,绝大多数请求都需要重新计算 32K 前缀。
| 长文本测试 | 第一轮 | 最终版 |
|---|---|---|
| 输入特征 | 100 个请求使用相同 32K 前缀 | 同样使用相同 32K 前缀 |
| Prefix cache | 从第二个请求开始大量命中 | 命中率仅 0.0%–1.3% |
| KV cache 容量 | 未记录 | 306 万 token |
| 平均 TTFT | 304 毫秒 | 118 秒 |
| 应如何解读 | 主要反映缓存命中,不是真实 32K Prefill 速度 | 主要反映重复 Prefill 与排队代价 |
因此,最终测试中 118 秒的平均 TTFT 主要包含排队和重复 Prefill 的时间,不能视为单个请求的纯计算耗时。按该轮数据粗略估算,单个 32K Prefill 约为 1.2 秒,对应约 26K token/s;这一估算会受到批处理和调度方式影响,仅用于判断量级。
这也是增大 batch 带来的副作用。将批预算提高到 16,384 后,激活占用增加;同时,未限制范围的 CUDA graph capture 占用了 5.64 GiB,KV cache 由 10.75 GiB 缩小至 7.86 GiB。最终配置将高并发 TTFT 降低了约 12 秒,但也压缩了长文本前缀缓存空间。
在当前业务假设下,我保留了这一取舍:高并发请求更常见,而大量请求复用同一段 32K 前缀属于相对特殊的负载。若实际业务更依赖长前缀复用,则应重新分配 CUDA graph 与 KV cache 的显存预算。
八、GPUStack 在部署中承担的工作
从提交部署到 API 就绪,整个过程不到 6 分钟。模型分发、镜像拉取、容器创建、参数注入、健康检查和端口映射均由 GPUStack 完成。

实例状态为 Running,绑定 cuda:0–7,分配显存 544 GiB。
其中最需要注意的是镜像标签。该仓库在 Docker Hub 上按照 GPU 架构提供三个 tag:
| 镜像 tag | 对应架构 | 适用 GPU |
|---|---|---|
sm80 | Ampere SM80 | A100 |
sm86 | Ampere SM86 | A6000、RTX 30 系列 |
sm89 | Ada SM89 | RTX 4090、L40S |
这些镜像均为单架构构建,不包含 Hopper 的 FA3 kernel。镜像 tag 必须与 GPU 架构匹配,否则实例无法正常启动。
其余参数由 GPUStack 透传给推理引擎:TP=8,最大上下文为 100 万 token,tokenizer-mode 和两个 parser 均设为 deepseek_v41,投机解码使用 dspark,Engram 开启 cpu_offload。整个过程中不需要修改 vLLM 源码,A100 所需的兼容逻辑由 vllm-backport 提供。
缓存也减少了重复部署的等待时间。模型保存在 /var/lib/gpustack/cache/model_scope,实例重启时不需要重新下载;vLLM 编译缓存使用独立目录,第二次启动时可以复用已有的 Triton 编译结果。本次记录到的约 40 秒权重加载时间,也受益于这些持久化缓存。
九、下一步优化方向
当前配置已经能够稳定运行,但仍有三项值得继续验证的优化。
| 后续动作 | 实测依据 | 目标 |
|---|---|---|
| 把图捕获限制到合理范围 | 不限制时占用 5.64 GiB,限制到 384 时占用 2.76 GiB | 释放约 3 GiB 给 KV cache |
| 提高长文本缓存容量 | 现有 306 万 token 容量低于 320 万 token 工作集 | 避免重复 32K 前缀时命中率接近归零 |
测试 VLLM_MARLIN_USE_ATOMIC_ADD | 启动日志持续提示 MoE 小 size_n 场景可开启 | 验证是否降低 Marlin 开销 |
把图捕获限制到合理范围
当前 CUDA graph capture 未设置上限,51 个 piecewise graph 和 49 个 full graph 共占用 5.64 GiB。对照测试中,将最大 capture size 限制为 384 后,占用降至 2.76 GiB,可为 KV cache 释放近 3 GiB。相比继续增大 batch,这项调整对显存分配的作用更直接,但仍需补充完整的性能回归测试。
让长文本缓存容纳完整工作集
现有 KV cache 容量约为 306 万 token,低于测试所需的 320 万 token,因此命中率仅为 0.0%–1.3%。一种做法是限制 CUDA graph capture,为 KV cache 让出更多显存;另一种做法是使用 LMCache,将冷 KV 迁移到 1 TB 主机内存。镜像已经包含 LMCache,后续可以直接进行对照测试。
测试 Marlin 已给出的优化开关
启动日志提示,MoE 的小 size_n 场景可以尝试开启 VLLM_MARLIN_USE_ATOMIC_ADD。本轮没有设置该环境变量,暂时无法判断它对吞吐和延迟的实际影响,下一轮需要单独做 A/B 测试。
对于高并发下 36.4 秒的平均 TTFT,继续增大 batch 的空间已经有限。batch tokens 从 4,096 提高到 16,384 后,TTFT 改善约 25%;若要继续降低延迟,可能需要调整调度策略或引入数据并行,这已经超出本次单实例适配的范围。
十、写在最后
A100 已经不是最新一代 GPU,但仍是许多团队的重要存量资源。是否值得在这类硬件上部署新模型,不能只看“能否启动”,还要看兼容路径引入了多少开销,以及最终性能是否满足业务需求。
这次测试给出的答案相对明确。借助 vllm-backport,A100 可以通过 Marlin 反量化、Triton 回退、Engram offload 和 DSpark 投机解码运行 DeepSeek-V4.1-Flash-1017;GPUStack 则负责模型分发、镜像、参数和实例生命周期管理。整个过程无需修改 vLLM 源码。
性能方面,单流输出为 129 token/s,1K 输入、2K 输出场景的总输出吞吐为 1,537 token/s,100 万 token 上下文可以正常启用。限制也同样清楚:平均并发达到 458 时,平均 TTFT 为 36.4 秒;当 KV cache 小于长前缀工作集时,prefix cache 的收益也会迅速下降。
因此,这套方案适合希望继续利用 A100 存量资源、并且能够接受兼容层开销的团队。如果业务重点是极低首 token 延迟、大规模高并发,或者稳定的长前缀复用,还需要进一步调整部署架构,不能只依赖单实例参数优化。
测试说明
- 性能数据来自 GPUStack 内置 Benchmark 的 5 组 profile,共 2,400 个正式请求,零失败。
- 启动、回退路径与显存数据来自实际容器日志。
- 模型参数与架构信息来自 DeepSeek 官方模型卡片、DeepSeek-V4.1-Flash-1017
config.json与技术报告,推荐参数来自 wtdcode/vllm-backport 仓库 README。 - 测试环境为 8 × NVIDIA A100-SXM4-80GB、NVIDIA Driver 595.91.07、CUDA 13.2、Ubuntu 24.04、GPUStack、
lazymio/vllm-backport:latest-sm80、TP=8、最大上下文 1,000,000 token、KV cache 格式fp8_ds_mla。
本文基于8张A100-SXM4-80GB GPU,使用vLLM与vllm-backport适配DeepSeek-V4.1-Flash-1017模型,重点分析FP4/FP8权重在Ampere架构上的软件反量化路径、显存分配策略(含Engram CPU offload与KV cache压缩)、三项关键兼容性回退(对称内存、DeepGEMM、Marlin padding),以及五组压测结果。单流输出129 token/s,100万token上下文可启用,但高并发下TTFT显著升高至36.4秒,揭示了兼容层带来的核心性能代价。
3379

被折叠的 条评论
为什么被折叠?



