A high-throughput and memory-efficient inference and serving engine for LLMs
Mirrored from https://github.com/tduncan-lum/Nvidia-Optimization-Stack---VLLM.git
Synced Nov 11, 21:15 UTC
[Misc] Split the LoRA code (#30253)
Signed-off-by: Jee Jee Li <pandaleefree@gmail.com>
Jee Jee Li committed
Dec 9, 2025 at 00:59 UTC
67312cad11835bd75ca55fda83708d4806b82436
9 files changed
+265
-243
tests/lora/test_layers.py
+1
-1
@@ -28,7 +28,7 @@ from vllm.lora.layers import (
28
RowParallelLinearWithShardedLoRA,
29
VocabParallelEmbeddingWithLoRA,
30
)
31
-from vllm.lora.models import LoRALayerWeights, PackedLoRALayerWeights
31
+from vllm.lora.lora_weights import LoRALayerWeights, PackedLoRALayerWeights
32
from vllm.lora.punica_wrapper import get_punica_wrapper
33
from vllm.model_executor.layers.linear import (
34
ColumnParallelLinear,
tests/lora/test_lora_checkpoints.py
+1
-1
@@ -3,7 +3,7 @@
3
4
import pytest
5
6
-from vllm.lora.models import LoRAModel
6
+from vllm.lora.lora_model import LoRAModel
7
from vllm.lora.peft_helper import PEFTHelper
8
from vllm.model_executor.models.baichuan import BaiChuanBaseForCausalLM
9
from vllm.model_executor.models.utils import WeightsMapper
tests/lora/test_lora_huggingface.py
+1
-1
@@ -3,7 +3,7 @@
3
4
import pytest
5
6
-from vllm.lora.models import LoRAModel
6
+from vllm.lora.lora_model import LoRAModel
7
from vllm.lora.peft_helper import PEFTHelper
8
from vllm.lora.utils import get_adapter_absolute_path
9
from vllm.model_executor.models.qwen3 import Qwen3ForCausalLM
tests/lora/test_lora_manager.py
+2
-2
@@ -15,10 +15,10 @@ from vllm.lora.layers import (
15
MergedColumnParallelLinearWithLoRA,
16
RowParallelLinearWithLoRA,
17
)
18
+from vllm.lora.lora_model import LoRAModel
19
from vllm.lora.lora_weights import LoRALayerWeights, PackedLoRALayerWeights
19
-from vllm.lora.models import (
20
+from vllm.lora.model_manager import (
21
LoRAMapping,
21
- LoRAModel,
22
LoRAModelManager,
23
LRUCacheLoRAModelManager,
24
)
tests/lora/test_worker.py
+1
-1
@@ -16,7 +16,7 @@ from vllm.config import (
16
)
17
from vllm.config.load import LoadConfig
18
from vllm.config.lora import LoRAConfig
19
-from vllm.lora.models import LoRAMapping
19
+from vllm.lora.model_manager import LoRAMapping
20
from vllm.lora.request import LoRARequest
21
from vllm.v1.worker.gpu_worker import Worker
22
vllm/lora/lora_model.py
new
+246
@@ -0,0 +1,246 @@
1
+# SPDX-License-Identifier: Apache-2.0
2
+# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
+
4
+import os
5
+
6
+import safetensors.torch
7
+import torch
8
+
9
+from vllm.logger import init_logger
10
+from vllm.lora.lora_weights import LoRALayerWeights
11
+from vllm.lora.peft_helper import PEFTHelper
12
+from vllm.lora.utils import (
13
+ get_lora_id,
14
+ is_base_embeddding_weights,
15
+ is_regex_target_modules,
16
+ parse_fine_tuned_lora_name,
17
+)
18
+from vllm.model_executor.model_loader.tensorizer import TensorizerConfig
19
+from vllm.model_executor.models.utils import WeightsMapper
20
+from vllm.utils.platform_utils import is_pin_memory_available
21
+
22
+logger = init_logger(__name__)
23
+
24
+
25
+class LoRAModel:
26
+ """A LoRA fine-tuned model."""
27
+
28
+ def __init__(
29
+ self,
30
+ lora_model_id: int,
31
+ rank: int,
32
+ loras: dict[str, LoRALayerWeights],
33
+ ) -> None:
34
+ """
35
+ Args:
36
+ lora_model_id: The integer id for the lora model.
37
+ rank: lora rank.
38
+ loras: module name -> weights for lora-replaced layers.
39
+
40
+ """
41
+ self.id = lora_model_id
42
+
43
+ assert lora_model_id > 0, (
44
+ f"a valid lora id should be greater than 0, got {self.id}"
45
+ )
46
+ self.rank = rank
47
+ self.loras: dict[str, LoRALayerWeights] = loras
48
+
49
+ def clone(self, lora_model_id: int) -> "LoRAModel":
50
+ """Return a copy of the object with different ids.
51
+
52
+ Will share the underlying tensors."""
53
+ return self.__class__(
54
+ lora_model_id,
55
+ rank=self.rank,
56
+ loras=self.loras.copy(),
57
+ )
58
+
59
+ def get_lora(self, module_name: str) -> LoRALayerWeights | None:
60
+ """Get LoRA for a given module by name"""
61
+ return self.loras.get(module_name, None)
62
+
63
+ def check_lora_name(self, lora_name: str) -> bool:
64
+ return lora_name in self.loras
65
+
66
+ @classmethod
67
+ def from_lora_tensors(
68
+ cls,
69
+ lora_model_id: int,
70
+ tensors: dict[str, torch.Tensor],
71
+ peft_helper: PEFTHelper,
72
+ device: str = "cuda",
73
+ dtype: torch.dtype | None = None,
74
+ model_vocab_size: int | None = None,
75
+ weights_mapper: WeightsMapper | None = None,
76
+ ) -> "LoRAModel":
77
+ """Create a LoRAModel from a dictionary of tensors."""
78
+ pin_memory = str(device) == "cpu" and is_pin_memory_available()
79
+ loras: dict[str, LoRALayerWeights] = {}
80
+ for tensor_name, tensor in tensors.items():
81
+ if is_base_embeddding_weights(tensor_name):
82
+ continue
83
+ module_name, is_lora_a = parse_fine_tuned_lora_name(
84
+ tensor_name, weights_mapper
85
+ )
86
+ if module_name not in loras:
87
+ loras[module_name] = LoRALayerWeights.from_config(
88
+ module_name, peft_helper
89
+ )
90
+
91
+ if is_lora_a:
92
+ if (
93
+ "lora_embedding_A" in tensor_name
94
+ and model_vocab_size is not None
95
+ and model_vocab_size != tensor.shape[1]
96
+ ):
97
+ raise RuntimeError(
98
+ f"The embedding LoRA size({tensor.shape[1]}) must be consistent"
99
+ f" with the base model's vocabulary size({model_vocab_size})."
100
+ )
101
+ loras[module_name].lora_a = tensor.to(device=device, dtype=dtype)
102
+ if pin_memory:
103
+ loras[module_name].lora_a = loras[module_name].lora_a.pin_memory()
104
+ else:
105
+ loras[module_name].lora_b = tensor.to(device=device, dtype=dtype)
106
+
107
+ if pin_memory:
108
+ loras[module_name].lora_b = loras[module_name].lora_b.pin_memory()
109
+
110
+ return cls(lora_model_id, peft_helper.r, loras)
111
+
112
+ @classmethod
113
+ def from_local_checkpoint(
114
+ cls,
115
+ lora_dir: str,
116
+ expected_lora_modules: set[str],
117
+ peft_helper: PEFTHelper,
118
+ *,
119
+ lora_model_id: int | None = None,
120
+ device: str = "cuda",
121
+ dtype: torch.dtype | None = None,
122
+ model_vocab_size: int | None = None,
123
+ weights_mapper: WeightsMapper | None = None,
124
+ tensorizer_config_dict: dict | None = None,
125
+ ) -> "LoRAModel":
126
+ """Create a LoRAModel from a local checkpoint.
127
+
128
+ Args:
129
+ lora_dir: The local path that has lora data.
130
+ expected_lora_modules: Name of modules that are expected to be
131
+ replaced by lora.
132
+ peft_helper: Loaded lora configuration information.
133
+ lora_model_id: LoRA model id. If not given, automatically set by
134
+ a global counter.
135
+ device: Device where the lora model is loaded.
136
+ dtype: dtype of the lora model weights.
137
+
138
+ Returns:
139
+ Loaded LoRA Model.
140
+ """
141
+ lora_tensor_path = os.path.join(lora_dir, "adapter_model.safetensors")
142
+ lora_bin_file_path = os.path.join(lora_dir, "adapter_model.bin")
143
+ lora_pt_file_path = os.path.join(lora_dir, "adapter_model.pt")
144
+
145
+ tensors: dict[str, torch.Tensor] = {}
146
+ unexpected_modules: list[list[str] | str] = []
147
+
148
+ def check_unexpected_modules(modules: dict):
149
+ for lora_module in modules.keys(): # noqa
150
+ if is_base_embeddding_weights(lora_module):
151
+ continue
152
+ # Handle PEFT file format where experts.base_layer is the
153
+ # gate_up_proj and experts is the down_proj
154
+ if "base_layer" in lora_module:
155
+ continue
156
+ module_name, _ = parse_fine_tuned_lora_name(lora_module, weights_mapper)
157
+ # Case for expert lora weights
158
+ if ".experts" in module_name:
159
+ expert_idx = module_name.find(".experts")
160
+ expert_suffix = module_name[expert_idx + 1 :]
161
+ if expert_suffix not in expected_lora_modules:
162
+ unexpected_modules.append(module_name)
163
+
164
+ elif module_name.rsplit(".", 1)[-1] not in expected_lora_modules:
165
+ unexpected_modules.append(module_name)
166
+
167
+ if unexpected_modules:
168
+ raise ValueError(
169
+ f"While loading {lora_dir}, expected"
170
+ f" target modules in {expected_lora_modules}"
171
+ f" but received {unexpected_modules}."
172
+ f" Please verify that the loaded LoRA module is correct"
173
+ )
174
+
175
+ if tensorizer_config_dict:
176
+ from tensorizer import TensorDeserializer
177
+
178
+ tensorizer_config = TensorizerConfig(**tensorizer_config_dict)
179
+ lora_tensor_path = os.path.join(
180
+ tensorizer_config.tensorizer_dir, "adapter_model.tensors"
181
+ )
182
+ tensorizer_args = tensorizer_config._construct_tensorizer_args()
183
+ tensors = TensorDeserializer(
184
+ lora_tensor_path,
185
+ dtype=tensorizer_config.dtype,
186
+ **tensorizer_args.deserialization_kwargs,
187
+ )
188
+ check_unexpected_modules(tensors)
189
+
190
+ elif os.path.isfile(lora_tensor_path):
191
+ # Find unexpected modules.
192
+ # Use safetensor key as a source of truth to find expected modules.
193
+ # in peft if you have target_modules A, B, C and C does not exist
194
+ # in the model it won’t error and model will be trained with A, B
195
+ # loraified. C won’t exist in the safetensor but it will exist in
196
+ # the target_modules of the adapter_config.json.
197
+ unexpected_modules = []
198
+ with safetensors.safe_open(lora_tensor_path, framework="pt") as f: # type: ignore
199
+ # Load tensors if there are only expected modules.
200
+ check_unexpected_modules(f)
201
+ for module in f.keys(): # noqa
202
+ tensors[module] = f.get_tensor(module)
203
+ elif os.path.isfile(lora_bin_file_path) or os.path.isfile(lora_pt_file_path):
204
+ # When a bin/pt file is provided, we rely on config to find
205
+ # unexpected modules.
206
+ unexpected_modules = []
207
+ target_modules = peft_helper.target_modules
208
+ if not isinstance(target_modules, list):
209
+ target_modules = [target_modules]
210
+ for module in target_modules:
211
+ # Compatible with more modules,
212
+ # such as:layers.11.self_attn.k_proj
213
+ part_name = module.split(".")[-1]
214
+ if part_name not in expected_lora_modules:
215
+ unexpected_modules.append(module)
216
+ # loaded lora's target modules must be a subset of
217
+ # expected_lora_modules. It is not reliable. See
218
+ # https://github.com/vllm-project/vllm/pull/5909. But there's no
219
+ # other better mechanism.
220
+ if unexpected_modules and not is_regex_target_modules(
221
+ peft_helper.target_modules, expected_lora_modules
222
+ ):
223
+ raise ValueError(
224
+ f"While loading {lora_dir}, expected"
225
+ f" target modules in {expected_lora_modules}"
226
+ f" but received {unexpected_modules}."
227
+ f" Please verify that the loaded LoRA module is correct"
228
+ )
229
+ lora_file_path = (
230
+ lora_bin_file_path
231
+ if os.path.isfile(lora_bin_file_path)
232
+ else lora_pt_file_path
233
+ )
234
+ tensors = torch.load(lora_file_path, map_location=device, weights_only=True)
235
+ else:
236
+ raise ValueError(f"{lora_dir} doesn't contain tensors")
237
+
238
+ return cls.from_lora_tensors(
239
+ lora_model_id=get_lora_id() if lora_model_id is None else lora_model_id,
240
+ tensors=tensors,
241
+ peft_helper=peft_helper,
242
+ device=device,
243
+ dtype=dtype,
244
+ model_vocab_size=model_vocab_size,
245
+ weights_mapper=weights_mapper,
246
+ )
vllm/lora/model_manager.py
renamed
+2
-235
@@ -2,38 +2,32 @@
2
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4
import math
5
-import os
5
from collections.abc import Callable
6
from typing import TypeVar
7
8
import regex as re
10
-import safetensors.torch
9
import torch
10
from torch import nn
11
12
from vllm.config.lora import LoRAConfig
13
from vllm.logger import init_logger
14
from vllm.lora.layers import BaseLayerWithLoRA, FusedMoE3DWithLoRA, LoRAMapping
15
+from vllm.lora.lora_model import LoRAModel
16
from vllm.lora.lora_weights import LoRALayerWeights, PackedLoRALayerWeights
18
-from vllm.lora.peft_helper import PEFTHelper
17
from vllm.lora.punica_wrapper import get_punica_wrapper
18
from vllm.lora.utils import (
19
from_layer,
20
from_layer_logits_processor,
21
get_supported_lora_modules,
24
- is_base_embeddding_weights,
22
is_moe_model,
26
- is_regex_target_modules,
27
- parse_fine_tuned_lora_name,
23
process_packed_modules_mapping,
24
replace_submodule,
25
)
26
from vllm.model_executor.layers.fused_moe import FusedMoE
32
-from vllm.model_executor.model_loader.tensorizer import TensorizerConfig
27
from vllm.model_executor.models import SupportsLoRA, supports_multimodal
28
from vllm.model_executor.models.interfaces import is_pooling_model
29
from vllm.model_executor.models.module_mapping import MultiModelKeys
36
-from vllm.model_executor.models.utils import PPMissingLayer, WeightsMapper
30
+from vllm.model_executor.models.utils import PPMissingLayer
31
from vllm.utils.cache import LRUCache
32
from vllm.utils.platform_utils import is_pin_memory_available
33
@@ -53,233 +47,6 @@ class AdapterLRUCache(LRUCache[int, T]):
47
return super()._on_remove(key, value)
48
49
56
-_GLOBAL_LORA_ID = 0
57
-
58
-
59
-def get_lora_id():
60
- global _GLOBAL_LORA_ID
61
- _GLOBAL_LORA_ID += 1
62
- return _GLOBAL_LORA_ID
63
-
64
-
65
-class LoRAModel:
66
- """A LoRA fine-tuned model."""
67
-
68
- def __init__(
69
- self,
70
- lora_model_id: int,
71
- rank: int,
72
- loras: dict[str, LoRALayerWeights],
73
- ) -> None:
74
- """
75
- Args:
76
- lora_model_id: The integer id for the lora model.
77
- rank: lora rank.
78
- loras: module name -> weights for lora-replaced layers.
79
-
80
- """
81
- self.id = lora_model_id
82
-
83
- assert lora_model_id > 0, (
84
- f"a valid lora id should be greater than 0, got {self.id}"
85
- )
86
- self.rank = rank
87
- self.loras: dict[str, LoRALayerWeights] = loras
88
-
89
- def clone(self, lora_model_id: int) -> "LoRAModel":
90
- """Return a copy of the object with different ids.
91
-
92
- Will share the underlying tensors."""
93
- return self.__class__(
94
- lora_model_id,
95
- rank=self.rank,
96
- loras=self.loras.copy(),
97
- )
98
-
99
- def get_lora(self, module_name: str) -> LoRALayerWeights | None:
100
- """Get LoRA for a given module by name"""
101
- return self.loras.get(module_name, None)
102
-
103
- def check_lora_name(self, lora_name: str) -> bool:
104
- return lora_name in self.loras
105
-
106
- @classmethod
107
- def from_lora_tensors(
108
- cls,
109
- lora_model_id: int,
110
- tensors: dict[str, torch.Tensor],
111
- peft_helper: PEFTHelper,
112
- device: str = "cuda",
113
- dtype: torch.dtype | None = None,
114
- model_vocab_size: int | None = None,
115
- weights_mapper: WeightsMapper | None = None,
116
- ) -> "LoRAModel":
117
- """Create a LoRAModel from a dictionary of tensors."""
118
-
119
- loras: dict[str, LoRALayerWeights] = {}
120
- for tensor_name, tensor in tensors.items():
121
- if is_base_embeddding_weights(tensor_name):
122
- continue
123
- module_name, is_lora_a = parse_fine_tuned_lora_name(
124
- tensor_name, weights_mapper
125
- )
126
- if module_name not in loras:
127
- loras[module_name] = LoRALayerWeights.from_config(
128
- module_name, peft_helper
129
- )
130
-
131
- if is_lora_a:
132
- if (
133
- "lora_embedding_A" in tensor_name
134
- and model_vocab_size is not None
135
- and model_vocab_size != tensor.shape[1]
136
- ):
137
- raise RuntimeError(
138
- f"The embedding LoRA size({tensor.shape[1]}) must be consistent"
139
- f" with the base model's vocabulary size({model_vocab_size})."
140
- )
141
- loras[module_name].lora_a = tensor.to(device=device, dtype=dtype)
142
- else:
143
- loras[module_name].lora_b = tensor.to(device=device, dtype=dtype)
144
- return cls(lora_model_id, peft_helper.r, loras)
145
-
146
- @classmethod
147
- def from_local_checkpoint(
148
- cls,
149
- lora_dir: str,
150
- expected_lora_modules: set[str],
151
- peft_helper: PEFTHelper,
152
- *,
153
- lora_model_id: int | None = None,
154
- device: str = "cuda",
155
- dtype: torch.dtype | None = None,
156
- model_vocab_size: int | None = None,
157
- weights_mapper: WeightsMapper | None = None,
158
- tensorizer_config_dict: dict | None = None,
159
- ) -> "LoRAModel":
160
- """Create a LoRAModel from a local checkpoint.
161
-
162
- Args:
163
- lora_dir: The local path that has lora data.
164
- expected_lora_modules: Name of modules that are expected to be
165
- replaced by lora.
166
- peft_helper: Loaded lora configuration information.
167
- lora_model_id: LoRA model id. If not given, automatically set by
168
- a global counter.
169
- device: Device where the lora model is loaded.
170
- dtype: dtype of the lora model weights.
171
-
172
- Returns:
173
- Loaded LoRA Model.
174
- """
175
- lora_tensor_path = os.path.join(lora_dir, "adapter_model.safetensors")
176
- lora_bin_file_path = os.path.join(lora_dir, "adapter_model.bin")
177
- lora_pt_file_path = os.path.join(lora_dir, "adapter_model.pt")
178
-
179
- tensors: dict[str, torch.Tensor] = {}
180
- unexpected_modules: list[list[str] | str] = []
181
-
182
- def check_unexpected_modules(modules: dict):
183
- for lora_module in modules.keys(): # noqa
184
- if is_base_embeddding_weights(lora_module):
185
- continue
186
- # Handle PEFT file format where experts.base_layer is the
187
- # gate_up_proj and experts is the down_proj
188
- if "base_layer" in lora_module:
189
- continue
190
- module_name, _ = parse_fine_tuned_lora_name(lora_module, weights_mapper)
191
- # Case for expert lora weights
192
- if ".experts" in module_name:
193
- expert_idx = module_name.find(".experts")
194
- expert_suffix = module_name[expert_idx + 1 :]
195
- if expert_suffix not in expected_lora_modules:
196
- unexpected_modules.append(module_name)
197
-
198
- elif module_name.rsplit(".", 1)[-1] not in expected_lora_modules:
199
- unexpected_modules.append(module_name)
200
-
201
- if unexpected_modules:
202
- raise ValueError(
203
- f"While loading {lora_dir}, expected"
204
- f" target modules in {expected_lora_modules}"
205
- f" but received {unexpected_modules}."
206
- f" Please verify that the loaded LoRA module is correct"
207
- )
208
-
209
- if tensorizer_config_dict:
210
- from tensorizer import TensorDeserializer
211
-
212
- tensorizer_config = TensorizerConfig(**tensorizer_config_dict)
213
- lora_tensor_path = os.path.join(
214
- tensorizer_config.tensorizer_dir, "adapter_model.tensors"
215
- )
216
- tensorizer_args = tensorizer_config._construct_tensorizer_args()
217
- tensors = TensorDeserializer(
218
- lora_tensor_path,
219
- dtype=tensorizer_config.dtype,
220
- **tensorizer_args.deserialization_kwargs,
221
- )
222
- check_unexpected_modules(tensors)
223
-
224
- elif os.path.isfile(lora_tensor_path):
225
- # Find unexpected modules.
226
- # Use safetensor key as a source of truth to find expected modules.
227
- # in peft if you have target_modules A, B, C and C does not exist
228
- # in the model it won’t error and model will be trained with A, B
229
- # loraified. C won’t exist in the safetensor but it will exist in
230
- # the target_modules of the adapter_config.json.
231
- unexpected_modules = []
232
- with safetensors.safe_open(lora_tensor_path, framework="pt") as f: # type: ignore
233
- # Load tensors if there are only expected modules.
234
- check_unexpected_modules(f)
235
- for module in f.keys(): # noqa
236
- tensors[module] = f.get_tensor(module)
237
- elif os.path.isfile(lora_bin_file_path) or os.path.isfile(lora_pt_file_path):
238
- # When a bin/pt file is provided, we rely on config to find
239
- # unexpected modules.
240
- unexpected_modules = []
241
- target_modules = peft_helper.target_modules
242
- if not isinstance(target_modules, list):
243
- target_modules = [target_modules]
244
- for module in target_modules:
245
- # Compatible with more modules,
246
- # such as:layers.11.self_attn.k_proj
247
- part_name = module.split(".")[-1]
248
- if part_name not in expected_lora_modules:
249
- unexpected_modules.append(module)
250
- # loaded lora's target modules must be a subset of
251
- # expected_lora_modules. It is not reliable. See
252
- # https://github.com/vllm-project/vllm/pull/5909. But there's no
253
- # other better mechanism.
254
- if unexpected_modules and not is_regex_target_modules(
255
- peft_helper.target_modules, expected_lora_modules
256
- ):
257
- raise ValueError(
258
- f"While loading {lora_dir}, expected"
259
- f" target modules in {expected_lora_modules}"
260
- f" but received {unexpected_modules}."
261
- f" Please verify that the loaded LoRA module is correct"
262
- )
263
- lora_file_path = (
264
- lora_bin_file_path
265
- if os.path.isfile(lora_bin_file_path)
266
- else lora_pt_file_path
267
- )
268
- tensors = torch.load(lora_file_path, map_location=device, weights_only=True)
269
- else:
270
- raise ValueError(f"{lora_dir} doesn't contain tensors")
271
-
272
- return cls.from_lora_tensors(
273
- lora_model_id=get_lora_id() if lora_model_id is None else lora_model_id,
274
- tensors=tensors,
275
- peft_helper=peft_helper,
276
- device=device,
277
- dtype=dtype,
278
- model_vocab_size=model_vocab_size,
279
- weights_mapper=weights_mapper,
280
- )
281
-
282
-
50
class LoRAModelManager:
51
"""A manager that manages multiple LoRA-fine-tuned models."""
52
vllm/lora/utils.py
+9
@@ -48,6 +48,15 @@ if TYPE_CHECKING:
48
49
logger = init_logger(__name__)
50
51
+_GLOBAL_LORA_ID = 0
52
+
53
+
54
+def get_lora_id():
55
+ global _GLOBAL_LORA_ID
56
+ _GLOBAL_LORA_ID += 1
57
+ return _GLOBAL_LORA_ID
58
+
59
+
60
_all_lora_classes: set[type[BaseLayerWithLoRA]] = {
61
VocabParallelEmbeddingWithLoRA,
62
ColumnParallelLinearWithLoRA,
vllm/lora/worker_manager.py
+2
-2
@@ -8,8 +8,8 @@ import torch
8
9
from vllm.config import VllmConfig
10
from vllm.logger import init_logger
11
-from vllm.lora.models import (
12
- LoRAModel,
11
+from vllm.lora.lora_model import LoRAModel
12
+from vllm.lora.model_manager import (
13
LoRAModelManager,
14
LRUCacheLoRAModelManager,
15
create_lora_manager,