GLM-5.2-NVFP4 在 8×A800 上部署实战(上)
背景:把官方主打 Blackwell(B200/B300)的
GLM-5.2-NVFP4模型,硬塞到 8 张中国特供版 A800(sm80)上,实测单流 74--85 tok/s,4 并发 × 32k 上下文可跑通。
配套开源仓库:glm52-nvfp4-a800-vllm-deploy(Gitee),含 Dockerfile、补丁、一键脚本。
文章目录
- [GLM-5.2-NVFP4 在 8×A800 上部署实战(上)](#GLM-5.2-NVFP4 在 8×A800 上部署实战(上))
-
- [一 先给结论](#一 先给结论)
- [二 硬件环境](#二 硬件环境)
- [三 A800 为什么不能直接跑](#三 A800 为什么不能直接跑)
-
- [1. NVFP4 权重](#1. NVFP4 权重)
- [2. DSA 稀疏注意力(真正的问题)](#2. DSA 稀疏注意力(真正的问题))
- [四 准备源码并打补丁](#四 准备源码并打补丁)
-
- [手工修 indexer.py](#手工修 indexer.py)
- [五 修复 v0.26.0 的 3 处 API 漂移](#五 修复 v0.26.0 的 3 处 API 漂移)
-
- [1. 补 import](#1. 补 import)
- [2. 给 XPUMLASparseMetadata 补字段](#2. 给 XPUMLASparseMetadata 补字段)
- [3. build() 里填真实计数](#3. build() 里填真实计数)
- [六 下篇预告](#六 下篇预告)
一 先给结论
- 能跑,但不能开箱即用。 vLLM v0.26.0 官方的稀疏 MLA 后端只支持 SM90/SM100,A800 是 sm80,直接启动会崩溃。解决办法是应用社区补丁 PR #47629,新增纯 Triton 的
TRITON_MLA_SPARSE后端,然后再修复 3 处 v0.26.0 与补丁之间的 API 漂移,以及 1 个关键启动参数。整个补丁都是 Python 层改动,不需要重新编译 CUDA。
二 硬件环境
| 项 | 配置 |
|---|---|
| GPU | 8× NVIDIA A800 80GB PCIe(sm80,即 Ampere 架构) |
| 驱动 | ≥ R580 |
| 内存 | ≥ 512GB,最好能把 433G 权重全缓存进页缓存 |
| 模型 | GLM-5.2-NVFP4,约 433G,47 个 safetensors,架构 GlmMoeDsaForCausalLM |
| 基础镜像 | vllm/vllm-openai:v0.26.0 |
注意:不要用 NVIDIA NGC 的
vllm:26.01,它内置的 vLLM 是 0.11.1,太老,连 NVFP4 MoE 都不支持。
三 A800 为什么不能直接跑
- GLM-5.2 是 MoE + MLA + DSA 稀疏注意力 + 原生 MTP 的结构,并且用了 NVFP4 量化。A800 有两个硬伤:
1. NVFP4 权重
- A800 没有 FP4 Tensor Core,vLLM 内部会走 Marlin FP4 软件回退(W4A16,运行时反量化为 BF16)。v0.26.0 已经支持这条路径,日志里能看到:
bash
Using 'MARLIN' NvFp4 MoE backend
2. DSA 稀疏注意力(真正的问题)
v0.26.0 里稀疏 MLA 后端只有两种:
FLASHMLA_SPARSE:仅 SM90FLASH_ATTN_MLA_SPARSE:SM90/SM100
sm80 上一个后端都没有 ,所以 A800 直接跑必崩。社区补丁 PR #47629(源自 PR #38476)就是为了解决这个问题,新增了一个纯 Triton 实现的 TRITON_MLA_SPARSE 后端,并附带 bf16 Triton indexer 回退。
四 准备源码并打补丁
bash
mkdir -p ~/glm52-deploy && cd ~/glm52-deploy
# 1. 拉取与镜像一致的 v0.26.0 源码
git clone --depth 1 --branch v0.26.0 https://github.com/vllm-project/vllm.git vllm-src
cd vllm-src
# 2. 下载 PR #47629 diff
curl -sL https://github.com/vllm-project/vllm/pull/47629.diff -o ../pr-47629.diff
# 3. 应用补丁,排除 C++、docs、tests,以及会冲突的 indexer.py
git apply --exclude='csrc/**' --exclude='docs/**' --exclude='tests/**' \
--exclude='vllm/v1/attention/backends/mla/indexer.py' \
../pr-47629.diff
手工修 indexer.py
indexer.py 是唯一冲突的文件。把下面两处改掉:
python
# import 处
from vllm.utils.deep_gemm import (..., is_deep_gemm_supported, ...)
# build() 判断处
if current_platform.is_cuda() and is_deep_gemm_supported():
原因:has_deep_gemm() 只检查有没有 deep_gemm 这个包,而镜像里刚好 vendored 了一份,导致它在 A800 上也返回 True;但 A800 实际上不支持 DeepGEMM,真正该用的是 is_deep_gemm_supported()。
五 修复 v0.26.0 的 3 处 API 漂移
- PR #47629 基于 vLLM main 分支,v0.26.0 比它老一点,直接应用会报
AttributeError/NotImplementedError。所有修改都在vllm/v1/attention/backends/mla/xpu_mla_sparse.py。
1. 补 import
python
from vllm.v1.attention.backends.utils import split_decodes_and_prefills
2. 给 XPUMLASparseMetadata 补字段
v0.26.0 的 forward_impl 会访问下面这些字段,但 main 上的元数据类才有:
python
num_decode_tokens: int = 0
num_prefill_tokens: int = 0
num_decodes: int = 0
num_prefills: int = 0
prefill_max_seq_len: int = 0
seq_lens: Optional[torch.Tensor] = None
prefill: Optional[object] = None
cp_kv_cache_interleave_size: int = 1
dataclass 规则:带默认值的字段必须放在所有非默认字段之后。
3. build() 里填真实计数
python
(num_decodes, num_prefills, num_decode_tokens, num_prefill_tokens) = (
split_decodes_and_prefills(
common_attn_metadata,
decode_threshold=1,
require_uniform=False,
treat_short_extends_as_decodes=True,
)
)
metadata = XPUMLASparseMetadata(
# ... 原有参数 ...
num_decodes=num_decodes,
num_prefills=num_prefills,
num_decode_tokens=num_decode_tokens,
num_prefill_tokens=num_prefill_tokens,
seq_lens=common_attn_metadata.seq_lens,
)
如果不填真实值,num_decodes 等全为 0,forward_impl 会把 decode token 错误地路由到未实现的 MHA 路径。
六 下篇预告
到这里源码层的工作就做完了。下篇会讲:如何写 Dockerfile 构建补丁镜像;启动参数里那一个"必填参数"是什么;部署、验证、踩坑与性能数据。
版权声明:本文补丁基于 vLLM PR #47629,vLLM 采用 Apache-2.0 许可证。