在单块 AMD MI300X 上运行 DeepSeek V4 Flash
本仓库包含我在生产环境中于单块 AMD MI300X 上运行 deepseek-ai/DeepSeek-V4-Flash-0731 所使用的配置和补丁。其中包括 Docker Compose 栈、SHA-256 固定的文件覆盖层、与上游的参考差异对比,以及调优表格。该检查点按原样运行,无需额外的权重量化或卸载。
固定栈的测试结果(vLLM ROCm 每夜版 0.26.1rc1.dev229+g124154a88.rocm723,AITER 0.1.19):
| 指标 | 结果 |
|---|---|
| 单流解码(每流中位数,DSpark-7) | 168.6 tok/s |
| 使用调优内核的预填充 | ≈ 7.9–8.5K tok/s(出厂配置下新提示词为 6,988–7,019 tok/s) |
| 8 条并发流 | 聚合 542 tok/s,每流中位数 90.3 tok/s |
| 64 流突发 | 聚合 830 tok/s,无 OOM,无引擎错误 |
| 上下文 | 已验证 256K(架构支持 1M) |
| HBM 中的权重 | 156.67 GiB —— 无额外量化或权重卸载 |
官方 vLLM 方案面向 NVIDIA 和更新的 AMD 硬件。要在 MI300X 上稳定运行该模型,需要修复其 FP8 格式、高并发下的 MoE 路由、因果投机验证、CPU-KV 同步,以及若干未调优的内核形状。本仓库收集了这些修复,并固定了生产环境中使用的版本。
为什么选择 MI300X
MI300X 拥有 192 GB 的 HBM3 和 5.3 TB/s 的内存带宽,其 HBM 容量是 H100 SXM5 的 2.4 倍(AMD)。Doubleword 的文章估计其标价大约只有后者的一半。对于这个 304B 参数的检查点,内存容量使其可以简单地在单 GPU 上部署:
- 整个模型可放入 HBM,无需 PCIe 权重流式传输或层卸载。
- 还有空间容纳 20 GB 的 GPU KV 池,以及 96 GiB 的 CPU 层用于存放被逐出的前缀缓存条目。
- 单卡可处理 2–8 条典型并发流,以及最多 64 流的突发。
MI300X(CDNA3)实现了 AMD/Graphcore 的 E4M3 fnuz 变体,而 MI325X 及更新型号使用 OCP 标准的 FP8(背景信息)。在 MI300X 上假设 OCP 语义的内核,在缩放域上可能产生两倍的误差。这种 FP8 实现上的正确性是第一优先级;性能调优随后进行。
先前工作,以及本仓库新增的内容
Fergus Finn 的 MI300X 工作日志以及配套的 Doubleword 仓库指出了 FP8 不兼容问题、gfx942 上缺失的 AITER 快速路径、稀疏 MLA 解码中的 HIP-graph 风险,以及 MoE 路由错误。官方 vLLM 方案涵盖 NVIDIA 硬件和更新的 AMD GPU(4K 上下文下的 MI325X 和 MI355X),但不包含针对 0731 检查点的单 MI300X 生产配置。
该仓库新增了以下内容:
- 针对固定版本 ROCm nightly 的正确性覆盖补丁,包括上游 vLLM 尚未合入的修复。
- 一套经过验证的服务配置,采用概率性 DSpark 草稿生成、块拒绝和静态 K=7。它使用 2,048 token 的调度器预算和 1,024 token 的长预填充上限,以防止冷提示词阻塞其他流。
- 针对打包表中缺失的常见 gfx942 形状的 AITER GEMM 调优表,以及针对 MXFP4 专家层的 gfx942 OGS 几何覆盖。
- 一种混合 KV 策略:20 GB fp8_ds_mla GPU 缓存 + 96 GiB 原生 CPU 卸载,并附带加载路径围栏修复——该问题在上游 issue #47282 中有记录,但 PR #47291 从未合入。
仓库结构
.
├── compose.yaml # The production stack (vLLM ROCm + Caddy), digest-pinned
├── Caddyfile.example # Copy to Caddyfile; set hostname, email, and source CIDR
├── vllm-entrypoint.sh # Removes stale CPU-KV mmaps from /dev/shm before start
├── SHA256SUMS # SHA-256 pins for every runtime artifact
├── patches/
│ ├── *.py # Byte-for-byte production overlays (mounted read-only)
│ ├── diffs/*.patch # Unified diffs vs. the upstream base revision
│ └── README.md # Provenance and regeneration instructions
└── tuning/
└── *.csv # AITER A8W8 blockscale tuning tables for gfx942
运行时配置
该技术栈使用摘要固定的官方 vLLM ROCm nightly 版本,并包含:
- --trust-remote-code 以及 DeepSeek V4 tokenizer、推理和工具解析器
- fp8_ds_mla KV 缓存(UE8M0 块缩放 FP8,而非通用非缩放 FP8),采用 256-token 块
- VLLM_ROCM_USE_AITER=1 和 --moe-backend triton;Triton OGS 处理分组的 MXFP4 专家层,而 AITER 处理注意力层和密集线性层
- DSpark-7 推测解码,采用概率性草稿生成和块拒绝
- 完整/可中断的 CUDA graph 捕获,在稳定解码阶段每个 token 仅启动一次 graph
- Caddy 作为 IP 白名单 HTTPS 代理
部署步骤
1. 主机前置要求
一块 MI300X(gfx942,304 个 CU,约 192 GiB HBM)、可用的 AMD 内核驱动、较新的 Docker Compose、约 235 GiB 内存用于 CPU KV 层,以及约 500 GB 磁盘空间(仅模型缓存就约 156 GB)。
2. 拉取固定版本的运行时和模型
VLLM_IMAGE='vllm/vllm-openai-rocm@sha256:e68d18b2ba50298661bfc49baf01158fbf036645c2362cccf3e8a7a79fe6c69a'
MODEL='deepseek-ai/DeepSeek-V4-Flash-0731'
REVISION='7872f01b1d1fe23eabc4c98b48bffcef5a386062'
docker pull "$VLLM_IMAGE"
docker run --rm --entrypoint hf \
-v /root/.cache/huggingface:/root/.cache/huggingface \
"$VLLM_IMAGE" download "$MODEL" --revision "$REVISION"
3. 准备文件
cp Caddyfile.example Caddyfile # then set your hostname, email, and remote_ip CIDR
mkdir -p aiter-cache crash-dumps
chmod +x vllm-entrypoint.sh
sha256sum -c SHA256SUMS # verify the overlays before first start
4. 启动
docker compose config -q
docker compose up -d
docker compose logs -f inference
正常启动约需 5 分钟,且必须显示以下所有内容:
Model loading took 156.67 GiB
DSpark draft model loaded: 96 params
GPU KV cache size: 1,927,444 tokens
Maximum concurrency for 262,144 tokens per request: 7.35x
Created mmap file /dev/shm/vllm_offload_...mmap (103.08 GB)
Capturing CUDA graphs (FULL)
Application startup complete
在 graph 捕获后,运行 rocm-smi --showmeminfo vram。预热后的高水位标记约为 205.8 GB 中的 204.5 GB。如果仅剩几百 MB,服务器可能能启动,但会在第一个请求时失败。
5. 冒烟测试
HOST='your-host.example.com'
curl -fsS "https://$HOST/v1/models"
curl -sS "https://$HOST/v1/completions" \
-H 'Content-Type: application/json' \
-d "{\"model\": \"deepseek-ai/DeepSeek-V4-Flash-0731\",
\"prompt\": \"Calculate 17 * 23. Answer with the number only.\",
\"temperature\": 0, \"max_tokens\": 32}"
补丁文件
每个 patches/*.py 文件都是一个完整的文件覆盖层,以只读方式挂载到容器中对应文件之上;compose.yaml 中包含目标路径。相应的 diffs/*.patch 记录了其相对于上游基线的变更。基础镜像仍保持摘要固定(digest-pinned),因此升级需要更改镜像引用并重新验证整个技术栈。
| 覆盖层 | 挂载于 | 修复内容 | 适用场景 |
|---|---|---|---|
| gpt_oss_triton_kernels_moe.pack128-fused-silu-fast-routing.py | vllm/.../fused_moe/experts/gpt_oss_triton_kernels_moe.py | MXFP4 位矩阵填充通道 + 融合 SiLU 分组专家 + 快速 DeepSeek 路由 | MXFP4 Triton 路径所必需;掩码修复尚未合入上游 |
| mxfp4.fused-silu.py | vllm/.../fused_moe/oracle/mxfp4.py | 融合 SiLU 内核的 Gate/Up 交错布局 | 需与 fused-SiLU 覆盖层搭配使用;若保留标准 SiLU 路径,则两者均跳过 |
| triton-kernels-matmul-ogs-opt-flags.dsv4-mi300x.py | vllm/third_party/triton_kernels/matmul_ogs_details/opt_flags.py | gfx942 MXFP4 OGS 瓦片几何形状(最多 1,536 个路由行) | 针对 gfx942 的性能优化;默认几何形状在路由行数超过 768 时性能急剧下降 |
| fused_compress_quant_cache.fnuz-shuffle.py | vllm/models/deepseek_v4/common/ops/fused_compress_quant_cache.py | Lightning Indexer 缓存写入器中的 FNUZ FP8 + 16×16 预洗牌 | MI300X 上必需;MI325X/MI355X 使用 OCP FP8,必须保留默认字节序 |
| aiter_pa_mqa_logits.i64.py | aiter/ops/triton/gluon/pa_mqa_logits.py | ChunkK=256 分页 MQA 内核中的 64 位偏移量 | 当 KV 偏移量可能超过 4 GiB 时必需;小型 KV 池可跳过 |
| rocm_aiter_mla_sparse.prefill-bh64.py | vllm/v1/attention/ops/rocm_aiter_mla_sparse.py | 确定性 torch.topk 预填充 + BLOCK_H=64 头-512 稀疏预填充 | 确定性是可复现工具调用所必需的;BLOCK_H=64 是性能优化 |
| rocm_aiter_mla.dspark-causal.py | vllm/v1/attention/backends/mla/rocm_aiter_mla.py | 因果多 token 投机验证 | ROCm 小头 MLA 上运行 DSpark 所必需——现已合入上游;该覆盖层与上游文件逐字一致 |
| dspark-speculator.independent-draft-gumbel.py + spec-decode-utils.independent-draft-gumbel.py | vllm/v1/worker/gpu/spec_decode/dspark/speculator.py + .../spec_decode/utils.py | 将草稿提案 Gumbel 噪声与拒绝/恢复噪声分离 | 仅在 `draft_sample_method=probabilistic` 时需要(该方案的贪心路径不需要) |
| kv_offload_cpu_gpu_worker.load-war.py | vllm/v1/kv_offload/cpu/gpu_worker.py | 将 CPU→GPU 的 KV 恢复操作置于进行中的计算之后(栅栏同步)(#47282,PR #47291) | 仅在 `--kv-offloading-backend native` 时需要 |
两个重要的正确性修复
MXFP4 路由。MoE 位矩阵内核将其块列填充到 Triton 块大小,但填充通道是按全局张量边界进行掩码的,而非按逻辑块大小。在高负载下,填充通道会破坏路由矩阵,导致长提示词下出现近似匹配的工具名称和遗忘的 schema。一行修复代码为 `mask = (offs_local < BLOCK_SIZE) & (offs_global < nonzero_indx_size)`,取自 Doubleword 提交 c32932bb9。该补丁还包含针对分组 MXFP4 专家的融合 SiLU 和快速路由更改。
FP8 格式。DeepSeek V4 的 Lightning Indexer 缓存使用 FP8。标准写入器按行主序输出 OCP E4M3 字节,而 MI300X 上的 AITER 则按预混洗的 16×16 分块布局消费 AMD FNUZ E4M3 字节。在最坏情况下,将一种格式解释为另一种格式会产生两倍的缩放误差。该补丁在 ROCm 上选择 `float8e4b8`(FP8_MAX=224.0)和混洗写入偏移,而在其他平台上保持 OCP 路径不变。
投机解码
该技术栈使用带块拒绝的概率性草稿生成。两个 Gumbel 补丁确保草稿提案噪声与拒绝和恢复噪声相互独立。
性能
生产配置中的关键优化:
| 变更 | 效果 |
|---|---|
| 针对 304-CU gfx942 调优 21 种常见 A8W8 GEMM 形状 | 单/双流解码 +42–62%;8–64 流时 +10–35% |
| 融合 SiLU、快速 DeepSeek 路由、批量敏感的专家分块 | 原生 C1 解码 34.5 → 56.6 tok/s(+64%);路由内核 42.6 → 11.9 µs/层 |
| BLOCK_H=64 稀疏预填充分块 | 预填充达到 7.9–8.5K tok/s;稀疏注意力追踪 317 → 142 ms/请求 |
| 静态 K=7,概率性 + 块拒绝,因果验证 | 单流 119.5 tok/s,输出正确 |
| 2,048 token 预算 + 1,024 token 长预填充上限 | 52K 预填充之后的短请求尾延迟:8.2 s → 0.5 s |
| 20 GB GPU KV + 96 GiB CPU 层级 | 等效 193 万 token 容量;已接纳 7 个 256K 请求 |
最终并发扫描
不同的约 400 词提示词,流式输出,temperature=1.0,top_p=0.95;C1–C8 输出 512 token,C64 输出 256 token:
| 流数 | 聚合 tok/s | 每流解码中位数 | TTFT p50 |
|---|---|---|---|
| 1 | 126.2 | 168.6 tok/s | 1.026 秒 |
| 2 | 145.4 | 152.7 | 0.939 秒 |
| 4 | 316.8 | 108.6 | 0.369 秒 |
| 8 | 542.3 | 90.3 | 1.027 秒 |
| 64 | 830.2 | 16.4 | 2.190 秒 |
DSpark 的接纳能力取决于提示词本身;请将这些数据视为针对这一特定图像的准入条件,而非通用模型基准。
预填充
使用调优后的内核,未缓存预填充可达 7.9–8.5K tok/s,具体取决于调度器预算:在 C1 下、8,192 token 预算时为 7.90–7.99K,在 C4 下为 8.46–8.51K。生产配置使用 2,048 token 预算以实现延迟隔离,在新提示词上可达到 6,988–7,019 tok/s。在 1,024 token 长预填充上限下,8.9K token 的提示词在 C1 下可达 5.20–5.29K tok/s。作为交换,排在 52K 冷预填充之后的短请求,其 TTFT 从 8.2 秒降至 0.5 秒。380K 缓存 token 的热召回在 120–125 秒冷预填充后需要 0.64–2.65 秒。
生产注意事项
- HBM 余量有限。预热后的高水位线为 205.8 GB 中的 204.5 GB。30 GB 的 KV 池可以加载,但在图捕获阶段会因 HSA_STATUS_ERROR_OUT_OF_RESOURCES 而失败。不要提高 --kv-cache-memory-bytes;请监控 HBM 使用量的增长。
- CPU KV 层级存储的是缓存条目,而非权重。--kv-offloading-size 96 --kv-offloading-backend native 会在 /dev/shm 中映射约 103 GB 空间,用于存放被逐出的前缀缓存条目。入口点在崩溃后会清除过期的映射。
- 1,664 token 的调度器警告属于预期现象。DSpark-7 会从 2,048 token 预算中预留草稿槽位。提高预算会保留更多进行中的滑动窗口状态,并减少可用的 KV 容量。
- 重启后需预热内核。首次预填充会初始化内核,8.9K token 需要 5.3 秒;后续运行只需 1.7 秒。在接纳流量之前,先运行一次未缓存的预填充。
- 不仅要测试吞吐量,也要测试正确性。验证套件包括两轮工具调用测试用例、BFCL 子集(74–76/90 次精确调用)、OpenCode 工具模式检查,以及在原生路径和 DSpark 路径上的 380K token 针检索测试。冷启动和缓存预填充可能走不同的浮点路径,因此两条路径都要测试。
许可证与来源
该技术栈、文档以及源自 vLLM 的覆盖层均采用 Apache-2.0 许可证(见 LICENSE);源自 AITER 的覆盖层保留其 MIT 许可证头。每个差异补丁的上游基础版本均记录在 patches/README.md 中。模型本身采用 MIT 许可证。
参考资料
所有链接已于 2026-08-04 验证。
- DeepSeek-V4-Flash-0731 模型卡 —— 官方发布;304B 参数;融合 DSpark 模块;推荐 temperature=1.0,top_p=0.95;MIT 许可证
- 官方 vLLM DeepSeek V4 Flash 配方 —— 参考启动配置,DSpark(num_speculative_tokens=7)、FP8 KV、块大小 256、deepseek_v4 解析器;针对 MI325X/MI355X 的 AMD 指南
- 在 AMD MI300X 上部署 DeepSeek-V4-Flash(Fergus Finn,Doubleword,2026 年 6 月)—— 本仓库所基于的部署工作日志:FNUZ 与 OCP FP8 对比、gfx942 上的 AITER 缺口、HIP 图风险、路由错误
- doublewordai/vllm-amd-blog-doubleword —— 上述内容的演示 PR,包括提交 c32932bb9(“按逻辑块大小掩码 MXFP4 位矩阵填充通道”)
- vLLM 提交 77469c9 —— “[ROCm][MLA] 对 AITER MLA 小头验证展平进行因果掩码 (#50476)”
- vLLM issue #47282 —— CPU-KV 加载路径与计算之间缺少跨流同步(WAR 缺口)
- vLLM PR #47291 —— 提议的 WAR 修复,尚未合并;此处作为覆盖层携带
- AMD Instinct MI300X —— 192 GB HBM3,5.3 TB/s 峰值带宽,2.61 PFLOPS 峰值 FP8
- ROCm/AITER —— 用于 ROCm 注意力机制和密集线性层的 AMD 调优内核库
- vLLM —— 服务运行时(vllm/vllm-openai-rocm 下的 ROCm 夜间版)