Prhub

#44571 [Bugfix] Exclude vision embedder from quantization in Gemma4 Unified

原始 PR 作者 lucianommartins 合并时间 2026-06-05 11:47 文件变更 1 提交数 3 评论 1 代码增减 +3 / -1

执行摘要

修复 Gemma4 Unified 视觉编码器被量化的问题

修复 W4A16 compressed-tensors 检查点加载在 Gemma4UnifiedForConditionalGeneration 上崩溃的问题。PR body 明确描述了错误:ValueError: There is no module or parameter named 'vision_embedder.patch_dense.weight',因为模块创建了量化参数但检查点包含普通权重。

值得精读,这是一个典型的由缺少 prefix 导致量化模块无法正确匹配忽略规则的问题。对于有量化忽略列表的模型实现,确保正确传递 prefix 是良好实践。

讨论亮点

Review 中主要由 Isotr0py 批准,mgoin 批准并评论 "Thanks for using prefix!",表明对传递前缀方案的认可。无其他争议。

实现拆解

  1. 修改 Gemma4UnifiedVisionEmbedder.__init__ 签名:在文件 vllm/model_executor/models/gemma4_unified.py 中,为 __init__ 方法添加 prefix="" 参数,允许从外部传入前缀。
  2. patch_dense 层传递前缀:在创建 ColumnParallelLinear 时添加 prefix=f"{prefix}.patch_dense",使该层能正确获取其在模块层次结构中的路径(如 vision_embedder.patch_dense)。
  3. 在父模块中传递前缀:在 Gemma4UnifiedForConditionalGeneration.__init__ 中实例化 Gemma4UnifiedVisionEmbedder 时传入 prefix=maybe_prefix(prefix, "vision_embedder"),将父级前缀传递给视觉编码器。
  4. 根本原因:由于之前未传递前缀,get_quant_method 内部收到的 prefix 为空字符串,无法与 compressed-tensors 忽略列表中配置的模式(如 vision_embedder.*)匹配,导致量化方法被错误地应用到视觉编码器层。传递前缀后,忽略规则正确生效,视觉编码器不会被量化。
文件 模块 状态 重要度
vllm/model_executor/models/gemma4_unified.py 模型定义 modified 6.07

关键符号

Gemma4UnifiedVisionEmbedder.__init__ Gemma4UnifiedForConditionalGeneration.__init__

关键源码片段

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

核心修复文件。修改了 `Gemma4UnifiedVisionEmbedder.__init__` 签名以接受 `prefix` 参数,并在 `ColumnParallelLinear` 和父模块调用中正确传递前缀,使量化忽略规则生效。

# vllm/model_executor/models/gemma4_unified.py (head 版本关键变更 )class Gemma4UnifiedVisionEmbedder(nn.Module):
    # ...
    def __init__(self, config, quant_config=None, prefix=""):
        super().__init__()
        patch_dim = config.model_patch_size**2 * 3
        mm_embed_dim = config.mm_embed_dim
​
        self.patch_ln1 = nn.LayerNorm(patch_dim)
        self.patch_dense = ColumnParallelLinear(
            patch_dim,
            mm_embed_dim,
            bias=True,
            quant_config=quant_config,
            prefix=f"{prefix}.patch_dense", # 关键变更:传递正确前缀以匹配忽略列表
            gather_output=True,
        )
        self.patch_ln2 = nn.LayerNorm(mm_embed_dim)
        # ... 其余代码不变class Gemma4UnifiedForConditionalGeneration(nn.Module):
    def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
        # ... 其他初始化
        self.vision_embedder = (
            Gemma4UnifiedVisionEmbedder(
                config.vision_config,
                quant_config=quant_config,
                prefix=maybe_prefix(prefix, "vision_embedder"), # 关键变更:传入父级前缀
            )
            if config.vision_config is not None
            else None
        )
        # ...

评论区精华

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

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

风险与影响

风险极低。变更仅添加了 prefix 参数传递,不影响未量化检查点的加载(quant_config=None 是量化相关分支的默认行为)。视觉编码器的量化行为现在与有形变体(使用普通 nn.Linear)一致,不会引入回归。

直接影响:解决了 Gemma4UnifiedForConditionalGeneration 加载 W4A16 compressed-tensors 检查点时的崩溃问题,使该模型在量化场景下可用。间接影响:使视觉编码器的模块命名更加规范,便于后续调试和扩展。

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论