执行摘要
- 一句话:B200 上 GLM-4.7-Flash 改用 paged MLA prefill 修复 rollout
- 推荐动作:值得一读,但主要是启动器层面的硬件适配,不需要深挖核心库。可关注两个设计点:一是用「launcher 参数按硬件分支」而非改核心 backend 来规避硬件兼容问题,保持了核心库的整洁;二是显式保留
sglang_attention_backend 透传口子,给用户留了绕过默认路径的逃生舱。后续建议在 sglang 升级时重点回归 B200 的 MLA prefill 路径。
功能与动机
PR body 明确描述症状:B200 rollout prefill 失败,报错 Unsupported head dimensions: head_dim_qk=256, head_dim_vo=256。根因是 flashinfer_mla_backend.py 在 SM100 上选择了 ragged CUTLASS prefill 路径,而 fmha_cutlass_sm100.cu 不支持 256 维 QK 和 value head。修复目标是让 GLM-4.7-Flash 在 B200 上开箱可用,同时不改变 GPU 拓扑。
实现拆解
- 扩展参数模型:在
scripts/run_glm47_flash.py 的 ScriptArgs 中将 hardware 从 Literal["H200"] 扩展为 Literal["H200", "B200"],默认仍为 H200;新增 sglang_attention_backend: str | None = None,允许显式指定 SGLang attention backend。
- 按硬件差异化 rollout 并行度:
sglang_args 中的 --rollout-num-gpus-per-engine 由固定值 4 改为 2 if args.hardware == "B200" else 1。原因是 GLM-4.7-Flash 有 20 个 attention head,rollout TP 必须整除 20;且 B200 上需要 TP2 配合 paged MLA 路径。注意 H200 的默认值从 4 变为 1,这会改变 H200 上的推理吞吐表现。
- 条件追加 SGLang flag:当
sglang_attention_backend 非 None 且非 default 时透传 --sglang-attention-backend;当 hardware == "B200" 且 backend 为自动选择、default 或 flashinfer 时追加 --sglang-flashinfer-mla-disable-ragged,从而避开 SM100 ragged kernel。显式选择 Triton 等其它 backend 时不会追加该 flag。
- 文档同步:
docs/models/glm/glm4-7-flash.md 更新 launcher 默认值说明,明确默认 hardware=H200、新增 sglang_attention_backend=None,并说明 B200 用 --rollout-num-gpus-per-engine 2、H200 用 1。
- 测试配套:第三个 commit 删除了一个专用的 launcher 参数测试文件,理由是脚本参数是刻意维护的,单测收益有限;最终只靠双 B200 端到端冒烟验证(跑到首个 optimizer step)。没有新增自动化测试。
关键文件:
scripts/run_glm47_flash.py(模块 启动脚本;类别 source;类型 core-logic;符号 ScriptArgs, execute): 启动器核心改动所在:扩展 hardware 支持 B200、按硬件设置 rollout TP、条件追加 --sglang-flashinfer-mla-disable-ragged 以绕过 SM100 ragged kernel 限制。
docs/models/glm/glm4-7-flash.md(模块 模型文档;类别 docs;类型 documentation): 同步说明 launcher 默认值、B200 支持以及 rollout 并行度差异,避免文档与脚本行为脱节。
关键符号:ScriptArgs, execute
关键源码片段
scripts/run_glm47_flash.py
启动器核心改动所在:扩展 hardware 支持 B200、按硬件设置 rollout TP、条件追加 --sglang-flashinfer-mla-disable-ragged 以绕过 SM100 ragged kernel 限制。
"""GLM-4.7-Flash 启动器:B200 上强制走 paged MLA prefill。"""
from dataclasses import dataclass
from typing import Literal
import miles.utils.external_utils.command_utils as U
@dataclass
class ScriptArgs(U.ExecuteTrainConfig):
# 只有 H200/B200 两个合法值,默认仍是 H200,保持旧行为。
hardware: Literal["H200", "B200"] = "H200"
# 允许用户显式选择 SGLang attention backend,None 表示交给 SGLang 自动选。
sglang_attention_backend: str | None = None
def execute(args: ScriptArgs):
# GLM-4.7-Flash 有 20 个 attention head,rollout TP 必须整除 20。
# B200 上用 TP2 配合 paged MLA prefill;H200 上保持 TP1 以换取吞吐。
sglang_args = (
f"--rollout-num-gpus-per-engine {2 if args.hardware == 'B200' else 1} "
"--sglang-mem-fraction-static 0.7 "
"--sglang-speculative-algorithm EAGLE "
"--sglang-speculative-num-steps 2 "
"--sglang-speculative-eagle-topk 1 "
"--sglang-speculative-num-draft-tokens 3 "
"--use-rollout-routing-replay "
)
# 显式指定非默认 backend 时透传,方便用户切到 Triton 等替代实现。
if args.sglang_attention_backend not in (None, "default"):
sglang_args += f"--sglang-attention-backend {args.sglang_attention_backend} "
# B200 上 FlashInfer 的 SM100 ragged prefill kernel 不支持 head_dim=256 的
# QK 与 VO,只有自动选择 / 默认 /flashinfer 三种情况才需要禁用 ragged 路径;
# 若用户显式选了其它 backend(如 Triton),则无需追加该 flag。
if args.hardware == "B200" and args.sglang_attention_backend in (None, "default", "flashinfer"):
sglang_args += "--sglang-flashinfer-mla-disable-ragged "
评论区精华
reviewer yueming-yuan 快速 approve,并提出 nit:"i think we might not need test for scripts args, given we will only edit it intentionally"。这与提交历史中删除 launcher 参数测试文件的 commit 完全对应,说明团队默认 scripts/ 下的启动器参数属于有意维护的配置,不为它背书自动化测试。
- 是否需要为 scripts 启动器参数编写测试 (testing): 作者采纳该建议,在后续 commit 中删除了专用的 launcher 参数测试文件,只保留双 B200 运行时冒烟验证。
风险与影响
- 风险:
- H200 并行度变化:patch 中
--rollout-num-gpus-per-engine 从固定 4 改为 H200=1、B200=2,PR body 声称 "node8/TP4/EP8/rollout4 remain",但与最终实现并不完全吻合,H200 的 rollout 引擎数实际从 4 降到 1,可能影响 H200 推理吞吐,文档未量化该影响。
- 缺少自动化测试:提交中删除了唯一的参数测试,且没有新增针对
--sglang-flashinfer-mla-disable-ragged 的校验,回归只能靠手动冒烟。
- 依赖 SGLang 内部 flag:
--sglang-flashinfer-mla-disable-ragged 是 SGLang 侧面暴露的开关,后续升级 sglang(本仓库常有此类升级,如 PR#1795)时若 flag 改名或默认行为变化,B200 路径可能再次失效。
- 魔法字符串硬件分支:
hardware == "B200" 的硬编码在脚本内,未来新增其它 GPU 型号时容易遗漏条件组合。
- 影响:影响范围局限于 scripts/run_glm47_flash.py 启动器和对应文档页。受益方是在 B200 上运行 GLM-4.7-Flash 训练的团队,从「完全跑不起来」变为「可端到端跑到 optimizer step」;H200 用户行为路径保持不变,但 rollout 并行度有变化,需要观察吞吐表现。对 miles 核心库、session、router 等模块零影响,团队协作上也没有引发争议。
- 风险标记:硬件硬编码分支, 缺少自动化测试, H200 默认并行度变更, 依赖 SGLang 内部 flag
关联脉络
- PR #2040 [AMD] DeepSeek-V4: use the ROCm precision-parity norm path: 同为 scripts 启动器中按硬件(ROCm)分支选择不同实现路径的适配模式,与 2047 的 B200 硬件分支思路一致。
- PR #1733 [AMD] Drop inert DSv4 rollout knobs and add an MTP recipe: 同样是脚本层按硬件/算法调整 rollout 配置,说明 miles 的硬件适配主要沉淀在启动脚本层。
- PR #2009 [docs] Add Inkling-Small model page: 与本次 docs 变更同属模型文档维护,反映模型文档与启动脚本同步更新的惯例。
参与讨论