tonyd2wild/MiniMax-M3-2x-DGX-Spark-36-tok-s

GitHub: tonyd2wild/MiniMax-M3-2x-DGX-Spark-36-tok-s

该项目展示了如何在2×NVIDIA DGX Spark上通过W4A16量化、NVFP4 KV cache及EAGLE-3投机解码,完整部署428B参数的MiniMax-M3模型并达到36 tok/s的推理速度。

Stars: 39 | Forks: 3

# MiniMax-M3 在 2x DGX Spark 上的部署 — 36 tok/s,完整 428B 参数(无剪枝) **这是 [a3refaat](https://github.com/a3refaat) 的技术栈。** 本仓库是对 `minimax-m3-4bit-w4a16` 分支下的 [a3refaat/spark-vllm-docker](https://github.com/a3refaat/spark-vllm-docker)(MIT 协议,上游 fork 自 [eugr/spark-vllm-docker](https://github.com/eugr/spark-vllm-docker))的复现与扩展,详细记录在他的 NVIDIA 论坛帖子 [forums.developer.nvidia.com/t/375595](https://forums.developer.nvidia.com/t/375595) 中。容器镜像、vLLM 源码补丁、b12x kernel 集成、KVarN 的向后移植及其 MiniMax-M3 扩展、EAGLE3 drafter checkpoint 以及各项配方(recipes)**均是他的成果**。我们的测试数据**在独立硬件上证实了他发布的 tg32 35.49(峰值 36.79)**。我们所补充的内容包括:复现过程本身、两个构建/运维修复([`patches/`](patches/))、对他搁置配方的恢复、参数 A/B 测试结果(包含一个客观的负面结果),以及 [`DEFAULT-CONFIG.md`](DEFAULT-CONFIG.md) 中记录的部署避坑指南。完整致谢见[下方](#credits--links)。 ## TL;DR - **你将获得:** 一个 Docker 镜像,一个模型,**三种服务配方(lanes)** —— 根据工作负载进行选择。上下文更少但速度更快 = lane C;速度更慢但上下文更长 = lane B;**lane A 则是两者的平衡(经实测验证的最佳选择)**。 - **测试数据(lane A,于 2026-07-05 在我们的设备对上验证):** 在 196K 最大上下文、208,128-token KV 池、单流、温度为 0 的设置下,**JSON 为 36.6 tok/s / 代码为 31.8 tok/s**。这在独立硬件上证实了 a3refaat 发布的 **tg32 35.49(峰值 36.79)**。 - **428B 模型如何装下:** W4A16 GPTQ(磁盘占用 224G → TP=2 下每节点 112G)+ 4-bit KV cache + EAGLE-3 drafter,运行在两台 128G 统一内存的 GB10 机器上。 - **适用对象:** 任何希望在 2x DGX Spark 设备对上复现完整尺寸(无剪枝)MiniMax-M3,并需要确切镜像、配方及启动避坑指南的人。 ## 硬件 两台 NVIDIA DGX Spark(GB10,**每台 128G 统一内存,约 121 GiB 可用**),通过直连线缆连接 **200G RoCE**,位于 `enp1s0f0np0` / `rocep1s0f0`,网段 `192.168.192.0/24`。 | 角色 | 节点 | GPU | fabric IP | 备注 | | --- | --- | --- | --- | --- | | 头节点 (rank0,提供服务 `:8000`) | Bluey | GB10 | 192.168.192.1 | `NCCL_IB_GID_INDEX=3` | | 工作节点 (rank1) | Reddie | GB10 | 192.168.192.2 | 历史记录为 GID 5 — 参见 [`DEFAULT-CONFIG.md`](DEFAULT-CONFIG.md) 避坑指南 | a3refaat 的脚本使用链路本地 ConnectX 自动发现;我们使用静态寻址 —— 两者效果等同。 **428B 模型如何在两台 Spark 上装下:** - **权重:** W4A16 GPTQ ([`Sebesky/MiniMax-M3-W4A16-GPTQ`](https://huggingface.co/Sebesky/MiniMax-M3-W4A16-GPTQ), Marlin int4 MoE) = **磁盘占用 224G → TP=2 下每节点 112G**,在 128G 统一内存的 GB10(约 121 GiB 可用)上仅为 KV cache 剩下 **每节点约 9G**。 - **KV:** 如果是 bf16,~9G 根本不够用 —— 但 MiniMax-M3 的稀疏注意力 (MSA) 层仅包含 **2 个 KV head**,并且两套 4-bit KV 栈(b12x nvfp4, KVarN k4v2)都对剩余部分进行了压缩。这就是 9G/节点如何在 196K 最大上下文(lane A)下变出 208,128-token 池,或者在无 drafter 的 262K+ 上下文(lane B)下生效的原理。 - **速度:** 在这种规模下,解码受限于显存带宽,因此 EAGLE-3 的 token 摊销是提升吞吐量的真正杠杆 —— [`Sebesky/MiniMax-M3-EAGLE3-RTN-INT4`](https://huggingface.co/Sebesky/MiniMax-M3-EAGLE3-RTN-INT4) drafter(1.6G,包含 embed/lm_head 的 int4-RTN)复用了与目标模型相同的 4-bit KV。 ## 快速开始 在 [`DEFAULT-CONFIG.md`](DEFAULT-CONFIG.md) 中有字节级精确的流程。摘要如下: 1. 克隆他的分支,应用 [`patches/dockerfile-unreachable-ref-fetch.patch`](patches/dockerfile-unreachable-ref-fetch.patch) (在冷缓存下,指定的 vLLM ref 无法访问)以及 [`patches/mod-prometheus-graceful-skip.patch`](patches/mod-prometheus-graceful-skip.patch) (否则依赖偏移会导致每次启动中止),然后运行 `./build-deploy.sh`(约 29G 镜像),并通过 `docker save | ssh docker load` 经由 fabric 网络分发。 2. 一次性暂存权重:在头节点下载 224G 目标模型 + 1.6G drafter,通过 200G RoCE 链路 rsync 到工作节点(比起再次下载 224G 节省时间,仅需约 4 分钟)。 3. 在两个节点上执行 `docker rm -f vllm_node` + 清除页面缓存,然后使用 **GMU 0.929**(不是 0.93 —— 参见临界状态避坑指南)运行 `./run-recipe.sh --no-ray -d recipes/.yaml`。 4. 在进行任何基准测试之前,让第一个请求消耗掉约 60 秒的 b12x JIT 预热时间。 ## 设置(详细说明) 完整的有序流程 —— 打补丁 → 在头节点构建 → 分发镜像 → 在两个节点暂存权重 → 清理容器 + 清除缓存 → 从头节点服务 → 预热 → 测试 —— 位于 [`DEFAULT-CONFIG.md`](DEFAULT-CONFIG.md) 中。各阶段简述如下: ### 权重 在**两个**节点上预取 —— 服务容器运行时带有 `HF_HUB_OFFLINE=1`。 - **目标模型:** [`Sebesky/MiniMax-M3-W4A16-GPTQ`](https://huggingface.co/Sebesky/MiniMax-M3-W4A16-GPTQ) (Marlin W4A16 MoE,**磁盘占用 224G**)。 - **Drafter (lanes A/C):** [`Sebesky/MiniMax-M3-EAGLE3-RTN-INT4`](https://huggingface.co/Sebesky/MiniMax-M3-EAGLE3-RTN-INT4) (**1.6G**,包含 embed/lm_head 的 int4-RTN)。不要替换为 bf16 或“精简版”共享 embed drafter —— 这种全 int4 变体才是经过验证的版本。 - 在头节点下载一次,然后通过 200G 链路进行 `rsync` —— **对于 224G 目标模型只需约 4 分钟**,无需再次从互联网拉取。 ### 镜像 / 构建 `vllm-node-minimax-m3-b12x` (~29G) = 基于指定 ref `979b56a66c96` 从源码构建的 vLLM + 他的 `minimax-m3-fused-fp8-kv` 源码补丁 + Rust 工具解析器,并在其上叠加了他内置的 b12x kernel 库 (`Dockerfile.deploy`)。一个镜像支持所有三个 lane —— 每个配方的特定修改会在启动时应用到一个全新的容器中。克隆他的分支,应用两个补丁,运行 `./build-deploy.sh`,然后进行分发: ``` docker save vllm-node-minimax-m3-b12x | ssh tonyspark2@192.168.192.2 docker load ``` ### 启动 在头节点上从打好补丁的检出目录运行(在切换配方之前运行 `./launch-cluster.sh stop` —— 修改内容不得叠加): ``` # lane A — BALANCED,hero config:b12x nvfp4 + EAGLE3,GMU 0.929 ./run-recipe.sh --no-ray --gpu-mem 0.929 -d recipes/minimax-m3-w4a16-gptq-b12x-nvfp4-eagle3.yaml ``` lane-A 的关键设置(来自配方):TP=2, `kv_cache_dtype: nvfp4`, `attention_backend: b12x`, EAGLE3 `num_speculative_tokens: 3`, `max_model_len: 196608`, `max_num_seqs: 1`, `block_size: 128`。使用**原版 (stock) NCCL** 提供服务 —— 不要导出 `NCCLPROTO=LL` / `NCCL_MAX_NCHANNELS=2`(参见基准测试)。 ### 验证 等待 `http://192.168.192.1:8000/health` 返回 200(模型加载 + Triton 预热需要几分钟),然后进行冒烟测试: ``` curl http://192.168.192.1:8000/v1/chat/completions -H 'Content-Type: application/json' -d '{ "model": "Sebesky/MiniMax-M3-W4A16-GPTQ", "messages": [{"role": "user", "content": "Reply exactly: OK M3 LIVE"}], "max_tokens": 16}' ``` **绝对不要对启动后的第一个请求进行基准测试** —— 它会承担约 60 秒的 b12x JIT 预热时间。请先针对每种工作负载模式发送一个抛弃型请求。 ## 基准测试 lane A 已于 2026-07-05 在我们的设备对(Bluey + Reddie)上验证。**lanes B 和 C 目前正在测试中** —— 下面的参考数据是作者在他自己的 2x-GB10 设备对上测得的。测试规范(我们的规范,与 MiMo 仓库相同):256-token 探测,温度为 0,单流,引擎已预热(绝不是启动后的第一个请求),`completion_tokens / wall`。完整数据、测试规范和启动证据见:[`benchmarks/RESULTS.md`](benchmarks/RESULTS.md)。 | lane | 配置 | 我们的解码 t/s (2026-07-05) | 作者的解码 t/s | 最大上下文 / KV 池 | 状态 | | --- | --- | --- | --- | --- | --- | | **A — 均衡 (BALANCED)** | b12x nvfp4 KV + EAGLE3 spec-3, GMU 0.929 | **36.6 JSON / 31.8 code** (thinking 已禁用) | tg32 35.49, 峰值 36.79 | 196K / **208,128 tokens** | ✅ 已验证,正在提供服务 | | **C — 速度 (SPEED)** | KVarN k4v2 + EAGLE3 | ⏳ 目前测试中 | 39.7 / 30.4 / 26.4 @512/65K/120K (接受长度 3.36, 78.6% @120K) | 131K / 170,752 | ⏳ 在我们的设备对上测试中 | | **B — 上下文 (CONTEXT)** | KVarN k4v2, 无 drafter | ⏳ 目前测试中 | ~22.7, 随深度保持平稳 | 262K (观测到 370K) | ⏳ 在我们的设备对上测试中 | 均为单流,`max_num_seqs: 1`。lane A 在我们的设备对上测得(256-token 探测,温度 0,单流,引擎已预热,GMU 0.929): | 工作负载 | thinking 已禁用 | adaptive | | --- | ---: | ---: | | JSON | **36.6** | 35.4 | | 代码 | 31.8 | 29.2 | 这不仅在独立硬件上重现了 a3refaat 发布的 tg32 35.49(峰值 36.79)。 **已测试的调节杠杆(lane A,在相同配置下进行 A/B 测试):** - **关闭 thinking 优于 adaptive:** JSON 提升 +1.2 tok/s(36.6 对比 35.4),代码提升 +2.6(31.8 对比 29.2)。接受工程 (Acceptance engineering) 在 M3 上奏效,就像它在我们 MiMo DFlash 部署中的表现一样。 - **`NCCLPROTO=LL` + `NCCL_MAX_NCHANNELS=2` —— 在 M3 上会损失 5–9%**(代码 28.8 对比 31.8,JSON ~33.8–35.4 对比 36.6),尽管它能在相同 fabric 网络上的 32B 级别 dense-stream 模型上获得真实的速度提升(参见我们的 [MiMo DFlash repos](https://github.com/tonyd2wild/MiMo-V2.5-DFlash-NVFP4-KV-2x-DGX-Spark))。 假设:428B Mo 的 all-reduce 操作非常消耗带宽,而 LL 更适合微小消息。**结论:NCCL 杠杆的选择依赖于模型类别 —— 请针对每次部署进行 A/B 测试,不要直接在不同模型规模间生搬硬套。** ## 配置 **根据工作负载选择 lane。** 一个镜像,一个模型,三种配方: | lane | 配方 | KV / drafter | 最大上下文 / KV 池 | 最适用于 | | --- | --- | --- | --- | --- | | **A — 均衡 (BALANCED)** (最佳) | [`b12x-nvfp4-eagle3`](recipes/minimax-m3-w4a16-gptq-b12x-nvfp4-eagle3.yaml) | b12x nvfp4 KV + EAGLE3 spec-3 | 196K / 208,128 tokens | 默认的平衡选项 | | **C — 速度 (SPEED)** | [`kvarn-eagle3`](recipes/minimax-m3-w4a16-gptq-kvarn-eagle3.yaml) (他被搁置的配方,从 git 历史中恢复) | KVarN k4v2 + EAGLE3 | 131K / 170,752 tokens | 最大吞吐量,上下文较短 | | **B — 上下文 (CONTEXT)** | [`kvarn`](recipes/minimax-m3-w4a16-gptq-kvarn.yaml) | KVarN k4v2, 无 drafter | 262K (观测到 370K) | 最大上下文,速度较慢 | 每个 yaml 的出处(全部从他的分支字节级精确重现;lane C 从他的 git 历史中恢复)见 [`recipes/README.md`](recipes/README.md)。第四个配方,[`b12x-fp8-eagle3`](recipes/minimax-m3-w4a16-gptq-b12x-fp8-eagle3.yaml),是他的 fp8-KV 生产配置 —— 原样包含在内,在此不作为主打 lane。 **可调旋钮 (lane A 默认值):** - **`gpu_memory_utilization`:** **在此设备对上为 0.929**(他的配方默认值为 0.93)。在我们的启动状态下,0.93 因差 0.02 GiB 而未通过启动可用内存检查;0.925 虽然能启动,但会将 KV 缩小到低于 196K 的要求;0.929 启动时具有约 100MB 的余量和一个 208,128-token 的池。请在你的硬件上进行区间测试 —— 其失败模式很明确(过高会报告确切的 GiB 差值,过低会报告确切的池大小)。 - **`max_model_len`:** 196608 (lane A)。不同 lane 之间用上下文换取速度 —— 131K (C), 262K+ (B)。 - **`kv_cache_dtype`:** `nvfp4` (lane A) 或 KVarN `k4v2` (lanes B/C) —— 均为 4-bit。 - **`num_speculative_tokens`:** 3 (EAGLE3 spec-decode; lanes A/C)。Lane B 没有 drafter。 - **`max_num_seqs`:** 1 —— 所有已发布的数据(他的和我们的)都是单序列;针对 208K 池的并发性能尚未经过测试。 - **`thinking_mode`:** 他的配方默认将 chat template 设为 adaptive/enabled;对于吞吐量至关重要的结构化工作负载,通过 `chat_template_kwargs` 针对单次请求禁用该功能(JSON 提升 +1.2 / 代码提升 +2.6 —— 参见基准测试)。 - **NCCL:** 使用原版 (stock) —— 不要导出 `NCCLPROTO=LL` / `NCCL_MAX_NCHANNELS=2`(在 M3 上会损失 5–9%;参见基准测试)。 ## 故障排除 所有问题都在此设备对上遇到过;确切的错误特征和修复方法见 [`DEFAULT-CONFIG.md`](DEFAULT-CONFIG.md): 1. **冷缓存构建失败** —— 指定的 vLLM ref `979b56a66c96` 仅存在于一个已删除的分支上(`refs/pull/45381/head` 可到达);已在 3 个抓取点打好补丁 ([补丁 1](patches/dockerfile-unreachable-ref-fetch.patch))。 2. **依赖项偏移导致启动中止** —— prometheus-fastapi-instrumentator 8.0.2 已经包含了他的路由修改所应用的修复 → 锚点不匹配 → 整个启动中止。该修改现在会检测 `_resolve_path` 并平滑跳过 ([补丁 2](patches/mod-prometheus-graceful-skip.patch))。 3. **来自中止启动的陈旧占位符容器** 会占用下一次启动的执行脚本(`/workspace/exec-script.sh: No such file`)—— 每次重试之前,在两个节点上执行 `docker rm -f vllm_node`。 4. **GMU 处于临界状态,已精确划定范围:** 在我们的启动状态下,0.93 因差 0.02 GiB 失败;0.925 虽然能启动,但会将 KV 缩小到低于 196K 的要求;**0.929 是最佳点**(启动时具有约 100MB 余量,池大小 208,128)。 5. **各节点的用户名不同** (tonyspark1/tonyspark2) —— 没问题,前提是头节点有一个 `~/.ssh/config` Host 条目将工作节点 IP 映射到其用户。 6. **绝不 benchmark 第一个请求** —— 它会承担 b12x JIT 预热(约 60 秒)。 7. **权重暂存** —— 下载一次,然后通过 fabric 进行 rsync(约 4 分钟,而不是再次下载 224G)。 8. **Reddie 的 fabric IP 在拆除后可能会消失** —— 如果缺少 `192.168.192.2`,执行 `sudo ip addr add 192.168.192.2/24 dev enp1s0f0np0`。 9. **在加载 224G 期间,当可用 RAM < 2G 时,Bluey 的权重加载会导致 UVM 抖动** —— 在加载期间运行缓存清除循环,但一旦加载路径处于 `instanttensor` 下,就绝对不要再运行该循环。 ## 致谢与链接 此部署几乎完全建立在先前的公开成果之上: - **a3refaat** —— 本仓库重现的整个部署包: [a3refaat/spark-vllm-docker](https://github.com/a3refaat/spark-vllm-docker) 分支 `minimax-m3-4bit-w4a16` —— b12x/KVarN MiniMax-M3 集成修改、融合 fp8-KV vLLM 补丁、各项配方、GB10 统一内存操作规则,以及论坛文章 ([forums.developer.nvidia.com/t/375595](https://forums.developer.nvidia.com/t/375595))。 我们的 lane-A 数据是对他数据的印证,且是在他从未接触过的硬件上测得的。 - **Sebesky** —— 此部署加载的 HF checkpoints: [`Sebesky/MiniMax-M3-W4A16-GPTQ`](https://huggingface.co/Sebesky/MiniMax-M3-W4A16-GPTQ) (W4A16 GPTQ target) 和 [`Sebesky/MiniMax-M3-EAGLE3-RTN-INT4`](https://huggingface.co/Sebesky/MiniMax-M3-EAGLE3-RTN-INT4) (int4-RTN EAGLE3 drafter)。 - **Inferact** —— int4 checkpoint 衍生自的原始 MiniMax-M3 EAGLE3 drafter。 - **huawei-csl / philippebich** —— KVarN 免校准 KV cache 量化及其 vLLM 实现 ([PR #46812](https://github.com/vllm-project/vllm/pull/46812))。 - **gpieceoffice** —— 率先在 DGX Spark 上使用 KVarN ([forums.developer.nvidia.com/t/375421](https://forums.developer.nvidia.com/t/375421))。 - **eugr (Eugene Rakhmatulin)** —— a3refaat 分支构建所基于的上游 [spark-vllm-docker](https://github.com/eugr/spark-vllm-docker) 集群工具 (MIT)。 - **MiniMax** —— MiniMax-M3 模型。请注意,权重受 **MiniMax Community License** 许可 —— 无论本仓库中的任何代码许可如何,模型本身均受非商业限制。 - **vLLM 项目** —— 驱动一切的引擎。 ### 许可证 - **我们的原创内容** (README, DEFAULT-CONFIG, 基准测试文档): [Apache-2.0](LICENSE)。 - **重现的配方** (`recipes/*.yaml`) 以及针对其基于 MIT 许可文件的 `patches/` 差异仍保留在 MIT 许可下,并保留了上游声明: [LICENSE.upstream-MIT](LICENSE.upstream-MIT)。配方注释头保持字节级精确一致。 - **模型权重单独说明**:MiniMax-M3 处于 MiniMax Community License (非商业限制) 之下;GPTQ/EAGLE3 checkpoints、基础镜像和 NVIDIA 工具具有其各自的上游条款。
标签:Docker, NVIDIA DGX, vLLM, 大模型推理, 安全防御评估, 开源复现, 推理优化, 模型量化, 请求拦截