Prhub

#46163 [CI] Fix missing `tp_size` attribute on `RoutedExperts`

原始 PR 作者 fxmarty-amd 合并时间 2026-06-22 08:46 文件变更 1 提交数 2 评论 1 代码增减 +3 / -4

执行摘要

修复 RoutedExperts 缺少 tp_size 属性导致的崩溃

修复 AMD CI 流水线中 Gemma-4 模型加载时的崩溃:AttributeError: 'RoutedExperts' object has no attribute 'tp_size'。根本原因是 layer.tp_size 已被移除,但 moe_wna16.py 中的权重加载器未同步更新。PR body 附带了完整的堆栈跟踪,显示崩溃发生在 gemma4.pyload_weights 中,最终归结到 moe_wna16_weight_loader

建议快速合并。这是一个典型的属性名兼容性修复,修改直接、风险低。对于关注 MoE 量化模型加载的开发者,该 PR 可作为了解 RoutedExperts 配置结构调整的参考。

讨论亮点

PR 获得 3 个 Approved(BowenBao、yewentao256、mgoin),无 review 评论或争议。Issue 评论中 AndreasKaratzas 指出 AMD CI 测试将在其他 PR 中解决,本 PR 仅聚焦于属性兼容性修复。

实现拆解

  1. 定位问题:在 vllm/model_executor/layers/quantization/moe_wna16.pymoe_wna16_weight_loader 函数中,第 467 行和 476-477 行使用了 layer.tp_size,但 RoutedExperts 层不再直接暴露该属性。
  2. 新增局部变量:在第 429 行(原 428 行之后)插入 tp_size = layer.moe_config.moe_parallel_config.tp_size,从 MoE 并行配置对象中读取正确的 TP 大小。
  3. 替换引用:将第 467-468 行的 loaded_weight.view(layer.tp_size, -1, ...) 替换为 loaded_weight.view(tp_size, -1, ...),并将第 476-477 行的 loaded_weight.size(0), layer.tp_size, -1 替换为 loaded_weight.size(0), tp_size, -1
  4. 整理代码格式:合并了 w13_qzeros 分支的 view 调用,使代码更紧凑。整个修改仅涉及一个文件,共 7 行变更(+3/-4),无新增测试或配置变化。
文件 模块 状态 重要度
vllm/model_executor/layers/quantization/moe_wna16.py 量化层 modified 5.74

关键符号

moe_wna16_weight_loader

关键源码片段

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

唯一修改的文件。修复了 MoE WNA16 权重加载器中对 `tp_size` 的错误引用,确保从正确的配置链中获取张量并行大小。

# vllm/model_executor/layers/quantization/moe_wna16.py
# 关键变更:新增局部变量 tp_size 以替换已移除的 layer.tp_sizedef moe_wna16_weight_loader(
    param: torch.nn.Parameter,
    loaded_weight: torch.Tensor,
    weight_name: str,
    shard_id: str,
    expert_id: int,
    return_success: bool = False,
):
    # ... 前置转换逻辑 ...
​
    device = get_tp_group().device
    tp_rank = get_tensor_model_parallel_rank()
    # 修复:从 moe_config 中获取 tp_size,而非直接访问 layer.tp_size(已被移除)
    tp_size = layer.moe_config.moe_parallel_config.tp_size
    loaded_weight = loaded_weight.to(device)
    shard_size = layer.intermediate_size_per_partition
​
    # ... 重复 qzeros/scales 逻辑 ...
​
    if "w13_qzeros" in weight_name:
        # 使用 tp_size 变量来分割张量
        tensor = loaded_weight.view(tp_size, -1, loaded_weight.size(1))[tp_rank]
        # ... 后续赋值 ...
    elif "w2_qzeros" in weight_name:
        param.data[expert_id] = loaded_weight.view(
            loaded_weight.size(0), tp_size, -1
        )[:, tp_rank]
        # ... 后续 ...

评论区精华

没有提炼出高价值讨论线程

当前评论区没有形成足够清晰的争议点或结论,后续有更多讨论时会体现在这里。

风险与影响

风险极低:修改范围局限在单一函数 (moe_wna16_weight_loader),仅将硬编码的属性访问改为从 moe_config 间接获取。由于 layer.moe_config.moe_parallel_config.tp_size 是 MoE 层的标准配置路径,该修改不会引入回归,且不影响非 MoE 场景或无 TP 的量化模型。

影响范围窄:仅影响使用 MoE + WNA16 量化(如 AWQ/GPTQ 量化 + MoE 模型)的模型加载路径,具体为 Gemma-4 等模型。修复后,这些模型可以在启用了张量并行的环境下正常加载权重。对不涉及 MoE 或 WNA16 量化的场景无影响。

低影响

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论