Prhub

#47953 [Bugfix][Spec Decode] Restrict embedding-width share guard to EAGLE drafts

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

执行摘要

修复 Embedding 宽度检查误伤 MTP Draft

修复 Issue #47794:Gemma4 MTP 在 nightly 中因 _maybe_share_embeddings 中的 embedding 宽度检查导致引擎初始化失败,报错 mat1 and mat2 shapes cannot be multiplied (3840x5632)。根因是 #43957 的守卫被错误应用到了 MTP draft 上。

该 PR 修复了一个影响 Gemma4 MTP 的关键 bug,设计简洁(通过 has_own_embed_tokens 属性区分 EAGLE/MTP),且已有多人验证。建议尽快合入以便下游用户使用。

讨论亮点
  • reviewer benchislett 要求删除单独新增的测试文件,认为测试可整合到已有测试中。作者在下一 commit 中移除了该文件。
  • realmorita 确认在 26B checkpoint 上引擎初始化成功,短对话正常。
  • Mazyod 提供生产环境验证:Gemma-4-31B fp8_block + MTP draft 在 v0.25.1 上修复后正常启动和服务。
  • lucianommartins 呼吁尽快合并或回退 #43957,称 #43957 导致了灾难性副作用。
  • eugr 报告 main 分支上 Gemma4 MTP 仍损坏(可能指 #43957 尚未回退)。

实现拆解

  1. 定位守卫条件:在 vllm/v1/spec_decode/llm_base_proposer.py_maybe_share_embeddings 方法中,找到宽度检查的入口 if share_embeddings:
  2. 添加 EAGLE 专属判断:将条件改为 if share_embeddings and hasattr(self.model, "has_own_embed_tokens"):,该属性仅存在于 EAGLE draft 模型上,MTP draft 不具有此属性。
  3. 保留原有逻辑:EAGLE draft 下仍执行宽度比较,不一致时跳过共享;MTP draft 则直接执行共享(恢复到 #43957 之前的行为)。
  4. 移除测试文件:根据 reviewer 建议,删除了单独增加的测试文件,回归测试由现有测试覆盖。
文件 模块 状态 重要度
vllm/v1/spec_decode/llm_base_proposer.py 推测解码 modified 5.96

关键符号

_maybe_share_embeddings

关键源码片段

vllm/v1/spec_decode/llm_base_proposer.py core-logic

核心修复文件,修改 `_maybe_share_embeddings` 方法中的条件判断,将宽度检查限制为仅 EAGLE draft。

# vllm/v1/spec_decode/llm_base_proposer.py (head)
# ... 前面逻辑确定 share_embeddings 为 True ...# 原代码:if share_embeddings: # 对 MTP 和 EAGLE 都执行宽度检查
# 新代码:仅当 draft 具有 has_own_embed_tokens 属性(即 EAGLE 模型)时才检查
if share_embeddings and hasattr(self.model, "has_own_embed_tokens"):
    # EAGLE drafts 使用自己隐藏大小的输入嵌入,所以仅当宽度匹配时才共享。
    # MTP drafts 投影 target 宽度的嵌入(例如 Gemma4 MTP 的 pre_projection
    # 输入是 2 * backbone_hidden_size),因此宽度检查不适用于它们。
    draft_embed = self.model.model.embed_tokens
    if isinstance(target_embed_tokens.weight, torch.Tensor) and isinstance(
        draft_embed.weight, torch.Tensor
    ):
        target_dim = target_embed_tokens.weight.shape[-1]
        draft_dim = draft_embed.weight.shape[-1]
        if target_dim != draft_dim:
            share_embeddings = False
            logger.info(
                "Target embedding dim (%d) differs from draft "
                "embedding dim (%d). Keeping separate embedding "
                "weights.",
                target_dim,
                draft_dim,
            )# 共享逻辑保持不变
if share_embeddings:
    if hasattr(self.model.model, "embed_tokens"):
        del self.model.model.embed_tokens
    self.model.model.embed_tokens = target_embed_tokens

评论区精华

移除测试文件 other

reviewer benchislett 建议不要新增独立的测试文件,认为测试可以合并到现有测试中。

结论:作者从 commit 中移除了测试文件,并在评论中说明已完成。 · 已解决

生产环境验证 正确性

用户 Mazyod 报告在生产配置(Gemma-4-31B fp8_block + MTP draft)上验证了修复有效,引擎启动成功。

结论:修复在实际负载中得到验证。 · 已解决

回退 #43957 的讨论 设计

用户 lucianommartins 呼吁加速合并此 PR 或回退 #43957,认为 #43957 导致灾难性副作用。

结论:本 PR 被合入,未回退 #43957。 · 已解决

风险与影响

风险极低:改动仅影响 _maybe_share_embeddings 中一行条件判断,且通过添加 hasattr 判断隔离了 EAGLE 和 MTP 分支。EAGLE 行为保持不变,MTP 恢复到 #43957 之前的无条件共享行为。但缺少针对 Gemma4 MTP 的官方 CI 回归测试(测试文件被移除),未来若有类似重构可能再次引入同样问题。

正向影响:修复 Gemma4 MTP 模型初始化崩溃,使其能在 vLLM 中正常使用。影响所有使用 MTP speculative decoding 的用户,尤其是 Gemma4 用户。
负面影响:无。
影响范围:仅涉及 speculative decoding 中 MTP draft 的 embedding 共享路径。

缺少回归测试 核心路径变更

关联 Issue

#43957 [XPU] Fix Eagle3 initialization on XPU
#47794 [Bug]: Gemma4 MTP fails to start after embedding sharing guard in PR #43957
#47833 [Bugfix][Spec Decode] Always share target embeddings for MTP drafts (#47794)

完整报告

参与讨论