Reduce `AutoWeightsLoader` kwargs (#53106)

Signed-off-by: Harry Mellor <19981378+hmellor@users.noreply.github.com>

Harry Mellor committed Aug 20, 2026 at 16:40 UTC 1fe3a1571ac67581478a11743e55a306de1d136f
84 files changed +578 -569
tests/models/inkling/test_moe_weight_layout.py
+1 -1
@@ -104,7 +104,7 @@ def test_inkling_mapper_maps_modelopt_exclusions() -> None:
104 )
105
106 quant_config.apply_vllm_mapper(
107 - _TmlForCausalLMBase.hf_to_vllm_mapper.get_unstacked_mapper()
107 + _TmlForCausalLMBase.hf_to_vllm_mapper.get_rename_mapper()
108 )
109
110 assert quant_config.is_layer_excluded("model.layers.2.mlp.experts")
tests/models/test_dspark_mla.py
+3 -5
@@ -55,11 +55,9 @@ def test_dspark_mla_checkpoint_weight_mapping(checkpoint_name, runtime_name, sha
55 def test_dspark_mla_shares_frozen_target_weights_and_skips_training_head():
56 assert not K3DSparkForCausalLM.has_own_embed_tokens
57 assert not K3DSparkForCausalLM.has_own_lm_head
58 - assert set(K3DSparkForCausalLM.checkpoint_skip_substrs) == {
59 - "confidence_head",
60 - "embed_tokens",
61 - "lm_head",
62 - }
58 + mapper = K3DSparkForCausalLM.hf_to_vllm_mapper
59 + for name in ("confidence_head.weight", "embed_tokens.weight", "lm_head.weight"):
60 + assert mapper._map_name(name) is None
61
62
63 @pytest.mark.cpu_test
tests/models/test_utils.py
+28 -76
@@ -2,6 +2,7 @@
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4 import pytest
5 +import regex as re
6 import torch
7
8 from vllm.model_executor.layers.vocab_parallel_embedding import (
@@ -10,6 +11,7 @@ from vllm.model_executor.layers.vocab_parallel_embedding import (
11 )
12 from vllm.model_executor.models.utils import (
13 AutoWeightsLoader,
14 + WeightsMapper,
15 _merge_multimodal_embeddings,
16 )
17 from vllm.platforms import current_platform
@@ -93,82 +95,6 @@ def test_module_with_child_containing_batchnorm_can_autoload():
95 assert new_mod.nested_mod.bn.num_batches_tracked.item() == 1
96
97
96 -@pytest.mark.cpu_test
97 -def test_module_skip_prefix():
98 - """Ensure the auto weight loader can skip prefix."""
99 - mod = ModuleWithNestedBatchNorm()
100 - # Run some data through the module with batchnorm
101 - mod(torch.Tensor([[1, 2], [3, 4]]))
102 -
103 - # Try to load the weights to a new instance
104 - def weight_generator():
105 - # weights needed to be filtered out
106 - redundant_weights = {
107 - "prefix.bn.weight": torch.Tensor([1, 2]),
108 - "prefix.bn.bias": torch.Tensor([3, 4]),
109 - }
110 - yield from (mod.state_dict() | redundant_weights).items()
111 -
112 - new_mod = ModuleWithNestedBatchNorm()
113 -
114 - assert not torch.all(
115 - new_mod.nested_mod.bn.running_mean == mod.nested_mod.bn.running_mean
116 - )
117 - assert not torch.all(
118 - new_mod.nested_mod.bn.running_var == mod.nested_mod.bn.running_var
119 - )
120 - assert new_mod.nested_mod.bn.num_batches_tracked.item() == 0
121 -
122 - loader = AutoWeightsLoader(new_mod, skip_prefixes=["prefix."])
123 - loader.load_weights(weight_generator())
124 -
125 - # Ensure the stats are updated
126 - assert torch.all(
127 - new_mod.nested_mod.bn.running_mean == mod.nested_mod.bn.running_mean
128 - )
129 - assert torch.all(new_mod.nested_mod.bn.running_var == mod.nested_mod.bn.running_var)
130 - assert new_mod.nested_mod.bn.num_batches_tracked.item() == 1
131 -
132 -
133 -@pytest.mark.cpu_test
134 -def test_module_skip_substr():
135 - """Ensure the auto weight loader can skip prefix."""
136 - mod = ModuleWithNestedBatchNorm()
137 - # Run some data through the module with batchnorm
138 - mod(torch.Tensor([[1, 2], [3, 4]]))
139 -
140 - # Try to load the weights to a new instance
141 - def weight_generator():
142 - # weights needed to be filtered out
143 - redundant_weights = {
144 - "nested_mod.0.substr.weight": torch.Tensor([1, 2]),
145 - "nested_mod.0.substr.bias": torch.Tensor([3, 4]),
146 - "nested_mod.substr.weight": torch.Tensor([1, 2]),
147 - "nested_mod.substr.bias": torch.Tensor([3, 4]),
148 - }
149 - yield from (mod.state_dict() | redundant_weights).items()
150 -
151 - new_mod = ModuleWithNestedBatchNorm()
152 -
153 - assert not torch.all(
154 - new_mod.nested_mod.bn.running_mean == mod.nested_mod.bn.running_mean
155 - )
156 - assert not torch.all(
157 - new_mod.nested_mod.bn.running_var == mod.nested_mod.bn.running_var
158 - )
159 - assert new_mod.nested_mod.bn.num_batches_tracked.item() == 0
160 -
161 - loader = AutoWeightsLoader(new_mod, skip_substrs=["substr."])
162 - loader.load_weights(weight_generator())
163 -
164 - # Ensure the stats are updated
165 - assert torch.all(
166 - new_mod.nested_mod.bn.running_mean == mod.nested_mod.bn.running_mean
167 - )
168 - assert torch.all(new_mod.nested_mod.bn.running_var == mod.nested_mod.bn.running_var)
169 - assert new_mod.nested_mod.bn.num_batches_tracked.item() == 1
170 -
171 -
98 VOCAB_SIZE = 16
99 HIDDEN_SIZE = 2
100
@@ -265,3 +191,29 @@ def test_merge_multimodal_embeddings_no_sync():
191 _merge_multimodal_embeddings(
192 inputs_embeds, multimodal_embeddings, is_multimodal
193 )
194 +
195 +
196 +@pytest.mark.cpu_test
197 +def test_get_rename_mapper_keeps_only_renames():
198 + """`None` means "do not load", which is meaningless to the consumers of
199 + this mapper (LoRA name parsing, quantization config layer lists), and
200 + applying it would silently shrink their lists."""
201 + mapper = WeightsMapper(
202 + orig_to_new_regex={re.compile(r"^drop_regex\."): None},
203 + orig_to_new_substr={"drop_substr": None, "keep_substr": "kept"},
204 + orig_to_new_stacked={".q_proj": (".qkv_proj", "q")},
205 + orig_to_new_prefix={"drop_prefix.": None, "keep_prefix.": "kept."},
206 + orig_to_new_suffix={".drop_suffix": None},
207 + )
208 + renames = mapper.get_rename_mapper()
209 +
210 + assert renames.orig_to_new_regex == {}
211 + assert renames.orig_to_new_substr == {"keep_substr": "kept"}
212 + assert renames.orig_to_new_stacked == {}
213 + assert renames.orig_to_new_prefix == {"keep_prefix.": "kept."}
214 + assert renames.orig_to_new_suffix == {}
215 +
216 + # Names the full mapper drops now survive unchanged.
217 + for name in ("drop_regex.w", "drop_substr.w", "drop_prefix.w", "w.drop_suffix"):
218 + assert mapper._map_name(name) is None
219 + assert renames._map_name(name) == name
tests/quantization/test_modelopt.py
+2 -2
@@ -214,9 +214,9 @@ def test_modelopt_mixed_precision_composes_gemma4_mappers():
214 )
215
216 config.apply_vllm_mapper(
217 - Gemma4ForConditionalGeneration.hf_to_vllm_mapper.get_unstacked_mapper()
217 + Gemma4ForConditionalGeneration.hf_to_vllm_mapper.get_rename_mapper()
218 )
219 - config.apply_vllm_mapper(Gemma4ForCausalLM.hf_to_vllm_mapper.get_unstacked_mapper())
219 + config.apply_vllm_mapper(Gemma4ForCausalLM.hf_to_vllm_mapper.get_rename_mapper())
220
221 expected_prefix = "language_model.model.layers.0.moe.experts"
222 assert set(config.quantized_layers) == {
vllm/lora/worker_manager.py
+4 -5
@@ -128,14 +128,13 @@ class WorkerLoRAManager:
128 # loading weights, throwing an exception if validation fails.
129 peft_helper.validate_legal(self.lora_config)
130
131 - # For some models like Qwen2VL, we need to use hf_to_vllm_mapper
132 - # to ensure correct loading of lora weights. Drop the QKV/MLP fusion
133 - # substr maps so constituent names (e.g. `q_proj`) survive for the
134 - # LoRA manager to pack, while keeping genuine renames/prefixes.
131 + # For some models like Qwen2VL, we need to use hf_to_vllm_mapper to ensure
132 + # correct loading of lora weights. We only need to know about renames for
133 + # this, so we use get_rename_mapper() to ignore stacking and deletions.
134 model = self._adapter_manager.model
135 hf_to_vllm_mapper = getattr(model, "hf_to_vllm_mapper", None)
136 if hf_to_vllm_mapper is not None:
138 - hf_to_vllm_mapper = hf_to_vllm_mapper.get_unstacked_mapper()
137 + hf_to_vllm_mapper = hf_to_vllm_mapper.get_rename_mapper()
138
139 # Get model-defined prefixes to skip during LoRA loading.
140 lora_skip_prefixes = getattr(model, "lora_skip_prefixes", None)
vllm/model_executor/model_loader/utils.py
+1 -1
@@ -281,6 +281,6 @@ def configure_quant_config(
281
282 # pass mappings by reference to quant_config
283 if hf_to_vllm_mapper is not None:
284 - quant_config.apply_vllm_mapper(hf_to_vllm_mapper.get_unstacked_mapper())
284 + quant_config.apply_vllm_mapper(hf_to_vllm_mapper.get_rename_mapper())
285 if packed_mapping is not None:
286 quant_config.packed_modules_mapping = packed_mapping
vllm/model_executor/models/adapters.py
+8 -5
@@ -236,7 +236,8 @@ def _create_pooling_model_cls(orig_cls: type[_T]) -> type[_T]:
236
237 def default_load_weights(weights):
238 loader = AutoWeightsLoader(self)
239 - return loader.load_weights(weights)
239 + mapper = getattr(self, "hf_to_vllm_mapper", None)
240 + return loader.load_weights(weights, mapper=mapper)
241
242 load_weights = getattr(super(), "load_weights", default_load_weights)
243 return load_weights(mapped_weights)
@@ -584,10 +585,11 @@ def load_weights_using_from_2_way_softmax(
585 )
586 loaded_weights.add(score_weight_name)
587
587 - lm_head_name = "lm_head.weight"
588 + lm_head_name: str | None = "lm_head.weight"
589 if hf_to_vllm_mapper := getattr(model, "hf_to_vllm_mapper", None):
590 lm_head_name = hf_to_vllm_mapper._map_name(lm_head_name)
590 - loaded_weights.discard(lm_head_name)
591 + if lm_head_name is not None:
592 + loaded_weights.discard(lm_head_name)
593 return loaded_weights
594
595
@@ -649,10 +651,11 @@ def load_weights_no_post_processing(model, weights: Iterable[tuple[str, torch.Te
651 )
652 loaded_weights.add(score_weight_name)
653
652 - lm_head_name = "lm_head.weight"
654 + lm_head_name: str | None = "lm_head.weight"
655 if hf_to_vllm_mapper := getattr(model, "hf_to_vllm_mapper", None):
656 lm_head_name = hf_to_vllm_mapper._map_name(lm_head_name)
655 - loaded_weights.discard(lm_head_name)
657 + if lm_head_name is not None:
658 + loaded_weights.discard(lm_head_name)
659 return loaded_weights
660
661
vllm/model_executor/models/aimv2.py
+6 -9
@@ -219,6 +219,11 @@ class AIMv2Model(torch.nn.Module):
219 require_post_norm=require_post_norm,
220 prefix=f"{prefix}.trunk",
221 )
222 + # post_trunk_norm is optional (absent for clip-skip backbones).
223 + if self.trunk.post_trunk_norm is None:
224 + self.hf_to_vllm_mapper = self.hf_to_vllm_mapper | WeightsMapper(
225 + orig_to_new_prefix={"trunk.post_trunk_norm.": None}
226 + )
227
228 def forward(self, pixel_values: torch.Tensor) -> torch.Tensor:
229 x = self.preprocessor(pixel_values)
@@ -227,13 +232,5 @@ class AIMv2Model(torch.nn.Module):
232 return x
233
234 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
230 - loader = AutoWeightsLoader(
231 - self,
232 - # post_trunk_norm is optional (absent for clip-skip backbones).
233 - skip_prefixes=(
234 - ["trunk.post_trunk_norm."]
235 - if self.trunk.post_trunk_norm is None
236 - else None
237 - ),
238 - )
235 + loader = AutoWeightsLoader(self)
236 return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
vllm/model_executor/models/arcee.py
+5 -2
@@ -285,7 +285,10 @@ class ArceeForCausalLM(
285 ".q_proj": (".qkv_proj", "q"),
286 ".k_proj": (".qkv_proj", "k"),
287 ".v_proj": (".qkv_proj", "v"),
288 - }
288 + },
289 + orig_to_new_substr={
290 + "gate_proj": None,
291 + },
292 )
293 # Map fused module names to their submodule components
294 # (for quantization and LoRA)
@@ -356,7 +359,7 @@ class ArceeForCausalLM(
359 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
360 """Load weights into the model (delegates to inner model and handles
361 tied embeddings)."""
359 - loader = AutoWeightsLoader(self, skip_substrs=["gate_proj"])
362 + loader = AutoWeightsLoader(self)
363 # AutoWeightLoader handles weight name remapping, including fusing
364 # separate q_proj, k_proj, v_proj into qkv_proj
365 return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
vllm/model_executor/models/aria.py
+7 -15
@@ -13,18 +13,13 @@ from vllm.config import VllmConfig
13 from vllm.config.multimodal import BaseDummyOptions, ImageDummyOptions
14 from vllm.inputs import MultiModalDataDict
15 from vllm.model_executor.layers.activation import get_act_fn
16 -from vllm.model_executor.layers.fused_moe import (
17 - FusedMoEFactory,
18 -)
16 +from vllm.model_executor.layers.fused_moe import FusedMoEFactory
17 from vllm.model_executor.layers.linear import ColumnParallelLinear, RowParallelLinear
18 from vllm.model_executor.layers.logits_processor import LogitsProcessor
19 from vllm.model_executor.layers.quantization import QuantizationConfig
20 from vllm.model_executor.layers.vocab_parallel_embedding import ParallelLMHead
21 from vllm.multimodal import MULTIMODAL_REGISTRY
24 -from vllm.multimodal.inputs import (
25 - MultiModalFieldConfig,
26 - MultiModalKwargsItems,
27 -)
22 +from vllm.multimodal.inputs import MultiModalFieldConfig, MultiModalKwargsItems
23 from vllm.multimodal.parse import MultiModalDataItems
24 from vllm.multimodal.processing import (
25 BaseDummyInputsBuilder,
@@ -42,11 +37,7 @@ from .idefics2_vision_model import (
37 )
38 from .interfaces import MultiModalEmbeddings, SupportsMultiModal, SupportsQuant
39 from .llama import LlamaDecoderLayer, LlamaMLP, LlamaModel
45 -from .utils import (
46 - AutoWeightsLoader,
47 - WeightsMapper,
48 - maybe_prefix,
49 -)
40 +from .utils import AutoWeightsLoader, WeightsMapper, maybe_prefix
41
42
43 class AriaImagePixelInputs(TensorSchema):
@@ -88,16 +79,17 @@ class AriaVisionTransformer(Idefics3VisionTransformer, SupportsQuant):
79 self.post_layernorm = nn.Identity()
80
81 hf_to_vllm_mapper = WeightsMapper(
82 + # NOTE: post_layernorm is not used in Aria.
83 + orig_to_new_substr={"post_layernorm": None},
84 orig_to_new_stacked={
85 ".q_proj": (".qkv_proj", "q"),
86 ".k_proj": (".qkv_proj", "k"),
87 ".v_proj": (".qkv_proj", "v"),
95 - }
88 + },
89 )
90
91 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
99 - # NOTE: post_layernorm is not used in Aria.
100 - loader = AutoWeightsLoader(self, skip_substrs=["post_layernorm"])
92 + loader = AutoWeightsLoader(self)
93 return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
94
95
vllm/model_executor/models/bagel.py
+3 -9
@@ -338,14 +338,9 @@ class BagelForConditionalGeneration(
338 The image generation part is not supported in vLLM.
339 """
340
341 - # Weight mapping from HF to vLLM
341 + # pos_embed is handled by the PositionEmbedding module
342 hf_to_vllm_mapper = WeightsMapper(
343 - orig_to_new_prefix={
344 - "language_model.": "language_model.",
345 - "vit_model.": "vit_model.",
346 - "connector.": "connector.",
347 - "vit_pos_embed.": "vit_pos_embed.",
348 - }
343 + orig_to_new_prefix={"vit_pos_embed.pos_embed": None}
344 )
345
346 @classmethod
@@ -580,6 +575,5 @@ class BagelForConditionalGeneration(
575
576 filtered_weights.append((name, tensor))
577
583 - # Skip vit_pos_embed.pos_embed as it's handled by PositionEmbedding module
584 - loader = AutoWeightsLoader(self, skip_prefixes=["vit_pos_embed.pos_embed"])
578 + loader = AutoWeightsLoader(self)
579 return loader.load_weights(filtered_weights, mapper=self.hf_to_vllm_mapper)
vllm/model_executor/models/bert.py
+10 -3
@@ -2,6 +2,7 @@
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4 from collections.abc import Iterable, Set
5 +from dataclasses import replace
6
7 import torch
8 from torch import nn
@@ -382,6 +383,7 @@ class BertModel(nn.Module, SupportsQuant):
383 ".self.key": (".self.qkv_proj", "k"),
384 ".self.value": (".self.qkv_proj", "v"),
385 },
386 + orig_to_new_prefix={"pooler.": None},
387 )
388
389 def __init__(
@@ -416,13 +418,16 @@ class BertModel(nn.Module, SupportsQuant):
418 return self.encoder(hidden_states)
419
420 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
419 - loader = AutoWeightsLoader(self, skip_prefixes=["pooler."])
421 + loader = AutoWeightsLoader(self)
422 return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
423
424
425 class BertPoolingModel(BertModel):
426 is_pooling_model = True
427
428 + # Unlike `BertModel`, this model has a pooler to load weights into.
429 + hf_to_vllm_mapper = replace(BertModel.hf_to_vllm_mapper, orig_to_new_prefix={})
430 +
431 def __init__(
432 self,
433 *,
@@ -488,11 +493,13 @@ class BertEmbeddingModel(nn.Module, SupportsQuant):
493 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]):
494 weights_list = list(weights)
495
496 + orig_to_new_prefix: dict[str, str | None] = {"lm_head.": None}
497 has_model_prefix = any(name.startswith("model.") for name, _ in weights_list)
498 if not has_model_prefix:
493 - mapper = WeightsMapper(orig_to_new_prefix={"": "model."})
499 + orig_to_new_prefix[""] = "model."
500 + mapper = WeightsMapper(orig_to_new_prefix=orig_to_new_prefix)
501
495 - loader = AutoWeightsLoader(self, skip_prefixes=["lm_head."])
502 + loader = AutoWeightsLoader(self)
503 return loader.load_weights(weights_list, mapper=mapper)
504
505 def _build_model(self, vllm_config: VllmConfig, prefix: str = "") -> BertModel:
vllm/model_executor/models/blip.py
+4 -4
@@ -313,6 +313,9 @@ class BlipVisionModel(nn.Module, SupportsQuant):
313 )
314 else:
315 self.post_layernorm = None
316 + self.hf_to_vllm_mapper = self.hf_to_vllm_mapper | WeightsMapper(
317 + orig_to_new_prefix={"post_layernorm.": None}
318 + )
319
320 def forward(self, pixel_values: torch.Tensor) -> torch.Tensor:
321 hidden_states = self.embeddings(pixel_values)
@@ -324,10 +327,7 @@ class BlipVisionModel(nn.Module, SupportsQuant):
327 return self.post_layernorm(hidden_states)
328
329 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
327 - skip_prefixes: list[str] = []
328 - if self.post_layernorm is None:
329 - skip_prefixes.append("post_layernorm.")
330 - loader = AutoWeightsLoader(self, skip_prefixes=skip_prefixes)
330 + loader = AutoWeightsLoader(self)
331
332 # omit layers when num_hidden_layers_override is set
333 def _filter(ws):
vllm/model_executor/models/clip.py
+7 -6
@@ -669,6 +669,9 @@ class CLIPVisionTransformer(nn.Module):
669 self.post_layernorm = nn.LayerNorm(embed_dim, eps=config.layer_norm_eps)
670 else:
671 self.post_layernorm = None
672 + self.hf_to_vllm_mapper = self.hf_to_vllm_mapper | WeightsMapper(
673 + orig_to_new_prefix={"post_layernorm.": None}
674 + )
675
676 @property
677 def dtype(self):
@@ -707,10 +710,7 @@ class CLIPVisionTransformer(nn.Module):
710 return encoder_outputs
711
712 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
710 - skip_prefixes: list[str] = []
711 - if self.post_layernorm is None:
712 - skip_prefixes.append("post_layernorm.")
713 - loader = AutoWeightsLoader(self, skip_prefixes=skip_prefixes)
713 + loader = AutoWeightsLoader(self)
714
715 # Drop layers beyond num_hidden_layers_override.
716 def _filter(ws):
@@ -775,6 +775,8 @@ class CLIPVisionModel(nn.Module):
775 class CLIPEmbeddingModel(nn.Module, SupportsMultiModal, SupportsQuant):
776 is_pooling_model = True
777
778 + hf_to_vllm_mapper = WeightsMapper(orig_to_new_substr={".position_ids": None})
779 +
780 packed_modules_mapping = {"qkv_proj": ["q_proj", "k_proj", "v_proj"]}
781
782 @classmethod
@@ -981,8 +983,7 @@ class CLIPEmbeddingModel(nn.Module, SupportsMultiModal, SupportsQuant):
983 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]):
984 loader = AutoWeightsLoader(
985 self,
984 - skip_substrs=[".position_ids"],
986 ignore_unexpected_prefixes=["logit_scale."],
987 )
988
988 - return loader.load_weights(weights)
989 + return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
vllm/model_executor/models/cohere2_moe.py
+3 -2
@@ -474,7 +474,8 @@ class Cohere2MoeForCausalLM(nn.Module, SupportsPP, SupportsQuant):
474 ".mlp.up_proj": (".mlp.gate_up_proj", 1),
475 ".shared_experts.gate_proj": (".shared_experts.gate_up_proj", 0),
476 ".shared_experts.up_proj": (".shared_experts.gate_up_proj", 1),
477 - }
477 + },
478 + orig_to_new_prefix={"lm_head.": None},
479 )
480 packed_modules_mapping = {
481 "qkv_proj": [
@@ -529,5 +530,5 @@ class Cohere2MoeForCausalLM(nn.Module, SupportsPP, SupportsQuant):
530 return self.logits_processor(self.model.embed_tokens, hidden_states)
531
532 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
532 - loader = AutoWeightsLoader(self, skip_prefixes=["lm_head."])
533 + loader = AutoWeightsLoader(self)
534 return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
vllm/model_executor/models/cohere_asr.py
+10 -9
@@ -2014,7 +2014,15 @@ class CohereAsrForConditionalGeneration(
2014 }
2015
2016 hf_to_vllm_mapper = WeightsMapper(
2017 - orig_to_new_substr={".fc1.": ".mlp.fc1.", ".fc2.": ".mlp.fc2."}
2017 + orig_to_new_substr={
2018 + ".fc1.": ".mlp.fc1.",
2019 + ".fc2.": ".mlp.fc2.",
2020 + "model.conv.batch_norm.num_batches_tracked": None,
2021 + },
2022 + orig_to_new_prefix={
2023 + "model.preprocessor.featurizer.fb": None,
2024 + "model.preprocessor.featurizer.window": None,
2025 + },
2026 )
2027
2028 supports_transcription_only = True
@@ -2273,14 +2281,7 @@ class CohereAsrForConditionalGeneration(
2281
2282 return name, loaded_weight
2283
2276 - loader = AutoWeightsLoader(
2277 - self,
2278 - skip_prefixes=[
2279 - "model.preprocessor.featurizer.fb",
2280 - "model.preprocessor.featurizer.window",
2281 - ],
2282 - skip_substrs=["model.conv.batch_norm.num_batches_tracked"],
2283 - )
2284 + loader = AutoWeightsLoader(self)
2285
2286 return loader.load_weights(
2287 map(transform, weights), mapper=self.hf_to_vllm_mapper
vllm/model_executor/models/cohere_eagle.py
+6 -8
@@ -22,6 +22,7 @@ from vllm.model_executor.models.commandr import (
22
23 from .utils import (
24 AutoWeightsLoader,
25 + WeightsMapper,
26 get_draft_quant_config,
27 maybe_prefix,
28 process_eagle_weight,
@@ -145,6 +146,10 @@ class EagleCohereForCausalLM(CohereForCausalLM):
146 # use tied embeddings so these weights are absent from the draft file.
147 self.has_own_embed_tokens = False
148 self.has_own_lm_head = False
149 + if self.config.tie_word_embeddings:
150 + self.hf_to_vllm_mapper = self.hf_to_vllm_mapper | WeightsMapper(
151 + orig_to_new_prefix={"model.embed_tokens.": None}
152 + )
153 target_layer_num = vllm_config.model_config.get_num_layers(
154 vllm_config.parallel_config
155 )
@@ -181,14 +186,7 @@ class EagleCohereForCausalLM(CohereForCausalLM):
186 process_eagle_weight(self, name)
187 return name, weight
188
184 - loader = AutoWeightsLoader(
185 - self,
186 - skip_prefixes=(
187 - ["lm_head.", "model.embed_tokens."]
188 - if self.config.tie_word_embeddings
189 - else None
190 - ),
191 - )
189 + loader = AutoWeightsLoader(self)
190
191 loaded_weight_names = loader.load_weights(
192 map(_track_and_forward, weights), mapper=self.hf_to_vllm_mapper
vllm/model_executor/models/colbert.py
+5 -4
@@ -358,11 +358,12 @@ class ColBERTJinaRobertaModel(ColBERTMixin, nn.Module):
358 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]):
359 other_weights, colbert_loaded = self._load_colbert_weights(weights)
360
361 - mapper = WeightsMapper(orig_to_new_prefix={"roberta.": "model."})
362 -
363 - # Skip HF pooler weights (model.pooler.*) as they not used in ColBERT
364 - loader = AutoWeightsLoader(self, skip_prefixes=["model.pooler."])
361 + # HF pooler weights are not used in ColBERT
362 + mapper = WeightsMapper(
363 + orig_to_new_prefix={"roberta.": "model.", "model.pooler.": None}
364 + )
365
366 + loader = AutoWeightsLoader(self)
367 loaded = loader.load_weights(other_weights, mapper=mapper)
368 return loaded | colbert_loaded
369
vllm/model_executor/models/colqwen3_5.py
+2 -4
@@ -140,6 +140,7 @@ class ColQwen3_5Model(
140 hf_to_vllm_mapper = WeightsMapper(
141 orig_to_new_prefix={
142 "language_model.": "language_model.model.",
143 + "mtp.": None,
144 }
145 )
146
@@ -238,10 +239,7 @@ class ColQwen3_5Model(
239 else:
240 model_weights.append((name, weight))
241
241 - loader = AutoWeightsLoader(
242 - self,
243 - skip_prefixes=["mtp."],
244 - )
242 + loader = AutoWeightsLoader(self)
243 loaded = loader.load_weights(model_weights, mapper=self.hf_to_vllm_mapper)
244
245 for name, weight in proj_weights:
vllm/model_executor/models/commandr.py
+2 -3
@@ -415,6 +415,7 @@ class CohereForCausalLM(nn.Module, SupportsLoRA, SupportsPP, SupportsQuant):
415 # (e.g. "*.weight_quantizer._double_scale"); drop them before loading.
416 # See #41925.
417 orig_to_new_substr={"_quantizer.": None},
418 + orig_to_new_prefix={"lm_head": None},
419 )
420 packed_modules_mapping = {
421 "qkv_proj": ["q_proj", "k_proj", "v_proj"],
@@ -472,7 +473,5 @@ class CohereForCausalLM(nn.Module, SupportsLoRA, SupportsPP, SupportsQuant):
473 return logits
474
475 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
475 - loader = AutoWeightsLoader(
476 - self, skip_prefixes=["lm_head", "rotary_emb.inv_freq"]
477 - )
476 + loader = AutoWeightsLoader(self)
477 return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
vllm/model_executor/models/deepseek_eagle.py
+1 -4
@@ -253,8 +253,5 @@ class EagleDeepseekV3ForCausalLM(DeepseekV3ForCausalLM):
253 process_eagle_weight(self, name)
254 return name, loaded_weight
255
256 - loader = AutoWeightsLoader(
257 - self,
258 - skip_prefixes=None,
259 - )
256 + loader = AutoWeightsLoader(self)
257 loader.load_weights(map(transform, weights))
vllm/model_executor/models/deepseek_eagle3.py
+7 -8
@@ -384,18 +384,17 @@ class Eagle3DeepseekV2ForCausalLM(LocalArgmaxMixin, DeepseekV2ForCausalLM):
384 model_weights[name] = loaded_weight
385 process_eagle_weight(self, name)
386
387 - skip_substrs = []
387 + orig_to_new_substr: dict[str, str | None] = {}
388 if not includes_draft_id_mapping:
389 - skip_substrs.append("draft_id_to_target_id")
389 + orig_to_new_substr["draft_id_to_target_id"] = None
390 if not includes_embed_tokens:
391 - skip_substrs.append("embed_tokens")
391 + orig_to_new_substr["embed_tokens"] = None
392
393 - loader = AutoWeightsLoader(
394 - self,
395 - skip_prefixes=None,
396 - skip_substrs=skip_substrs,
393 + loader = AutoWeightsLoader(self)
394 + loader.load_weights(
395 + model_weights.items(),
396 + mapper=WeightsMapper(orig_to_new_substr=orig_to_new_substr),
397 )
398 - loader.load_weights(model_weights.items())
398
399
400 # Aliases for compatibility
vllm/model_executor/models/ernie45_moe.py
+3 -6
@@ -403,7 +403,8 @@ class Ernie4_5_MoeModel(nn.Module):
403 ".mlp.up_proj": (".mlp.gate_up_proj", 1),
404 ".shared_experts.gate_proj": (".shared_experts.gate_up_proj", 0),
405 ".shared_experts.up_proj": (".shared_experts.gate_up_proj", 1),
406 - }
406 + },
407 + orig_to_new_substr={"mtp": None},
408 )
409
410 def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
@@ -497,11 +498,7 @@ class Ernie4_5_MoeModel(nn.Module):
498 yield name, loaded_weight
499
500 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
500 - loader = AutoWeightsLoader(
501 - self,
502 - skip_substrs=["mtp"],
503 - ignore_unexpected_suffixes=[".bias", "_bias"],
504 - )
501 + loader = AutoWeightsLoader(self)
502 return loader.load_weights(
503 self._preprocess(weights), mapper=self.hf_to_vllm_mapper
504 )
vllm/model_executor/models/exaone4_5.py
+11 -5
@@ -52,7 +52,12 @@ from vllm.multimodal import MULTIMODAL_REGISTRY
52
53 from .qwen2_vl import Qwen2VLDummyInputsBuilder as Exaone4_5_DummyInputsBuilder
54 from .qwen2_vl import Qwen2VLMultiModalProcessor as Exaone4_5_MultiModalProcessor
55 -from .utils import AutoWeightsLoader, init_vllm_registered_model, maybe_prefix
55 +from .utils import (
56 + AutoWeightsLoader,
57 + WeightsMapper,
58 + init_vllm_registered_model,
59 + maybe_prefix,
60 +)
61
62 logger = init_logger(__name__)
63
@@ -317,6 +322,10 @@ class Exaone4_5_ProcessingInfo(Qwen2VLProcessingInfo):
322 dummy_inputs=Exaone4_5_DummyInputsBuilder,
323 )
324 class Exaone4_5_ForConditionalGeneration(Qwen2_5_VLForConditionalGeneration):
325 + hf_to_vllm_mapper = Qwen2_5_VLForConditionalGeneration.hf_to_vllm_mapper | (
326 + WeightsMapper(orig_to_new_prefix={"mtp.": None})
327 + )
328 +
329 def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
330 nn.Module.__init__(self)
331
@@ -353,10 +362,7 @@ class Exaone4_5_ForConditionalGeneration(Qwen2_5_VLForConditionalGeneration):
362 )
363
364 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
356 - loader = AutoWeightsLoader(
357 - self,
358 - skip_prefixes=(["mtp."]),
359 - )
365 + loader = AutoWeightsLoader(self)
366 return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
367
368 @classmethod
vllm/model_executor/models/exaone_moe.py
+2 -2
@@ -471,7 +471,8 @@ class ExaoneMoeForCausalLM(nn.Module, SupportsLoRA, SupportsPP):
471 ".mlp.up_proj": (".mlp.gate_up_proj", 1),
472 ".shared_experts.gate_proj": (".shared_experts.gate_up_proj", 0),
473 ".shared_experts.up_proj": (".shared_experts.gate_up_proj", 1),
474 - }
474 + },
475 + orig_to_new_prefix={"mtp.": None},
476 )
477 packed_modules_mapping = {
478 "qkv_proj": [
@@ -560,7 +561,6 @@ class ExaoneMoeForCausalLM(nn.Module, SupportsLoRA, SupportsPP):
561 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
562 loader = AutoWeightsLoader(
563 self,
563 - skip_prefixes=["mtp."],
564 # Skip loading extra parameters for GPTQ/modelopt models.
565 ignore_unexpected_suffixes=[
566 ".bias",
vllm/model_executor/models/fireredasr2.py
+5 -4
@@ -332,7 +332,10 @@ class FireRedASR2ForConditionalGeneration(
332 "net.0": "pre_layer_norm",
333 "net.1": "linear_expand",
334 "net.4": "linear_project",
335 - }
335 + },
336 + orig_to_new_prefix={
337 + "model.encoder.audio_encoder.positional_encoding.pe": None,
338 + },
339 )
340
341 supports_transcription_only = True
@@ -477,8 +480,6 @@ class FireRedASR2ForConditionalGeneration(
480 return logits
481
482 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
480 - loader = AutoWeightsLoader(
481 - self, skip_prefixes=["model.encoder.audio_encoder.positional_encoding.pe"]
482 - )
483 + loader = AutoWeightsLoader(self)
484
485 return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
vllm/model_executor/models/fireredlid.py
+10 -12
@@ -589,7 +589,15 @@ class FireRedLIDForConditionalGeneration(
589 "net.0": "pre_layer_norm",
590 "net.1": "linear_expand",
591 "net.4": "linear_project",
592 - }
592 + },
593 + orig_to_new_prefix={
594 + # Position encoding buffers are rebuilt at init, and the output
595 + # projection is tied to the embedding.
596 + "model.encoder.positional_encoding.pe": None,
597 + "model.decoder.positional_encoding.pe": None,
598 + "model.decoder.tgt_word_prj.weight": None,
599 + "proj_out.": None,
600 + },
601 )
602
603 def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
@@ -778,15 +786,5 @@ class FireRedLIDForConditionalGeneration(
786 return text.strip()
787
788 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
781 - loader = AutoWeightsLoader(
782 - self,
783 - skip_prefixes=[
784 - # Position encoding buffers are rebuilt at init
785 - "model.encoder.positional_encoding.pe",
786 - "model.decoder.positional_encoding.pe",
787 - # Tied output projection (shared with embedding)
788 - "model.decoder.tgt_word_prj.weight",
789 - "proj_out.",
790 - ],
791 - )
789 + loader = AutoWeightsLoader(self)
790 return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
vllm/model_executor/models/funaudiochat.py
+4 -2
@@ -760,6 +760,8 @@ class FunAudioChatMultiModalProcessor(
760 dummy_inputs=FunAudioChatDummyInputsBuilder,
761 )
762 class FunAudioChatForConditionalGeneration(nn.Module, SupportsMultiModal, SupportsPP):
763 + hf_to_vllm_mapper = WeightsMapper(orig_to_new_prefix={"audio_invert_tower.": None})
764 +
765 @classmethod
766 def get_placeholder_str(cls, modality: str, i: int) -> str | None:
767 if modality.startswith("audio"):
@@ -969,5 +971,5 @@ class FunAudioChatForConditionalGeneration(nn.Module, SupportsMultiModal, Suppor
971 return self.language_model.compute_logits(hidden_states)
972
973 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
972 - loader = AutoWeightsLoader(self, skip_prefixes=["audio_invert_tower."])
973 - return loader.load_weights(weights)
974 + loader = AutoWeightsLoader(self)
975 + return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
vllm/model_executor/models/gemma3n.py
+10 -7
@@ -1056,6 +1056,14 @@ class Gemma3nTextModel(nn.Module, SupportsQuant):
1056
1057
1058 class Gemma3nForCausalLM(nn.Module):
1059 + hf_to_vllm_mapper = WeightsMapper(
1060 + orig_to_new_substr={
1061 + "embed_audio.": None,
1062 + "embed_vision.": None,
1063 + "audio_tower.": None,
1064 + "vision_tower.": None,
1065 + }
1066 + )
1067 packed_modules_mapping = {
1068 "qkv_proj": [
1069 "q_proj",
@@ -1112,10 +1120,5 @@ class Gemma3nForCausalLM(nn.Module):
1120 return logits
1121
1122 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
1115 - loader = AutoWeightsLoader(
1116 - self,
1117 - skip_substrs=(
1118 - ["embed_audio.", "embed_vision.", "audio_tower.", "vision_tower."]
1119 - ),
1120 - )
1121 - return loader.load_weights(weights)
1123 + loader = AutoWeightsLoader(self)
1124 + return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
vllm/model_executor/models/gemma4.py
+13 -10
@@ -1693,13 +1693,16 @@ class Gemma4ForCausalLM(
1693
1694 yield name, weight
1695
1696 - # Skip multimodal weights — handled by the multimodal wrapper.
1697 - skip = [
1698 - "audio_tower.",
1699 - "vision_tower.",
1700 - "embed_audio.",
1701 - "embed_vision.",
1702 - ]
1703 -
1704 - loader = AutoWeightsLoader(self, skip_substrs=skip)
1705 - return loader.load_weights(_weight_iterator())
1696 + # Drop multimodal weights, which are handled by the multimodal wrapper.
1697 + # `_weight_iterator` already applies this model's renames by hand, so
1698 + # `hf_to_vllm_mapper` is deliberately not passed here.
1699 + mapper = WeightsMapper(
1700 + orig_to_new_substr={
1701 + "audio_tower.": None,
1702 + "vision_tower.": None,
1703 + "embed_audio.": None,
1704 + "embed_vision.": None,
1705 + }
1706 + )
1707 + loader = AutoWeightsLoader(self)
1708 + return loader.load_weights(_weight_iterator(), mapper=mapper)
vllm/model_executor/models/glm4.py
+13 -14
@@ -45,11 +45,7 @@ from vllm.v1.attention.backend import AttentionType
45 from .interfaces import SupportsLoRA, SupportsPP
46 from .llama import LlamaMLP as Glm4MLP
47 from .llama import LlamaModel
48 -from .utils import (
49 - AutoWeightsLoader,
50 - PPMissingLayer,
51 - maybe_prefix,
52 -)
48 +from .utils import AutoWeightsLoader, PPMissingLayer, WeightsMapper, maybe_prefix
49
50
51 class Glm4Attention(nn.Module):
@@ -269,6 +265,16 @@ class Glm4ForCausalLM(nn.Module, SupportsLoRA, SupportsPP):
265 self.model.make_empty_intermediate_tensors
266 )
267
268 + # Drop the speculative (MTP) layers, which are loaded by the draft
269 + # model instead. They are appended after the main decoder layers.
270 + num_nextn_layers = getattr(config, "num_nextn_predict_layers", 0)
271 + self.hf_to_vllm_mapper = WeightsMapper(
272 + orig_to_new_prefix={
273 + f"model.layers.{config.num_hidden_layers + i}.": None
274 + for i in range(num_nextn_layers)
275 + }
276 + )
277 +
278 def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
279 return self.model.embed_input_ids(input_ids)
280
@@ -292,12 +298,5 @@ class Glm4ForCausalLM(nn.Module, SupportsLoRA, SupportsPP):
298 return logits
299
300 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
295 - # Skip the speculative (MTP) layers, which are loaded by the
296 - # draft model instead.
297 - num_nextn_layers = getattr(self.config, "num_nextn_predict_layers", 0)
298 - skip_prefixes = [
299 - f"model.layers.{self.config.num_hidden_layers + i}."
300 - for i in range(num_nextn_layers)
301 - ]
302 - loader = AutoWeightsLoader(self, skip_prefixes=skip_prefixes)
303 - return loader.load_weights(weights)
301 + loader = AutoWeightsLoader(self)
302 + return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
vllm/model_executor/models/glmasr.py
+6 -3
@@ -916,6 +916,10 @@ class GlmAsrForConditionalGeneration(
916 ):
917 supported_languages = ISO639_1_SUPPORTED_LANGS
918
919 + hf_to_vllm_mapper = WeightsMapper(
920 + orig_to_new_prefix={"audio_tower.embed_positions": None}
921 + )
922 +
923 packed_modules_mapping = {
924 "qkv_proj": ["q_proj", "k_proj", "v_proj"],
925 "gate_up_proj": ["gate_proj", "up_proj"],
@@ -1083,9 +1087,8 @@ class GlmAsrForConditionalGeneration(
1087 return self.language_model.compute_logits(hidden_states)
1088
1089 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
1086 - skip_prefixes = ["audio_tower.embed_positions"]
1087 - loader = AutoWeightsLoader(self, skip_prefixes=skip_prefixes)
1088 - return loader.load_weights(weights)
1090 + loader = AutoWeightsLoader(self)
1091 + return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
1092
1093 @classmethod
1094 def _get_audio_token(cls, model_config: ModelConfig) -> str:
vllm/model_executor/models/gpt2.py
+9 -4
@@ -52,6 +52,7 @@ from vllm.sequence import IntermediateTensors
52 from .interfaces import SupportsCrossEncoding, SupportsPP
53 from .utils import (
54 AutoWeightsLoader,
55 + WeightsMapper,
56 make_empty_intermediate_tensors_factory,
57 make_layers,
58 maybe_prefix,
@@ -182,6 +183,11 @@ class GPT2Block(nn.Module):
183
184 @support_torch_compile
185 class GPT2Model(nn.Module):
186 + # Drop attention mask buffers; NOTE: "c_attn.bias" must not be dropped.
187 + hf_to_vllm_mapper = WeightsMapper(
188 + orig_to_new_substr={".attn.bias": None, ".attn.masked_bias": None}
189 + )
190 +
191 def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
192 super().__init__()
193
@@ -253,11 +259,10 @@ class GPT2Model(nn.Module):
259 yield name, loaded_weight
260
261 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
256 - # Skip attention mask buffers; NOTE: "c_attn.bias" must not be skipped.
257 - loader = AutoWeightsLoader(
258 - self, skip_substrs=[".attn.bias", ".attn.masked_bias"]
262 + loader = AutoWeightsLoader(self)
263 + return loader.load_weights(
264 + self._transpose_conv1d(weights), mapper=self.hf_to_vllm_mapper
265 )
260 - return loader.load_weights(self._transpose_conv1d(weights))
266
267
268 class GPT2LMHeadModel(nn.Module, SupportsPP):
vllm/model_executor/models/gpt_j.py
+6 -2
@@ -243,7 +243,11 @@ class GPTJForCausalLM(nn.Module, SupportsPP):
243 ".q_proj": (".qkv_proj", "q"),
244 ".k_proj": (".qkv_proj", "k"),
245 ".v_proj": (".qkv_proj", "v"),
246 - }
246 + },
247 + orig_to_new_substr={
248 + "attn.bias": None,
249 + "attn.masked_bias": None,
250 + },
251 )
252
253 def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
@@ -291,5 +295,5 @@ class GPTJForCausalLM(nn.Module, SupportsPP):
295 return logits
296
297 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
294 - loader = AutoWeightsLoader(self, skip_substrs=["attn.bias", "attn.masked_bias"])
298 + loader = AutoWeightsLoader(self)
299 return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
vllm/model_executor/models/gpt_neox.py
+8 -3
@@ -48,6 +48,7 @@ from vllm.sequence import IntermediateTensors
48 from .interfaces import SupportsPP
49 from .utils import (
50 AutoWeightsLoader,
51 + WeightsMapper,
52 make_empty_intermediate_tensors_factory,
53 make_layers,
54 maybe_prefix,
@@ -196,6 +197,10 @@ class GPTNeoXLayer(nn.Module):
197
198 @support_torch_compile
199 class GPTNeoXModel(nn.Module):
200 + hf_to_vllm_mapper = WeightsMapper(
201 + orig_to_new_substr={"attention.bias": None, "attention.masked_bias": None}
202 + )
203 +
204 def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
205 super().__init__()
206
@@ -262,10 +267,10 @@ class GPTNeoXModel(nn.Module):
267 yield name, loaded_weight
268
269 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
265 - loader = AutoWeightsLoader(
266 - self, skip_substrs=["attention.bias", "attention.masked_bias"]
270 + loader = AutoWeightsLoader(self)
271 + return loader.load_weights(
272 + self._repack_qkv(weights), mapper=self.hf_to_vllm_mapper
273 )
268 - return loader.load_weights(self._repack_qkv(weights))
274
275
276 class GPTNeoXForCausalLM(nn.Module, SupportsPP):
vllm/model_executor/models/idefics2_vision_model.py
+9 -7
@@ -19,7 +19,6 @@
19 """PyTorch Idefics2 model."""
20
21 from collections.abc import Iterable
22 -from typing import ClassVar
22
23 import torch
24 from torch import nn
@@ -360,7 +359,7 @@ class Idefics2Encoder(nn.Module):
359
360
361 class Idefics2VisionTransformer(nn.Module):
363 - hf_to_vllm_mapper: ClassVar[WeightsMapper] = WeightsMapper(
362 + hf_to_vllm_mapper = WeightsMapper(
363 orig_to_new_stacked={
364 ".q_proj": (".qkv_proj", "q"),
365 ".k_proj": (".qkv_proj", "k"),
@@ -408,6 +407,13 @@ class Idefics2VisionTransformer(nn.Module):
407 if require_post_norm
408 else nn.Identity()
409 )
410 + # head is a pooling header absent from this model.
411 + orig_to_new_prefix: dict[str, str | None] = {"head.": None}
412 + if not require_post_norm:
413 + orig_to_new_prefix["post_layernorm."] = None
414 + self.hf_to_vllm_mapper = self.hf_to_vllm_mapper | WeightsMapper(
415 + orig_to_new_prefix=orig_to_new_prefix
416 + )
417
418 def get_input_embeddings(self):
419 return self.embeddings
@@ -469,11 +475,7 @@ class Idefics2VisionTransformer(nn.Module):
475 return last_hidden_state
476
477 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
472 - # head is a pooling header absent from this model.
473 - skip_prefixes = ["head."]
474 - if not self.require_post_norm:
475 - skip_prefixes.append("post_layernorm.")
476 - loader = AutoWeightsLoader(self, skip_prefixes=skip_prefixes)
478 + loader = AutoWeightsLoader(self)
479
480 layer_count = len(self.encoder.layers)
481
vllm/model_executor/models/interfaces.py
+2 -3
@@ -1150,7 +1150,7 @@ class SupportsLateInteraction(Protocol):
1150 class SupportsQuant:
1151 """The interface required for all models that support quantization."""
1152
1153 - hf_to_vllm_mapper: ClassVar["WeightsMapper | None"] = None
1153 + hf_to_vllm_mapper: "WeightsMapper | None" = None
1154 packed_modules_mapping: ClassVar[dict[str, list[str]]]
1155 quant_config: QuantizationConfig | None = None
1156
@@ -1184,8 +1184,7 @@ class SupportsQuant:
1184 if self.quant_config is None:
1185 return
1186 if (hf_to_vllm_mapper := self.hf_to_vllm_mapper) is not None:
1187 - unstacked_mapper = hf_to_vllm_mapper.get_unstacked_mapper()
1188 - self.quant_config.apply_vllm_mapper(unstacked_mapper)
1187 + self.quant_config.apply_vllm_mapper(hf_to_vllm_mapper.get_rename_mapper())
1188 if packed_modules_mapping := getattr(self, "packed_modules_mapping", None):
1189 self.quant_config.packed_modules_mapping.update(packed_modules_mapping)
1190
vllm/model_executor/models/interns1_pro.py
+9 -8
@@ -616,17 +616,18 @@ class InternS1ProForConditionalGeneration(
616
617 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]):
618 """load weights"""
619 - skip_prefixes = ["model.time_series."]
619 + orig_to_new_prefix: dict[str, str | None] = {
620 + "model.visual.": "visual.",
621 + "lm_head.": "language_model.lm_head.",
622 + "model.language_model.": "language_model.model.",
623 + "model.time_series.": None,
624 + }
625 if self.visual is None:
621 - skip_prefixes.append("visual.")
626 + orig_to_new_prefix["visual."] = None
627 # FIXME(Isotr0py): See if we can avoid tighing FoPE to PP layers
628 weights_mapper = WeightsMapper(
624 - orig_to_new_prefix={
625 - "model.visual.": "visual.",
626 - "lm_head.": "language_model.lm_head.",
627 - "model.language_model.": "language_model.model.",
628 - },
629 + orig_to_new_prefix=orig_to_new_prefix,
630 orig_to_new_suffix=self.get_frope_params_map(),
631 )
631 - loader = AutoWeightsLoader(self, skip_prefixes=skip_prefixes)
632 + loader = AutoWeightsLoader(self)
633 return loader.load_weights(weights, mapper=weights_mapper)
vllm/model_executor/models/interns2_preview.py
+9 -5
@@ -13,7 +13,7 @@ from .qwen3_vl import (
13 Qwen3VLMultiModalProcessor,
14 Qwen3VLProcessingInfo,
15 )
16 -from .utils import AutoWeightsLoader
16 +from .utils import AutoWeightsLoader, WeightsMapper
17
18
19 class InternS2PreviewProcessingInfo(Qwen3VLProcessingInfo):
@@ -30,9 +30,13 @@ class InternS2PreviewProcessingInfo(Qwen3VLProcessingInfo):
30 dummy_inputs=Qwen3VLDummyInputsBuilder,
31 )
32 class InternS2PreviewForConditionalGeneration(Qwen3_5MoeForConditionalGeneration):
33 - def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
34 - loader = AutoWeightsLoader(
35 - self,
36 - skip_prefixes=["mtp.", "model.time_series.", "time_series."],
33 + # `mtp.` is already dropped by `Qwen3_5ForConditionalGeneration`.
34 + hf_to_vllm_mapper = Qwen3_5MoeForConditionalGeneration.hf_to_vllm_mapper | (
35 + WeightsMapper(
36 + orig_to_new_prefix={"model.time_series.": None, "time_series.": None}
37 )
38 + )
39 +
40 + def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
41 + loader = AutoWeightsLoader(self)
42 return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
vllm/model_executor/models/internvl.py
+27 -18
@@ -59,7 +59,12 @@ from .interfaces import (
59 SupportsMultiModal,
60 SupportsPP,
61 )
62 -from .utils import AutoWeightsLoader, init_vllm_registered_model, maybe_prefix
62 +from .utils import (
63 + AutoWeightsLoader,
64 + WeightsMapper,
65 + init_vllm_registered_model,
66 + maybe_prefix,
67 +)
68
69
70 class InternVLImagePixelInputs(TensorSchema):
@@ -554,6 +559,25 @@ class InternVLChatModel(
559 ):
560 supports_encoder_tp_data = True
561
562 + hf_to_vllm_mapper = WeightsMapper(
563 + orig_to_new_prefix=dict.fromkeys(
564 + [
565 + "action_embed",
566 + "temporal_embed",
567 + "track_embed",
568 + "track_embed_decoder",
569 + "box_token",
570 + "cg_criterion",
571 + "cg_model",
572 + "loc_encoder",
573 + "loc_decoder",
574 + "sam",
575 + "temporal_token",
576 + "track_token",
577 + ]
578 + )
579 + )
580 +
581 @classmethod
582 def get_placeholder_str(cls, modality: str, i: int) -> str | None:
583 if modality.startswith("image"):
@@ -865,23 +889,8 @@ class InternVLChatModel(
889 return self.language_model.compute_logits(hidden_states)
890
891 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
868 - # unused modules appear in OpenGVLab/InternVideo2_5_Chat_8B
869 - skip_prefixes = [
870 - "action_embed",
871 - "temporal_embed",
872 - "track_embed",
873 - "track_embed_decoder",
874 - "box_token",
875 - "cg_criterion",
876 - "cg_model",
877 - "loc_encoder",
878 - "loc_decoder",
879 - "sam",
880 - "temporal_token",
881 - "track_token",
882 - ]
883 - loader = AutoWeightsLoader(self, skip_prefixes=skip_prefixes)
884 - return loader.load_weights(weights)
892 + loader = AutoWeightsLoader(self)
893 + return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
894
895 def get_mm_mapping(self) -> MultiModelKeys:
896 """
vllm/model_executor/models/jina.py
+4 -2
@@ -43,6 +43,8 @@ logger = logging.getLogger(__name__)
43 class JinaForRanking(nn.Module, SupportsLateInteraction):
44 is_pooling_model = True
45
46 + hf_to_vllm_mapper = WeightsMapper(orig_to_new_prefix={"lm_head.": None})
47 +
48 def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
49 super().__init__()
50 config = vllm_config.model_config.hf_config
@@ -87,8 +89,8 @@ class JinaForRanking(nn.Module, SupportsLateInteraction):
89 return hidden_states
90
91 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
90 - loader = AutoWeightsLoader(self, skip_prefixes=(["lm_head."]))
91 - return loader.load_weights(weights)
92 + loader = AutoWeightsLoader(self)
93 + return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
94
95
96 class JinaForRankingPool(StepPool):
vllm/model_executor/models/keye.py
+3 -2
@@ -721,7 +721,8 @@ class KeyeSiglipVisionModel(nn.Module):
721 ".q_proj": (".qkv_proj", "q"),
722 ".k_proj": (".qkv_proj", "k"),
723 ".v_proj": (".qkv_proj", "v"),
724 - }
724 + },
725 + orig_to_new_prefix={"vision_model.head.": None},
726 )
727
728 def __init__(
@@ -782,7 +783,7 @@ class KeyeSiglipVisionModel(nn.Module):
783 )
784
785 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
785 - loader = AutoWeightsLoader(self, skip_prefixes=["vision_model.head."])
786 + loader = AutoWeightsLoader(self)
787 return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
788
789
vllm/model_executor/models/kimi_audio.py
+8 -15
@@ -380,6 +380,12 @@ class KimiAudioForConditionalGeneration(
380 "model.embed_tokens.": "language_model.model.embed_tokens.",
381 "model.norm.": "language_model.model.norm.",
382 "lm_head.": "language_model.lm_head.",
383 + # MIMO/TTS weights and any `model.` residue no rule above
384 + # claimed: this model only does ASR (speech-to-text).
385 + "model.": None,
386 + "mimo_layers.": None,
387 + "mimo_output.": None,
388 + "mimo_norm.": None,
389 },
390 orig_to_new_substr={
391 ".fc1.": ".mlp.fc1.",
@@ -573,21 +579,8 @@ class KimiAudioForConditionalGeneration(
579 return self.language_model.compute_logits(hidden_states)
580
581 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
576 - """Load weights, skipping MIMO layers (TTS-only) for ASR."""
577 - # Filter out MIMO/TTS weights since we only do ASR (speech-to-text)
578 - skipped_patterns = [
579 - # Audio tower
580 - "model.",
581 - # MIMO/TTS
582 - "mimo_layers.",
583 - "mimo_output.",
584 - "mimo_norm.",
585 - ]
586 -
587 - # Load main model weights (LLM + projector) with mapper
588 - loader = AutoWeightsLoader(self, skip_prefixes=skipped_patterns)
589 - loaded = loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
590 - return loaded
582 + loader = AutoWeightsLoader(self)
583 + return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
584
585 @classmethod
586 def get_speech_to_text_config(
vllm/model_executor/models/lfm2_siglip2.py
+5 -4
@@ -484,6 +484,10 @@ class Siglip2Model(torch.nn.Module):
484 require_post_norm=require_post_norm,
485 prefix=maybe_prefix(prefix, "vision_model"),
486 )
487 + if self.vision_model.post_layernorm is None:
488 + self.hf_to_vllm_mapper = self.hf_to_vllm_mapper | WeightsMapper(
489 + orig_to_new_prefix={"vision_model.post_layernorm.": None}
490 + )
491
492 def forward(
493 self,
@@ -510,10 +514,7 @@ class Siglip2Model(torch.nn.Module):
514 )
515
516 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
513 - skip_prefixes = []
514 - if self.vision_model.post_layernorm is None:
515 - skip_prefixes.append("vision_model.post_layernorm.")
516 - loader = AutoWeightsLoader(self, skip_prefixes=skip_prefixes)
517 + loader = AutoWeightsLoader(self)
518
519 # Drop layers omitted by num_hidden_layers_override.
520 layer_count = len(self.vision_model.encoder.layers)
vllm/model_executor/models/llama.py
+1 -2
@@ -26,7 +26,6 @@
26
27 from collections.abc import Iterable
28 from itertools import islice
29 -from typing import ClassVar
29
30 import torch
31 from torch import nn
@@ -343,7 +342,7 @@ class LlamaDecoderLayer(nn.Module):
342 },
343 )
344 class LlamaModel(nn.Module, EagleModelMixin):
346 - hf_to_vllm_mapper: ClassVar[WeightsMapper] = WeightsMapper(
345 + hf_to_vllm_mapper = WeightsMapper(
346 orig_to_new_stacked={
347 # weight_name: (param_name, shard_id)
348 ".q_proj": (".qkv_proj", "q"),
vllm/model_executor/models/llama4_eagle.py
+1 -5
@@ -206,9 +206,5 @@ class EagleLlama4ForCausalLM(Llama4ForCausalLM, SupportsMultiModalEmbeddings):
206 process_eagle_weight(self, name)
207 return name, weight
208
209 - loader = AutoWeightsLoader(
210 - self,
211 - # lm_head is tied with target model (Llama4ForCausalLM)
212 - skip_prefixes=([]),
213 - )
209 + loader = AutoWeightsLoader(self)
210 loader.load_weights(map(transform, weights))
vllm/model_executor/models/llama_eagle.py
+1 -4
@@ -175,8 +175,5 @@ class EagleLlamaForCausalLM(LlamaForCausalLM):
175 process_eagle_weight(self, name)
176 return name, loaded_weight
177
178 - loader = AutoWeightsLoader(
179 - self,
180 - skip_prefixes=None,
181 - )
178 + loader = AutoWeightsLoader(self)
179 loader.load_weights(map(transform, weights))
vllm/model_executor/models/llama_eagle3.py
+9 -10
@@ -415,18 +415,17 @@ class Eagle3LlamaForCausalLM(LlamaForCausalLM):
415 "Please provide mask_hidden in the weights."
416 )
417
418 - skip_substrs = ["mask_hidden"]
418 + orig_to_new_substr = {"mask_hidden": None}
419 if not includes_draft_id_mapping:
420 - skip_substrs.append("draft_id_to_target_id")
420 + orig_to_new_substr["draft_id_to_target_id"] = None
421 if not includes_embed_tokens:
422 - skip_substrs.append("embed_tokens")
422 + orig_to_new_substr["embed_tokens"] = None
423 if not self.model.use_aux_hidden_state:
424 - skip_substrs.append("fc.")
424 + orig_to_new_substr["fc."] = None
425 if not self.model.norm_before_fc:
426 - skip_substrs.append("input_norm.")
427 - loader = AutoWeightsLoader(
428 - self,
429 - skip_prefixes=None,
430 - skip_substrs=skip_substrs,
426 + orig_to_new_substr["input_norm."] = None
427 + loader = AutoWeightsLoader(self)
428 + loader.load_weights(
429 + model_weights.items(),
430 + mapper=WeightsMapper(orig_to_new_substr=orig_to_new_substr),
431 )
432 - loader.load_weights(model_weights.items())
vllm/model_executor/models/longcat_flash_ngram.py
+7 -5
@@ -31,7 +31,7 @@ from vllm.v1.worker.gpu.states import RequestState
31
32 from .interfaces import SupportsLoRA, SupportsPP
33 from .longcat_flash import FlashConfig, FlashModel
34 -from .utils import AutoWeightsLoader, PPMissingLayer, maybe_prefix
34 +from .utils import AutoWeightsLoader, PPMissingLayer, WeightsMapper, maybe_prefix
35
36
37 def uses_ngram_embedding(config: FlashConfig) -> bool:
@@ -204,6 +204,9 @@ class FlashNgramModel(FlashModel):
204 class LongcatFlashNgramForCausalLM(nn.Module, SupportsLoRA, SupportsPP):
205 """LongCat-Flash-Lite for causal LM (MRV2-only, n-gram embedding)."""
206
207 + # MTP weights are not part of this model.
208 + hf_to_vllm_mapper = WeightsMapper(orig_to_new_prefix={"model.mtp.": None})
209 +
210 packed_modules_mapping = {
211 "qkv_proj": ["q_proj", "k_proj", "v_proj"],
212 "gate_up_proj": ["gate_proj", "up_proj"],
@@ -266,10 +269,9 @@ class LongcatFlashNgramForCausalLM(nn.Module, SupportsLoRA, SupportsPP):
269
270 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
271 # AutoWeightsLoader routes ``model.*`` to FlashNgramModel.load_weights
269 - # (which handles the ngram split) and ``lm_head.*`` to the head. MTP
270 - # weights are not part of this model.
271 - loader = AutoWeightsLoader(self, skip_prefixes=["model.mtp."])
272 - return loader.load_weights(weights)
272 + # (which handles the ngram split) and ``lm_head.*`` to the head.
273 + loader = AutoWeightsLoader(self)
274 + return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
275
276
277 class LongcatNgramModelState(DefaultModelState):
vllm/model_executor/models/mimo.py
+6 -4
@@ -41,7 +41,7 @@ from vllm.model_executor.layers.vocab_parallel_embedding import ParallelLMHead
41 from vllm.model_executor.models.qwen2 import Qwen2ForCausalLM, Qwen2Model
42 from vllm.sequence import IntermediateTensors
43
44 -from .utils import AutoWeightsLoader, PPMissingLayer, maybe_prefix
44 +from .utils import AutoWeightsLoader, PPMissingLayer, WeightsMapper, maybe_prefix
45
46 logger = init_logger(__name__)
47
@@ -87,6 +87,9 @@ class MiMoModel(Qwen2Model):
87
88
89 class MiMoForCausalLM(Qwen2ForCausalLM, nn.Module):
90 + # MTP layers are loaded by the draft model, not the main model.
91 + hf_to_vllm_mapper = WeightsMapper(orig_to_new_prefix={"model.mtp_layers.": None})
92 +
93 def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
94 nn.Module.__init__(self)
95 config = vllm_config.model_config.hf_config
@@ -119,9 +122,8 @@ class MiMoForCausalLM(Qwen2ForCausalLM, nn.Module):
122 )
123
124 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
122 - # MTP layers are loaded by the draft model, not the main model.
123 - loader = AutoWeightsLoader(self, skip_prefixes=["model.mtp_layers."])
124 - return loader.load_weights(weights)
125 + loader = AutoWeightsLoader(self)
126 + return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
127
128 def compute_logits(
129 self,
vllm/model_executor/models/mimo_v2_omni.py
+2 -1
@@ -1189,6 +1189,7 @@ class MiMoV2OmniForCausalLM(nn.Module, SupportsMultiModal, SupportsPP, SupportsQ
1189 # mapping for original checkpoint
1190 "lm_head.": "language_model.lm_head.",
1191 "model.": "language_model.model.",
1192 + "audio_tokenizer.": None,
1193 }
1194 )
1195
@@ -1490,6 +1491,6 @@ class MiMoV2OmniForCausalLM(nn.Module, SupportsMultiModal, SupportsPP, SupportsQ
1491 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
1492 audio_loaded: set[str] = set()
1493
1493 - loader = AutoWeightsLoader(self, skip_prefixes=["audio_tokenizer."])
1494 + loader = AutoWeightsLoader(self)
1495 auto_loaded = loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
1496 return audio_loaded | auto_loaded
vllm/model_executor/models/minicpmo.py
+11 -3
@@ -71,7 +71,12 @@ from .minicpmv import (
71 MiniCPMVProcessingInfo,
72 _minicpmv_field_config,
73 )
74 -from .utils import AutoWeightsLoader, cast_overflow_tensors, maybe_prefix
74 +from .utils import (
75 + AutoWeightsLoader,
76 + WeightsMapper,
77 + cast_overflow_tensors,
78 + maybe_prefix,
79 +)
80
81 CPU_DEVICE = torch.device("cpu")
82
@@ -672,6 +677,9 @@ class MiniCPMWhisperEncoder(WhisperEncoder):
677 class MiniCPMOBaseModel:
678 """Base mixin class for MiniCPM-O models with audio support."""
679
680 + # Unlike the vision-only MiniCPM-V models, audio weights are loaded here.
681 + hf_to_vllm_mapper = WeightsMapper(orig_to_new_prefix={"tts": None})
682 +
683 packed_modules_mapping = {
684 "qkv_proj": [
685 "q_proj",
@@ -718,8 +726,8 @@ class MiniCPMOBaseModel:
726 return model
727
728 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
721 - loader = AutoWeightsLoader(self, skip_prefixes=["tts"])
722 - loaded = loader.load_weights(weights)
729 + loader = AutoWeightsLoader(self)
730 + loaded = loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
731 self._ensure_resampler_device()
732 return loaded
733
vllm/model_executor/models/minicpmv.py
+13 -7
@@ -109,7 +109,7 @@ from .interfaces import (
109 SupportsMultiModal,
110 SupportsPP,
111 )
112 -from .utils import AutoWeightsLoader, flatten_bn, maybe_prefix
112 +from .utils import AutoWeightsLoader, WeightsMapper, flatten_bn, maybe_prefix
113
114 # For profile run
115 _MAX_FRAMES_PER_VIDEO = 16
@@ -1567,6 +1567,10 @@ class MiniCPMV2_5(MiniCPMVBaseModel, SupportsLoRA):
1567
1568
1569 class MiniCPMV2_6(MiniCPMVBaseModel, SupportsLoRA):
1570 + hf_to_vllm_mapper = WeightsMapper(
1571 + # The vision-only models have no audio tower or TTS head to load weights into.
1572 + orig_to_new_prefix={"apm.": None, "audio": None, "tts": None}
1573 + )
1574 packed_modules_mapping = {
1575 "qkv_proj": [
1576 "q_proj",
@@ -1660,13 +1664,14 @@ class MiniCPMV2_6(MiniCPMVBaseModel, SupportsLoRA):
1664 return self.resampler(vision_embedding, tgt_sizes)
1665
1666 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
1663 - loader = AutoWeightsLoader(self, skip_prefixes=["apm.", "audio", "tts"])
1664 - loaded = loader.load_weights(weights)
1667 + loader = AutoWeightsLoader(self)
1668 + loaded = loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
1669 self._ensure_resampler_device()
1670 return loaded
1671
1672
1673 class MiniCPMV4_0(MiniCPMVBaseModel, SupportsLoRA):
1674 + hf_to_vllm_mapper = MiniCPMV2_6.hf_to_vllm_mapper
1675 packed_modules_mapping = {
1676 "qkv_proj": [
1677 "q_proj",
@@ -1758,13 +1763,14 @@ class MiniCPMV4_0(MiniCPMVBaseModel, SupportsLoRA):
1763 return self.resampler(vision_embedding, tgt_sizes)
1764
1765 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
1761 - loader = AutoWeightsLoader(self, skip_prefixes=["apm.", "audio", "tts"])
1762 - loaded = loader.load_weights(weights)
1766 + loader = AutoWeightsLoader(self)
1767 + loaded = loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
1768 self._ensure_resampler_device()
1769 return loaded
1770
1771
1772 class MiniCPMV4_5(MiniCPMVBaseModel, SupportsLoRA):
1773 + hf_to_vllm_mapper = MiniCPMV2_6.hf_to_vllm_mapper
1774 packed_modules_mapping = {
1775 "qkv_proj": [
1776 "q_proj",
@@ -1861,8 +1867,8 @@ class MiniCPMV4_5(MiniCPMVBaseModel, SupportsLoRA):
1867 return self.resampler(vision_embedding, tgt_sizes, all_temporal_ids)
1868
1869 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
1864 - loader = AutoWeightsLoader(self, skip_prefixes=["apm.", "audio", "tts"])
1865 - loaded = loader.load_weights(weights)
1870 + loader = AutoWeightsLoader(self)
1871 + loaded = loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
1872 self._ensure_resampler_device()
1873 return loaded
1874
vllm/model_executor/models/minicpmv4_6.py
+2 -1
@@ -958,6 +958,7 @@ class MiniCPMV4_6ForConditionalGeneration(
958 "model.merger.": "merger.",
959 "model.language_model.": "language_model.model.",
960 "lm_head.": "language_model.lm_head.",
961 + "mtp.": None,
962 }
963 )
964
@@ -1281,7 +1282,7 @@ class MiniCPMV4_6ForConditionalGeneration(
1282 self,
1283 weights: Iterable[tuple[str, torch.Tensor]],
1284 ) -> set[str]:
1284 - loader = AutoWeightsLoader(self, skip_prefixes=["mtp."])
1285 + loader = AutoWeightsLoader(self)
1286 return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
1287
1288 def get_mm_mapping(self) -> MultiModelKeys:
vllm/model_executor/models/minimax_m2.py
+9 -11
@@ -371,6 +371,14 @@ class MiniMaxM2Model(nn.Module, EagleModelMixin):
371 ["hidden_states", "residual"], config.hidden_size
372 )
373
374 + # Drop spec-decode (MTP) layers; they are appended after the main
375 + # decoder layers and have no destination in the main model.
376 + if num_mtp := getattr(config, "num_mtp_modules", 0):
377 + base = config.num_hidden_layers
378 + self.hf_to_vllm_mapper = self.hf_to_vllm_mapper | WeightsMapper(
379 + orig_to_new_prefix={f"layers.{base + i}.": None for i in range(num_mtp)}
380 + )
381 +
382 def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
383 return self.embed_tokens(input_ids)
384
@@ -413,17 +421,7 @@ class MiniMaxM2Model(nn.Module, EagleModelMixin):
421 return hidden_states
422
423 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
416 - # Skip spec-decode (MTP) layers; they are appended after the main
417 - # decoder layers and have no destination in the main model.
418 - skip_prefixes = None
419 - num_mtp = getattr(self.config, "num_mtp_modules", 0)
420 - if num_mtp:
421 - base = self.config.num_hidden_layers
422 - skip_prefixes = [f"layers.{base + i}." for i in range(num_mtp)]
423 - loader = AutoWeightsLoader(
424 - self,
425 - skip_prefixes=skip_prefixes,
426 - )
424 + loader = AutoWeightsLoader(self)
425 return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
426
427
vllm/model_executor/models/modernbert.py
+4 -2
@@ -434,6 +434,8 @@ class ModernBertPredictionHead(nn.Module):
434 class ModernBertForTokenClassification(nn.Module):
435 is_pooling_model = True
436
437 + hf_to_vllm_mapper = WeightsMapper(orig_to_new_prefix={"drop": None})
438 +
439 def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
440 super().__init__()
441 config = vllm_config.model_config.hf_config
@@ -456,8 +458,8 @@ class ModernBertForTokenClassification(nn.Module):
458 return self.model.embed_input_ids(input_ids)
459
460 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]):
459 - loader = AutoWeightsLoader(self, skip_prefixes=["drop"])
460 - loaded_params = loader.load_weights(weights)
461 + loader = AutoWeightsLoader(self)
462 + loaded_params = loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
463 return loaded_params
464
465 def forward(
vllm/model_executor/models/moss_audio.py
+2 -4
@@ -1450,6 +1450,7 @@ class MossAudioModel(nn.Module, SupportsMultiModal, SupportsPP, SupportsLoRA):
1450 "language_model.embed_tokens.": "language_model.model.embed_tokens.",
1451 "language_model.layers.": "language_model.model.layers.",
1452 "language_model.norm.": "language_model.model.norm.",
1453 + "audio_encoder.embed_positions": None,
1454 },
1455 orig_to_new_stacked={
1456 ".gate_proj": (".gate_up_proj", 0),
@@ -1865,8 +1866,5 @@ class MossAudioModel(nn.Module, SupportsMultiModal, SupportsPP, SupportsLoRA):
1866 return self.language_model.compute_logits(hidden_states)
1867
1868 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
1868 - loader = AutoWeightsLoader(
1869 - self,
1870 - skip_prefixes=["audio_encoder.embed_positions"],
1871 - )
1869 + loader = AutoWeightsLoader(self)
1870 return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
vllm/model_executor/models/nemotron_h.py
+2 -2
@@ -708,7 +708,7 @@ class NemotronHForCausalLM(
708 is_non_gated_moe: bool = True
709
710 hf_to_vllm_mapper = WeightsMapper(
711 - orig_to_new_prefix={"backbone": "model"},
711 + orig_to_new_prefix={"backbone": "model", "mtp": None},
712 orig_to_new_substr={"A_log": "A", "embeddings": "embed_tokens"},
713 orig_to_new_stacked={
714 ".q_proj": (".qkv_proj", "q"),
@@ -887,5 +887,5 @@ class NemotronHForCausalLM(
887 return logits
888
889 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
890 - loader = AutoWeightsLoader(self, skip_prefixes=["mtp"])
890 + loader = AutoWeightsLoader(self)
891 return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
vllm/model_executor/models/nemotron_vl.py
+8 -5
@@ -89,6 +89,12 @@ class NemotronVLProcessingInfo(BaseInternVLProcessingInfo):
89 dummy_inputs=BaseInternVLDummyInputsBuilder[NemotronVLProcessingInfo],
90 )
91 class LlamaNemotronVLChatModel(nn.Module, SupportsMultiModal, SupportsPP, SupportsLoRA):
92 + # Ignore registered buffers, see
93 + # https://huggingface.co/nvidia/C-RADIOv2-H/blob/main/input_conditioner.py#L28
94 + hf_to_vllm_mapper = WeightsMapper(
95 + orig_to_new_substr={"norm_mean": None, "norm_std": None}
96 + )
97 +
98 @classmethod
99 def get_placeholder_str(cls, modality: str, i: int) -> str | None:
100 if modality.startswith("image"):
@@ -377,11 +383,8 @@ class LlamaNemotronVLChatModel(nn.Module, SupportsMultiModal, SupportsPP, Suppor
383 return self.language_model.compute_logits(hidden_states)
384
385 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
380 - ## Ignore registered_buffers
381 - ## see https://huggingface.co/nvidia/C-RADIOv2-H/blob/main/input_conditioner.py#L28 # noqa: E501
382 - skip_substrs = ["norm_mean", "norm_std"]
383 - loader = AutoWeightsLoader(self, skip_substrs=skip_substrs)
384 - return loader.load_weights(weights)
386 + loader = AutoWeightsLoader(self)
387 + return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
388
389 def get_mm_mapping(self) -> MultiModelKeys:
390 """
vllm/model_executor/models/paddleocr_vl.py
+11 -13
@@ -887,7 +887,16 @@ class SiglipVisionModel(nn.Module):
887 ".q_proj": (".qkv_proj", "q"),
888 ".k_proj": (".qkv_proj", "k"),
889 ".v_proj": (".qkv_proj", "v"),
890 - }
890 + },
891 + # The SigLIP attention pooling head and packing pos embedding are
892 + # present in the checkpoint but absent from this vision tower.
893 + orig_to_new_substr={
894 + "head.attention": None,
895 + "head.layernorm": None,
896 + "head.mlp": None,
897 + "head.probe": None,
898 + "packing_position_embedding": None,
899 + },
900 )
901
902 def __init__(
@@ -934,18 +943,7 @@ class SiglipVisionModel(nn.Module):
943 )
944
945 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
937 - # Skip the SigLIP attention pooling head and packing pos embedding
938 - # present in the checkpoint but absent from this vision tower.
939 - loader = AutoWeightsLoader(
940 - self,
941 - skip_substrs=[
942 - "head.attention",
943 - "head.layernorm",
944 - "head.mlp",
945 - "head.probe",
946 - "packing_position_embedding",
947 - ],
948 - )
946 + loader = AutoWeightsLoader(self)
947 return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
948
949
vllm/model_executor/models/phi4mm.py
+2 -1
@@ -1016,6 +1016,7 @@ class Phi4MMForCausalLM(nn.Module, SupportsLoRA, SupportsMultiModal):
1016 hf_to_vllm_mapper = WeightsMapper(
1017 orig_to_new_substr={
1018 "base_layer.": "",
1019 + "lora": None,
1020 },
1021 orig_to_new_prefix={
1022 "model.embed_tokens_extend.audio_embed.audio_projection.vision.": "embed_tokens_extend.audio_projection_for_vision.", # noqa: E501
@@ -1258,7 +1259,7 @@ class Phi4MMForCausalLM(nn.Module, SupportsLoRA, SupportsMultiModal):
1259 return logits
1260
1261 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> None:
1261 - loader = AutoWeightsLoader(self, skip_substrs=["lora"])
1262 + loader = AutoWeightsLoader(self)
1263 return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
1264
1265 def get_mm_mapping(self) -> MultiModelKeys:
vllm/model_executor/models/qwen2_5_omni_thinker.py
+3 -1
@@ -1112,6 +1112,8 @@ class Qwen2_5OmniThinkerForConditionalGeneration(
1112 "thinker.lm_head.": "language_model.lm_head.",
1113 "thinker.model.": "language_model.model.",
1114 "thinker.": "",
1115 + "talker.": None,
1116 + "token2wav.": None,
1117 }
1118 )
1119 packed_modules_mapping = {
@@ -1591,7 +1593,7 @@ class Qwen2_5OmniThinkerForConditionalGeneration(
1593 return self.language_model.compute_logits(hidden_states)
1594
1595 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
1594 - loader = AutoWeightsLoader(self, skip_prefixes=["talker.", "token2wav."])
1596 + loader = AutoWeightsLoader(self)
1597 return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
1598
1599 def get_mm_mapping(self) -> MultiModelKeys:
vllm/model_executor/models/qwen3_5.py
+8 -9
@@ -319,7 +319,7 @@ class Qwen3_5ForCausalLMBase(
319 # `model.language_model.` prefix inherited from the VL training stack.
320 # Strip it so both prefixed and clean checkpoints load correctly.
321 hf_to_vllm_mapper = WeightsMapper(
322 - orig_to_new_prefix={"model.language_model.": "model."},
322 + orig_to_new_prefix={"model.language_model.": "model.", "mtp.": None},
323 )
324
325 def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
@@ -430,10 +430,7 @@ class Qwen3_5ForCausalLMBase(
430 return self.logits_processor(self.lm_head, hidden_states)
431
432 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
433 - loader = AutoWeightsLoader(
434 - self,
435 - skip_prefixes=["mtp."],
436 - )
433 + loader = AutoWeightsLoader(self)
434 return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
435
436 def get_mrope_input_positions(
@@ -470,6 +467,11 @@ class Qwen3_5MoeForCausalLM(Qwen3_5ForCausalLMBase, QwenNextMixtureOfExperts):
467 class Qwen3_5ForConditionalGeneration(Qwen3VLForConditionalGeneration, IsHybrid):
468 supports_multimodal_pruning = True
469
470 + hf_to_vllm_mapper = (
471 + Qwen3VLForConditionalGeneration.hf_to_vllm_mapper
472 + | WeightsMapper(orig_to_new_prefix={"mtp.": None})
473 + )
474 +
475 packed_modules_mapping = Qwen3VLForConditionalGeneration.packed_modules_mapping | {
476 "in_proj_qkvz": ["in_proj_qkv", "in_proj_z"],
477 "in_proj_ba": ["in_proj_b", "in_proj_a"],
@@ -590,10 +592,7 @@ class Qwen3_5ForConditionalGeneration(Qwen3VLForConditionalGeneration, IsHybrid)
592 return hidden_states
593
594 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
593 - loader = AutoWeightsLoader(
594 - self,
595 - skip_prefixes=["mtp."],
596 - )
595 + loader = AutoWeightsLoader(self)
596 return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
597
598 @classmethod
vllm/model_executor/models/qwen3_asr.py
+3 -4
@@ -372,6 +372,8 @@ class Qwen3ASRForConditionalGeneration(
372 "model.language_model.": "language_model.model.",
373 "model.multi_modal_projector.linear_1.": "audio_tower.proj1.",
374 "model.multi_modal_projector.linear_2.": "audio_tower.proj2.",
375 + "talker.": None,
376 + "code2wav.": None,
377 }
378 )
379
@@ -545,10 +547,7 @@ class Qwen3ASRForConditionalGeneration(
547 return self.language_model.compute_logits(hidden_states)
548
549 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
548 - loader = AutoWeightsLoader(
549 - self,
550 - skip_prefixes=["talker.", "code2wav."],
551 - )
550 + loader = AutoWeightsLoader(self)
551 loaded_weights = loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
552
553 return loaded_weights
vllm/model_executor/models/qwen3_asr_forced_aligner.py
+3 -4
@@ -59,6 +59,8 @@ class Qwen3ASRForcedAlignerForTokenClassification(
59 "thinker.lm_head.": "classifier.",
60 "thinker.model.": "language_model.model.",
61 "thinker.": "",
62 + "talker.": None,
63 + "code2wav.": None,
64 }
65 )
66
@@ -113,8 +115,5 @@ class Qwen3ASRForcedAlignerForTokenClassification(
115 return self.classifier(hidden_states)
116
117 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
116 - loader = AutoWeightsLoader(
117 - self,
118 - skip_prefixes=["talker.", "code2wav."],
119 - )
118 + loader = AutoWeightsLoader(self)
119 return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
vllm/model_executor/models/qwen3_dflash.py
+8 -11
@@ -835,21 +835,18 @@ class DFlashQwen3ForCausalLM(Qwen3ForCausalLM):
835 model_weights["model.mask_embedding"] = mask_embedding
836 self.model.has_separate_mask_embedding = True
837
838 - skip_substrs = []
838 + orig_to_new_substr = {}
839 if not includes_draft_id_mapping:
840 - skip_substrs.append("draft_id_to_target_id")
840 + orig_to_new_substr["draft_id_to_target_id"] = None
841 if not includes_embed_tokens:
842 - skip_substrs.append("embed_tokens")
842 + orig_to_new_substr["embed_tokens"] = None
843 if not self.model.use_aux_hidden_state:
844 - skip_substrs.append("fc.")
844 + orig_to_new_substr["fc."] = None
845 if not self.model.has_separate_mask_embedding:
846 - skip_substrs.append("mask_embedding")
847 - loader = AutoWeightsLoader(
848 - self,
849 - skip_prefixes=None,
850 - skip_substrs=skip_substrs,
851 - )
852 - loader.load_weights(model_weights.items())
846 + orig_to_new_substr["mask_embedding"] = None
847 + mapper = WeightsMapper(orig_to_new_substr=orig_to_new_substr)
848 + loader = AutoWeightsLoader(self)
849 + loader.load_weights(model_weights.items(), mapper=mapper)
850 self.model._build_fused_kv_buffers()
851
852 def _read_mask_embedding(self) -> torch.Tensor | None:
vllm/model_executor/models/qwen3_dspark.py
+14 -8
@@ -30,7 +30,12 @@ from vllm.model_executor.layers.vocab_parallel_embedding import (
30 )
31
32 from .qwen3_dflash import DFlashQwen3ForCausalLM, DFlashQwen3Model
33 -from .utils import AutoWeightsLoader, maybe_prefix, process_eagle_weight
33 +from .utils import (
34 + AutoWeightsLoader,
35 + WeightsMapper,
36 + maybe_prefix,
37 + process_eagle_weight,
38 +)
39
40 logger = init_logger(__name__)
41
@@ -275,16 +280,17 @@ class Qwen3DSparkForCausalLM(DFlashQwen3ForCausalLM):
280 # mask_embedding is an unused placeholder param; DSpark masks via the vocab row.
281 # embed_tokens / lm_head are optional; when omitted they are shared from
282 # the target by load_dspark_model, so skip the unloaded params here.
278 - skip_substrs = ["mask_embedding"]
283 + orig_to_new_substr = {"mask_embedding": None}
284 if not includes_embed_tokens:
280 - skip_substrs.append("embed_tokens")
285 + orig_to_new_substr["embed_tokens"] = None
286 if not includes_lm_head:
282 - skip_substrs.append("lm_head")
287 + orig_to_new_substr["lm_head"] = None
288 if not includes_draft_id_mapping:
284 - skip_substrs.append("draft_id_to_target_id")
289 + orig_to_new_substr["draft_id_to_target_id"] = None
290 if self.model.confidence_head is None or not includes_confidence_head:
291 self.model.confidence_head = None
287 - skip_substrs.append("confidence_head")
288 - loader = AutoWeightsLoader(self, skip_substrs=skip_substrs)
289 - loader.load_weights(model_weights.items())
292 + orig_to_new_substr["confidence_head"] = None
293 + mapper = WeightsMapper(orig_to_new_substr=orig_to_new_substr)
294 + loader = AutoWeightsLoader(self)
295 + loader.load_weights(model_weights.items(), mapper=mapper)
296 self.model._build_fused_kv_buffers()
vllm/model_executor/models/qwen3_eagle3.py
+8 -11
@@ -425,18 +425,15 @@ class Eagle3Qwen3ForCausalLM(Qwen3ForCausalLM):
425 "Please provide mask_hidden in the weights."
426 )
427
428 - skip_substrs = ["mask_hidden"]
428 + orig_to_new_substr = {"mask_hidden": None}
429 if not includes_draft_id_mapping:
430 - skip_substrs.append("draft_id_to_target_id")
430 + orig_to_new_substr["draft_id_to_target_id"] = None
431 if not includes_embed_tokens:
432 - skip_substrs.append("embed_tokens")
432 + orig_to_new_substr["embed_tokens"] = None
433 if not self.model.use_aux_hidden_state:
434 - skip_substrs.append("fc.")
434 + orig_to_new_substr["fc."] = None
435 if not self.model.norm_before_fc:
436 - skip_substrs.append("input_norm.")
437 - loader = AutoWeightsLoader(
438 - self,
439 - skip_prefixes=None,
440 - skip_substrs=skip_substrs,
441 - )
442 - loader.load_weights(model_weights.items())
436 + orig_to_new_substr["input_norm."] = None
437 + mapper = WeightsMapper(orig_to_new_substr=orig_to_new_substr)
438 + loader = AutoWeightsLoader(self)
439 + loader.load_weights(model_weights.items(), mapper=mapper)
vllm/model_executor/models/qwen3_next.py
+5 -2
@@ -727,6 +727,9 @@ class Qwen3NextForCausalLM(
727 IsHybrid,
728 SupportsEagle3,
729 ):
730 + # MTP weights are loaded by the draft model, not this one.
731 + hf_to_vllm_mapper = WeightsMapper(orig_to_new_prefix={"mtp.": None})
732 +
733 packed_modules_mapping = {
734 "qkv_proj": [
735 "q_proj",
@@ -833,5 +836,5 @@ class Qwen3NextForCausalLM(
836 return self.logits_processor(self.lm_head, hidden_states)
837
838 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
836 - loader = AutoWeightsLoader(self, skip_prefixes=["mtp."])
837 - return loader.load_weights(weights)
839 + loader = AutoWeightsLoader(self)
840 + return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
vllm/model_executor/models/qwen3_omni_moe_thinker.py
+3 -4
@@ -1587,6 +1587,8 @@ class Qwen3OmniMoeThinkerForConditionalGeneration(
1587 "thinker.lm_head.": "language_model.lm_head.",
1588 "thinker.model.": "language_model.model.",
1589 "thinker.": "",
1590 + "talker.": None,
1591 + "code2wav.": None,
1592 }
1593 )
1594
@@ -1943,10 +1945,7 @@ class Qwen3OmniMoeThinkerForConditionalGeneration(
1945 return self.language_model.compute_logits(hidden_states)
1946
1947 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
1946 - loader = AutoWeightsLoader(
1947 - self,
1948 - skip_prefixes=["talker.", "code2wav."],
1949 - )
1948 + loader = AutoWeightsLoader(self)
1949 loaded_weights = loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
1950
1951 return loaded_weights
vllm/model_executor/models/roberta.py
+5 -3
@@ -147,19 +147,21 @@ class RobertaEmbeddingModel(BertEmbeddingModel):
147
148 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]):
149 weights_list = list(weights)
150 + orig_to_new_prefix: dict[str, str | None] = {"lm_head.": None}
151 has_roberta_prefix = any(
152 name.startswith("roberta.") for name, _ in weights_list
153 )
154 if has_roberta_prefix:
155 # For models with the `roberta.` prefix e.g.
156 # `FacebookAI/roberta-base`
156 - mapper = WeightsMapper(orig_to_new_prefix={"roberta.": "model."})
157 + orig_to_new_prefix["roberta."] = "model."
158 else:
159 # For models without the `roberta.` prefix e.g.
160 # `sentence-transformers/stsb-roberta-base-v2`
160 - mapper = WeightsMapper(orig_to_new_prefix={"": "model."})
161 + orig_to_new_prefix[""] = "model."
162 + mapper = WeightsMapper(orig_to_new_prefix=orig_to_new_prefix)
163
162 - loader = AutoWeightsLoader(self, skip_prefixes=["lm_head."])
164 + loader = AutoWeightsLoader(self)
165 return loader.load_weights(weights_list, mapper=mapper)
166
167
vllm/model_executor/models/siglip.py
+14 -8
@@ -738,6 +738,16 @@ class SiglipVisionTransformer(nn.Module):
738 )
739 self.last_hs_proc = partial(self.maybe_layer_norm_and_apply_head)
740
741 + drops = dict[str, None]()
742 + if self.post_layernorm is None:
743 + drops["post_layernorm."] = None
744 + if self.head is None:
745 + drops["head."] = None
746 + if drops:
747 + self.hf_to_vllm_mapper = self.hf_to_vllm_mapper | WeightsMapper(
748 + orig_to_new_prefix=drops
749 + )
750 +
751 @property
752 def dtype(self):
753 return next(self.parameters()).dtype
@@ -797,12 +807,7 @@ class SiglipVisionTransformer(nn.Module):
807 return encoder_outputs
808
809 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
800 - skip_prefixes = []
801 - if self.post_layernorm is None:
802 - skip_prefixes.append("post_layernorm.")
803 - if self.head is None:
804 - skip_prefixes.append("head.")
805 - loader = AutoWeightsLoader(self, skip_prefixes=skip_prefixes)
810 + loader = AutoWeightsLoader(self)
811
812 layer_count = len(self.encoder.layers)
813
@@ -912,6 +917,8 @@ class SiglipTextEmbeddings(nn.Module):
917 class SiglipEmbeddingModel(nn.Module, SupportsMultiModal, SupportsQuant):
918 is_pooling_model = True
919
920 + hf_to_vllm_mapper = WeightsMapper(orig_to_new_substr={".position_ids": None})
921 +
922 packed_modules_mapping = {"qkv_proj": ["q_proj", "k_proj", "v_proj"]}
923
924 @classmethod
@@ -1154,8 +1161,7 @@ class SiglipEmbeddingModel(nn.Module, SupportsMultiModal, SupportsQuant):
1161 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]):
1162 loader = AutoWeightsLoader(
1163 self,
1157 - skip_substrs=[".position_ids"],
1164 ignore_unexpected_prefixes=["logit_scale.", "logit_bias."],
1165 )
1166
1161 - return loader.load_weights(weights)
1167 + return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
vllm/model_executor/models/skyworkr1v.py
+27 -17
@@ -35,7 +35,12 @@ from .internvl import (
35 BaseInternVLMultiModalProcessor,
36 BaseInternVLProcessingInfo,
37 )
38 -from .utils import AutoWeightsLoader, init_vllm_registered_model, maybe_prefix
38 +from .utils import (
39 + AutoWeightsLoader,
40 + WeightsMapper,
41 + init_vllm_registered_model,
42 + maybe_prefix,
43 +)
44
45
46 class SkyworkR1VImagePixelInputs(TensorSchema):
@@ -120,6 +125,25 @@ class SkyworkR1VProcessingInfo(BaseInternVLProcessingInfo):
125 dummy_inputs=BaseInternVLDummyInputsBuilder,
126 )
127 class SkyworkR1VChatModel(nn.Module, SupportsMultiModal, SupportsPP):
128 + hf_to_vllm_mapper = WeightsMapper(
129 + orig_to_new_prefix=dict.fromkeys(
130 + [
131 + "action_embed",
132 + "temporal_embed",
133 + "track_embed",
134 + "track_embed_decoder",
135 + "box_token",
136 + "cg_criterion",
137 + "cg_model",
138 + "loc_encoder",
139 + "loc_decoder",
140 + "sam",
141 + "temporal_token",
142 + "track_token",
143 + ]
144 + )
145 + )
146 +
147 @classmethod
148 def get_placeholder_str(cls, modality: str, i: int) -> str | None:
149 if modality.startswith("image"):
@@ -381,19 +405,5 @@ class SkyworkR1VChatModel(nn.Module, SupportsMultiModal, SupportsPP):
405 return self.language_model.compute_logits(hidden_states)
406
407 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
384 - skip_prefixes = [
385 - "action_embed",
386 - "temporal_embed",
387 - "track_embed",
388 - "track_embed_decoder",
389 - "box_token",
390 - "cg_criterion",
391 - "cg_model",
392 - "loc_encoder",
393 - "loc_decoder",
394 - "sam",
395 - "temporal_token",
396 - "track_token",
397 - ]
398 - loader = AutoWeightsLoader(self, skip_prefixes=skip_prefixes)
399 - return loader.load_weights(weights)
408 + loader = AutoWeightsLoader(self)
409 + return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
vllm/model_executor/models/transformers/base.py
-6
@@ -122,10 +122,6 @@ class Base(
122 self.tp_group = get_tp_group()
123
124 # Attrs for weight loading (see self.load_weights)
125 - self.skip_prefixes: list[str] = []
126 - """Skip loading weights whose qualname starts with these prefixes."""
127 - self.skip_substrs: list[str] = []
128 - """Skip loading weights whose qualname contains these substrings."""
125 self.ignore_unexpected_prefixes: list[str] = []
126 """Ignore unexpected weights whose qualname starts with these prefixes."""
127 self.ignore_unexpected_suffixes: list[str] = []
@@ -731,8 +727,6 @@ class Base(
727 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
728 loader = AutoWeightsLoader(
729 self,
734 - skip_prefixes=self.skip_prefixes,
735 - skip_substrs=self.skip_substrs,
730 ignore_unexpected_prefixes=self.ignore_unexpected_prefixes,
731 ignore_unexpected_suffixes=self.ignore_unexpected_suffixes,
732 )
vllm/model_executor/models/transformers/legacy.py
+15 -17
@@ -30,26 +30,24 @@ class LegacyMixin:
30 def __init__(self, *, vllm_config: "VllmConfig", prefix: str = ""):
31 super().__init__(vllm_config=vllm_config, prefix=prefix)
32
33 - # Skip unsupported/unwanted output embeddings layers
34 - self.skip_prefixes.extend(
35 - [
36 - "model.lm_head.",
37 - "model.predictions.",
38 - "model.qa_outputs.",
39 - "model.embeddings_project.",
40 - "model.discriminator_predictions.",
41 - ]
33 + # Drop unsupported/unwanted output embeddings layers.
34 + self.hf_to_vllm_mapper.orig_to_new_prefix.update(
35 + {
36 + "model.lm_head.": None,
37 + "model.predictions.": None,
38 + "model.qa_outputs.": None,
39 + "model.embeddings_project.": None,
40 + "model.discriminator_predictions.": None,
41 + }
42 )
43
44 - # Some encoder models have the position_ids buffer in the checkpoint.
45 - # vLLM will always pass position_ids as an argument, so we skip loading
46 - # the buffer if it exists
47 - self.skip_substrs.append("position_ids")
44 + # Some encoder models have the position_ids buffer in the checkpoint. vLLM will
45 + # always pass position_ids as an argument, so we drop the buffer if it exists.
46 + self.hf_to_vllm_mapper.orig_to_new_substr["position_ids"] = None
47
49 - # Some encoder models have the bias of the final classifier layer
50 - # in the checkpoint. vLLM does not use this bias, so we skip loading
51 - # it if it exists
52 - self.skip_substrs.append("score.bias")
48 + # Some encoder models have the bias of the final classifier layer in the
49 + # checkpoint. vLLM does not use this bias, so we drop it if it exists.
50 + self.hf_to_vllm_mapper.orig_to_new_substr["score.bias"] = None
51
52 # roberta-like models an extra padding in positions.
53 # FIXME(Isotr0py): This is quite hacky for roberta edge case,
vllm/model_executor/models/utils.py
+35 -37
@@ -160,14 +160,26 @@ class WeightsMapper:
160 if (out_name := self._map_name(name)) is not None
161 }
162
163 - def get_unstacked_mapper(self) -> "WeightsMapper":
164 - """Mapper variant that drops stacked maps, keeping all genuine renames/prefixes.
165 -
166 - Consumers that reference the checkpoint's *unstacked* module names (LoRA name
167 - parsing and the quantization config's layer lists) need the constituent names
168 - (e.g. `q_proj`) to survive rather than being rewritten to the stacked vLLM name
169 - (`qkv_proj`)."""
170 - return replace(self, orig_to_new_stacked={})
163 + def get_rename_mapper(self) -> "WeightsMapper":
164 + """Mapper variant keeping only the renames.
165 +
166 + This is what consumers that *name* modules rather than load them need:
167 + LoRA name parsing and the quantization config's layer lists.
168 +
169 + Stacked maps are dropped so that constituent names (e.g. `q_proj`) survive
170 + rather than being rewritten to the stacked vLLM name (`qkv_proj`). Mappings to
171 + `None` are dropped because "do not load this weight" is meaningless to such a
172 + consumer, and applying it would silently shrink a quantization config's ignore
173 + list or make LoRA name parsing fail."""
174 + remove_none = lambda d: {k: v for k, v in d.items() if v is not None}
175 + return replace(
176 + self,
177 + orig_to_new_regex=remove_none(self.orig_to_new_regex),
178 + orig_to_new_substr=remove_none(self.orig_to_new_substr),
179 + orig_to_new_stacked={},
180 + orig_to_new_prefix=remove_none(self.orig_to_new_prefix),
181 + orig_to_new_suffix=remove_none(self.orig_to_new_suffix),
182 + )
183
184
185 def _get_tied_embedding_params(module: nn.Module) -> dict[str, str]:
@@ -201,32 +213,28 @@ class AutoWeightsLoader:
213 """
214
215 # Models trained using early version ColossalAI or quantized by
204 - # GPTQModel may include these tensors in checkpoint. Skip them.
205 - ROTARY_EMBEDS_UNUSED_WEIGHTS = [
206 - "rotary_pos_emb.inv_freq",
207 - "rotary_emb.inv_freq",
208 - "rotary_emb.cos_cached",
209 - "rotary_emb.sin_cached",
210 - ]
216 + # GPTQModel may include these tensors in checkpoint. Drop them.
217 + REMOVE_UNUSED_ROTARY_EMBEDS_MAPPER = WeightsMapper(
218 + orig_to_new_substr={
219 + "rotary_pos_emb.inv_freq": None,
220 + "rotary_emb.inv_freq": None,
221 + "rotary_emb.cos_cached": None,
222 + "rotary_emb.sin_cached": None,
223 + }
224 + )
225
226 def __init__(
227 self,
228 module: nn.Module,
229 *,
216 - skip_prefixes: list[str] | None = None,
217 - skip_substrs: list[str] | None = None,
230 ignore_unexpected_prefixes: list[str] | None = None,
231 ignore_unexpected_suffixes: list[str] | None = None,
232 ) -> None:
233 super().__init__()
234
235 self.module = module
224 - self.skip_prefixes = skip_prefixes or []
225 - self.skip_substrs = skip_substrs or []
236 self.ignore_unexpected_prefixes = ignore_unexpected_prefixes or []
237 self.ignore_unexpected_suffixes = ignore_unexpected_suffixes or []
228 - # update default skip_substrs
229 - self.skip_substrs += self.ROTARY_EMBEDS_UNUSED_WEIGHTS
238
239 # Weight tying makes two qualnames point at the same `nn.Parameter`
240 # (e.g. `lm_head.weight` and `model.embed_tokens.weight`). Loading both
@@ -265,11 +273,7 @@ class AutoWeightsLoader:
273 return ".".join((prefix, rest))
274
275 def _can_skip(self, qualname: str) -> bool:
268 - return (
269 - qualname in self.aliased_params
270 - or any(qualname.startswith(p) for p in self.skip_prefixes)
271 - or any(substr in qualname for substr in self.skip_substrs)
272 - )
276 + return qualname in self.aliased_params
277
278 def _can_ignore_unexpected(self, qualname: str) -> bool:
279 iup = (qualname.startswith(p) for p in self.ignore_unexpected_prefixes)
@@ -375,11 +379,6 @@ class AutoWeightsLoader:
379 prefix = self._get_qualname(base_prefix, child_prefix)
380
381 if child_prefix in child_modules:
378 - if self._can_skip(prefix + "."):
379 - logger.debug("Skipping module %s", prefix)
380 -
381 - continue
382 -
382 yield from self._load_module(
383 prefix, child_modules[child_prefix], child_weights
384 )
@@ -393,9 +392,7 @@ class AutoWeightsLoader:
392 prefix, child_params[child_prefix], child_weights
393 )
394 else:
396 - can_skip_module = self._can_skip(prefix + ".")
397 - can_skip_param = self._can_skip(prefix)
398 - if can_skip_module or can_skip_param:
395 + if self._can_skip(prefix):
396 logger.debug("Skipping missing %s", prefix)
397
398 continue
@@ -429,18 +426,19 @@ class AutoWeightsLoader:
426 # Ignore unexpected biases (typically from GPTQ models)
427 self.ignore_unexpected_suffixes.append(".bias")
428
429 + mapper = mapper or WeightsMapper()
430 # Many models store quant_config in the base model instead of the causal model.
431 # We look at the causal model's direct children for this reason.
432 modules = (self.module, *self.module.children())
433 iterator = (m.quant_config for m in modules if hasattr(m, "quant_config"))
434 if quant_config := next(iterator, None):
435 # Get mappings and ignore prefixes for KV cache quantization scales
438 - mapper = mapper or WeightsMapper()
436 mapper |= quant_config.get_cache_scale_mapper()
437 ignore_unexpected_suffixes = quant_config._ignore_unexpected_suffixes
438 self.ignore_unexpected_suffixes.extend(ignore_unexpected_suffixes)
442 - if mapper is not None:
443 - weights = mapper.apply(weights)
439 + mapper |= self.REMOVE_UNUSED_ROTARY_EMBEDS_MAPPER
440 +
441 + weights = mapper.apply(weights)
442 weights = self._filter_skipped(weights)
443
444 autoloaded_weights = set(self._load_module("", self.module, weights))
vllm/model_executor/models/whisper.py
+2 -1
@@ -838,6 +838,7 @@ class WhisperForConditionalGeneration(
838 ".encoder_attn.k_proj": (".encoder_attn.kv_proj", 0),
839 ".encoder_attn.v_proj": (".encoder_attn.kv_proj", 1),
840 },
841 + orig_to_new_prefix={"proj_out.": None},
842 )
843
844 # Whisper only supports audio-conditioned generation.
@@ -1048,7 +1049,7 @@ class WhisperForConditionalGeneration(
1049 return logits
1050
1051 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
1051 - loader = AutoWeightsLoader(self, skip_prefixes=["proj_out."])
1052 + loader = AutoWeightsLoader(self)
1053
1054 # add fake zeros bias for k_proj to state_dict
1055 weights = _create_fake_bias_for_k_proj(weights, ".k_proj.weight")
vllm/models/deepseek_v4/amd/model.py
+4 -3
@@ -947,11 +947,12 @@ def _make_deepseek_v4_weights_mapper(
947 # When shared experts are fused into the routed MXFP4 grouped GEMM, the
948 # shared_experts tensors are redirected to routed expert slots ; leave
949 # their names untouched here.
950 - substr_map = (
950 + orig_to_new_substr: dict[str, str | None] = (
951 {}
952 if fuse_shared_experts
953 else {".shared_experts.w2": ".shared_experts.down_proj"}
954 )
955 + orig_to_new_substr["mtp."] = None
956 return WeightsMapper(
957 orig_to_new_prefix={
958 "layers.": "model.layers.",
@@ -967,7 +968,7 @@ def _make_deepseek_v4_weights_mapper(
968 ".ffn.gate.bias": ".ffn.gate.e_score_correction_bias",
969 ".input_scale": ".input_scale_2",
970 },
970 - orig_to_new_substr=substr_map,
971 + orig_to_new_substr=orig_to_new_substr,
972 )
973
974
@@ -1038,7 +1039,7 @@ class DeepseekV4ForCausalLM(nn.Module, SupportsPP, SupportsEagle3):
1039 return getattr(self.model, "_mtp_hidden_buffer", None)
1040
1041 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
1041 - loader = AutoWeightsLoader(self, skip_substrs=["mtp."])
1042 + loader = AutoWeightsLoader(self)
1043 return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
1044
1045 def process_weights_after_loading(self) -> None:
vllm/models/deepseek_v4/nvidia/model.py
+2 -1
@@ -1392,6 +1392,7 @@ def _make_deepseek_v4_weights_mapper(expert_dtype: str) -> WeightsMapper:
1392 },
1393 orig_to_new_substr={
1394 ".shared_experts.w2": ".shared_experts.down_proj",
1395 + "mtp.": None,
1396 },
1397 )
1398
@@ -1517,7 +1518,7 @@ class DeepseekV4ForCausalLM(
1518 return getattr(self.model, "_mtp_hidden_buffer", None)
1519
1520 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
1520 - loader = AutoWeightsLoader(self, skip_substrs=["mtp."])
1521 + loader = AutoWeightsLoader(self)
1522 loaded_params = loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
1523 self.process_weights_after_loading()
1524 return loaded_params
vllm/models/deepseek_v4/xpu/model.py
+2 -1
@@ -1299,6 +1299,7 @@ def _make_deepseek_v4_weights_mapper(expert_dtype: str) -> WeightsMapper:
1299 },
1300 orig_to_new_substr={
1301 ".shared_experts.w2": ".shared_experts.down_proj",
1302 + "mtp.": None,
1303 },
1304 )
1305
@@ -1364,7 +1365,7 @@ class DeepseekV4ForCausalLM(nn.Module, SupportsPP, SupportsEagle3):
1365 return getattr(self.model, "_mtp_hidden_buffer", None)
1366
1367 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
1367 - loader = AutoWeightsLoader(self, skip_substrs=["mtp."])
1368 + loader = AutoWeightsLoader(self)
1369 loaded_params = loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
1370 self.model.finalize_mega_moe_weights()
1371 return loaded_params
vllm/models/dots3_note/nvidia/multimodal.py
+11 -6
@@ -141,6 +141,16 @@ class Dots3NoteForCausalLM(nn.Module, SupportsMultiModal, SupportsPP):
141 self.language_model.make_empty_intermediate_tensors
142 )
143
144 + orig_to_new_prefix = dict[str, None]()
145 + if self.visual is None:
146 + orig_to_new_prefix["visual."] = None
147 + if self.audio_tower is None:
148 + orig_to_new_prefix["audio_tower."] = None
149 + if orig_to_new_prefix:
150 + self.hf_to_vllm_mapper = self.hf_to_vllm_mapper | WeightsMapper(
151 + orig_to_new_prefix=orig_to_new_prefix
152 + )
153 +
154 def _process_image_input(
155 self,
156 pixel_values: torch.Tensor,
@@ -283,12 +293,7 @@ class Dots3NoteForCausalLM(nn.Module, SupportsMultiModal, SupportsPP):
293 return self.language_model.compute_logits(hidden_states)
294
295 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
286 - skip_prefixes = []
287 - if self.visual is None:
288 - skip_prefixes.append("visual.")
289 - if self.audio_tower is None:
290 - skip_prefixes.append("audio_tower.")
291 - return AutoWeightsLoader(self, skip_prefixes=skip_prefixes).load_weights(
296 + return AutoWeightsLoader(self).load_weights(
297 weights,
298 mapper=self.hf_to_vllm_mapper,
299 )
vllm/models/inkling/amd/model.py
+3 -2
@@ -656,8 +656,9 @@ def _load_inkling_weights(
656
657 yield name, weight
658
659 - loader = AutoWeightsLoader(module, skip_prefixes=["model.mtp."])
660 - loaded |= loader.load_weights(_iter_loadable_weights())
659 + mapper = WeightsMapper(orig_to_new_prefix={"model.mtp.": None})
660 + loader = AutoWeightsLoader(module)
661 + loaded |= loader.load_weights(_iter_loadable_weights(), mapper=mapper)
662
663 # Post-load MoE fixups (default input scales, zeroed EP-padding experts).
664 for moe_name, moe in moe_modules.items():
vllm/models/inkling/nvidia/model.py
+3 -2
@@ -693,8 +693,9 @@ def _load_inkling_weights(
693
694 # The release checkpoint also carries auxiliary prediction-head weights;
695 # they are not part of the causal LM served by this implementation.
696 - loader = AutoWeightsLoader(module, skip_prefixes=["model.mtp."])
697 - loaded |= loader.load_weights(_iter_loadable_weights())
696 + mapper = WeightsMapper(orig_to_new_prefix={"model.mtp.": None})
697 + loader = AutoWeightsLoader(module)
698 + loaded |= loader.load_weights(_iter_loadable_weights(), mapper=mapper)
699
700 # Post-load MoE fixups (default input scales, zeroed EP-padding experts).
701 for moe_name, moe in moe_modules.items():
vllm/models/kimi_k3/nvidia/dspark_mla.py
+8 -8
@@ -399,9 +399,14 @@ class K3DSparkForCausalLM(nn.Module):
399 has_own_embed_tokens = False
400 has_own_lm_head = False
401 draft_id_to_target_id = None
402 - checkpoint_skip_substrs = ("confidence_head", "embed_tokens", "lm_head")
403 -
402 hf_to_vllm_mapper = WeightsMapper(
403 + # confidence_head is training-only. The frozen target embedding and LM
404 + # head are shared after this draft-specific checkpoint is loaded.
405 + orig_to_new_substr={
406 + "confidence_head": None,
407 + "embed_tokens": None,
408 + "lm_head": None,
409 + },
410 orig_to_new_prefix={"": "model."},
411 orig_to_new_stacked={
412 ".gate_proj": (".gate_up_proj", 0),
@@ -477,12 +482,7 @@ class K3DSparkForCausalLM(nn.Module):
482 return self.model.markov_head.bias(markov_embed, self.logits_processor)
483
484 def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
480 - # confidence_head is training-only. The frozen target embedding and LM
481 - # head are shared after this draft-specific checkpoint is loaded.
482 - loader = AutoWeightsLoader(
483 - self,
484 - skip_substrs=list(self.checkpoint_skip_substrs),
485 - )
485 + loader = AutoWeightsLoader(self)
486 # read: 1. all weights. 2. context kv weights
487 weights = _duplicate_context_kv_weights(weights, len(self.model.layers))
488 loaded_weights = loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)