Signed-off-by: Hollow Man <hollowman@opensuse.org> Co-authored-by: Jee Jee Li <pandaleefree@gmail.com>
110 lines
3.4 KiB
Python
110 lines
3.4 KiB
Python
# SPDX-License-Identifier: Apache-2.0
|
|
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
|
|
|
from collections.abc import Iterable
|
|
from typing import TYPE_CHECKING, overload
|
|
|
|
import torch
|
|
import torch.nn as nn
|
|
from transformers import PretrainedConfig
|
|
|
|
from vllm.config.lora import LoRAConfig
|
|
|
|
if TYPE_CHECKING:
|
|
from vllm.lora.punica_wrapper import PunicaWrapperBase
|
|
|
|
|
|
class BaseLayerWithLoRA(nn.Module):
|
|
def __getattr__(self, name):
|
|
d = self.__dict__
|
|
if name in d.get("_parameters", ()):
|
|
return d["_parameters"][name]
|
|
if name in d.get("_buffers", ()):
|
|
return d["_buffers"][name]
|
|
if name in d.get("_modules", ()):
|
|
return d["_modules"][name]
|
|
# Forward public misses to ``base_layer``; private names are framework
|
|
# bookkeeping and must stay local.
|
|
if not name.startswith("_"):
|
|
base_layer = d.get("_modules", {}).get("base_layer")
|
|
if base_layer is not None:
|
|
return getattr(base_layer, name)
|
|
raise AttributeError(
|
|
f"{type(self).__name__!r} object has no attribute {name!r}"
|
|
)
|
|
|
|
def load_weights(
|
|
self, weights: Iterable[tuple[str, torch.Tensor]]
|
|
) -> Iterable[str]:
|
|
"""Load checkpoint weights into the wrapped base layer."""
|
|
base_load_weights = getattr(self.base_layer, "load_weights", None)
|
|
if callable(base_load_weights):
|
|
return base_load_weights(weights)
|
|
|
|
from vllm.model_executor.models.utils import AutoWeightsLoader
|
|
|
|
return AutoWeightsLoader(self.base_layer).load_weights(weights)
|
|
|
|
@overload
|
|
def slice_lora_a(
|
|
self, lora_a: list[torch.Tensor | None]
|
|
) -> list[torch.Tensor | None]: ...
|
|
@overload
|
|
def slice_lora_a(self, lora_a: torch.Tensor) -> torch.Tensor: ...
|
|
def slice_lora_a(
|
|
self, lora_a: torch.Tensor | list[torch.Tensor | None]
|
|
) -> torch.Tensor | list[torch.Tensor | None]:
|
|
"""Slice lora a if splitting for tensor parallelism."""
|
|
...
|
|
|
|
@overload
|
|
def slice_lora_b(
|
|
self, lora_b: list[torch.Tensor | None]
|
|
) -> list[torch.Tensor | None]: ...
|
|
@overload
|
|
def slice_lora_b(self, lora_b: torch.Tensor) -> torch.Tensor: ...
|
|
def slice_lora_b(
|
|
self, lora_b: torch.Tensor | list[torch.Tensor | None]
|
|
) -> torch.Tensor | list[torch.Tensor | None]:
|
|
"""Slice lora b if splitting with tensor parallelism."""
|
|
...
|
|
|
|
def create_lora_weights(
|
|
self,
|
|
max_loras: int,
|
|
lora_config: LoRAConfig,
|
|
model_config: PretrainedConfig | None = None,
|
|
) -> None:
|
|
"""Initializes lora matrices."""
|
|
...
|
|
|
|
def reset_lora(self, index: int):
|
|
"""Resets the lora weights at index back to 0."""
|
|
...
|
|
|
|
def set_lora(
|
|
self,
|
|
index: int,
|
|
lora_a: torch.Tensor | list[torch.Tensor],
|
|
lora_b: torch.Tensor | list[torch.Tensor],
|
|
):
|
|
"""Overwrites lora tensors at index."""
|
|
...
|
|
|
|
def set_mapping(
|
|
self,
|
|
punica_wrapper,
|
|
):
|
|
self.punica_wrapper: PunicaWrapperBase = punica_wrapper
|
|
|
|
@classmethod
|
|
def can_replace_layer(
|
|
cls,
|
|
source_layer: nn.Module,
|
|
lora_config: LoRAConfig,
|
|
packed_modules_list: list,
|
|
model_config: PretrainedConfig | None = None,
|
|
) -> bool:
|
|
"""Returns True if the layer can be replaced by this LoRA layer."""
|
|
raise NotImplementedError
|