1313# limitations under the License.
1414
1515import math
16- from typing import Any , Literal , Optional , Tuple
16+ from typing import Any , Literal , Optional
1717
1818import torch
1919import torch .nn as nn
@@ -62,7 +62,7 @@ def bias(self) -> torch.Tensor | None:
6262 """Return the wrapped linear bias."""
6363 return getattr (self .to_wrap , "bias" , None )
6464
65- def forward (self , x : torch .Tensor , * args : Any , ** kwargs : Any ) -> Tuple [ torch . Tensor , Optional [ torch . Tensor ]] :
65+ def forward (self , x : torch .Tensor , * args : Any , ** kwargs : Any ):
6666 """Forward pass that combines the wrapped module output with the adapter output.
6767
6868 Args:
@@ -71,18 +71,21 @@ def forward(self, x: torch.Tensor, *args: Any, **kwargs: Any) -> Tuple[torch.Ten
7171 **kwargs: Additional keyword arguments for the wrapped module.
7272
7373 Returns:
74- A tuple containing:
75- - Combined output (linear_output + adapter_output) if adapter is enabled,
76- otherwise just the linear_output
77- - Bias term (if present, otherwise None)
74+ When the wrapped module returns a Megatron-style tuple, a
75+ ``(combined_output, bias)`` tuple; when it returns a bare tensor
76+ (e.g. a plain ``nn.Linear``), a bare tensor so the wrapper stays a
77+ drop-in replacement in simple (non-parallel) models.
7878 """
7979 # pylint: disable=C0115,C0116
8080 linear_output , bias , layernorm_output = self .base_linear_forward (x , * args , ** kwargs )
8181 if not self ._adapter_enabled :
82- return linear_output , bias
82+ return linear_output if not self . _base_returns_tuple else ( linear_output , bias )
8383 adapter_output = self .adapter_forward (self .adapter , layernorm_output .contiguous (), * args , ** kwargs )
8484 adapter_output = adapter_output .reshape (linear_output .shape )
85- return linear_output + adapter_output , bias
85+ combined = linear_output + adapter_output
86+ if not self ._base_returns_tuple :
87+ return combined
88+ return combined , bias
8689
8790
8891class LoRATopKRouter (AdapterWrapper ):
@@ -343,11 +346,18 @@ def forward(self, x: torch.Tensor) -> tuple[torch.Tensor, None]:
343346 return out , None
344347
345348
346- class LinearAdapter (nn .Linear ):
347- """Linear with LoRA that preserves the base weight and bias checkpoint keys.
349+ class LinearAdapter (nn .Module ):
350+ """Delta-only LoRA adapter for a plain ``nn.Linear``, mirroring :class:`ParallelLinearAdapter`'s role.
351+
352+ This adapter holds *only* the low-rank LoRA delta (``linear_in`` -> ``linear_out``) and
353+ produces just the scaled adaptation term. It is intended to be wrapped together with the
354+ original linear by :class:`LoRALinear` (the ``to_wrap`` / ``adapter`` pattern), so that
355+ base weights and adapter weights live in distinct submodules and adapter state is
356+ checkpointed under the ``adapter.`` prefix.
348357
349358 Args:
350- orig_linear: The linear module to augment.
359+ orig_linear: The linear module to augment (only its shape/dtype/device are used; its
360+ weights are *not* copied).
351361 dim: LoRA's dimension (in_features -> dim -> out_features).
352362 alpha: LoRA's scaling alpha.
353363 dropout: Dropout probability (default: 0.0).
@@ -366,47 +376,31 @@ def __init__(
366376 lora_A_init_method : Literal ["xavier" , "uniform" ] = "xavier" ,
367377 lora_dtype : Optional [torch .dtype ] = None ,
368378 ) -> None :
369- """Initialize LinearAdapter by copying from original Linear and adding LoRA components .
379+ """Initialize the LoRA delta weights from the original Linear's shape and dtype .
370380
371381 Args:
372- orig_linear: The original Linear module to adapt.
382+ orig_linear: The original Linear module to adapt (weights are not copied) .
373383 dim: LoRA rank dimension.
374384 alpha: LoRA scaling factor.
375385 dropout: Dropout probability.
376386 dropout_position: When to apply dropout ('pre' or 'post' LoRA computation).
377387 lora_A_init_method: Initialization method for LoRA matrix A.
378388 lora_dtype: Data type for LoRA weights.
379389 """
390+ super ().__init__ ()
380391 assert isinstance (orig_linear , nn .Linear )
381- super (LinearAdapter , self ).__init__ (
382- in_features = orig_linear .in_features ,
383- out_features = orig_linear .out_features ,
384- bias = orig_linear .bias is not None ,
385- device = orig_linear .weight .device ,
386- dtype = orig_linear .weight .dtype ,
387- )
388- # copy weights
389- self .weight .data .copy_ (orig_linear .weight .data )
390- if orig_linear .bias is not None :
391- self .bias .data .copy_ (orig_linear .bias .data )
392- # initialize the adapter
392+ self .in_features = orig_linear .in_features
393+ self .out_features = orig_linear .out_features
393394 self ._init_adapter (
394395 dim = dim ,
395396 alpha = alpha ,
396397 dropout = dropout ,
397398 dropout_position = dropout_position ,
398399 lora_A_init_method = lora_A_init_method ,
399400 lora_dtype = lora_dtype ,
401+ device = orig_linear .weight .device ,
402+ base_dtype = orig_linear .weight .dtype ,
400403 )
401- self ._adapter_enabled = True
402-
403- def enable_adapter_layers (self ) -> None :
404- """Enable the adapter layers, allowing them to contribute to the forward pass output."""
405- self ._adapter_enabled = True
406-
407- def disable_adapter_layers (self ) -> None :
408- """Disable the adapter layers, making the forward pass return only the base module output."""
409- self ._adapter_enabled = False
410404
411405 @torch .no_grad
412406 def _init_adapter (
@@ -417,8 +411,10 @@ def _init_adapter(
417411 dropout_position : Literal ["pre" , "post" ] = "pre" ,
418412 lora_A_init_method : Literal ["xavier" , "uniform" ] = "xavier" ,
419413 lora_dtype : Optional [torch .dtype ] = None ,
414+ device : Optional [torch .device ] = None ,
415+ base_dtype : Optional [torch .dtype ] = None ,
420416 ) -> None :
421- """Initialize the LoRA weights and freeze the base parameters .
417+ """Initialize the LoRA delta weights .
422418
423419 Args:
424420 dim: LoRA's dimension (in_features -> dim -> out_features).
@@ -427,20 +423,16 @@ def _init_adapter(
427423 dropout_position: Where to apply dropout relative to LoRA (choices: ['pre', 'post'], default='pre').
428424 lora_A_init_method: Initialization method for lora_A (choices: ['xavier', 'uniform']).
429425 lora_dtype: Adapter weight dtype. Defaults to the base weight dtype.
426+ device: Device for the LoRA weights.
427+ base_dtype: Base weight dtype, used when ``lora_dtype`` is not provided.
430428 """
431429 self .dim = dim
432430 self .alpha = alpha
433431 self .scale = alpha / dim
434432
435- # Freeze original weights
436- device = self .weight .device
437- self .weight .requires_grad = False
438- if self .bias is not None :
439- self .bias .requires_grad = False
440-
441433 in_features = self .in_features
442434 out_features = self .out_features
443- dtype = lora_dtype or self . weight . dtype
435+ dtype = lora_dtype or base_dtype
444436
445437 self .linear_in = nn .Linear (in_features , dim , bias = False , dtype = dtype , device = device )
446438 self .linear_out = nn .Linear (dim , out_features , bias = False , dtype = dtype , device = device )
@@ -457,24 +449,20 @@ def _init_adapter(
457449 self .dropout_position = dropout_position
458450
459451 def forward (self , x : torch .Tensor ) -> torch .Tensor :
460- """Forward pass combining Linear output with LoRA adaptation .
452+ """Compute the scaled LoRA delta only (no base-weight term) .
461453
462454 Args:
463455 x: Input tensor.
464456
465457 Returns:
466- Combined output from original linear layer and LoRA adaptation.
458+ The scaled low-rank adaptation ``scale * linear_out(linear_in(x))`` with dropout
459+ applied per ``dropout_position``.
467460 """
468461 # pylint: disable=C0115,C0116
469- res = torch .nn .functional .linear (x , self .weight , self .bias )
470-
471- if not self ._adapter_enabled :
472- return res
473-
474462 if self .dropout_position == "pre" :
475463 x = self .dropout (x )
476464 lora_res = self .linear_out (self .linear_in (x ))
477465 lora_res = lora_res * self .scale
478466 if self .dropout_position == "post" :
479467 lora_res = self .dropout (lora_res )
480- return res + lora_res
468+ return lora_res
0 commit comments