Skip to content
AILinkDeepTech
Go back
Deep Learning Medium

Low-Rank Adaptation (LoRA) Implementation in PyTorch

Abstract

A PyTorch implementation of Low-Rank Adaptation (LoRA): low-rank A/B matrices wrapped around a frozen linear layer, scaled by alpha/rank, with shape, freezing, and rank-property tests.

Low-Rank Adaptation (LoRA) Implementation in PyTorch

This implementation builds Low-Rank Adaptation (LoRA) from scratch. It wraps a frozen nn.Linear layer with low-rank A/B matrices whose update is scaled by alpha / rank, dramatically reducing the number of trainable parameters for fine-tuning large models.

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.linalg  
import math

class LoRALayer(nn.Module):
    def __init__(self, in_features, out_features, rank=4, alpha=1):
        super().__init__()
        
        self.alpha = alpha
        self.rank = rank
        
        # Initialize LoRA matrices A and B
        self.lora_A = nn.Parameter(torch.zeros(in_features, rank))
        self.lora_B = nn.Parameter(torch.zeros(rank, out_features))
        
        nn.init.kaiming_uniform_(self.lora_A, a=math.sqrt(5))
        nn.init.zeros_(self.lora_B)  

    def forward(self, x):
        # Compute: (x @ A) @ B * (alpha/rank)
        return (x @ self.lora_A @ self.lora_B) * (self.alpha / self.rank)

class LinearWithLoRA(nn.Module):
    def __init__(self, linear_layer, rank=4, alpha=1, freeze_weights=True):
        super().__init__()
        
        self.linear = linear_layer
        if freeze_weights:
            for param in self.linear.parameters():
                param.requires_grad = False
                
        # Add LoRA layer
        self.lora = LoRALayer(
            linear_layer.in_features,
            linear_layer.out_features,
            rank=rank,
            alpha=alpha
        )

    def forward(self, x):
        # linear + LoRA adjustment
        return self.linear(x) + self.lora(x)
    
# Test cases
def test_lora():
    in_features, out_features = 10, 5
    batch_size = 3
    rank = 2
    
    original_layer = nn.Linear(in_features, out_features)
    
    x = torch.randn(batch_size, in_features)
    
    # Wrap with LoRA
    lora_layer = LinearWithLoRA(original_layer, rank=rank)

    # Test forward pass
    output = lora_layer(x)
    assert output.shape == (batch_size, out_features), f"Shape mismatch: {output.shape}"
    print("(Shape test) passed!")

    # Freezing test
    original_params = sum(p.requires_grad for p in original_layer.parameters())
    assert original_params == 0, "Original weights not frozen"
    lora_params = sum(p.requires_grad for p in lora_layer.lora.parameters())
    assert lora_params == 2, "LoRA parameters not trainable"
    print("(Parameter freezing test) passed!")

    # Low-rank property test
    lora_contribution = lora_layer.lora(x)
    if len(lora_contribution.shape) > 2:
        lora_contribution = lora_contribution.reshape(-1, lora_contribution.shape[-1])
    rank_effective = torch.linalg.matrix_rank(lora_contribution)
    assert rank_effective <= rank, f"Rank constraint violated: {rank_effective} > {rank}"
    print("(Rank test) passed!")

    return "All tests passed successfully!"

if __name__ == "__main__":
    print(test_lora())

    input_size = 128
    output_size = 64
    batch_size = 32
    
    x = torch.randn(batch_size, input_size)
    
    original_layer = nn.Linear(input_size, output_size)
    
    # Add LoRA
    lora_model = LinearWithLoRA(original_layer, rank=8, alpha=16)
    
    # Forward pass
    output = lora_model(x)
    print(f"\nExample output shape: {output.shape}")


Cite this Explanation

@article{ailinkdeeptech2025loraalgo,
  title={Low-Rank Adaptation (LoRA) Implementation in PyTorch},
  author={AILinkDeepTech},
  journal={AILinkDeepTech Algorithm Explanations},
  year={2025},
  url={https://ailinkdeeptech.com/research/lora_algo}
}

Related Explanations