main
py 78 lines 2.61 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4
5 import torch
6 import torch.nn as nn
7 from transformers import PreTrainedConfig
8
9 from vllm.config.lora import LoRAConfig
10 from vllm.model_executor.custom_op import maybe_get_oot_by_class
11 from vllm.model_executor.layers.linear import ReplicatedLinear
12
13 from .base_linear import BaseLinearLayerWithLoRA
14
15
16 class ReplicatedLinearWithLoRA(BaseLinearLayerWithLoRA):
17 def __init__(self, base_layer: ReplicatedLinear) -> None:
18 super().__init__(
19 base_layer,
20 )
21 # To ensure interface compatibility, set to 1 always.
22 self.output_size = self.base_layer.output_size
23 self.n_slices = 1
24
25 def forward(
26 self, input_: torch.Tensor
27 ) -> torch.Tensor | tuple[torch.Tensor, torch.Tensor | None]:
28 """Forward of ReplicatedLinearWithLoRA.
29
30 Args:
31 input_: Tensor whose last dimension is `input_size`.
32
33 Returns:
34 - output
35 - bias
36
37 """
38 bias = self.base_layer.bias if not self.base_layer.skip_bias_add else None
39
40 # Matrix multiply.
41 output = self.apply(input_, bias)
42
43 output_bias = self.base_layer.bias if self.base_layer.skip_bias_add else None
44
45 if not self.base_layer.return_bias:
46 return output
47
48 return output, output_bias
49
50 def apply(self, x: torch.Tensor, bias: torch.Tensor | None = None) -> torch.Tensor:
51 # ReplicatedLinear subclasses such as GateLinear override forward() to
52 # dispatch custom kernels and/or adjust the output dtype. Apply LoRA on
53 # top of the actual base-layer output instead of bypassing that path.
54 return self._apply_base_forward(x)
55
56 # ReplicatedLinear should always be replaced, regardless of the fully
57 # sharded LoRAs setting, because it is, by definition, copied per GPU.
58 @classmethod
59 def can_replace_layer(
60 cls,
61 source_layer: nn.Module,
62 lora_config: LoRAConfig,
63 packed_modules_list: list,
64 model_config: PreTrainedConfig | None = None,
65 ) -> bool:
66 return isinstance(source_layer, maybe_get_oot_by_class(ReplicatedLinear))
67
68 def slice_lora_a(
69 self, lora_a: torch.Tensor | list[torch.Tensor | None]
70 ) -> torch.Tensor | list[torch.Tensor | None]:
71 """Slice lora a if splitting for tensor parallelism."""
72 return lora_a
73
74 def slice_lora_b(
75 self, lora_b: torch.Tensor | list[torch.Tensor | None]
76 ) -> torch.Tensor | list[torch.Tensor | None]:
77 """Slice lora b if splitting with tensor parallelism."""
78 return lora_b