From aaeaaae699b7089013509f09e2ec048d53cacb0b Mon Sep 17 00:00:00 2001 From: yangzhuxinyzx <153831768+yangzhuxinyzx@users.noreply.github.com> Date: Thu, 15 Oct 2026 15:45:36 +0800 Subject: [PATCH] [Bugfix] Scope native GGUF streams to their receiving module Assisted-by: OpenAI Codex Signed-off-by: yangzhuxinyzx <153831768+yangzhuxinyzx@users.noreply.github.com> --- tests/models/gguf/test_multimodal_weights.py | 44 +++++++++++++++++++ .../model_loader/gguf_loader.py | 16 +++++-- 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/tests/models/gguf/test_multimodal_weights.py b/tests/models/gguf/test_multimodal_weights.py index 5c622c031..273074ec1 100644 --- a/tests/models/gguf/test_multimodal_weights.py +++ b/tests/models/gguf/test_multimodal_weights.py @@ -167,3 +167,47 @@ def test_legacy_multimodal_still_requires_mmproj(monkeypatch): config = SimpleNamespace(hf_config=SimpleNamespace(vision_config=object())) with pytest.raises(AssertionError, match="mm_proj"): loader._get_gguf_weight_type(config, "text.gguf", {}) + + +@pytest.mark.parametrize("wrapped", [False, True]) +def test_native_stream_names_follow_the_receiving_model(monkeypatch, wrapped): + from vllm.config import LoadConfig + from vllm.model_executor.models.qwen3_vl import Qwen3VLForConditionalGeneration + from vllm.model_executor.models.utils import AutoWeightsLoader + + loader = GGUFModelLoader(LoadConfig(load_format="gguf")) + loader._native_adapter = SimpleNamespace(language_model_prefix="language_model") + root = torch.nn.Module() + root.language_model = torch.nn.Module() + root.language_model.model = torch.nn.Module() + root.language_model.model.ple = torch.nn.Linear(2, 2, bias=False) + receiving = root if wrapped else root.language_model + names = {"ple": "model.ple.weight", "unrelated": "model.other.weight"} + monkeypatch.setattr(loader, "_prepare_weights", lambda _: "text.gguf") + monkeypatch.setattr(loader, "_get_gguf_weights_map", lambda _: names) + touched = [] + + def iterator(config, path, filtered): + for raw, name in filtered.items(): + assert raw == "ple", "non-PLE payload must not be touched" + touched.append(raw) + yield name, torch.ones(2, 2) + + monkeypatch.setattr(loader, "_get_weights_iterator", iterator) + prefix = "language_model." if wrapped else "" + mapper = Qwen3VLForConditionalGeneration.hf_to_vllm_mapper if wrapped else None + seen = [] + + def skip(name): + seen.append(name) + return name != prefix + "model.ple.weight" + + weights = list( + loader.get_all_weights(SimpleNamespace(), receiving, skip_weight=skip) + ) + assert touched == ["ple"] + assert seen == [prefix + n for n in names.values()] + assert weights[0][0] == prefix + "model.ple.weight" + loaded = AutoWeightsLoader(receiving).load_weights(weights, mapper=mapper) + assert loaded == {prefix + "model.ple.weight"} + torch.testing.assert_close(root.language_model.model.ple.weight, torch.ones(2, 2)) diff --git a/vllm/model_executor/model_loader/gguf_loader.py b/vllm/model_executor/model_loader/gguf_loader.py index 4309da02b..7e7ec6e2c 100644 --- a/vllm/model_executor/model_loader/gguf_loader.py +++ b/vllm/model_executor/model_loader/gguf_loader.py @@ -469,15 +469,25 @@ class GGUFModelLoader(BaseModelLoader): gguf_weights_map = self._get_gguf_weights_map(model_config) self._gguf_prepared_model_config = model_config self._gguf_prepared_weights_map = gguf_weights_map + adapter = getattr(self, "_native_adapter", None) + language_prefix = getattr(adapter, "language_model_prefix", "") + weight_prefix = "" + if ( + language_prefix + and model is not None + and any(name == language_prefix for name, _ in model.named_modules()) + ): + weight_prefix = language_prefix + "." if skip_weight is not None: gguf_weights_map = { raw: name for raw, name in gguf_weights_map.items() - if not skip_weight(name) + if not skip_weight(weight_prefix + name) } - yield from self._get_weights_iterator( + for name, tensor in self._get_weights_iterator( model_config, local_model_path, gguf_weights_map - ) + ): + yield weight_prefix + name, tensor def load_weights(self, model: nn.Module, model_config: ModelConfig) -> None: model.load_weights(self.get_all_weights(model_config, model))