Prhub

#26026 [bug fix] Fix 3 issues when using Gemma4 MTP

原始 PR 作者 pyc96 合并时间 2026-05-23 18:16 文件变更 3 提交数 4 评论 3 代码增减 +20 / -11

执行摘要

修复 Gemma4 MTP 三个初始化崩溃问题

Gemma4 MTP assistant 模型在初始化时崩溃,无法正常启动服务。PR body 中引用了两个堆栈跟踪:

  • AttributeError: 'Gemma4AssistantForCausalLM' object has no attribute 'pp_group' —— 因为 MTP 类跳过了 Gemma4CausalLM.__init__,未设置 pp_group
  • TypeError: 'NoneType' object cannot be interpreted as an integer —— 因为 num_expertsNone,但仍调用 FusedMoE.make_expert_params_mapping
  • 第三个问题:BF16 checkpoint 不应使用 flashinfer 作为 MoE runner 后端,但当前代码对所有 moe_runner_backend == "auto" 的情况都选择了 flashinfer_trtllm

此 PR 值得关注,它展示了处理模型初始化兼容性问题的典型模式:

  • 当子类跳过了父类的 __init__ 时,需要显式设置父类依赖的成员变量。
  • 对于 MoE 模型的 Dense 变体,需要安全处理 num_experts 缺失的情况。
  • 硬件特定的自动后端选择应结合量化类型共同判断,避免对不支持的后端进行硬编码。建议其他模型后端自动选择逻辑也参考此模式。
讨论亮点

仅有一条审核评论:kpham-sgl 审阅者批准了该 PR,表示 "LGTM, thanks for the bug fix"。没有其他讨论或争议。

实现拆解

  1. 修复 MTP 类缺失 pp_group 属性 (python/sglang/srt/models/gemma4_mtp.py):

    • 新增导入 from sglang.srt.distributed import get_pp_group
    • Gemma4AssistantForCausalLM.__init__ 中显式调用 self.pp_group = get_pp_group(),确保 pp_group 在模型初始化时被正确设置,避免后续 tie_weights 等操作中因父类 __init__ 被跳过而引发的 AttributeError
  2. 修复 Dense 子类中 num_expertsNone 的问题 (python/sglang/srt/models/gemma4_causal.py):

    • num_experts = self.config.num_experts 改为 num_experts = getattr(self.config, "num_experts", None) or 0,安全处理 MoE 属性缺失的情况。
    • per_expert_params_mapping 的构造包裹在条件判断 if num_experts: ... else [] 中,当 num_experts 为 0 时返回空列表,避免调用 FusedMoE.make_expert_params_mapping 时因 None 传参而崩溃。
  3. 修复 BF16 下 MoE runner 后端的自动选择 (python/sglang/srt/server_args.py):

    • 在 SM100 的 MoE 后端自动选择逻辑中,增加 if self.get_model_config().quantization == "modelopt_fp4": 条件判断,只有当量化配置为 modelopt_fp4 时,才设置 self.moe_runner_backend = "flashinfer_trtllm" 并更新 self.quantization = "modelopt_fp4"。对于非 FP4 的其他量化类型(如 BF16),保持默认 MoE runner 后端,避免使用不支持的 flashinfer 后端。
  4. 测试与验证:通过运行 #24552 的测试验证修复效果,PR 提交前服务器在初始化阶段崩溃,修复后服务可正常启动。本次 PR 未新增测试文件,但后续 CI 覆盖了 Gemma4 MTP 相关的回归场景。

文件 模块 状态 重要度
python/sglang/srt/models/gemma4_causal.py 模型层 modified 6.87
python/sglang/srt/server_args.py 服务配置 modified 6.26
python/sglang/srt/models/gemma4_mtp.py 模型层 modified 6.25

关键符号

Gemma4AssistantForCausalLM.__init__ Gemma4ForCausalLM.load_weights

关键源码片段

python/sglang/srt/models/gemma4_causal.py core-logic

核心修复:使用 `getattr` 安全获取 `num_experts`,并条件构造 `per_expert_params_mapping`,避免 Dense 子类因 `num_experts=None` 崩溃。

# 关键变更:安全处理 num_experts
# Dense 子类(如 Gemma4 MTP assistant)复用此 load_weights
# 但 num_experts 可能为 None 或不存在,因此使用 getattr 默认 None
# 再通过 or 0 确保后续 make_expert_params_mapping 不会收到 None
num_experts = getattr(self.config, "num_experts", None) or 0# 只有当 num_experts 非零(即模型确实是 MoE)时才生成 per-expert mapping
# 对于 Dense 子类,直接返回空列表,避免 TypeError
per_expert_params_mapping = (
    FusedMoE.make_expert_params_mapping(
        ckpt_gate_proj_name="gate_proj",
        ckpt_down_proj_name="down_proj",
        ckpt_up_proj_name="up_proj",
        num_experts=num_experts,
    )
    if num_experts
    else []
)
python/sglang/srt/server_args.py core-logic

修复 Gemma4 在 SM100 上使用 BF16 时 MoE 后端自动选择错误的问题,增加了量化类型判断。

# 关键变更:仅在 modelopt_fp4 量化时选择 flashinfer_trtllm
# 当前版本 flashinfer 不支持 bf16 checkpoint,因此自动选择不能硬编码
if is_sm100_supported() and self.moe_runner_backend == "auto":
    # 必须先检查量化类型,避免 BF16 模型错误使用 flashinfer
    if self.get_model_config().quantization == "modelopt_fp4":
        self.quantization = "modelopt_fp4"
        self.moe_runner_backend = "flashinfer_trtllm"
        logger.info(
            "Use flashinfer_trtllm as MoE runner backend on "
            "SM100 for Gemma-4 (modelopt_fp4)"
        )
python/sglang/srt/models/gemma4_mtp.py entrypoint

修复 MTP 类因跳过父类 __init__ 而缺失 pp_group 属性的问题。

class Gemma4AssistantForCausalLM(Gemma4ForCausalLM):
    """Gemma 4 MTP assistant: target embed + recurrent hidden through pre/post projection; own lm_head."""
​
    def __init__(
        self,
        config: PretrainedConfig,
        quant_config: Optional[QuantizationConfig] = None,
        prefix: str = "",
    ) -> None:
        text_config = copy.deepcopy(_get_text_config(config))
        text_config.num_kv_shared_layers = 0
        PreTrainedModel.__init__(self, config=text_config) # 跳过 Gemma4ForCausalLM.__init__
        self.assistant_config = config
        self.config = text_config
        self.quant_config = quant_config
        # 显式设置 pp_group,因为父类 __init__ 被跳过
        # 否则后续 tie_weights 中访问 self.pp_group.world_size 会抛出 AttributeError
        self.pp_group = get_pp_group()
        # ... 其余初始化不变

评论区精华

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

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

风险与影响

  1. 回归风险(低)gemma4_causal.py 中的 load_weights 改为条件调用 make_expert_params_mapping,对原本使用 MoE 的 Gemma4 模型没有影响,因为 num_experts 仍然来自 config.num_experts 且非零。但若未来有新的 Dense 子类也继承此方法,需确保其 num_experts 属性正确。
  2. 兼容性风险(低)server_args.py 中的修改增加了 quantization 判断,仅影响 SM100 平台上的 auto 模式选择。对于非 SM100 或其他量化类型无影响。
  3. 测试覆盖(中等):PR 描述中提到通过运行 #24552 的测试验证,但未新增独立的单元测试。后续需要关注 CI 中 Gemma4 MTP 相关的回归测试是否已覆盖这些场景。
  1. 用户影响(高):修复了 Gemma4 MTP 模型无法启动的严重 bug,所有尝试使用 Gemma4 MTP 的用户都将受益。
  2. 系统影响(低):改动集中在模型初始化和配置选择逻辑,不涉及运行时推理路径,对已正常运行的 Gemma4 模型无影响。
  3. 团队影响(低):改动较小,仅涉及 3 个文件,代码审查简单,已获得批准。
缺少测试覆盖

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论