@Tech2Wild: 在家运行完整的GLM-5.2,744B参数,全部256个专家,未剪枝,跨4×NVIDIA DGX Spark (GB10)。200K上下文 · MTP …

X AI KOLs Following 模型

摘要

一份详细的指南,介绍如何跨4个NVIDIA DGX Spark节点运行未剪枝的GLM-5.2模型(744B参数,256个专家),支持200K上下文,总吞吐量高达60.5 tok/s。包含性能基准测试、致谢和补丁。

🧠⚡ 在家运行完整的GLM-5.2,744B参数,全部256个专家,未剪枝,跨4×NVIDIA DGX Spark (GB10)。 200K上下文 · MTP推测解码 · fp8稀疏MLA KV · vLLM原生多节点 ~30 tok/s单流,60 tok/s @ 6并发。 完整可复现的配方,已开源 👇
查看原文
查看缓存全文

缓存时间: 2026/07/06 06:02

🧠⚡ 在家运行完整版 GLM-5.2:全部 744B 参数、256 个专家、未经剪枝,跨 4× NVIDIA DGX Spark (GB10)。200K 上下文 · MTP 推测解码 · fp8 稀疏 MLA KV · vLLM 原生多节点 ~30 tok/s 单流,60 tok/s @ 6 并发。完整可复现方案,已开源 👇

tonyd2wild/GLM-5.2-QuantTrio-200K-4x-DGX-Spark

来源:https://github.com/tonyd2wild/GLM-5.2-QuantTrio-200K-4x-DGX-Spark

GLM-5.2(未剪枝 QuantTrio Int4-Int8Mix)在 4× NVIDIA DGX Spark (GB10) 集群上以 200K 上下文运行

一份完整、可供追随者复现的方案,用于在 4× NVIDIA DGX Spark (GB10) 节点上通过 RoCE 网络部署 GLM-5.2 —— 使用 未剪枝 的 QuantTrio GLM-5.2-Int4-Int8Mix 检查点,全部 256 个专家完整保留,支持 200,000 token 上下文MTP 推测解码(k=4)、fp8 稀疏 MLA KV 缓存以及完整 CUDA 图。vLLM 原生多节点(无 Ray),每个节点只需一个 docker run 命令。

实测性能:28.8 tok/s 单流(中位数),60.5 tok/s 聚合(6 并发),200K 上下文,未剪枝。

实测性能(最终版,2026-07-05)

并发数聚合 tok/s每流平均每流最小值MTP 接受长度
1(热启动,3 次中位数)28.828.827.33.3–3.6
237.620.218.83.50
339.313.613.13.22
453.514.113.43.28
559.112.511.83.22
660.510.610.13.23

(512 token 生成,temp 0,低深度上下文。c1 是 3 次运行的热中位数——27.3/29.0/28.8;冷启动(重启后首次请求)读取较低(16–22 tok/s)。c3+ 行仅因 patches/fix-indexer-mtp-overhang.py 而存在——未打补丁的 vLLM 在 3 并发时会崩溃。上下文深度表(16K/32K 预填充/解码)是唯一待办项——见基准测试。)


1. 致谢与传承

本方案完全建立在以下贡献者的工作之上。如果你使用它,你实际上在使用他们的成果。

贡献者贡献内容
CosmicRaisins (https://github.com/CosmicRaisins/glm-5.2-gb10)整个 sm_121 稀疏 MLA 移植:glm-5.2-gb10 仓库、10 个 Triton 内核、DeepGEMM 绕过、本仓库 launch.sh 所继承的启动框架。Apache-2.0 许可。没有这些,这一切都无法工作。
Zatz未剪枝的 QuantTrio 方案——证明了完整 256 专家的 Int4-Int8Mix 检查点能够适应并在 4× GB10 上运行(论坛帖子 374125 (https://forums.developer.nvidia.com/t/glm-5-2-on-a-4x-gb10-cluster-22-tok-s-decode-256k-ctx-recipe/374125),第 57 和 84 楼)。
back199640缩小差距的调优(帖子 374125,第 80 和 89 楼):--async-scheduling、MTP k=4 配合 draft_tensor_parallel_size: 1、头部填充技巧以及使用显式 --kv-cache-memory-bytes 实现确定性启动。
ciprianvegmods/ 中的 baked-mod 脚本(glm52-sparse.zip,帖子 374125 第 34 楼),用于复制 CosmicRaisins 的修改,以及 NCCL 通道收窄发现(NCCL_MIN/MAX_NCHANNELS=4,第 107 楼)。
eugr / spark-vllm-docker (https://github.com/eugr/spark-vllm-docker)用于构建 GB10 vLLM 容器的镜像构建框架(build-and-copy.sh)。
QuantTrio (https://huggingface.co/QuantTrio)GLM-5.2-Int4-Int8Mix 检查点本身。
p33zy探索了替代的 NVFP4 量化路径以及 GB10 硬件加速权衡(帖子 374125)。
aidendle94共享了容器/镜像资源(最初用于 GB10 上的 DeepSeek),部分延续到了 GLM-5.2 的启动过程中(帖子 374125)。
Claude Code在帖子中提供了技术说明:sm_121 能力检测、cudagraph 捕获安全性、b12x 安装要求以及稀疏 MLA 索引器路径(帖子 374125)。

本部署的贡献(我们在启动过程中发现并回馈的问题):

  • 索引器 MTP 悬垂修复patches/fix-indexer-mtp-overhang.py):当 max_model_len 恰好是块大小的整数倍且启用了 MTP 时,DSA 索引器将展开的块表缓冲区少分配了一个块——在并发请求 ≥3 时导致引擎崩溃。
  • 加载阶段的页面缓存丢弃过程(陷阱 6):在权重加载期间,每个节点定期执行 drop_caches,解决了 GB10 内核回收停滞的问题。
  • 精确 200K 上下文的内存预算数值(陷阱 7 和配置表):gmu 0.91 + --kv-cache-memory-bytes 10950000000

论坛帖子(请阅读两者——它们是主要来源):

  • https://forums.developer.nvidia.com/t/glm-5-2-on-a-4x-gb10-cluster-22-tok-s-decode-256k-ctx-recipe/374125
  • https://forums.developer.nvidia.com/t/followup-mystery-solved-4x-spark-glm-5-2-nfp4-24tp-s-128k-ctx-no-reap/375416

2. 硬件要求

  • 4× NVIDIA DGX Spark (GB10) —— 每节点 121 GB 统一内存。
  • 四节点间的 RoCE 网络。 我们使用 CRS812 交换机,fabric 子网 192.168.192.0/24端到端 MTU 9000(巨帧)——包括交换机和每个 NIC。如果 NCCL 能够看到 IB 设备,直接线缆连接的网络也可以工作。
  • 每个节点约 420 GB 空闲磁盘空间——405 GB 权重加上镜像、缓存和余量。

3. 为什么选择这个检查点

QuantTrio/GLM-5.2-Int4-Int8Mix —— 未剪枝。

  • 零质量妥协。 没有 REAP/专家剪枝:全部 256 个专家完整保留。你提供的是真正的模型,而不是一个经过外科手术缩小版的模型。
  • 真实的内存余量。 405 GB 权重 → TP=4 时每节点 约 95 GiB 权重。在一个 121 GB 统一内存的 GB10 上,这为 KV 缓存、CUDA 图和操作系统留下了真正的空间。相比之下,429 GB 的 NVFP4 混合方案:约 107 GB/节点——这是一个临界点,一旦页面缓存或预热分配介入,就会 OOM。
  • MTP 草稿模型在检查点内部(第 78 层)。无需单独下载、对齐或版本匹配草稿模型——--speculative-config 直接指向检查点本身。

4. 仓库内容

文件说明
launch.sh4 节点启动器(改编自 CosmicRaisins,Apache-2.0)。编辑 EDIT 标记的配置块,从头节点运行。
mods/glm52-sm12x-sparse/run.sh内置镜像修改:安装 Triton 稀疏 MLA 内核 + DeepGEMM 绕过(来自 ciprianveg 的 zip 存档,原样复制)。
mods/glm52-b12x-sparse/run.sh内置镜像修改:安装 b12x 以实现 CUDA-graph 安全的稀疏 MLA 解码(来自 ciprianveg 的 zip 存档,原样复制)。
patches/fix-indexer-mtp-overhang.py内置镜像补丁:修复 DSA 索引器的展开块表缓冲区在 MTP 下少一个块的问题(需要 --max-num-seqs >= 3)。见步骤 (h)。
LICENSE, NOTICEApache-2.0 + 署名。

未提供:10 个 Triton 内核。 请从上游仓库 CosmicRaisins/glm-5.2-gb10 (https://github.com/CosmicRaisins/glm-5.2-gb10)(Apache-2.0)获取,目录 kernels/。你需要的 10 个文件:
b12x_sparse_helpers.py deepseek_v2.py flashmla_sparse.py patch_flashmla_ops.py sm12x_deep_gemm_fallbacks.py sm12x_mqa.py sm12x_sparse_mla_attn.py sparse_attn_indexer.py sparse_mla_env.py sparse_mla_kernels.py

5. 详细步骤

步骤 (a)–(b) 和 (h) 在一台构建机器上运行(任意一个 Spark 节点即可)。步骤 (c)–(f) 涉及 每个节点。步骤 (g) 仅从头节点运行。在步骤 (b) 的同一烘焙过程中执行步骤 (h)(索引器补丁),然后再分发镜像到步骤 (c)。

a. 构建 vLLM 镜像(约 35–60 分钟)

克隆 eugr/spark-vllm-docker (https://github.com/eugr/spark-vllm-docker) 并根据固定的 vLLM 提交构建:

git clone https://github.com/eugr/spark-vllm-docker
cd spark-vllm-docker
./build-and-copy.sh --vllm-ref ab666069935c1f23e8ef56038b4659ac9e8f19f8 \
  -t vllm-node-tf5-glm52-b12x:probe --tf5

b. 将修改烘焙到镜像中

从 CosmicRaisins/glm-5.2-gb10 (https://github.com/CosmicRaisins/glm-5.2-gb10) 的 kernels/ 目录获取 10 个内核文件,放入构建机器的 ~/glm-triton 目录,然后在容器中运行两个修改脚本并提交结果。内核必须挂载到 /root/models/models15/glm-triton —— 这是 mods/glm52-sm12x-sparse/run.sh 所期望的路径(脚本顶部的 KERNELS=)。我们实际运行的方法如下:

docker run -d --name glm52-modding \
  -v ~/glm-triton:/root/models/models15/glm-triton:ro \
  -v $(pwd)/mods/glm52-sm12x-sparse:/mods/glm52-sm12x-sparse:ro \
  -v $(pwd)/mods/glm52-b12x-sparse:/mods/glm52-b12x-sparse:ro \
  vllm-node-tf5-glm52-b12x:probe sleep infinity

docker exec glm52-modding bash /mods/glm52-sm12x-sparse/run.sh
docker exec glm52-modding bash /mods/glm52-b12x-sparse/run.sh

docker commit \
  --change 'ENTRYPOINT ["/opt/nvidia/nvidia_entrypoint.sh"]' \
  --change 'CMD []' \
  glm52-modding vllm-node-tf5-glm52-b12x:probe-modded

docker rm -f glm52-modding

警告——两个 Docker 陷阱,我们都踩过:

  1. docker commit 会继承修补容器的 --entrypoint 覆盖。如果你启动容器时使用了 entrypoint 覆盖(或使用了一个裸命令如 sleep infinity),提交的镜像会携带该覆盖,并且无法启动 vLLM。始终 使用 --change 'ENTRYPOINT ["/opt/nvidia/nvidia_entrypoint.sh"]' --change 'CMD []' 提交(如上所示)。
  2. 当通过管道将脚本传输到容器时,请使用 docker exec -i。如果没有 -i,脚本会 静默地不执行任何操作——不报错,什么也不运行,你最终提交的是一个未修补的镜像。两个脚本都会打印 行;sm12x 脚本必须以 === glm52-sm12x-sparse complete === 结尾,b12x 脚本必须显示成功的 import b12x

c. 将镜像分发到所有节点

# 从构建机器,针对每个其他节点:
docker save vllm-node-tf5-glm52-b12x:probe-modded | \
  ssh <用户>@<节点> docker load

(通过 RoCE 网络只需要几分钟,而不是几小时。在较慢的链路上,pigz 有帮助。)

d. 权重:下载一次,rsync 到所有节点

一次 下载检查点(405 GB——请在网络最好的节点上进行):

hf download QuantTrio/GLM-5.2-Int4-Int8Mix \
  --local-dir /var/tmp/models/glm52-int4-int8mix

然后 通过 RoCE 网络(而不是你的上行链路)分发:

# 在拥有权重的节点上,针对每个其他节点的 fabric IP:
rsync -a --info=progress2 /var/tmp/models/glm52-int4-int8mix/ \
  <用户>@192.168.192.X:/var/tmp/models/glm52-int4-int8mix/

每个 节点上创建 hub 布局符号链接(容器内的服务路径是 /cache/huggingface/hub/glm52-int4-int8mix):

mkdir -p /var/tmp/models/hub
ln -sfn ../glm52-int4-int8mix /var/tmp/models/hub/glm52-int4-int8mix

e. 在每个节点上准备 NCCL 2.30.4

镜像中自带的 NCCL 会在运行时通过 LD_PRELOAD 替换。在 每个 节点上:

pip download nvidia-nccl-cu13==2.30.4 -d /tmp/nccl --no-deps
mkdir -p /var/tmp/models/hub/nccl-2.30.4
cd /tmp/nccl && unzip -o nvidia_nccl_cu13-2.30.4*.whl 'nvidia/nccl/lib/libnccl.so.2'
cp nvidia/nccl/lib/libnccl.so.2 /var/tmp/models/hub/nccl-2.30.4/

f. 在每个节点上准备内核

将 CosmicRaisins/glm-5.2-gb10 的 kernels/ 目录中的 10 个 .py 文件复制到 每个 节点的 ~/glm-triton 目录(launch.sh 会逐个文件将其以只读方式绑定挂载到 vLLM 树上):

git clone https://github.com/CosmicRaisins/glm-5.2-gb10
for node in 192.168.192.1 192.168.192.2 192.168.192.3 192.168.192.4; do
  rsync -a glm-5.2-gb10/kernels/ <用户>@$node:~/glm-triton/
done

g. 启动

编辑 launch.shEDIT 标记的配置块(节点 IP、SSH 用户/密钥、HCA + 接口名称),然后从头节点运行:

./launch.sh --dry-run   # 先检查生成的 docker 命令是否合理
./launch.sh

每个节点使用 docker run;vLLM 原生多节点(--nnodes/--node-rank),无 Ray。工作节点先以 headless 方式启动,最后启动 head。预计权重加载约 12 分钟 + cudagraph 预热约 10 分钟,然后 curl http://<head-ip>:8210/v1/models 才会响应。

h. 烘焙索引器 MTP 悬垂补丁(需要 --max-num-seqs >= 3

在与步骤 (b) 相同的烘焙过程中执行此操作,然后提交并分发镜像。patches/fix-indexer-mtp-overhang.py 修复了一个 vLLM bug:DSA 索引器仅根据 max_model_len 计算展开的块表缓冲区大小;MTP 推测令牌可能使请求超出该大小一个块,当并发请求 ≥3 时,引擎崩溃并显示 RuntimeError: The expanded size of the tensor (3125) must match the existing size (3126)。有关完整故事,请参阅补丁的文档字符串。

已验证(2026-07-05): 补丁已确认存在于镜像中后,完整的并发扫描(c1–c6)以零崩溃完成——包括 c3+ 级别,这些级别在未打补丁的引擎上会可靠地崩溃。见基准测试

按照与修改脚本完全相同的方式烘焙它——将其挂载到修补容器中,并在 docker commit 之前运行:

docker run -d --name glm52-modding \
  ... \
  -v $(pwd)/patches:/patches:ro \
  vllm-node-tf5-glm52-b12x:probe sleep infinity

# (在步骤 b 的两个修改脚本之后)
docker exec glm52-modding python3 /patches/fix-indexer-mtp-overhang.py

docker commit \
  --change 'ENTRYPOINT ["/opt/nvidia/nvidia_entrypoint.sh"]' \
  --change 'CMD []' \
  glm52-modding vllm-node-tf5-glm52-b12x:probe-modded

docker rm -f glm52-modding

成功时会打印 patched: .../indexer.py,并且该补丁是幂等的(可以安全地重新运行)。

6. 关键服务配置及原理

设置原因
--tensor-parallel-size4每个 TP rank 对应一个 GB10;405 GB / 4 ≈ 每节点 95 GiB 权重。
--speculative-config{"method":"mtp","num_speculative_tokens":4,"draft_tensor_parallel_size":1,"attention_backend":"FLASHMLA_SPARSE"}MTP 草稿模型在检查点内(第 78 层)。k=4 且 draft TP=1(back199640, #89):小型草稿模型无需 TP,draft TP=1 消除了每个推测步骤的跨节点跳转。
--kv-cache-dtypefp8_ds_mlafp8 稀疏 MLA KV:将 KV 占用量减半,使得 200K 上下文仅需 10.5 GB/节点的缓存。
--compilation-config{"cudagraph_mode":"FULL"}解码使用完整 CUDA 图。需要 b12x 修改——没有它,图捕获会崩溃(torch.full 在捕获状态下)。
--async-scheduling开启将 CPU 调度与 GPU 执行重叠(back199640, #80)——对 GB10 的 tok/s 有意义。
--max-num-batched-tokens8192预填充块大小:足够大以实现约 700+ tok/s 的预填充速度,又足够小以避免在深度时耗尽内存。
--gpu-memory-utilization + --kv-cache-memory-bytes0.91 + 10950000000确定性启动 + 精确 200K 的 KV 预算。 仅用 gmu,vLLM 会根据 当前可用 内存来调整 KV 大小,这在 GB10 统一内存中会随页面缓存而变化——相同命令可能 OOM 或正常启动,取决于缓存状态。gmu 0.90 仅为 KV 留下 9.78 GiB,而 200000 上下文需要 10.19 GiB(见陷阱 7)。gmu 0.91 配合 KV 固定为 10.95 GB 每次都能启动一个 200,064 token 的池。
--max-model-len200000200K 上下文,在固定 KV 预算内配合 fp8_ds_mla 可容纳。
--max-num-seqs6最多 6 个并发流。需要索引器 MTP 悬垂补丁(步骤 h)——未打补丁时,引擎在并发请求 ≥3 时崩溃。为了纯单流延迟构建,可降至 1。
NCCL_MIN/MAX_NCHANNELS4ciprianveg (#107):在 GB10 RoCE 上收窄 NCCL 通道可减少争用;更多通道在此处反而更慢。
--reasoning-parser / --tool-call-parserglm45 / glm47GLM-5.2 推理轨迹和工具调用格式的正确解析器。
--distributed-executor-backendmp原生多进程 + --nnodes/--node-rank 会合。无 Ray。

7. 陷阱(来之不易)

  1. RoCE fabric IP 必须位于正确的接口上——并且持久化在 netplan 中。 如果 fabric IP 是临时添加的,重新启动或链路抖动后,链路本地地址(169.254.x.x)可能会占用该端口,从而 改变 GID 表——你的 NCCL_IB_GID_INDEX 现在指向错误的 GID,NCCL 要么失败,要么静默降级。将 fabric IP 写入 netplan,并在任何重启后使用 show_gids 验证。

  2. IB 设备直通是必需的。 如果没有 --device /dev/infiniband + --cap-add IPC_LOCK + --ulimit memlock=-1:-1,NCCL 会 静默地 回退到通过套接字接口的 TCP。一切正常;但解码速度大约是 12 tok/s 而不是 30+。如果数字偏低,请检查容器内的 nvidia-smi 是否显示 NCCL 版本以及

相似文章