Prhub

#52603 [Quantization] Remove the dead ocp_mx_scheme branch from moe_kernel_quantize_input

原始 PR 作者 xuebwang-amd 合并时间 2026-08-19 05:42 文件变更 1 提交数 1 评论 3 代码增减 +0 / -16

执行摘要

删除 fused_moe 量化入口的死代码分支与参数

该 PR 是 #46142 引入 quantization_emulation 后遗留清理项的闭环。PR body 明确指出:moe_kernel_quantize_input() 携带 ocp_mx_scheme 参数并在函数体开头将 *_a_fp8 短接到 _fp8_quantize_dequantize,但 “Nothing reaches that block.”。代码中留有 TODO:Remove this ocp_mx_scheme is not None block and rely solely on quantization_emulation。fxmarty-amd 在 #46142 review 中两次确认该块不再需要(“Yes I don't think this code block is needed” / “Let's address in an other PR.”),并在 #43983 review 中再次链接 utils.py#L288-L301 要求跟进,本 PR 即完成该请求。

值得快速浏览,可将其作为死代码删除类 PR 的范本:如何在不跑全量测试的前提下,用调用点穷举与路径等价性表论证“行为零变更”。不需要深入理解 fused MoE 内核细节;如果你正在做 quantization_emulation 或 OCP MX 的后续开发,请留意本 PR 收敛后的唯一分发入口。

讨论亮点

本 PR 的 review 讨论很少且无技术交锋。fxmarty-amd(#46142 中 TODO 的提出者)在批准时仅表示 “LGTM thanks a lot for the cleanup!”,没有提出新问题;这意味着最了解这段遗留历史的人认可清理的等价性论证。claude[bot] 提示 PR 来自 fork、自动化 review 被禁用,最终未触发。核心论证(26 个调用点穷举、位置元数分析、路径等价性表)全部在 PR body 和 commit message 中完成,而非在 review 中产生。

实现拆解

  1. 删除入口参数:在 vllm/model_executor/layers/fused_moe/utils.py 中删除 moe_kernel_quantize_input 的 ocp_mx_scheme: str | None = None 参数。该参数原本位于 quantization_emulation 之前的第 6 个位置参数位。提交信息穷举了全仓 26 个调用点:没有任何调用点以关键字 ocp_mx_scheme= 传入,最大位置传参元数为 5(够不到第 6 位),且不存在 **kwargs 透传、别名导入、functools.partial 或 getattr 引用,因此删参不改变任何现有调用行为。
  2. 删除短路分支:移除函数体开头的 if ocp_mx_scheme is not None: 整体块(16 行),其中包含三部分——对 w_mxfp4 / w_mxfp4_a_mxfp4 的 pass 空操作、对 *_a_fp8 的 QDQ 短路返回 _fp8_quantize_dequantize(A, A_scale)、以及对应的解释注释与 TODO 标记。
  3. 等价性确认:唯一有行为的分支是 .endswith("a_fp8")。OCP MX family 中只有 w_mxfp4_a_fp8 可达(w_mxfp6_e3m2_a_fp8 与 w_mxfp6_e2m3_a_fp8 已在 QuarkOCP_MX_MoEMethod.get_fused_moe_quant_config 中提前抛出 NotImplementedError),且该路径与幸存分发中的 quant_dtype == current_platform.fp8_dtype() + quantization_emulation 分支行为完全一致:两者都落在 _fp8_quantize_dequantize(A, A_scale),且该函数只接收 A 与 A_scale,不存在被绕过的其他逻辑。
  4. 验证配套:未新增测试文件,回归依赖 tests/kernels/moe/test_ocp_mx_moe.py 与 tests/kernels/moe/test_cutlass_moe.py,并跑 pre-commit 对目标文件做静态检查;E2E 计划在 ROCm MI325 上以 amd/gpt-oss-120b-w-mxfp4-a-fp8 + --moe-backend emulation 复测(PR body 标注结果 Coming soon)。
文件 模块 状态 重要度
vllm/model_executor/layers/fused_moe/utils.py 量化工具 modified 5.47

关键符号

moe_kernel_quantize_input

关键源码片段

vllm/model_executor/layers/fused_moe/utils.py data-contract

唯一变更文件,移除 `moe_kernel_quantize_input` 的 `ocp_mx_scheme` 参数与函数体开头的 OCP MX 短路分支,消除死代码与数据契约上的误导。

# vllm/model_executor/layers/fused_moe/utils.py(PR #52603 合并后)
​
​
def moe_kernel_quantize_input(
    A: torch.Tensor,
    A_scale: torch.Tensor | None,
    quant_dtype: None | torch.dtype | str,
    per_act_token_quant: bool,
    block_shape: list[int] | None = None,
    is_scale_swizzled: bool = True,
    quantization_emulation: bool = False,
    mx_alignment: int = 0,
) -> tuple[torch.Tensor, torch.Tensor | None]:
    # 旧版本在此处有一个 `ocp_mx_scheme` 参数和短路分支,会把 `*_a_fp8`
    # 提前送入 `_fp8_quantize_dequantize`,再走正常的 `quant_dtype` 分发。
    # 本次变更删除了该分支:全仓 26 个调用点没有任何一处填写此参数,
    # 且唯一可达的 `w_mxfp4_a_fp8` 与下面 FP8 + emulation 分支行为完全一致
    # (都是 `_fp8_quantize_dequantize(A, A_scale)`),因此等价收敛。
    if quant_dtype == current_platform.fp8_dtype():
        # 模拟量化模式:复用已有非模拟算子完成 QDQ(quantize-dequantize)往返
        if quantization_emulation:
            return _fp8_quantize_dequantize(A, A_scale)
        # 原生模式:直接走硬件量化
        else:
            return _fp8_quantize(A, A_scale, per_act_token_quant, block_shape)
    elif quant_dtype == torch.int8:
        # int8 目前不支持模拟量化,显式拒绝
        if quantization_emulation:
            raise NotImplementedError(
                "moe_kernel_quantize_input does not support quant_dtype=torch.int8"
                " MOE quantization emulation. Please open an issue."
            )
        return _int8_quantize(A, A_scale, per_act_token_quant, block_shape)
    elif quant_dtype == "nvfp4":
        if not quantization_emulation:
            return _nvfp4_quantize(A, A_scale, is_sf_swizzled_layout=is_scale_swizzled)
        else:
            # 模拟路径:用参考实现先 QDQ 再原样返回,供精度对齐使用
            assert A_scale is not None
            A = ref_nvfp4_quant_dequant(A, A_scale, block_size=16)
            return A, None
    elif quant_dtype == "mxfp4":
        # 非 XPU 且非模拟模式禁止使用,防止误走通用量化路径
        if not current_platform.is_xpu() and not quantization_emulation:
            raise NotImplementedError(
                "moe_kernel_quantize_input should not be used for native"
                " quant_dtype='mxfp4' MOE. Please open an issue."
            )
        return _mxfp4_quantize(A, A_scale, per_act_token_quant, block_shape)
    # 后续 `mxfp8`、`mxfp6` 等分支保持不变,统一由 `quant_dtype` 分发

评论区精华

fxmarty-amd 对清理闭环的确认 设计

原 TODO 提出人 fxmarty-amd 在批准时仅回复 “LGTM thanks a lot for the cleanup!”,未提出新增要求。PR body 已通过调用点穷举与路径等价性表(删除分支与幸存分支均落在 `_fp8_quantize_dequantize(A, A_scale)`)论证行为零变更。

结论:清理请求闭环,reviewer 认可等价性论证并批准合并。 · 已解决

fork PR 的自动化 review 说明 other

claude[bot] 提示该 PR 来自 fork,自动化 review 默认禁用;如需可让维护者通过 `@claude review` 手动触发一次。最终未触发。

结论:无实质技术影响,人类 reviewer 已完成批准。 · 已解决

风险与影响

  1. 数据契约风险(参数删除):moe_kernel_quantize_input 删除了位置索引为 6 的参数。仓库内 26 个调用点已穷举无引用,但若外部 fork 或深度下游直接 import 该内部函数,并按位置或 ocp_mx_scheme= 关键字传入第 7 个实参,会收到 TypeError。该函数属于 vllm.model_executor.layers.fused_moe 内部实现,非公开 API,影响面可控。
  2. 行为回归风险:等价性依赖 OCP_MXQuantizationEmulationTritonExperts.__init__ 同时设置 quantization_emulation = True 与 _quant_dtype = current_platform.fp8_dtype(),以及 TritonExperts.apply 的正确转发。若未来出现新的 *_a_fp8 OCP MX 变体且不走 emulation 初始化路径,将缺少旧分支兜底;当前无此类变体,风险仅停留在理论层。
  3. 测试覆盖风险:本 PR 无直接测试文件变更,依赖存量 MoE 回归测试与人工 E2E;若存量测试未覆盖 emulation + OCP MX 组合路径,存在漏检行为回归的可能。
  1. 用户与运行时影响:零影响,纯死代码删除,不改变任何量化结果或推理路径。
  2. 代码结构影响:moe_kernel_quantize_input 签名收敛,量化路径唯一由 quant_dtype + quantization_emulation 决定,消除了对 ocp_mx_scheme 的隐式依赖与后续维护者的误用空间。
  3. 团队与流程影响:低。单文件 16 行删除、1 个 commit、3 条评论即完成合并;为同类清理 PR 提供了“调用点穷举 + 路径等价性”的论证模板。
数据契约变更 无直接测试覆盖 依赖存量回归

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论