main
py 109 lines 3.42 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4 from collections.abc import Iterable
5 from typing import TYPE_CHECKING, overload
6
7 import torch
8 import torch.nn as nn
9 from transformers import PreTrainedConfig
10
11 from vllm.config.lora import LoRAConfig
12
13 if TYPE_CHECKING:
14 from vllm.lora.punica_wrapper import PunicaWrapperBase
15
16
17 class BaseLayerWithLoRA(nn.Module):
18 def __getattr__(self, name):
19 d = self.__dict__
20 if name in d.get("_parameters", ()):
21 return d["_parameters"][name]
22 if name in d.get("_buffers", ()):
23 return d["_buffers"][name]
24 if name in d.get("_modules", ()):
25 return d["_modules"][name]
26 # Forward public misses to ``base_layer``; private names are framework
27 # bookkeeping and must stay local.
28 if not name.startswith("_"):
29 base_layer = d.get("_modules", {}).get("base_layer")
30 if base_layer is not None:
31 return getattr(base_layer, name)
32 raise AttributeError(
33 f"{type(self).__name__!r} object has no attribute {name!r}"
34 )
35
36 def load_weights(
37 self, weights: Iterable[tuple[str, torch.Tensor]]
38 ) -> Iterable[str]:
39 """Load checkpoint weights into the wrapped base layer."""
40 base_load_weights = getattr(self.base_layer, "load_weights", None)
41 if callable(base_load_weights):
42 return base_load_weights(weights)
43
44 from vllm.model_executor.models.utils import AutoWeightsLoader
45
46 return AutoWeightsLoader(self.base_layer).load_weights(weights)
47
48 @overload
49 def slice_lora_a(
50 self, lora_a: list[torch.Tensor | None]
51 ) -> list[torch.Tensor | None]: ...
52 @overload
53 def slice_lora_a(self, lora_a: torch.Tensor) -> torch.Tensor: ...
54 def slice_lora_a(
55 self, lora_a: torch.Tensor | list[torch.Tensor | None]
56 ) -> torch.Tensor | list[torch.Tensor | None]:
57 """Slice lora a if splitting for tensor parallelism."""
58 ...
59
60 @overload
61 def slice_lora_b(
62 self, lora_b: list[torch.Tensor | None]
63 ) -> list[torch.Tensor | None]: ...
64 @overload
65 def slice_lora_b(self, lora_b: torch.Tensor) -> torch.Tensor: ...
66 def slice_lora_b(
67 self, lora_b: torch.Tensor | list[torch.Tensor | None]
68 ) -> torch.Tensor | list[torch.Tensor | None]:
69 """Slice lora b if splitting with tensor parallelism."""
70 ...
71
72 def create_lora_weights(
73 self,
74 max_loras: int,
75 lora_config: LoRAConfig,
76 model_config: PreTrainedConfig | None = None,
77 ) -> None:
78 """Initializes lora matrices."""
79 ...
80
81 def reset_lora(self, index: int):
82 """Resets the lora weights at index back to 0."""
83 ...
84
85 def set_lora(
86 self,
87 index: int,
88 lora_a: torch.Tensor | list[torch.Tensor],
89 lora_b: torch.Tensor | list[torch.Tensor],
90 ):
91 """Overwrites lora tensors at index."""
92 ...
93
94 def set_mapping(
95 self,
96 punica_wrapper,
97 ):
98 self.punica_wrapper: PunicaWrapperBase = punica_wrapper
99
100 @classmethod
101 def can_replace_layer(
102 cls,
103 source_layer: nn.Module,
104 lora_config: LoRAConfig,
105 packed_modules_list: list,
106 model_config: PreTrainedConfig | None = None,
107 ) -> bool:
108 """Returns True if the layer can be replaced by this LoRA layer."""
109 raise NotImplementedError