Prhub

#51248 [Quantization][Autoround][XPU] Support AutoRound MXFP8 MoE models

原始 PR 作者 jl9876 合并时间 2026-08-31 16:37 文件变更 3 提交数 5 评论 11 代码增减 +341 / -0

执行摘要

新增 AutoRound MXFP8 MoE 量化方案,支持 Qwen3 等模型在 XPU 上运行

PR body 明确说明目标是 "Adds XPU support for AutoRound-format MXFP8 MoE models"。在此之前,INC(Intel Neural Compressor)的 AutoRound 支持中,MXFP8 只有线性层方案(INCMxfp8LinearScheme),MoE 层只有 MXFP4 方案(INCMxfp4MoEMethod),MXFP8 的 MoE 路径缺失,导致 Qwen3-30B-A3B-MXFP8-AutoRound 这类 MoE checkpoint 无法以 inc 量化方式加载。PR 同时用 PIQA(acc 0.7905)和 GSM8K 5-shot(exact_match 0.9075 / 0.9166)数据论证精度达标;reviewer yiliu30 还要求附上 Qwen3-30B-A3B-Instruct-2507 的全精度参考基线(预期 0.9 以上)以佐证量化损失可控。

值得精读,尤其是关注量化方案扩展模式的人:可以学习 "scheme 接口分层(get_linear_method / get_moe_method) + FusedMoE 基础设施复用 + monkeypatch 隔离 kernel 的单测" 这套组合拳,它让一个多硬件厂商特性以极低侵入落地。通用用户只需知道 --quantization inc 现在已支持 MXFP8 MoE 即可。

讨论亮点

review 中核心交锋集中在三处:

  • 为什么 a1_scale / a2_scale 传 None:jikunshang 在 inc_mxfp8_moe.py 第 165 行附近发问,jl9876 解释 AutoRound 序列化 MXFP8 格式采用动态激活量化,checkpoint 只含量化权重与权重缩放、没有静态激活缩放张量,因此传 None,激活缩放由 MXFP8 后端运行时生成;jikunshang 认可("oh make sense.")。
  • 构造逻辑冗余问题:jikunshang 质疑某处初始化代码 "necessary?",并推测该逻辑是 vLLM 在线量化所需;jl9876 实测确认冗余后删除("I tested it and confirmed that it was redundant, so I've removed it.")。
  • 精度基线补充:yiliu30 总体 LGTM,但要求附上 Qwen3-30B-A3B-Instruct-2507 的 GSM8K 参考结果(预期 > 0.9);随后 APPROVED。

实现拆解

  1. 新增 MXFP8 MoE 量化方法:在 vllm/model_executor/layers/quantization/inc/schemes/inc_mxfp8_moe.py 中新增 INCMxfp8MoEMethod,继承 FusedMoEMethodBase。create_weights 按 [1, 32] 的 block 粒度注册 w13_weight、w2_weight(torch.float8_e4m3fn)与配套 scale(torch.uint8),并在入口校验 hidden_size 与 intermediate_size_per_partition 可被 MXFP8_BLOCK_SIZE(32)整除,不满足直接抛 ValueError;同时对 scale 参数打上 quant_method == "block" 标记。process_weights_after_loading 调用 convert_to_fp8_moe_kernel_format 将 AutoRound 序列化布局转为 fp8 MoE kernel 期望布局,再用 replace_parameter 原地替换参数,最后通过 make_fp8_moe_quant_config 与 make_fp8_moe_kernel 构建执行 kernel;apply 只是委托 kernel。提交 3e43794 专门修复了 post-load 阶段的处理,说明早期版本存在权重布局转换不完全的问题。
  2. 扩展 MXFP8 scheme 入口:inc_mxfp8_scheme.py 的 INCMxfp8Scheme 新增 get_moe_method,返回 INCMxfp8MoEMethod(layer.moe_config),与已有的 get_linear_method 形成对称接口。此前该 scheme 只处理线性层,MoE 层会落入非量化路径。
  3. 测试与精度验证配套:tests/quantization/test_auto_round.py 增加 qwen3_30b_a3b_mxfp8 配置 fixture 与真实模型参数 INCModel/Qwen3-30B-A3B-12L-MXFP8-test;两个新增单测分别用 monkeypatch 隔离 select_mxfp8_moe_backend,验证路由(linear 层走 INCMxfp8LinearScheme、mlp 层走 INCMxfp8MoEMethod、gate 不量化)和权重注册(形状、dtype、block 标记、非整除抛错)。PR body 给出 Qwen3-30B-A3B-MXFP8-AutoRound 在 PIQA(acc 0.7905)与 GSM8K 5-shot(exact_match 0.9166)上的手动评估结果。
文件 模块 状态 重要度
vllm/model_executor/layers/quantization/inc/schemes/inc_mxfp8_moe.py 量化后端 added 9.28
vllm/model_executor/layers/quantization/inc/schemes/inc_mxfp8_scheme.py 量化方案 modified 6.58
tests/quantization/test_auto_round.py 量化测试 modified 7.02

关键符号

INCMxfp8MoEMethod.__init__ INCMxfp8MoEMethod.create_weights INCMxfp8MoEMethod.process_weights_after_loading INCMxfp8MoEMethod.get_fused_moe_quant_config INCMxfp8MoEMethod.apply INCMxfp8Scheme.get_moe_method test_qwen3_30b_a3b_mxfp8_autoround_routes_to_mxfp8_moe test_inc_mxfp8_moe_method_registers_block_scaled_weights

关键源码片段

tests/quantization/test_auto_round.py test-coverage

新增 MXFP8 MoE 的配置 fixture、真实模型参数化用例与两个针对性单测,覆盖路由与权重注册,是保证该量化方案可维护性的关键配套。

def test_qwen3_30b_a3b_mxfp8_autoround_routes_to_mxfp8_moe(
    monkeypatch,
) -> None:
    # 用假的后端选择函数替换真实实现,
    # 从而在不加载真实模型和 kernel 的情况下验证路由逻辑
    expected_backend = object()
    expected_experts_cls = object()
    captured = {}
​
    def fake_select_mxfp8_moe_backend(*, config):
        captured["moe_config"] = config
        return expected_backend, expected_experts_cls
​
    monkeypatch.setattr(
        "vllm.model_executor.layers.quantization.inc.schemes."
        "inc_mxfp8_moe.select_mxfp8_moe_backend",
        fake_select_mxfp8_moe_backend,
    )
​
    config = make_qwen3_autoround_config("qwen3_30b_a3b_mxfp8")
    layer = object.__new__(RoutedExperts)
    layer.moe_config = cast(Any, "moe-config")
​
    # 同一个 config 对不同层类型应产出不同量化方案:
    # q_proj 线性层走 MXFP8 线性方案,mlp 走 MXFP8 MoE 方案,
    # gate 层按 extra_config 保持 16-bit 不量化
    linear_method = config.get_quant_method(
        object.__new__(LinearBase), "model.layers.0.self_attn.q_proj"
    )
    moe_method = config.get_quant_method(layer, "model.layers.0.mlp")
    gate_method = config.get_quant_method(
        object.__new__(LinearBase), "model.layers.0.mlp.gate"
    )
​
    from vllm.model_executor.layers.quantization.inc.schemes.inc_mxfp8_moe import (
        INCMxfp8MoEMethod,
    )
​
    assert isinstance(linear_method, INCLinearMethod)
    assert isinstance(linear_method.scheme, INCMxfp8LinearScheme)
    assert isinstance(moe_method, INCMxfp8MoEMethod)
    # 后端选择结果应透传,且 moe_config 应与 layer 上的一致
    assert moe_method.mxfp8_backend is expected_backend
    assert moe_method.experts_cls is expected_experts_cls
    assert captured["moe_config"] == layer.moe_config
    assert isinstance(gate_method, UnquantizedLinearMethod)

评论区精华

a1_scale / a2_scale 为何传 None 设计

jikunshang 在 `inc_mxfp8_moe.py` 的 `get_fused_moe_quant_config` 处追问 "why it's none here?"。jl9876 解释:`a1_scale` 与 `a2_scale` 是预计算的静态激活缩放,而序列化 AutoRound MXFP8 格式采用动态激活量化,checkpoint 只含量化权重与权重缩放,激活缩放由 MXFP8 后端在运行时生成。

结论:双方达成一致,jikunshang 回复 "oh make sense.",确认动态激活量化设计合理。 · 已解决

构造阶段疑似冗余的初始化逻辑 style

jikunshang 指出文件创建区域某处代码 "necessary?",并推测其服务于 vLLM 在线量化路径;jl9876 实测后确认 "it was redundant, so I've removed it"。

结论:冗余代码被删除,最终合入版本更精简。 · 已解决

请求补充全精度参考基线 测试

yiliu30 总体 LGTM,但要求附上 Qwen3-30B-A3B-Instruct-2507 的 GSM8K 结果作为参考,并提示此前测试分数应高于 0.9。

结论:PR body 已提供量化模型 GSM8K 5-shot exact_match 0.9075 / 0.9166 的结果,yiliu30 最终 APPROVED。 · 已解决

风险与影响

  1. XPU 后端选择未在单测覆盖:INCMxfp8MoEMethod.__init__ 调用 select_mxfp8_moe_backend(config=self.moe) 选择实际 kernel 后端与 experts 容器类,单测用 monkeypatch 完全绕过了该逻辑;若 XPU 上后端注册不完整,模型加载会在 __init__ 阶段失败,且只有真实模型参数化用例能兜底。
  2. 行为变更点:INCMxfp8Scheme.get_moe_method 新增后,所有走 inc 量化且 is_mxfp8 为真的 MoE 层都会从原本的非量化路径切换到新的 MXFP8 路径,属于隐式行为切换,依赖 can_handle 的判定准确性。
  3. 格式耦合:a1_scale / a2_scale 硬编码为 None,仅适配"序列化且动态激活"的 AutoRound 变体;若未来接入含静态激活缩放的 checkpoint,该方法不会读取,需要另一个 scheme 分支。
  4. 对齐约束限制:hidden_size 与 intermediate_size_per_partition 必须被 32 整除,个别 MoE 模型(hidden 尺寸非 32 倍数)会直接加载失败;这是有意的防护,但也是模型兼容性边界。
  5. 回归面小但精度依赖手工评估:+341/-0 不改既有路径,理论回归面小;端到端精度仅依赖 PR 内人工评估,缺少 CI 自动数值断言。

用户侧:Intel XPU 与 CUDA 用户现在可以用 --quantization inc 直接加载 AutoRound 产出的 MXFP8 MoE checkpoint(如 Qwen3-30B-A3B),打通了此前 MXFP8 MoE 无法加载的断层。系统侧:新增一个 FusedMoEMethodBase 子类与 scheme 接口方法,完全复用共享的 MXFP8 基础设施(convert_to_fp8_moe_kernel_format、make_fp8_moe_kernel、select_mxfp8_moe_backend),不触碰既有 CUDA 路径。团队侧:为 Intel INC 团队后续扩展其他 AutoRound 格式(静态激活、不同 block shape)提供了可复用的模板,也展示了厂商侧如何以最小侵入接入 vLLM 量化框架。

行为变更点:MXFP8 MoE 层由非量化切换到量化路径 XPU 后端选择逻辑未在单测中覆盖 仅支持动态激活的序列化 AutoRound 格式 尺寸对齐约束限制模型兼容性 端到端精度依赖手工评估

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论