Skip to content

vllm.lora.layers.base

BaseLayerWithLoRA

Bases: Module

Source code in vllm/lora/layers/base.py
class BaseLayerWithLoRA(nn.Module):

    def named_modules(
        self,
        memo: set[nn.Module] | None = None,
        prefix: str = "",
        remove_duplicate: bool = True,
    ) -> Iterable[tuple[str, nn.Module]]:
        """Make the LoRA wrapper transparent in the module tree.

        LoRA wrapping moves a layer's parameters under ``base_layer``
        (e.g. ``qkv_proj.weight`` -> ``qkv_proj.base_layer.weight``).
        Checkpoint files and model-specific ``load_weights()`` methods
        use the original (un-prefixed) names.

        This override flattens ``base_layer`` out of the hierarchy so
        that :meth:`named_parameters` and :meth:`named_buffers` return
        the original names, making weight loading work transparently.
        """
        if memo is None:
            memo = set()
        if remove_duplicate and self in memo:
            return
        memo.add(self)
        yield prefix, self

        base: nn.Module | None = getattr(self, "base_layer", None)
        if base is not None:
            if not (remove_duplicate and base in memo):
                memo.add(base)
                yield prefix, base
                for name, child in base._modules.items():
                    if child is not None:
                        child_prefix = f"{prefix}.{name}" if prefix else name
                        yield from child.named_modules(
                            memo, child_prefix, remove_duplicate
                        )

        for name, child in self._modules.items():
            if name == "base_layer" or child is None:
                continue
            child_prefix = f"{prefix}.{name}" if prefix else name
            yield from child.named_modules(
                memo, child_prefix, remove_duplicate
            )

    def load_weights(
        self, weights: Iterable[tuple[str, torch.Tensor]]
    ) -> set[str]:
        """Forward checkpoint weights to the unwrapped base layer."""
        from vllm.model_executor.models.utils import AutoWeightsLoader

        loader = AutoWeightsLoader(self.base_layer)
        return loader.load_weights(weights)

    def zero_lora_state(self) -> None:
        """Re-zero all unregistered GPU tensor attributes.

        LoRA stacked tensors (``lora_a_stacked``, ``lora_b_stacked``, etc.)
        are plain attributes, not ``nn.Parameter`` or registered buffers.
        After level-2 sleep the GPU memory backing them is discarded and
        remapped with undefined contents.  ``reload_weights()`` restores
        only parameters and buffers, so these tensors must be explicitly
        re-zeroed to avoid adding garbage to the base-model output.
        """
        params = set(id(p) for p in self.parameters())
        buffers = set(id(b) for b in self.buffers())
        registered = params | buffers

        for val in vars(self).values():
            if isinstance(val, torch.Tensor):
                tensors: Iterable[torch.Tensor] = (val,)
            elif isinstance(val, (tuple, list)):
                tensors = (v for v in val if isinstance(v, torch.Tensor))
            else:
                continue

            for t in tensors:
                if id(t) not in registered and t.device.type != "meta":
                    t.zero_()

    @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

can_replace_layer classmethod

can_replace_layer(
    source_layer: 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.

Source code in vllm/lora/layers/base.py
@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

create_lora_weights

create_lora_weights(
    max_loras: int,
    lora_config: LoRAConfig,
    model_config: PretrainedConfig | None = None,
) -> None

Initializes lora matrices.

Source code in vllm/lora/layers/base.py
def create_lora_weights(
    self,
    max_loras: int,
    lora_config: LoRAConfig,
    model_config: PretrainedConfig | None = None,
) -> None:
    """Initializes lora matrices."""
    ...

load_weights

load_weights(
    weights: Iterable[tuple[str, Tensor]],
) -> set[str]

Forward checkpoint weights to the unwrapped base layer.

Source code in vllm/lora/layers/base.py
def load_weights(
    self, weights: Iterable[tuple[str, torch.Tensor]]
) -> set[str]:
    """Forward checkpoint weights to the unwrapped base layer."""
    from vllm.model_executor.models.utils import AutoWeightsLoader

    loader = AutoWeightsLoader(self.base_layer)
    return loader.load_weights(weights)

named_modules

named_modules(
    memo: set[Module] | None = None,
    prefix: str = "",
    remove_duplicate: bool = True,
) -> Iterable[tuple[str, Module]]

Make the LoRA wrapper transparent in the module tree.

LoRA wrapping moves a layer's parameters under base_layer (e.g. qkv_proj.weight -> qkv_proj.base_layer.weight). Checkpoint files and model-specific load_weights() methods use the original (un-prefixed) names.

This override flattens base_layer out of the hierarchy so that :meth:named_parameters and :meth:named_buffers return the original names, making weight loading work transparently.

Source code in vllm/lora/layers/base.py
def named_modules(
    self,
    memo: set[nn.Module] | None = None,
    prefix: str = "",
    remove_duplicate: bool = True,
) -> Iterable[tuple[str, nn.Module]]:
    """Make the LoRA wrapper transparent in the module tree.

    LoRA wrapping moves a layer's parameters under ``base_layer``
    (e.g. ``qkv_proj.weight`` -> ``qkv_proj.base_layer.weight``).
    Checkpoint files and model-specific ``load_weights()`` methods
    use the original (un-prefixed) names.

    This override flattens ``base_layer`` out of the hierarchy so
    that :meth:`named_parameters` and :meth:`named_buffers` return
    the original names, making weight loading work transparently.
    """
    if memo is None:
        memo = set()
    if remove_duplicate and self in memo:
        return
    memo.add(self)
    yield prefix, self

    base: nn.Module | None = getattr(self, "base_layer", None)
    if base is not None:
        if not (remove_duplicate and base in memo):
            memo.add(base)
            yield prefix, base
            for name, child in base._modules.items():
                if child is not None:
                    child_prefix = f"{prefix}.{name}" if prefix else name
                    yield from child.named_modules(
                        memo, child_prefix, remove_duplicate
                    )

    for name, child in self._modules.items():
        if name == "base_layer" or child is None:
            continue
        child_prefix = f"{prefix}.{name}" if prefix else name
        yield from child.named_modules(
            memo, child_prefix, remove_duplicate
        )

reset_lora

reset_lora(index: int)

Resets the lora weights at index back to 0.

Source code in vllm/lora/layers/base.py
def reset_lora(self, index: int):
    """Resets the lora weights at index back to 0."""
    ...

set_lora

set_lora(
    index: int,
    lora_a: Tensor | list[Tensor],
    lora_b: Tensor | list[Tensor],
)

Overwrites lora tensors at index.

Source code in vllm/lora/layers/base.py
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."""
    ...

slice_lora_a

slice_lora_a(
    lora_a: list[Tensor | None],
) -> list[Tensor | None]
slice_lora_a(lora_a: Tensor) -> Tensor
slice_lora_a(
    lora_a: Tensor | list[Tensor | None],
) -> Tensor | list[Tensor | None]

Slice lora a if splitting for tensor parallelism.

Source code in vllm/lora/layers/base.py
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."""
    ...

slice_lora_b

slice_lora_b(
    lora_b: list[Tensor | None],
) -> list[Tensor | None]
slice_lora_b(lora_b: Tensor) -> Tensor
slice_lora_b(
    lora_b: Tensor | list[Tensor | None],
) -> Tensor | list[Tensor | None]

Slice lora b if splitting with tensor parallelism.

Source code in vllm/lora/layers/base.py
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."""
    ...

zero_lora_state

zero_lora_state() -> None

Re-zero all unregistered GPU tensor attributes.

LoRA stacked tensors (lora_a_stacked, lora_b_stacked, etc.) are plain attributes, not nn.Parameter or registered buffers. After level-2 sleep the GPU memory backing them is discarded and remapped with undefined contents. reload_weights() restores only parameters and buffers, so these tensors must be explicitly re-zeroed to avoid adding garbage to the base-model output.

Source code in vllm/lora/layers/base.py
def zero_lora_state(self) -> None:
    """Re-zero all unregistered GPU tensor attributes.

    LoRA stacked tensors (``lora_a_stacked``, ``lora_b_stacked``, etc.)
    are plain attributes, not ``nn.Parameter`` or registered buffers.
    After level-2 sleep the GPU memory backing them is discarded and
    remapped with undefined contents.  ``reload_weights()`` restores
    only parameters and buffers, so these tensors must be explicitly
    re-zeroed to avoid adding garbage to the base-model output.
    """
    params = set(id(p) for p in self.parameters())
    buffers = set(id(b) for b in self.buffers())
    registered = params | buffers

    for val in vars(self).values():
        if isinstance(val, torch.Tensor):
            tensors: Iterable[torch.Tensor] = (val,)
        elif isinstance(val, (tuple, list)):
            tensors = (v for v in val if isinstance(v, torch.Tensor))
        else:
            continue

        for t in tensors:
            if id(t) not in registered and t.device.type != "meta":
                t.zero_()