Generative AI
LoRA (Low-Rank Adaptation)
How decomposing a massive weight update into two low-rank matrices drastically reduces trainable parameters while maintaining learning capability.
Stage 1 of 4: Full-rank updates
Rank is 4, alpha is 16, resulting in 512 trainable parameters, which is 12.5% of full rank. Reconstruction loss is 0.00.
- Trainable weights
- Frozen base weights
- Loss
Standard fine-tuning updates millions of parameters in the massive base matrix W.
Check your understanding
Fine-tuning a massive generative model by updating every parameter is computationally exhausting. LoRA (Low-Rank Adaptation) freezes the original model and learns a tiny, efficient detour instead.
The problem with full fine-tuning
When a massive model like a Large Language Model (LLM) is pre-trained, it learns general patterns across billions of parameters, stored in massive weight matrices like the grey matrix you see here.
If you want to fine-tune it on a specific task, like writing code or speaking a specific language, the standard approach is to update every single parameter. This means you must load the entire model into GPU memory, compute gradients for every weight, and save a brand new multi-gigabyte copy of the model.
That is extremely expensive, slow, and often totally unnecessary.
Freezing the base
The first trick in LoRA is to stop updating the original weights altogether. We freeze .
In the simulation, this is when the padlock appears and turns grey. The gradients stop flowing through the massive matrix. The original knowledge of the model is perfectly preserved, which prevents catastrophic forgetting (where a model forgets how to speak English because it was fine-tuned too aggressively on French).
But if is frozen, how does the model learn anything new?
The LoRA bottleneck
Instead of changing , we add a new path next to it. We learn an additive update, , such that the new output is .
The magic of LoRA is that we do not make the same massive size as . Instead, we decompose it into two thin matrices: and .
If the original dimension is , then is and is . The bottleneck dimension is the rank.
By forcing the information to squeeze through this narrow rank , the number of parameters we have to train drops dramatically. For example, if and :
- A full update would need parameters.
- LoRA needs parameters. That is an 87.5% reduction, while often achieving the exact same performance.
Editing a masterpiece
Imagine you want to correct a few specific details on a massive, highly detailed map of the world (the base model).
Instead of redrawing the entire map from scratch (full fine-tuning), you place a sheet of clear tracing paper over it and only draw the new roads and borders on the tracing paper. The tracing paper is much smaller and lighter to carry (the LoRA weights), but when overlaid on the map, you get the updated world.
The Rank Trade-off
The rank is the most important hyperparameter in LoRA.
Grab the rank slider and sweep it across its full range. As the rank increases, the matrices and physically widen, and the number of trainable parameters grows.
Simultaneously, watch the loss curve, which here is a real reconstruction error: the simulation fits and to an actual fixed target update via truncated SVD, so the number you see is not a hand-picked formula, it is however much of that target the current rank can still capture. Giving the model a higher rank gives it more "expressivity", more capacity to learn complex updates, so the achievable loss floor drops, until the rank reaches the target update's own intrinsic dimension and the reconstruction is exact.
There is also an slider, which scales the applied update: . At , the update is nullified no matter how high the rank is, the bottleneck may have plenty of capacity, but nothing is added to . At , the update is applied completely unscaled.
Too low or too high?
At the bottleneck has no capacity at all: is exactly zero, and the loss sits at its worst value. Set the rank too low for a complex task (like ) and the matrices are barely more than vectors, lacking the mathematical capacity to express the necessary weight update. The loss plateaus early, leaving you with an underperforming model.
However, increasing the rank has diminishing returns. The difference between and is huge, but ranks well past a target update's own intrinsic rank barely move the loss further, while doubling your memory footprint. You always want to find the lowest rank that reaches your target loss.
What to take away
LoRA proves that the updates needed to fine-tune a model have a much lower intrinsic dimension than the model itself. We do not need to update billions of parameters to teach an LLM a new trick; a few million, intelligently arranged in a low-rank bottleneck, are more than enough.
Reference
- LoRA Update
- h = Wx + (α/r)·ABx
- Trainable Parameters
- 2 × d × r
- Compression Ratio
- (2 × d × r) / d²
- Alpha scaling
- α=0 → ΔW=0 regardless of r; α=r → ΔW=AB unscaled
- Truncated SVD
- A·B = Σᵢ σᵢ uᵢ vᵢᵀ, keeping only the r largest singular values
Break it on purpose
When the rank is too low, the matrices lack the capacity to express the necessary weight updates.