[LoRA] Avoid false target matches for unsupported module types (#52313)
Signed-off-by: linitra24 <Joy25810@foxmail.com> Co-authored-by: Jee Jee Li <pandaleefree@gmail.com>
This commit is contained in:
@@ -1,37 +1,7 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
||||
|
||||
|
||||
from vllm.lora.utils import is_in_target_modules, is_supported_lora_module
|
||||
|
||||
|
||||
class TestIsSupportedLoraModule:
|
||||
"""Tests for is_supported_lora_module (model-definition check)."""
|
||||
|
||||
def test_suffix_match(self):
|
||||
assert is_supported_lora_module(
|
||||
"model.layers.0.self_attn.o_proj", ["o_proj", "q_proj"]
|
||||
)
|
||||
|
||||
def test_no_match(self):
|
||||
assert not is_supported_lora_module(
|
||||
"model.layers.0.self_attn.o_proj", ["q_proj", "k_proj"]
|
||||
)
|
||||
|
||||
def test_exact_match(self):
|
||||
assert is_supported_lora_module("o_proj", ["o_proj"])
|
||||
|
||||
def test_regex_suffix_matching(self):
|
||||
"""Regex anchors to end — partial suffix should not match."""
|
||||
assert not is_supported_lora_module("model.layers.0.self_attn.o_proj", ["proj"])
|
||||
|
||||
def test_empty_supported_modules(self):
|
||||
assert not is_supported_lora_module("model.layers.0.self_attn.o_proj", [])
|
||||
|
||||
def test_multiple_supported_modules(self):
|
||||
supported = ["q_proj", "k_proj", "v_proj", "o_proj"]
|
||||
assert is_supported_lora_module("model.layers.0.self_attn.v_proj", supported)
|
||||
assert not is_supported_lora_module("model.layers.0.mlp.gate_proj", supported)
|
||||
from vllm.lora.utils import is_in_target_modules
|
||||
|
||||
|
||||
class TestIsInTargetModules:
|
||||
|
||||
@@ -418,7 +418,16 @@ class LoRAModelManager:
|
||||
if isinstance(module, PPMissingLayer):
|
||||
continue
|
||||
|
||||
if not self._match_target_modules(module_name):
|
||||
target_modules = self.lora_config.target_modules
|
||||
is_configured_target = target_modules is not None and is_in_target_modules(
|
||||
module_name,
|
||||
target_modules,
|
||||
self.packed_modules_mapping,
|
||||
)
|
||||
if (
|
||||
not self._match_target_modules(module_name, module)
|
||||
and not is_configured_target
|
||||
):
|
||||
continue
|
||||
|
||||
punica_wrapper = self._get_punica_wrapper(module_name)
|
||||
@@ -565,7 +574,7 @@ class LoRAModelManager:
|
||||
model = LoRAModel(lora_id, rank, {})
|
||||
for module_name, module in self.model.named_modules():
|
||||
if (
|
||||
not self._match_target_modules(module_name)
|
||||
not self._match_target_modules(module_name, module)
|
||||
or not isinstance(module, BaseLayerWithLoRA)
|
||||
or self._get_punica_wrapper(module_name) is None
|
||||
):
|
||||
@@ -701,7 +710,7 @@ class LoRAModelManager:
|
||||
)
|
||||
return adjusted_rank
|
||||
|
||||
def _match_target_modules(self, module_name: str) -> bool:
|
||||
def _match_target_modules(self, module_name: str, module: nn.Module) -> bool:
|
||||
"""Check if a module should have LoRA applied.
|
||||
|
||||
This method first checks if the module is in vLLM's supported LoRA
|
||||
@@ -711,11 +720,16 @@ class LoRAModelManager:
|
||||
Args:
|
||||
module_name: Full dot-separated module name (e.g.,
|
||||
"model.layers.0.self_attn.o_proj")
|
||||
module: Runtime module associated with ``module_name``.
|
||||
|
||||
Returns:
|
||||
True if LoRA should be applied to this module, False otherwise.
|
||||
"""
|
||||
if not is_supported_lora_module(module_name, self.supported_lora_modules):
|
||||
if not is_supported_lora_module(
|
||||
module_name,
|
||||
module,
|
||||
self.supported_lora_modules,
|
||||
):
|
||||
return False
|
||||
return is_in_target_modules(
|
||||
module_name,
|
||||
|
||||
+20
-16
@@ -4,7 +4,6 @@
|
||||
import os
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import regex as re
|
||||
from huggingface_hub.utils import HfHubHTTPError, HFValidationError
|
||||
from torch import nn
|
||||
from transformers import PretrainedConfig
|
||||
@@ -33,8 +32,10 @@ from vllm.lora.layers import (
|
||||
RowParallelLinearWithShardedLoRA,
|
||||
VocabParallelEmbeddingWithLoRA,
|
||||
)
|
||||
from vllm.model_executor.custom_op import maybe_get_oot_by_class
|
||||
from vllm.model_executor.layers.fused_moe import MoERunner
|
||||
from vllm.model_executor.layers.linear import LinearBase
|
||||
from vllm.model_executor.layers.vocab_parallel_embedding import VocabParallelEmbedding
|
||||
from vllm.model_executor.utils import get_moe_expert_mapping, get_packed_modules_mapping
|
||||
from vllm.transformers_utils.repo_utils import hf_api
|
||||
|
||||
@@ -230,11 +231,7 @@ def get_supported_lora_modules(model: nn.Module) -> list[str]:
|
||||
for name in embedding_modules:
|
||||
supported_lora_modules.add(name)
|
||||
|
||||
# get all the linear subfixes.
|
||||
if isinstance(module, (LinearBase,)):
|
||||
supported_lora_modules.add(name.split(".")[-1])
|
||||
|
||||
if isinstance(module, (MoERunner,)):
|
||||
if isinstance(module, (LinearBase, MoERunner)):
|
||||
supported_lora_modules.add(name.split(".")[-1])
|
||||
|
||||
return list(supported_lora_modules)
|
||||
@@ -242,29 +239,36 @@ def get_supported_lora_modules(model: nn.Module) -> list[str]:
|
||||
|
||||
def is_supported_lora_module(
|
||||
module_name: str,
|
||||
module: nn.Module,
|
||||
supported_lora_modules: list[str],
|
||||
) -> bool:
|
||||
"""Check if a module is in the model's supported LoRA modules.
|
||||
|
||||
Uses regex suffix matching against the model-defined supported modules
|
||||
list (e.g., matching "model.layers.0.self_attn.o_proj" against
|
||||
"o_proj").
|
||||
The module name must match a model-supported suffix, and the runtime
|
||||
module must belong to a module family handled by LoRA.
|
||||
|
||||
Args:
|
||||
module_name: Full dot-separated module name.
|
||||
module: Runtime module associated with ``module_name``.
|
||||
supported_lora_modules: List of module suffixes supported by the
|
||||
model.
|
||||
|
||||
Returns:
|
||||
True if the module is supported, False otherwise.
|
||||
"""
|
||||
return any(
|
||||
re.match(
|
||||
r".*\.{target_module}$".format(target_module=target_module),
|
||||
module_name,
|
||||
)
|
||||
or target_module == module_name
|
||||
for target_module in supported_lora_modules
|
||||
module_suffix = module_name.rsplit(".", 1)[-1]
|
||||
if module_suffix not in supported_lora_modules:
|
||||
return False
|
||||
|
||||
return isinstance(
|
||||
module,
|
||||
(
|
||||
LinearBase,
|
||||
MoERunner,
|
||||
VocabParallelEmbedding,
|
||||
maybe_get_oot_by_class(VocabParallelEmbedding),
|
||||
BaseLayerWithLoRA,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user