Interactive Essay
Why LoRA works: fine-tuning a giant model with a tiny matrix
Slide the rank up from 1 and watch a real GPT-2 weight update rebuild itself from a few small pieces.
Fine-tuning changes a big model's weights, but for many tasks the useful part of that change has a simple shape: two thin tables of numbers multiplied together. LoRA trains only those two thin tables and leaves the giant model frozen, so it adjusts a tiny fraction of the numbers and keeps most of the quality. Drag the slider to see it on a real fine-tune.
Trained adapter (r = 64): 87.0% on SST-2 (base model 60.9%). This is the trained model's score, so it stays the same as you move the slider.
How is the error computed?
The rebuild keeps the r largest singular values of the full 768 × 768 update, which is the best rank-r approximation there is. The error comes from the singular values it drops.
New to LoRA? Start with the one-minute version.
Why does LoRA work?
GPT-3 has 175 billion parameters. When the LoRA authors fine-tuned it, they trained 4.7 million numbers and left every original weight frozen. It scored about the same as fine-tuning the whole model, and better on two of the three tasks they tested. That is one trained number for every 37,000 frozen ones.
So how do you fine-tune a giant model while training almost none of it? The slider above shows it on one weight matrix from a real GPT-2 fine-tune.
The slider sets how many pieces the rebuild may use. On the LoRA update, a handful of pieces already captures most of the pattern. Switch to the full fine-tune and the rebuild stays blurry much longer, because that update changed every direction a little. The LoRA adapter here was trained with room for 64 pieces and scored 87.0% on this sentiment task, against 88.9% for the full fine-tune and 60.9% before training. Most of its change sits in a few pieces, and a separate adapter trained with room for just one piece still reached 83.6%.
I have set r=8 in a LoRA config and moved on more than once. It worked, so I never asked why eight was enough for a matrix with millions of entries. This essay is me finally asking. The fine-tune behind the slider is in ml-explainers/lora and reruns on a laptop in minutes.
The change a fine-tune needs can be far smaller than the matrix it changes.
What is LoRA? The one-minute version
If you have never fine-tuned a model, here is LoRA before any math. Press play or drag the timeline.
Step 1 of 7
A trained model is a giant grid of numbers
Every square is one weight. GPT-3 has 175 billion, all set during pretraining.
175,000,000,000 numbers in GPT-3
The big grid never moves. All the learning happens in two thin strips, and their product can only paint a striped change, where every row is the same pattern scaled up or down. The rest of this essay is about why that is enough, starting with rank: how many strip pairs you use.
Terms you'll see
- Fine-tuning:
- extra training so a pretrained model does a new task.
- Adapter:
- the trained pair of strips for one task (B and A, later on).
- Rank r:
- how many strip pairs an adapter uses.
- SST-2 and WikiSQL:
- two benchmarks, one for movie-review sentiment and one for turning questions into SQL.
- Wq and Wv:
- two weight matrices inside each attention layer that LoRA often adapts.
What is the rank of a matrix?
In the determinant essay, the plane collapsed to a line when the two columns lined up and the determinant hit zero. There is a name for the number of directions the outputs can still reach.
Rank
Drag the two column arrows below and watch the rank drop as they line up.
Rank
2
The columns point in different directions, so the outputs fill the plane.
det = 1.55
Try this
Rank 1 means every output lands on one line, however big the matrix is. A 4,096 × 4,096 matrix can have rank 1 too: almost 17 million entries, one direction of output. LoRA is built on that gap.
Low-rank matrices: one column times one row
Weight matrices are rarely square, so from here on a matrix has d rows and k columns. The simplest way to build one with rank 1 is to multiply a column by a row. Take a column b with d entries and a row aT with k entries. Their product b aT is a d × k grid where the entry in row i, column j is bi times aj.
Watch the grid fill in square by square. Then change b or a, or tap any square.
Tap a square to see which numbers made it.
Rank
1
Numbers stored
9
to produce 20 entries
Every column of b aT is b scaled by one entry of a, so every column points the same way. That is rank 1. Add a second pair and the columns can point two ways, so the rank goes up to 2. Keep going and a rank-r matrix is a sum of r column-times-row pairs. Put the r columns side by side as B and the r rows on top of each other as A, and the sum is the product BA:
The grid above made 20 entries from 9 stored numbers. In general, B and A hold r(d + k) numbers, against d · k for the full matrix.
Try this
How LoRA works: freeze W, train BA
A layer in a neural network multiplies its input by a weight matrix W, as the matrix essay showed. Full fine-tuning changes every entry of W. LoRA leaves W frozen and learns the change as a low-rank product, , so the layer computes:
In the one-minute version, B was the side strip and A was the top strip.
LoRA
Training adjusts B and A and never touches W. The widget shows two details that make this practical. Drag x, then press Reset B to zero.
Wx (frozen)
(1.35, 1.4)
BAx (update)
(0.93, -0.62)
h = Wx + BAx
(2.28, 0.78)
First, B starts at zero, so BA is zero and h equals Wx. The model starts exactly as it was.
Second, after training, W + BA merges into one matrix, so the fine-tuned model runs as fast as the original.
Try this
Hu et al. scale BA by a constant , and libraries follow them. They differ on how A starts out, but PEFT and most other libraries start B at zero.
Why a small LoRA rank is enough
Why would a few directions be enough? Aghajanyan, Zettlemoyer and Gupta tuned RoBERTa-Large to 90% of full fine-tuning on a paraphrase task while training about 200 numbers, projected back into the full model. Their reading is that pretraining leaves a model only a few directions away from many tasks.
Hu et al. looked inside the update too: it amplifies directions already in W that pretraining had left weak.
This has limits. On code and math, Biderman et al. found LoRA underperforms full fine-tuning in both instruction tuning and continued pretraining, with a smaller gap for instruction tuning. The full fine-tunes learned updates with a rank 10 to 100 times higher than typical LoRA settings, and LoRA learned less but forgot less. Hu et al. add that a task in a language the model never saw could need close to full rank.
For many tasks the useful change lives in a few directions, so a small r loses very little. For large, hard tasks it can lose more.
LoRA parameter count and memory
Here is r(d + k) at real model sizes. Pick a model, the matrices to adapt, and a rank.
Trainable parameters
18,874,368
0.07% of each adapted matrix
Adapter size (FP16)
37.7 MB
2 bytes per number
Update, per matrix per token
98,304 multiply-adds
vs 150,994,944 for a full d × d update
Layer, per matrix per token
151,093,248 unmerged
150,994,944 after merging, the same as the base model
The GPT-3 checkpoint shrinks from 350 GB to about 35 MB with r = 4 on Wq and Wv, so 100 task adapters plus one base model take about 354 GB, against 35 TB for 100 full copies. Training needed 1.2 TB of GPU memory with full fine-tuning and 350 GB with LoRA.
Applying the update as B(Ax) costs r(d + k) multiply-adds, far less than a full d × k update. Unmerged, that work comes on top of Wx, so the adapter is slightly slower than the base model. Merged, it is one matrix multiply again.
What the rank slider does not show
The slider rebuilt each update from its strongest directions, without showing what those directions are. It counts how many a fine-tune needs, and what each one does is still an open question.
One question to take with you: if a fine-tune only needs a few directions, which directions does your task need?
The code that trained and measured these updates is in ml-explainers/lora. The next essay in this series is on probability and loss functions.
Sources
- Hu et al. 2021, LoRA: Low-Rank Adaptation of Large Language Models
- Aghajanyan, Zettlemoyer and Gupta 2020, Intrinsic Dimensionality Explains the Effectiveness of Language Model Fine-Tuning
- Biderman et al. 2024, LoRA Learns Less and Forgets Less
- Brown et al. 2020, Language Models are Few-Shot Learners (GPT-3 sizes)
- ml-explainers/lora, the fine-tune behind the rank slider