Prhub

#42061 [ROCm][Bugfix] Re-tag AITER MoE weights as preshuffled after replace_parameter

原始 PR 作者 maeehart 合并时间 2026-05-09 12:42 文件变更 3 提交数 2 评论 4 代码增减 +21 / -0

执行摘要

修复 AITER MoE 权重 shuffle 标记丢失

AITER 的 shuffle 操作虽然正确执行了权重重排,但随后 replace_parameter 构造新的 nn.Parameter 时丢失了 is_shuffled 属性,导致运行时内核选择器读取 getattr(layer.w13_weight, "is_shuffled", False) -> False,回退到非预重排(Nswizzle0)路径,无法使用针对预重排权重优化的调优内核,且每次推理时每个 MoE 层都输出警告。

值得合并。修复逻辑清晰,与 Quark MoE 的既有做法一致(quark_moe.py:1286-1287),已在真实硬件上验证。建议如果后续有同类 replace_parameter 模式,可将其封装为通用工具函数。

讨论亮点

Reviewer @dllehr-amd 建议精简注释,认为“AITER backend requires weights to be marked as shuffled” 即可,无需大段解释。作者 @maeehart 采纳并修剪了所有四个位置的注释为单行。无其他争议。

实现拆解

  1. FP8 MoE 方法(vllm/model_executor/layers/quantization/fp8.py):在 _setup_kernel 的 replace_parameter 调用后,新增条件判断 if self.fp8_backend == Fp8MoeBackend.AITER: layer.w13_weight.is_shuffled = True; layer.w2_weight.is_shuffled = True。同时从 oracle/fp8.py 导入 Fp8MoeBackend 枚举。
  2. MXFP4 MoE 方法(vllm/model_executor/layers/quantization/mxfp4.py):在 GptOssMxfp4MoEMethod._setup_kernel 和 Mxfp4MoEMethod._setup_kernel 的 replace_parameter 调用后(bias 处理之前),新增条件判断 if self.mxfp4_backend == Mxfp4MoeBackend.AITER_MXFP4_BF16: layer.w13_weight.is_shuffled = True; layer.w2_weight.is_shuffled = True。
  3. 未量化 MoE 方法(vllm/model_executor/layers/fused_moe/unquantized_fused_moe_method.py):在 _setup_kernel 的 replace_parameter 调用后、is_weight_update 判断之前,新增条件判断 if self.unquantized_backend == UnquantizedMoeBackend.AITER: layer.w13_weight.is_shuffled = True; layer.w2_weight.is_shuffled = True。
  4. 所有新增代码都放在 replace_parameter 之后,确保刚创建的 Parameter 对象立即被标记。
  5. 测试:通过 DeepSeek-V3.2-Exp w8a8 FP8 在 MI355X 上验证,警告从每进程 24 条降为 0,且调优内核正确选择 Nswizzle1 路径。
文件 模块 状态 重要度
vllm/model_executor/layers/quantization/fp8.py 量化层 modified 6.11
vllm/model_executor/layers/quantization/mxfp4.py 量化层 modified 6.12
vllm/model_executor/layers/fused_moe/unquantized_fused_moe_method.py MoE 层 modified 5.71

关键符号

Fp8MoEMethod._setup_kernel GptOssMxfp4MoEMethod._setup_kernel Mxfp4MoEMethod._setup_kernel UnquantizedFusedMoEMethod._setup_kernel

关键源码片段

vllm/model_executor/layers/quantization/fp8.py data-contract

FP8 MoE 量化方法,新增 AITER 后端标记,同时导入 Fp8MoeBackend 枚举。

# vllm/model_executor/layers/quantization/fp8.py
# ... ( 省略无关代码 ) ...
​
def _setup_kernel(
    self,
    layer: FusedMoE,
    w13: torch.Tensor,
    w2: torch.Tensor,
    w13_scale: torch.Tensor,
    w2_scale: torch.Tensor,
    w13_input_scale: torch.Tensor | None,
    w2_input_scale: torch.Tensor | None,
) -> None:
    # Shuffle weights to runtime format.
    w13, w2, w13_scale, w2_scale = convert_to_fp8_moe_kernel_format(
        fp8_backend=self.fp8_backend,
        layer=layer,
        w13=w13,
        w2=w2,
        w13_scale=w13_scale,
        w2_scale=w2_scale,
        w13_input_scale=w13_input_scale,
        w2_input_scale=w2_input_scale,
    )
​
    # Replace parameters with updated versions. Note that this helper
    # function ensures the replacement is compatible with RL weight reloads.
    replace_parameter(layer, "w13_weight", w13)
    replace_parameter(layer, "w2_weight", w2)
    replace_parameter(layer, f"w13_{self.weight_scale_name}", w13_scale)
    replace_parameter(layer, f"w2_{self.weight_scale_name}", w2_scale)
​
    # AITER backend requires weights to be marked as shuffled.
    if self.fp8_backend == Fp8MoeBackend.AITER:
        layer.w13_weight.is_shuffled = True
        layer.w2_weight.is_shuffled = True
​
    self.moe_quant_config = self.get_fused_moe_quant_config(layer)
    if self.moe_quant_config:
        assert self.experts_cls is not None
        self.moe_kernel = make_fp8_moe_kernel(
            moe_quant_config=self.moe_quant_config,
            moe_config=self.moe,
            fp8_backend=self.fp8_backend,
            experts_cls=self.experts_cls,
            routing_tables=layer._maybe_init_expert_routing_tables(),
            shared_experts=layer.shared_experts,
        )
vllm/model_executor/layers/quantization/mxfp4.py data-contract

MXFP4 MoE 量化方法,GptOssMxfp4MoEMethod 和 Mxfp4MoEMethod 的 _setup_kernel 中各新增一处标记。

# vllm/model_executor/layers/quantization/mxfp4.py
# ... ( 省略无关代码 ) ...
​
def _setup_kernel(self, layer, w13, w2, w13_scale, w2_scale, w13_bias, w2_bias):
    # ... (convert weight to kernel format) ...
    if self.mxfp4_backend not in TRITON_BACKENDS:
        replace_parameter(layer, "w13_weight", w13)
        replace_parameter(layer, "w2_weight", w2)
        replace_parameter(layer, "w13_weight_scale", w13_scale)
        replace_parameter(layer, "w2_weight_scale", w2_scale)
    else:
        layer.w13_weight = w13
        layer.w2_weight = w2
        self.w13_precision_config = w13_scale
        self.w2_precision_config = w2_scale
​
    # AITER backend requires weights to be marked as shuffled.
    if self.mxfp4_backend == Mxfp4MoeBackend.AITER_MXFP4_BF16:
        layer.w13_weight.is_shuffled = True
        layer.w2_weight.is_shuffled = True
​
    if w13_bias is not None and w2_bias is not None:
        replace_parameter(layer, "w13_bias", w13_bias)
        replace_parameter(layer, "w2_bias", w2_bias)
    # ... (rest of method) ...
vllm/model_executor/layers/fused_moe/unquantized_fused_moe_method.py data-contract

未量化 MoE 方法,新增 AITER 后端标记。

# vllm/model_executor/layers/fused_moe/unquantized_fused_moe_method.py
# ... ( 省略无关代码 ) ...
​
def _setup_kernel(
    self,
    layer: Module,
    w13: torch.Tensor,
    w2: torch.Tensor,
) -> None:
    # Shuffle weights to runtime format.
    w13_new, w2_new = convert_to_unquantized_kernel_format(
        self.unquantized_backend,
        layer=layer,
        w13_weight=w13,
        w2_weight=w2,
    )
    # ... (is_weight_update handling) ...
    replace_parameter(layer, "w13_weight", w13_new, prefer_copy=is_weight_update)
    replace_parameter(layer, "w2_weight", w2_new, prefer_copy=is_weight_update)
​
    # AITER backend requires weights to be marked as shuffled.
    if self.unquantized_backend == UnquantizedMoeBackend.AITER:
        layer.w13_weight.is_shuffled = True
        layer.w2_weight.is_shuffled = True
​
    if not is_weight_update:
        # ... (setup kernel) ...

评论区精华

注释长度 style

Reviewer dllehr-amd 认为注释过于冗长,建议简化为“AITER backend requires weights to be marked as shuffled”。

结论:作者采纳建议,将四个文件中的注释均修剪为单行。 · 已解决

风险与影响

低风险。每个修改点仅在特定 AITER 后端分支下执行,不影响其他后端。is_shuffled 属性仅被 AITER 运行时读取,且数据布局确实已重排,标记正确。主路径(非 AITER 后端)无任何行为变化。未附带自动化测试,但作者提供了手动验证结果。

对使用 AITER 后端的 ROCm 用户,消除每次推理时每个 MoE 层的警告,并恢复调优内核选择,可能带来性能提升。对其他平台或后端无影响。

缺少测试覆盖

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论