执行摘要
- 一句话:修复 #44589 导致的权重加载回归
- 推荐动作:建议合并。本 PR 是重要的紧急修复,精确地处理了 #44589 的副作用,避免了全量回滚。对于理解 AutoWeightsLoader 与自定义 load_weights 的交互边界有参考价值。
功能与动机
PR #44589 移除了多个模型的 load_weights 方法,期望借助 AutoWeightsLoader 自动加载,但实际在 nightly CI 中造成了三个回归失败:MTEB 语言模型测试中 Jina 和 Gemma3 模型报 ValueError(权重未初始化),多模态扩展测试中 CohereForCausalLM 报参数缺失。Issue #47096 曾尝试回滚 #44589,但本 PR 采用更精确的前向修复方案。
实现拆解
- Gemma3Model(gemma3.py):将原先定义在
Gemma3ForCausalLM 上的 hf_to_vllm_mapper 移动至 Gemma3Model 类中,并为 Gemma3Model 新增 load_weights 方法,委托 AutoWeightsLoader 加载。Gemma3ForCausalLM 改为引用 Gemma3Model.hf_to_vllm_mapper。原因是 Gemma3Model 被直接注册为 Gemma3TextModel,需要自己拥有 mapper 才能正确加载。
- JinaEmbeddingsV5Model(jina.py):为
JinaEmbeddingsV5Model 添加类级 hf_to_vllm_mapper,通过 Qwen3ForCausalLM.hf_to_vllm_mapper | WeightsMapper(orig_to_new_prefix={"": "model."}) 合并父类映射并添加 model. 前缀。同时修改 load_weights 方法,将 AutoWeightsLoader 从加载 self.model 改为加载 self,并使用 self.hf_to_vllm_mapper 而非 self.model.hf_to_vllm_mapper。
- CohereForCausalLM(commandr.py):合并了两个重复的
hf_to_vllm_mapper 定义:第一个包含 orig_to_new_stacked 映射,第二个包含 orig_to_new_substr 用于过滤 _quantizer. 前缀。现合并为一个 WeightsMapper,同时包含两个参数。
- 补充导入:
jina.py 新增 WeightsMapper 导入。
关键文件:
vllm/model_executor/models/gemma3.py(模块 权重加载;类别 source;类型 data-contract;符号 load_weights, hf_to_vllm_mapper): 核心修复:将 hf_to_vllm_mapper 从 Gemma3ForCausalLM 移至 Gemma3Model,并恢复 load_weights 方法。
vllm/model_executor/models/jina.py(模块 权重加载;类别 source;类型 data-contract;符号 load_weights, hf_to_vllm_mapper): 修复 JinaEmbeddingsV5Model 权重加载:添加缺失的模型前缀映射,并将 loader 加载目标从 self.model 改为 self。
vllm/model_executor/models/commandr.py(模块 权重加载;类别 source;类型 data-contract;符号 hf_to_vllm_mapper): 修复 CohereForCausalLM 中 hf_to_vllm_mapper 重复定义导致映射覆盖的问题。
关键符号:load_weights
关键源码片段
vllm/model_executor/models/gemma3.py
核心修复:将 hf_to_vllm_mapper 从 Gemma3ForCausalLM 移至 Gemma3Model,并恢复 load_weights 方法。
# vllm/model_executor/models/gemma3.py
@support_torch_compile
class Gemma3Model(nn.Module):
# 将 mapper 从 Gemma3ForCausalLM 移到此处,
# 因为 Gemma3Model 被直接注册为模型,需要自己持有 mapper
hf_to_vllm_mapper = WeightsMapper(
orig_to_new_stacked={
".q_proj": (".qkv_proj", "q"),
".k_proj": (".qkv_proj", "k"),
".v_proj": (".qkv_proj", "v"),
".gate_proj": (".gate_up_proj", 0),
".up_proj": (".gate_up_proj", 1),
}
)
def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
loader = AutoWeightsLoader(self)
return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
class Gemma3ForCausalLM(nn.Module, SupportsLoRA, SupportsPP):
# 直接引用 Gemma3Model 的 mapper,避免重复定义
hf_to_vllm_mapper = Gemma3Model.hf_to_vllm_mapper
packed_modules_mapping = { ... }
vllm/model_executor/models/jina.py
修复 JinaEmbeddingsV5Model 权重加载:添加缺失的模型前缀映射,并将 loader 加载目标从 self.model 改为 self。
# vllm/model_executor/models/jina.py
class JinaEmbeddingsV5Model(Qwen3ForCausalLM, VllmModelForPooling):
is_pooling_model = True
# 合并父类 Qwen3 的 mapper,并添加 "model." 前缀映射,
# 使 checkpoint 中的裸键(如 "layers.0")能正确匹配到 self.model
hf_to_vllm_mapper = Qwen3ForCausalLM.hf_to_vllm_mapper | WeightsMapper(
orig_to_new_prefix={"": "model."}
)
def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
...
# 之前是 AutoWeightsLoader(self.model, ...),现在改为 self,
# 确保顶层 key 前缀正确解析
loader = AutoWeightsLoader(self, ignore_unexpected_prefixes=["lm_head."])
weights = _merge_weights(weights)
return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
vllm/model_executor/models/commandr.py
修复 CohereForCausalLM 中 hf_to_vllm_mapper 重复定义导致映射覆盖的问题。
# vllm/model_executor/models/commandr.py
class CohereForCausalLM(nn.Module, SupportsLoRA, SupportsPP, SupportsQuant):
# 合并两个独立的 WeightsMapper 为一个,避免第二个覆盖第一个的 stacked 映射
hf_to_vllm_mapper = WeightsMapper(
orig_to_new_stacked={
".q_proj": (".qkv_proj", "q"),
".k_proj": (".qkv_proj", "k"),
".v_proj": (".qkv_proj", "v"),
".gate_proj": (".gate_up_proj", 0),
".up_proj": (".gate_up_proj", 1),
},
# ModelOpt NVFP4 checkpoints 会携带量化器状态,
# 如 "*.weight_quantizer._double_scale",需要过滤掉
orig_to_new_substr={"_quantizer.": None},
)
packed_modules_mapping = { ... }
评论区精华
无实质性 review 讨论。njhill 直接批准了 PR。Claude bot 因 PR 来自 fork 自动关闭了 review。
风险与影响
- 风险:风险较低,变更仅针对特定模型的权重加载逻辑,且已在 nightly CI 对应测试上验证通过。但需要注意的是,这类精细的映射修复可能因未来
AutoWeightsLoader 的演化而再次失效。
- 影响:直接影响使用 Gemma3、Jina Embeddings V5 以及 Cohere(aya_vision)模型的用户,尤其是进行 MTEB 评测或多模态推理的场景。修复后这些模型可正常加载权重,不会回退到回滚 #44589 带来的功能丢失。
- 风险标记:核心路径变更, 依赖批量重构, 缺乏新增测试覆盖
关联脉络
- PR #44589 Remove unnecessary
load_weights methods: 本 PR 修复了 #44589 引入的三个回归问题。
- PR #47096 Revert "Remove unnecessary
load_weights methods" (#44589): 本 PR 替代了该回滚 PR,采用更精确的前向修复方案。
参与讨论