Prhub

#35919 [DeepSeek V4] Default FP4 checkpoints to FlashInfer MXFP4 MoE

原始 PR 作者 Fridge003 合并时间 2026-08-22 07:48 文件变更 4 提交数 2 评论 10 代码增减 +106 / -74

执行摘要

DSV4 FP4 检查点自动选 FlashInfer MXFP4 MoE runner

PR body 明确指出:DeepSeek V4 FP4 expert checkpoints require the FlashInfer MXFP4 MoE runner on supported NVIDIA GPUs. Select it automatically when the user leaves the MoE runner backend at auto. 此前仅 SM120 架构通过 _deepseek_v4_sm120_moe 后处理 pass 获得该默认值,SM90/SM100 上的 FP4 检查点用户必须手动传参才能走正确的 runner,配置成本高且易错。本 PR 将这一默认行为扩展至全部支持的 NVIDIA 架构,并并入统一的 overrides 注册表,同时保持显式用户选择优先。

值得精读。重点学习两点:一是「自动默认值」的 fallback 条件设计——平台、架构白名单、A2A 模式、反量化环境变量、显式用户选择逐层让位,避免默认值吞噬用户意图;二是单元测试的矩阵化写法,用 patch.object 逐项钉住每个 fallback 分支。FP4 + DeepEP/A2A 用户应验证自己的启动组合是否仍可用。

讨论亮点

该 PR 没有留下任何 review 评论(review_comments_count 为 0),核心验证集中在 issue 评论里的 CI 重跑记录:

  • Fridge003 多次发起 /rerun-testtest_deepseek_v4_flash_fp4_b200.py(4-gpu-b200)与 test_deepseek_v4_flash_fp4_h200.py(8-gpu-h200)首轮均失败,重跑后双双通过;test_model_overrides.py 单测也通过。
  • 由于缺少独立审查视角,所有风险覆盖依赖作者自测(B200 GSM8K 0.970、bs=1 decode 385.66 token/s)与新增单元测试。

实现拆解

本 PR 的核心是把 MoE runner 的自动选择逻辑从分散的 post-process pass 收敛进模型 overrides 注册表,并按 4 个步骤落地:

  1. 合并 MoE runner 选择逻辑python/sglang/srt/arg_groups/overrides.py):在 _deepseek_v4_overrides 中,当 server_args.moe_runner_backend == "auto" 时,先保留 NVFP4 混合检查点(nvfp4_moe_meta is not None)路由到 flashinfer_trtllm_routed 的既有分支;新增 elif 分支,在同时满足「device == "cuda"、非 HIP、moe_a2a_backend == "none"、未开启 envs.SGLANG_DSV4_FP4_DEQUANTmodel_config.is_fp4_experts、SM90/SM100/SM120 之一」时写入 flashinfer_mxfp4。同时删除 _deepseek_v4_sm120_moe 这个 register_post_process 函数,避免两处逻辑分叉。
  2. 清理遗留调用python/sglang/srt/server_args.py):删除 _handle_model_specific_adjustments 中通过 run_post_process_pass 调用 _deepseek_v4_sm120_moe 的 legacy 代码与相关 import(净删除 9 行)。这一步是必要的:符号已删除,遗留调用会立即 ImportError;同时符合近期 config 重构「默认值统一走 overrides 解析管线」的方向。
  3. 重写单元测试test/registered/unit/test_model_overrides.py):_args 默认构造现在携带 is_fp4_experts=True 的 FP4 检查点,使正向断言能命中新分支;新增 6 类 fallback 断言(显式用户选择、A2A/DeepEP、FP4 反量化 env、FP8 检查点、NPU/HIP、不支持的 NVIDIA 架构),并删除随 _deepseek_v4_sm120_moe 一起移除的 test_deepseek_v4_sm120_moe_pass
  4. E2E 测试演练自动选择test/registered/models_e2e/test_deepseek_v4_flash_fp4_b200.py):移除启动命令中显式的 --moe-runner-backend flashinfer_mxfp4,让 B200 每提交 CI 真实走一遍自动选择路径,防止默认值与手动参数脱节。PR body 报告该测试 9 项全部通过,启动日志出现 Use flashinfer_mxfp4 as MoE runner backend for DeepseekV4ForCausalLM
文件 模块 状态 重要度
python/sglang/srt/arg_groups/overrides.py 默认配置 modified 7.09
test/registered/unit/test_model_overrides.py 配置测试 modified 6.74
python/sglang/srt/server_args.py 启动参数 modified 5.31
test/registered/models_e2e/test_deepseek_v4_flash_fp4_b200.py E2E 测试 modified 4.1

关键符号

_deepseek_v4_overrides _deepseek_v4_sm120_moe test_deepseek_v4_overrides_at_callable_level test_deepseek_v4_sm120_moe_pass

关键源码片段

python/sglang/srt/arg_groups/overrides.py core-logic

核心变更文件:将 FP4 检查点的 flashinfer_mxfp4 默认选择逻辑并入 `_deepseek_v4_overrides`,删除仅覆盖 SM120 的 `_deepseek_v4_sm120_moe` 后处理 pass,是本次行为变更的主入口。

# python/sglang/srt/arg_groups/overrides.py
# 变更后的完整 _deepseek_v4_overrides:MoE runner 默认值选择集中在这里,
# 原先独立的 _deepseek_v4_sm120_moe post-process pass 已被删除并合并进本函数。@_register_for("DeepseekV4ForCausalLM")
def _deepseek_v4_overrides(server_args: Any, hf_config: Any) -> dict:
    """DeepSeek V4 attention/page/window/MoE-runner 默认值。    kv-cache dtype 与 NPU split-backend 写入、max_running_requests 填充
    和校验仍留在 hook 的 legacy slot。
    """
    from sglang.srt.server_args import ServerArgs
​
    model_arch = hf_config.architectures[0]
    overrides: Dict[str, Any] = {"attention_backend": "dsv4"}
​
    page_size = 256
    if server_args.device == "npu":
        # NPU 保持设备相关的 dsv4 后端(注册表路由到 Ascend V4 子类),
        # 只有 pool 几何与 dtype 不同,因此 page_size 改为 128。
        page_size = 128
        overrides["prefill_attention_backend"] = "dsv4"
        overrides["decode_attention_backend"] = "dsv4"
    overrides["page_size"] = page_size
    logger.info(
        f"Use dsv4 attention backend for {model_arch}, setting page_size to {page_size}."
    )
​
    # 用户未显式修改 swa_full_tokens_ratio 时才写入默认值 0.1
    if server_args.swa_full_tokens_ratio == ServerArgs.swa_full_tokens_ratio:
        overrides["swa_full_tokens_ratio"] = 0.1
        logger.info(f"Setting swa_full_tokens_ratio to 0.1 for {model_arch}.")
​
    # 仅当用户把 MoE runner 留在 auto 时,才做模型级默认选择;
    # 显式传入的 --moe-runner-backend 永远优先,不会被覆盖。
    if server_args.moe_runner_backend == "auto":
        model_config = server_args.get_model_config()
        # nvidia/DeepSeek-V4-Pro-NVFP4 是混合 FP8+NVFP4 检查点,
        # 必须使用 routed TRT-LLM runner,优先级高于 FP4 分支。
        if model_config.nvfp4_moe_meta is not None:
            overrides["moe_runner_backend"] = "flashinfer_trtllm_routed"
            logger.info(
                "Use flashinfer_trtllm_routed as MoE runner backend for "
                f"{model_arch} hybrid FP8+NVFP4 checkpoint."
            )
        elif (
            server_args.device == "cuda"
            and not is_hip()
            and server_args.moe_a2a_backend == "none"
            and not envs.SGLANG_DSV4_FP4_DEQUANT.get()
            and model_config.is_fp4_experts
            and (is_sm90_supported() or is_sm100_supported() or is_sm120_supported())
        ):
            # FP4 expert 检查点在受支持的 NVIDIA 架构上默认走 FlashInfer MXFP4:
            # - MXFP4 只支持标准(非 A2A)dispatcher,所以 DeepEP/A2A 下不选择;
            # - 开启运行时 FP4->FP8 反量化时保留通用 FP8 runner;
            # - 架构白名单之外的 GPU 不选择,避免引用无法启动的 kernel。
            overrides["moe_runner_backend"] = "flashinfer_mxfp4"
            logger.info(
                "Use flashinfer_mxfp4 as MoE runner backend for " f"{model_arch}."
            )
    return overrides

评论区精华

B200 / H200 E2E 重跑验证自动选择路径 测试

Fridge003 在 issue 评论中多次发起 `/rerun-test`,`test_deepseek_v4_flash_fp4_b200.py`(4-gpu-b200)与 `test_deepseek_v4_flash_fp4_h200.py`(8-gpu-h200)首轮均失败,重跑后双双通过;随后 `test_model_overrides.py` 单测也通过。

结论:B200(SM100)与 H200(SM90)E2E 最终通过,验证了移除显式 `--moe-runner-backend` 后自动选择 `flashinfer_mxfp4` 的路径。 · 已解决

缺少独立 review 评论 other

该 PR 的 review 评论数为 0,由作者 Fridge003 自行合并,未留下外部审查记录。

结论:默认值类变更缺少第二人审查视角,风险主要由单元测试矩阵与 E2E 自测兜底。 · 已解决

风险与影响

  1. 默认行为变更:FP4 检查点 + auto 用户在支持的 NVIDIA GPU 上会无提示切换到 flashinfer_mxfp4,若其原工作流依赖通用 FP8 runner 或反量化路径,需确认 SGLANG_DSV4_FP4_DEQUANT 等环境变量组合仍符合预期。
  2. FP4 + A2A/DeepEP 组合缺口moe_a2a_backend == "none" 是硬条件,测试只断言「不覆盖」,未验证 FP4 检查点搭配 --moe-a2a-backend deepep 时能否真正启动——该组合可能既不走 MXFP4 也无其他 fallback,存在静默配置缺口。
  3. SM90 新增覆盖:白名单从 SM120 扩展到 SM90/SM100,依赖 FlashInfer MXFP4 在 SM90 的 kernel 可用性;H200(SM90)E2E 重跑后通过,但 CI 首轮失败过,环境稳定性有待观察。
  4. 无外部 review:作者自行合并,缺少第二人审查,默认值类变更尤其依赖测试完备性来兜底。

用户侧:DeepSeek V4 FP4 检查点在 B200/GB300(SM100)、H200(SM90)与 SM120 设备上开箱即用,不再需要手工指定 --moe-runner-backend flashinfer_mxfp4,减少配置错误;启动日志会明确输出所选 backend。系统侧:配置解析路径简化,少一个 post-process pass,默认值统一收敛到 overrides.py 注册表,与 config 重构系列(PR#35905-35910)方向一致。性能侧:B200 上 GSM8K 0.970 达标,bs=1 decode 385.66 token/s、输出吞吐 2104.59 token/s,均通过测试门槛。

默认行为变更 FP4 + DeepEP 组合缺口 SM90 新增覆盖 缺少外部 review

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论