LoRA#
- class braintrace.nn.LoRA#
A standalone LoRA layer.
LoRA (Low-Rank Adaptation) injects two low-rank factors into a layer so a large pre-trained model can be fine-tuned with far fewer parameters. This subclass preserves the upstream
brainstate.nn.LoRAconstructor and replaces only the forward pass so that the multiplication is routed throughbraintrace.lora_matmul()and therefore participates in eligibility-trace computation.The layer adds a low-rank component \(\frac{1}{r} B A\) to the base weight, where \(B\) and \(A\) are learnable factors of rank \(r\):
\[W_{\mathrm{LoRA}} = W_{\text{orig}} + \frac{1}{r} B A\]The scaling factor is fixed to
1 / lora_rank.- Parameters:
in_features (int) – Number of input features.
lora_rank (int) – Rank of the LoRA decomposition.
out_features (int) – Number of output features.
base_module (brainstate.nn.Module or None, optional) – Optional base layer that is called on
xand added to the LoRA branch. DefaultNone.kernel_init (Callable or ArrayLike, optional) – Initializer used for both
lora_a(in×rank) andlora_b(rank×out). Default isLecunNormal(). To get the classic “LoRA-zero” initialisation useinit.ZeroInit().param_type (type, optional) –
ParamStatesubclass used to wrap the weights. Default isbrainstate.ParamState.in_size (int or Sequence[int], optional) – Optional explicit input size override. Default
None.
- Variables:
in_features (int) – Number of input features.
out_features (int) – Number of output features.
base_module (brainstate.nn.Module or None) – The optional base layer added to the LoRA branch.
weight (ParamState) –
ParamStatewhose value is a dict with two keys:'lora_a'of shape(in_features, lora_rank)and'lora_b'of shape(lora_rank, out_features).
Examples
>>> import brainstate >>> import braintrace >>> >>> # Create a standalone LoRA layer >>> brainstate.environ.set(precision=64) >>> layer = braintrace.nn.LoRA(in_features=3, lora_rank=2, out_features=4) >>> x = brainstate.random.randn(16, 3) >>> y = layer(x) >>> print(y.shape) (16, 4) >>> >>> # Wrap around an existing linear layer >>> linear = brainstate.nn.Linear(3, 4) >>> wrapper = braintrace.nn.LoRA(3, 2, 4, base_module=linear) >>> assert wrapper.base_module is linear >>> y = wrapper(x) >>> print(y.shape) (16, 4)
- update(x)#
Apply the low-rank adaptation through the ETP
lora_matmul.Computes \(y = \frac{1}{r}\, x\, \mathbf{A}\, \mathbf{B}\) via
braintrace.lora_matmul(), where \(\mathbf{A}\) is the input-facing factorlora_aof shape(in, rank)and \(\mathbf{B}\) is the output-facing factorlora_bof shape(rank, out)(so the LoRA factors participate in online-learning trace computation), and adds the optional base-module output.- Parameters:
x (ArrayLike) – Input array, of shape
(..., in_features).- Returns:
ArrayLike – The adapted output, of shape
(..., out_features).
- LoRA.__init__(in_features, lora_rank, out_features, *, base_module=None, kernel_init=LecunNormal( scale=1.0, mode='fan_in', in_axis=-2, out_axis=-1, distribution='truncated_normal', rng=RandomState(Array((), dtype=key<fry>) overlaying: [2233333421 2029709265]), unit=Unit("1") ), param_type=<class 'brainstate.ParamState'>, in_size=None)#