Prhub

#47031 [Bugfix] Fix GraniteMoeShared weight loading broken by #41184

原始 PR 作者 mganczarenko 合并时间 2026-07-01 22:39 文件变更 1 提交数 3 评论 1 代码增减 +3 / -3

执行摘要

修复 GraniteMoeShared 权重加载路径错误

修复 IBM GraniteMoeShared 模型在 FusedMoE 重构后权重加载失败的问题。用户运行 ibm-research/moe-7b-1b-active-shared-experts 时遇到 KeyError: 'layers.0.block_sparse_moe.experts.routed_experts.routed_experts.w13_weight',导致引擎初始化失败。

该 PR 值得合并,修复精确且影响面小。建议开发者在未来类似重构中更关注子类覆盖的协议一致性,并考虑增加回归测试。

讨论亮点

review 过程简单,主要由 reviewer jikunshang 批准。无额外争议或讨论。

实现拆解

  1. 定位根因:在 vllm/model_executor/models/granitemoeshared.py 的 load_weights() 方法中,三个 n.replace() 调用生成 expert 键时多插入了 routed_experts 段,与父类期望的 experts.{e}.w{n}.weight 格式不符。
  2. 修正替换目标:将 w1_name、w3_name 和 w2_name 的替换字符串中的 routed_experts. 删除,使生成的键路径为 experts.{e}.w{n}.weight。
  3. 验证修复:通过加载 ibm-research/moe-7b-1b-active-shared-experts 模型并执行一次生成验证,确认权重加载成功,无 KeyError。
文件 模块 状态 重要度
vllm/model_executor/models/granitemoeshared.py 模型加载 modified 5.23

关键符号

GraniteMoeModel.load_weights

关键源码片段

vllm/model_executor/models/granitemoeshared.py data-contract

包含 GraniteMoeModel.load_weights() 方法,是本次 Bug 的根因和修复所在。三处替换字符串中的 `routed_experts` 段被移除,对齐父类期望的专家键格式。

# vllm/model_executor/models/granitemoeshared.py
# 修复:移除 spurious `routed_experts` 段,使键路径与父类契约一致
​
def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
    new_weights = {}
    for n, p in weights:
        if n.endswith(".block_sparse_moe.input_linear.weight"):
            for e in range(p.size(0)):
                # 原:f".block_sparse_moe.experts.routed_experts.{e}.w1.weight"
                # 改后:f".block_sparse_moe.experts.{e}.w1.weight"
                w1_name = n.replace(
                    ".block_sparse_moe.input_linear.weight",
                    f".block_sparse_moe.experts.{e}.w1.weight",
                )
                w3_name = n.replace(
                    ".block_sparse_moe.input_linear.weight",
                    f".block_sparse_moe.experts.{e}.w3.weight",
                )
                w1_param, w3_param = p[e].chunk(2, dim=0)
                assert w1_name not in new_weights
                assert w3_name not in new_weights
                new_weights[w1_name] = w1_param
                new_weights[w3_name] = w3_param
        elif n.endswith(".block_sparse_moe.output_linear.weight"):
            for e in range(p.size(0)):
                # 原:...routed_experts.{e}.w2.weight
                # 改后:...experts.{e}.w2.weight
                w2_name = n.replace(
                    ".block_sparse_moe.output_linear.weight",
                    f".block_sparse_moe.experts.{e}.w2.weight",
                )
                w2_param = p[e]
                assert w2_name not in new_weights
                new_weights[w2_name] = w2_param
        elif n.endswith(".block_sparse_moe.router.layer.weight"):
            gate_name = n.replace(
                ".block_sparse_moe.router.layer.weight",
                ".block_sparse_moe.gate.weight",
            )
            assert gate_name not in new_weights
            new_weights[gate_name] = p
        else:
            new_weights[n] = p
    # 委托给父类进行实际权重赋值
    return GraniteMoeModel._load_weights(self, new_weights.items())

评论区精华

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

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

风险与影响

风险极低。改动仅修改三个字符串字面量,移除冗余的 routed_experts 段,逻辑完全符合父类契约。由于该修改仅影响权重加载路径,不会引入回归性功能问题。但缺少新增的单元测试用例覆盖该修复。

影响范围限定为 GraniteMoeShared 模型系列(如 ibm-research/moe-7b-1b-active-shared-experts),修复了该模型无法加载权重的阻断性 Bug。对其他模型无影响。

缺少测试覆盖

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论