ONE FROZEN MODEL · 0.052% TRAINED · 8.4 MB · ZERO ADDED LATENCY

LoRA:
how to teach a frozen model in 8 megabytes

x
W₀ · 8,006,464,512 · 🔒
Awaist r=8B
+h
h = W₀x + (α/r)·BAx — the frozen highway and the trainable detour just sum
▣ adapter · 8.4 MBΣ trained: 0 · frozen: 8,006,464,512

One finished model, one new skill, and not a single base weight touched. Follow one 4096×4096 weight matrix from a 16.7-million-number update down to a rank-8 detour. Then watch the whole adapter — 0.052% of the model — train on a gaming GPU and fold back in for zero-latency serving. The scenes play themselves — watch, or just scroll. are tappable. The base model never changes.

00

The 16-gigabyte photocopy

To teach a finished model one new skill, the old way clones all eight billion weights and retrains them. Before LoRA makes its move, weigh the incumbent: what full fine-tuning actually costs — in memory, in dollars, in near-identical copies — and why almost none of that cost is the model itself. The Σ counter stays at zero all chapter: LoRA hasn’t wired in a single trainable number yet.

STEP 01 / 04
EIGHT BILLION DIALS, ALREADY SET
the thing we want to teach — laid out as weight matrices
W · layer 1 query
4096 × 4096 = 16,777,216 numbers
× 32 layers
8,006,464,512 weights · 16 GB @ fp16

Llama-3-8B is 8,006,464,512 numbers — 32 layers, hidden width 4096 — frozen after a pretraining run that cost millions. Full unfreezes every one of them to nudge behavior. Our goal is small: make it answer in one company’s support voice. Full fine-tuning treats “learn a small new habit” and “re-open all eight billion dials” as the same operation.

Llama-3-8B is 8,006,464,512 trained weights — full fine-tuning unfreezes all of them to teach one new habit
STEP 02 / 04
THE OPTIMIZER TRIPLES THE BILL
what training one parameter actually keeps in memory
weight 2
grad 2
master 4
momentum 4
variance 4
= 16 bytes per parameter× 8,006,464,512 ≈ 128 GB
80 GB GPU ceiling128 GB ✕
the full fine-tune doesn’t fit the biggest single datacenter GPU

Training memory isn’t just the weights. keeps, per parameter, a 32-bit master copy plus two momentum buffers — the rule of thumb is ~16 bytes per parameter once gradients and mixed-precision states are counted. For 8B that’s ~128 GB, and the weights themselves are only an eighth of it. A full fine-tune of an 8B model doesn’t fit on a single 80 GB datacenter GPU.

Adam needs ~16 bytes per parameter — a full 8B fine-tune wants ~128 GB, more than an 80 GB GPU holds
STEP 03 / 04
ONE COPY PER CUSTOMER
ten tasks, fine-tuned the old way
16 GB· support
16 GB· legal
16 GB· medical
16 GB· german
16 GB· sql
16 GB· pirate
16 GB· formal
16 GB· concise
16 GB· sales
16 GB· kids
10 × 16 GB = 160 GB
99% of every slab is the same frozen model

Full fine-tuning also produces a full-size artifact — a fresh 16 GB checkpoint — for every task. Ten customers, ten voices: ten separate eight-billion-weight models, 160 GB, ten things to load and serve. The base they share is 99%+ identical; you’ve paid to store the same frozen ocean ten times over to capture ten different teaspoons.

ten fine-tuned variants = ten 16 GB models = 160 GB — ten near-identical copies of one frozen model
STEP 04 / 04
THE QUESTION LoRA ASKS
LoRA’s bet, drawn on the model itself
W · 8,006,464,512stays exactly as trained
ΔW
the only thing
that must change
keep 8.006B frozen · learn ΔW

Something is off. It is implausible that teaching “sound like our support team” requires rewriting all eight billion dials. What if the change a fine-tune actually makes is tiny — not in effort, but in shape — so we could train and store just that change and leave the alone? That is the entire bet of Low-Rank Adaptation: freeze the base, learn a small patch.

LoRA’s bet: the change fine-tuning makes is tiny in shape — so train and store only the change, not the model
deep dive: what full fine-tuning is still for

What full fine-tuning is still for. When you have the GPUs and the data, full fine-tuning remains the frontier move: large domain shifts, new languages, continued pretraining. The catch that stalks it is catastrophic forgetting — moving every weight risks overwriting abilities you never meant to touch, which a frozen base structurally cannot lose. For what the base model itself cost to make, see the AI-numbers tutorial’s training-debt chapter.

The MLOps tax. A separate 16 GB checkpoint per task isn’t just storage — it’s ten models to version, ten to redeploy after every base upgrade, ten resident copies if customers are served concurrently. The economics of one-copy-per-skill are what pushed serving stacks toward a shared frozen base long before the math of LoRA made it cheap.

The family LoRA belongs to. — parameter-efficient fine-tuning — is the umbrella: adapter modules bolted between layers (2019), prefix-tuning that trains fake context tokens, BitFit that trains only biases, (IA)³ that trains per-channel rescales. LoRA is the member that won serving, and Hugging Face’s peft library is where the whole family lives in practice.

01

The change has a low intrinsic rank

Before splitting anything, why believe the update is small in shape? The evidence predates LoRA — and it’s startling: whole models steered through a few hundred directions, and the steering getting easier as models grow. This chapter is the hunch that made the method inevitable. The counter holds at zero — nothing is built yet, only justified.

STEP 01 / 04
200 KNOBS TUNE A WHOLE MODEL
the fewest directions that must move, measured — RoBERTa, MRPC
· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
200
355,000,000 weights
tuning those 200 recovers90% of full fine-tuning
the skill lives in a small room

In 2020 — a year before LoRA — Aghajanyan et al. measured a model’s : the fewest independent directions you must move to fine-tune it. The result that lit the fuse: optimizing just 200 parameters, randomly projected into RoBERTa’s full weight space, recovers 90% of full fine-tuning performance on the MRPC task. Ninety percent of the skill lived in a 200-dimensional room inside a 355-million-parameter house.

200 tuned parameters recover 90% of full fine-tuning on a task — inside a 355M-parameter model (Aghajanyan 2020)
STEP 02 / 04
BIGGER MODELS, SMALLER ROOMS
the twist: bigger pretrained model → smaller steering room
smalldim ↑
largerdim ↓
largestdim ↓↓
capacity up, steering-dimension down — scale makes fine-tuning easier

The counterintuitive twist from the same work: the larger the pretrained model, the lower its intrinsic dimension. Scale doesn’t just add capacity; it packs skills into ever-smaller adaptable subspaces. So the eight-billion-weight model isn’t harder to steer than a small one — it’s easier, because the direction you need to push already almost exists inside it.

the bigger the base model, the fewer directions you need to fine-tune it — scale lowers intrinsic dimension
STEP 03 / 04
LoRA’S HYPOTHESIS, IN ONE LINE
the hypothesis, as one equation
Wnew=Wfrozen+ΔWlow rank r ≪ 4096
W: not low-rank — full knowledgeΔW: low-rank — small change
learn only the low-rank ΔW

LoRA turns the observation into a design. Its hypothesis: the weight update accumulated during adaptation has a low — it can be written as the product of two much smaller matrices with little loss. Not the weights are low-rank (they’re not); the change to them is. That one sentence is the whole method. Everything after it is bookkeeping.

LoRA’s one-line hypothesis: the update ΔW is low-rank — not the weights, the change to them
STEP 04 / 04
WHAT “LOW RANK” ACTUALLY BUYS
4096 possible directions — how many carry the change?
rank 8 · lit…direction 4096 · dim
8 directions used4088 near-empty
pay for the directions you use

A full 4096×4096 update matrix has up to 4096 independent directions and 16.7 million free numbers. If the real change only needs, say, 8 directions, you are storing 16.7 million numbers to express something that lives in 8 — a thousand-fold overpayment. Rank is the number of directions; LoRA’s claim is that a handful is enough. The next chapter cashes the claim into two skinny matrices.

a 4096×4096 update has 4096 possible directions — LoRA bets the real change needs a single-digit number of them
deep dive: rank, in pictures

Rank, in pictures. A matrix’s rank is how many of its rows (or columns) are genuinely independent — how many directions it can actually move an input in. A rank-8 4096×4096 matrix looks huge but only ever pushes activations around inside an 8-dimensional subspace.

The view. Singular value decomposition sorts a matrix’s directions by importance. Plot the singular values of a fine-tuning update and you see a few tall bars and a long near-zero tail — the picture behind the whole low-rank bet: most of a ΔW’s 4096 possible directions are essentially empty.

Why B·A covers every low-rank matrix. Any matrix of rank ≤ r can be written exactly as a product of a 4096×r and an r×4096 matrix — that’s what rank means. So parameterizing the update as B·A isn’t an approximation scheme; it’s the exact family of all rank-≤r updates, with the full-rank ones excluded on purpose.

The distinction that matters. The pretrained weights themselves are not low-rank — they carry the model’s whole distributed knowledge and use their directions well. It’s the change a fine-tune makes that collapses to a few directions. LoRA compresses ΔW, never W.

Paid off in chapter 05. The LoRA paper later checked the hunch quantitatively: the top singular directions of an r=64 adapter and an r=8 adapter nearly coincide — even r=1–2 captures the dominant directions. The dial chapter turns that measurement into a design rule.

02

One fat matrix becomes two thin ones

If the update needs only r directions, you never build the full ΔW at all — you build the two skinny matrices whose product is ΔW, and count the numbers you just saved. This chapter zooms to a single protagonist matrix, splits its 16.7-million-number update into a 65,536-number pair, and checks where the 256× discount comes from — and why it grows as models get wider.

STEP 01 / 04
MEET THE PROTAGONIST MATRIX
layer 1, query projection — one weight matrix of hundreds
4096
W_q16,777,216 numbers
← 4096 →
full ΔW for this one matrix = 16.7M numbers

Zoom to one weight matrix: the query projection in layer 1, W_q — a 4096×4096 grid, 16,777,216 numbers, one of hundreds of weight matrices in the model. Full fine-tuning would hand this one matrix its own 16.7-million-number update, then do the same for every other matrix in the stack. LoRA is about to express that same update in 65,536.

one attention matrix is 4096×4096 = 16,777,216 numbers — and Llama-3-8B has hundreds of them
STEP 02 / 04
B TIMES A
drawn to scale: two slivers stand in for the square
B · 4096×8
×waist r=8
A · 8×4096
=
ΔWrank ≤ 8
4096×4096 · implied
stored: 65,536 · implied: 16,777,216

The : ΔW = B·A, where B is 4096×r (tall and thin) and A is r×4096 (short and wide), meeting at a waist of width r. For r=8, A holds 8×4096 = 32,768 numbers, B holds 4096×8 = 32,768 — together 65,536. Their product is a full 4096×4096 matrix of rank at most 8. You store the two skinny factors; the fat matrix is only ever implied.

B (4096×8) times A (8×4096) reconstructs a full 4096×4096 update from just 65,536 stored numbers
STEP 03 / 04
256× FEWER, ON ONE MATRIX
one matrix’s update, before and after the split
16,777,216
65,536
= 256×
d / 2r = 4096 / 16GPT-3 175B: 350 GB → 35 MB · 10,000×
wider model → bigger discount

Do the division: 16,777,216 ÷ 65,536 = 256. One matrix’s update just got 256 times cheaper to store and train, with no approximation beyond “rank ≤ 8.” The reduction is d / 2r = 4096 / 16 — widen the model (larger d) and the savings grow. The bigger the base, the better LoRA’s deal, which is exactly the direction models keep heading. (For GPT-3 175B, the paper’s r=4 adapter shrank the checkpoint 10,000×, 350 GB → 35 MB.)

GPT-3’s LoRA checkpoint was 10,000× smaller — 350 GB → 35 MB — for on-par accuracy (Hu et al. 2021)
STEP 04 / 04
WHY r DIRECTIONS SUFFICE
the update’s singular-value spectrum, sorted by importance
kept · r=8dropped ≈ 0 · 4,088 more directions
low-rank isn’t lossy when the update is already low-rank

Isn’t a rank-8 matrix a crippled version of a rank-4096 one? For an arbitrary matrix, yes. For a fine-tuning update, chapter 01 said no: the change occupies a few directions, so the 4,088 directions you drop were near-empty to begin with. B·A doesn’t approximate the update you wanted — it is the shape the update was always going to take. Now wire it into the network so it can learn.

the 4088 directions LoRA drops were nearly empty to begin with — B·A is the update’s true shape, not a lossy copy
deep dive: the linear algebra of the shrink

Best rank-r, guaranteed. The sorts any matrix’s directions by importance, and the Eckart–Young theorem says truncating to the top r of them is the best rank-r approximation you can make. The other face of the same coin: any matrix of rank ≤ r factors exactly as B·A with inner width r — so LoRA’s parameterization loses nothing over “learn a rank-r update” stated abstractly.

The general count. For a d×k matrix the adapter costs r×(d+k) numbers against d×k for the full update — 8×(4096+4096) = 65,536 versus 16,777,216 here. The discount d·k / r(d+k) grows with width, which is why LoRA’s bargain keeps improving as models get larger.

The GQA wrinkle. gives Llama-3-8B 32 query heads but only 8 key/value heads, so K and V projections are 4096×1024 — their adapters would cost 8×(4096+1024) = 40,960, and the tidy 256× becomes a messier 328×. This run adapts the two genuinely square projections — query and output — for clean arithmetic; the mechanism is identical either way.

Spread beats depth. Given a fixed parameter budget, the LoRA paper found that adapting more matrices at low rank beats adapting few matrices at high rank — rank 2 on four projection types outperformed rank 8 concentrated on one. Coverage of the network matters more than capacity per matrix.

03

A bypass that starts as a no-op

The two skinny matrices exist — on paper. Now they must attach to a live, frozen network without wrecking it on the first step: a brand-new, randomly initialized bolt-on that somehow leaves the model’s behavior exactly untouched, then learns while data flows through the old path and the new one at once. The trick is an initialization so careful that the adapter begins life as a mathematical no-op.

STEP 01 / 04
A INITIALIZED RANDOM, B INITIALIZED ZERO
the initialization that makes a brand-new bolt-on invisible
000
B · 4096×8
·
.02−.07.01.05−.03.04
A · 8×4096 · 𝒩(0,σ²)
=
0
B·A = 0
adapter = no-op at init — attach without disturbing the base

The initialization is the clever bit. A gets small random Gaussian values; B is set to exactly zero. So at step zero, B·A = 0 and ΔW = 0 — the brand-new contributes nothing, and the model behaves exactly like the untouched base. You bolt on the detour and the output doesn’t move a hair. Training starts from the model you already trust, not from a random perturbation of it.

B starts at exactly zero, so the brand-new adapter outputs 0 — the model is byte-for-byte itself on step one
STEP 02 / 04
THE FROZEN HIGHWAY AND THE TRAINABLE RAMP
one input, two lanes — the forward pass through a LoRA layer
x
W₀ · frozen · 🔒
Awaist r=8B
+h
h = W₀x + (α/r)·BAx
detour contributes 0 at init — the highway carries everything, for now

The forward pass forks. The input x runs down the frozen highway W₀·x exactly as before, and simultaneously down a bypass: first A squeezes x through the width-r waist, then B expands it back, giving (α/r)·B·A·x. The two rejoin by addition: h = W₀x + (α/r)·BAx. The highway carries the model’s existing knowledge untouched; the ramp carries only the new skill.

forward pass: h = W₀x + (α/r)·BAx — the frozen highway and the trainable detour just sum at the exit
STEP 03 / 04
TWO PROJECTIONS, ONE LAYER
one transformer layer, four projections, two ramps
LAYER 1 · ATTENTION
▣ B·A
Q
ramped
·
K
🔒
·
V
🔒
▣ B·A
O
ramped
+131,072 trainable · 33M frozen — per layer

Real LoRA doesn’t patch one matrix; it patches a chosen set. Add a second detour on the same layer’s output projection W_o — another 4096×4096, another 65,536-number adapter — and the layer now has two low-rank ramps, 131,072 trainable numbers, its 33 million frozen weights still untouched. Attention has four projection matrices (Q, K, V, O); which of them you adapt is a knob, and adapting a couple is the cheap, common default.

adapting two of a layer’s four attention projections adds 131,072 trainable numbers over 33M frozen ones
STEP 04 / 04
α, THE VOLUME KNOB
the adapter’s volume knob, wired between the detour and the exit
B·A·x
α/r
set once · never re-tuned
+h
whisper
shout
how loudly the new skill speaks over the frozen base

What is that α/r factor? is a fixed constant that scales the detour’s contribution; dividing by r keeps the scale steady as you change rank, so you can retune r without re-tuning everything else. The LoRA authors set α to the first r they tried and never touched it again, noting it behaves almost exactly like a learning-rate scale. It’s the adapter’s volume knob: how loudly the new skill speaks over the base.

the α/r scale is the adapter’s volume knob — the LoRA authors set α once and treated it like a learning rate, never re-tuned
deep dive: attaching the detour

Why B = 0 and not A = 0. Zeroing either matrix makes B·A = 0, so the no-op start works both ways — B = 0 is the paper’s convention. With A holding real Gaussian values, B receives a nonzero gradient on the very first step, so the detour starts learning immediately; zero both and every gradient into the adapter vanishes with them.

Dropout on the ramp. Practical LoRA adds a small dropout on the detour’s input (the lora_dropout knob, typically 0.05–0.1). With so few trainable parameters carrying the whole skill, a little noise on the bypass is cheap insurance against memorizing the fine-tuning set.

Parallel is the load-bearing choice. The detour sits beside the frozen matrix and joins by addition — not in sequence after it. That placement is exactly what makes chapter 06 possible: a parallel branch can be folded into W₀ as one matrix, while a sequential module is stuck in the forward path forever, which is the latency tax the 2019 adapters paid.

Beyond attention. Anything that is a linear map can carry a detour: the MLP projections, the token embeddings, the LM head. The LoRA paper stuck to attention for its studies; later practice (QLoRA among others) found that spreading small ramps across more matrices usually beats concentrating rank in a few.

rsLoRA’s correction. The α/r scale over-shrinks the detour as r grows, which is one reason cranking rank often disappoints. rsLoRA rescales to α/√r, keeping the update’s magnitude stable at higher ranks — a one-line change that matters mostly above r ≈ 32.

04

Only the detour learns

Run one training step. The loss, if it had its way, would change the whole model — but the gradient is only allowed to land on two skinny matrices per detour. Watch where the memory goes: the optimizer’s 128 GB ledger collapses to 67 MB, the job fits a GPU you can buy retail, and the adapter replicates across all 32 layers to its full 4,194,304 numbers.

STEP 01 / 04
THE GRADIENT HITS A FROZEN WALL
the backward pass — the gradient may flow anywhere, but land almost nowhere
← earlier layers
W₀ · 🔒
no gradient stored
AΔBΔupdated
loss ⚡
through W₀: flows through, unchanged · at A/B: lands

computes, for every parameter, how it should change to lower the loss. In LoRA, W₀ is marked frozen: gradients flow through it to reach earlier layers, but none are stored for it, and it is never updated. The only weights that move are A and B — two skinny matrices per detour. The frozen ocean feels the current pass through it and stays exactly where it is.

gradients pass through the frozen weights but none are stored for them — only A and B are ever updated
STEP 02 / 04
THE OPTIMIZER STATE COLLAPSES
the same fine-tune, two memory bills
full fine-tune≈ 128 GB
weights 16
grads 16
Adam states 96
LoRA≈ 16 GB
frozen 16
↳ the hairline is the whole optimizer state: 67 MB
states: 128 GB → 67 MB · ~1,900× — the base stays; its optimizer baggage doesn’t

Here is the memory payoff. Adam’s expensive ~16-bytes-per-parameter bookkeeping is only ever paid for trainable parameters. Full fine-tuning: 8.006B × 16 ≈ 128 GB of states. LoRA — the whole adapter’s 4,194,304 numbers: 4,194,304 × 16 ≈ 67 MB. The frozen base still occupies 16 GB for the forward pass, but it needs no gradients, no momentum, no master copy. The optimizer’s ledger just shrank ~1,900×.

optimizer states go from ~128 GB (all 8B) to ~67 MB (4.19M) — a ~1,900× smaller ledger to carry
STEP 03 / 04
IT FITS ON THE GPU YOU HAVE
the same job, cashed out in hardware
H10080 GB
H10080 GB
128 GB · full FTthe datacenter
vs
RTX 409024 GB
~17 GB · LoRA ✓QLoRA: 4-bit base → <10 GB
fine-tuning left the datacenter

Cash it out in hardware. A full 8B fine-tune (~128 GB) needs two 80 GB datacenter GPUs. The same fine-tune as LoRA fits in ~16–18 GB — a single RTX 4090 you can buy retail. squeezes further: quantize the frozen base to 4-bit (~5 GB) and the whole fine-tune runs under ~10 GB. LoRA is why fine-tuning left the datacenter.

full 8B fine-tune: two 80 GB datacenter GPUs — the LoRA version fits one consumer 24 GB card
STEP 04 / 04
MULTIPLY BY THIRTY-TWO LAYERS
32 layers · 2 detours each
the whole adapter, wired through the frozen stack
131,072 × 32 =
4,194,304
trainable
0.052% of 8.006B
~5 in every 10,000

One layer’s detour learns; now instantiate the same pair in all 32 layers. 131,072 per layer × 32 = 4,194,304 trainable numbers — the whole adapter, wired end to end through the frozen stack. That is 0.052% of the model: for every ten thousand weights Llama-3-8B carries, LoRA trains about five. The step runs, the loss falls, and 8,006,464,512 weights haven’t budged.

131,072 × 32 layers = 4,194,304 trainable — 0.052% of the model, ~5 weights in every 10,000
deep dive: what “frozen” buys mechanically

What “frozen” means mechanically. One flag per tensor — requires_grad=False — and autograd stops storing gradients for it. The deeper consequence: the base is read-only in the backward pass, so it can be represented however you like — including quantized to 4-bit — without breaking the gradient math for A and B. That read-only door is exactly the one QLoRA walks through (chapter 06).

The honest caveat. LoRA shrinks optimizer and gradient memory, not activation memory — the forward pass still stores activations that scale with batch size × sequence length, exactly as in full fine-tuning. Gradient checkpointing still earns its keep on long contexts. For the full map of where GPU memory goes, see AI numbers every AI engineer should know.

Why LoRA tolerates hotter learning rates. Full fine-tuning nudges eight billion coupled weights, so a too-large step compounds into catastrophe; LoRA moves a rank-8 patch against a frozen backdrop, and practitioners routinely run it at roughly an order of magnitude higher learning rate than a full fine-tune of the same model.

LoRA+. The two matrices aren’t symmetric: A starts random and B starts at zero, and giving B a larger learning rate than A (rather than one shared rate) trains faster and slightly better — a 2024 refinement known as LoRA+.

05

How low can the rank go?

r is the one dial that sets the adapter’s size: parameters scale linearly with it, so every halving of rank halves the file. Turn it down, then — where does quality finally break? The LoRA authors ran that experiment on the biggest model of their day, and the answer embarrassed everyone who assumed bigger updates must know more.

STEP 01 / 04
RANK ONE STILL WORKS
the rank dial — every rung tried on GPT-3 175B
r=1
524,288
r=2
1,048,576
r=4
2,097,152
r=8
4,194,304
r=64
33,554,432
A
Bwaist r=1
task quality vs full fine-tuning~86%
│ full FT — near-flat from r=1 onward

The LoRA paper turned the dial to the floor. On GPT-3 175B, a rank of one — a single direction through the waist — for both the query and value projections matched or nearly matched full fine-tuning: 73.4% on WikiSQL, 91.3% on MNLI, within a point of the full-rank result. One direction, against a 175-billion-parameter model. The intrinsic-dimension hunch from chapter 01 wasn’t hand-waving; the numbers backed it hard.

rank 1 — a single direction — nearly matched full fine-tuning of GPT-3 175B (91.3% MNLI) (Hu et al. 2021)
STEP 02 / 04
THE r=64 ADAPTER IS MOSTLY r=8
the subspaces learned at r=8 and r=64, overlaid
top 8 — both adapters agreer=64’s extra 56 ≈ noise
more rank ≈ more noise

Why doesn’t more rank help much? The paper compared the subspaces learned at r=8 and r=64 and found their top singular directions almost identical — the extra 56 directions of the bigger adapter are largely noise the base never needed. Turning r up past a handful mostly buys parameters, not skill. The floor is low because the ceiling is too.

the top directions of an r=64 adapter and an r=8 adapter nearly coincide — the extra 56 are mostly noise
STEP 03 / 04
WHAT THE DETOUR AMPLIFIES
what ΔW actually does to the frozen features
frozen W · latent
→ + ΔW →
after the adapter
latent skill, turned up — not a new one invented

LoRA isn’t teaching the model random new tricks; it is turning up features the base already has but under-uses. The paper measured it: the update ΔW amplifies specific directions of the frozen W by a factor of about 21× — directions present in the pretrained weights but not emphasized there. Adaptation is mostly re-weighting latent skills, which is exactly why a few directions suffice.

the adapter amplifies directions already latent in the frozen weights by ~21× — it re-weights skills, doesn’t invent them
STEP 04 / 04
THE RANK YOU ACTUALLY PICK
the entire fine-tune, specified
··· ADAPTER CONFIG · r=8 ···
rank r·············8
alpha·············16
targets·············q_proj, o_proj
trainable·············4,194,304
size on disk·············8.4 MB
everything else: frozen
the whole adapter on a recipe card

In practice r is 8–64, α around 2r, adapting the attention projections — a few million parameters, a few megabytes, an afternoon on one GPU. Bigger r for harder skills far from the base; small r for nudging tone. The dial rarely needs to go high, and the cheap first experiment is almost always r=8. Our run holds there: r=8, alpha=16, targets q_proj and o_proj — 4,194,304 numbers. Time to make it permanent.

typical LoRA: r=8–64, α≈2r, a few MB, an afternoon on one GPU — and r=8 is a strong default
deep dive: the rank frontier

Choosing r by task distance. The closer the new skill sits to what the base already does, the lower the rank it needs. Tone and format live happily at r=4–8, domain vocabulary at r=16–32, genuinely new reasoning patterns push toward r=64 and beyond — and past that, full fine-tuning starts to earn its cost back.

α/r vs α/√r. The original α/r scale shrinks each direction’s contribution as rank grows, which can starve high-rank adapters. rsLoRA rescales to α/√r, keeping per-direction magnitude stable — a one-line change that mainly matters when you do turn the dial up.

Spread beats depth. A counterintuitive result from the paper: with a fixed parameter budget, adapting more weight matrices at low rank beats adapting fewer at high rank — r=2 across four projection types outperformed r=8 concentrated in one. Coverage of the network matters more than capacity per matrix.

Below the megabyte. VeRA shares one pair of frozen random matrices across all layers and trains only tiny per-layer scaling vectors — kilobyte-scale adapters. DoRA splits each update into a magnitude and a direction and learns them separately, buying back some full-fine-tuning behavior at LoRA prices.

Where LoRA loses. Large domain shifts — a new language, continued pretraining on billions of tokens, heavy code or math injection — can genuinely need more directions than any small r provides. The gap shows up as LoRA plateauing while full fine-tuning keeps improving.

Rank as regularizer. Read the dial the other way: a low r doesn’t just cap capacity, it constrains the update to a small subspace, which resists overfitting and catastrophic forgetting. Part of why r=8 “just works” is that it can’t wander far enough to break things.

06

Fold the detour back, pay zero latency

The adapter is trained. Now the bill comes due — or rather, doesn’t. At inference, does the extra detour cost speed? And when ten customers each have their own 8.4 MB personality, how does one frozen base serve them all at once? The answer to the first question is a fold; the answer to the second is the reason LoRA took over serving.

STEP 01 / 04
B·A FOLDS INTO W
merge once, offline: W′ = W₀ + (α/r)·B·A
W₀ · 8,006,464,512 · 🔒
Ar=8B+
the trainable detour, still parallel

The detour was always parallel to W₀ and joined by addition, which means it can be folded in: compute W′ = W₀ + (α/r)·B·A once, offline, and you get a single 4096×4096 matrix identical in shape to the original. The model has no adapter, no branch, no extra multiply — it is just a normal Llama with slightly different weights. This is LoRA’s signature move: an adapter that vanishes at inference.

merge once: W′ = W₀ + (α/r)·BA — the detour disappears into a normal weight matrix of the same shape
STEP 02 / 04
ZERO ADDED LATENCY, UNLIKE ADAPTERS
inference latency, per request — where the adapter generations differ
base model
baseline
sequential adapter
+Δ every request
merged LoRA
+0 ms
the skill was paid for at training time

This is LoRA’s edge over the adapter modules that came before it. Classic adapters insert extra layers that run in sequence, adding real inference latency — measurably worse at the small batch sizes serving actually uses. A merged LoRA adds exactly zero: same matrix dimensions, same FLOPs, same speed as the base model. You paid for the new skill entirely at training time.

merged LoRA adds 0 inference latency — the sequential adapters it replaced added measurable slowdown at serving batch sizes
STEP 03 / 04
OR DON’T MERGE: HOT-SWAP INSTEAD
one frozen base, a catalog of personalities
voice
legal
de
SQL
BASE · 16 GB · 🔒socket:
output: base model, no persona
adapters resident: 1000s · up to 4× naive throughput (S-LoRA)

Merging bakes one skill in. The opposite move is more powerful: keep the base frozen in GPU memory once, and 8.4 MB adapters per request — support voice, legal voice, German, SQL — each snapping onto the same 16 GB base. S-LoRA serves thousands of concurrent adapters from a single base on one GPU, batching different customers’ adapters together, up to 4× the throughput of naive serving. One model, a whole catalog of personalities.

S-LoRA serves thousands of adapters off one frozen base on a single GPU — you swap 8.4 MB, not 16 GB (2023)
STEP 04 / 04
4-BIT BASE, 65-BILLION-PARAMETER FINE-TUNE
QLoRA: compress the read-only base, keep the detour sharp
4-bit NF4 · 🔒
AB
fp16 · LoRA trains here
base weights: 16 GB → ~5 GB · dashed outline = what fp16 needed
full 16-bit fine-tune, 65B: >780 GBQLoRA: <48 GB
one 48 GB GPU · Guanaco: 99.3% of ChatGPT after 24 h

The frozen base is read-only during LoRA training, so it can be compressed hard without breaking the math. QLoRA quantizes it to 4-bit and back-props through it into the adapter, cutting the memory to fine-tune a 65-billion-parameter model from over 780 GB to under 48 GB — one GPU. Their Guanaco model reached 99.3% of ChatGPT’s Vicuna-benchmark score after 24 hours of fine-tuning on a single card. LoRA shrank the update; QLoRA shrank the frozen base underneath it.

QLoRA fine-tunes a 65B model on one 48 GB GPU (from >780 GB) — Guanaco hit 99.3% of ChatGPT in 24h (2023)
deep dive: merge or serve

When not to merge. Merging is for single-skill deploys. Multi-tenant serving, rapid iteration, and A/B-testing all want the base kept swappable — one resident model, adapters loaded per request — so the 8.4 MB file stays a file. Merging also destroys the clean rollback story: un-merging means subtracting B·A back out.

Merge drift. The fold is exact in math but not in floats: adding (α/r)·B·A into fp16 weights introduces tiny rounding differences, so a merged and an unmerged model can disagree in the last decimal places. Harmless in practice — but it is why bit-exact regression suites compare against one serving mode, not both.

Stacking LoRAs. Because adapters are additive, several can be summed or weight-averaged into one base — a style LoRA plus a language LoRA often composes surprisingly well. It breaks when the adapters fight over the same directions: interference grows with overlap, and three adapters trained on similar data can compose into nonsense.

The Stable Diffusion bazaar. The loudest proof that swapping is cheap: image-model communities trade hundreds of thousands of downloadable style and character LoRAs, megabytes each, layered and re-weighted onto multi-gigabyte checkpoints at load time — model skill as a shareable file format.

Serving stacks. S-LoRA keeps all adapters in host RAM and pages the active ones onto the GPU, batching requests that use different adapters through custom kernels; Punica’s SGMV kernel and vLLM’s multi-LoRA mode are the same idea in production form. Thousands of resident personalities per GPU is now table stakes.

QLoRA, one level down. Three tricks make the 4-bit base work. First, 4-bit NormalFloat, a data type whose quantiles match normally-distributed weights. Then double quantization, which quantizes the block-scale constants themselves and claws back ~0.37 bits per parameter; and paged optimizers, which spill optimizer state to CPU RAM on memory spikes instead of crashing the run.

Σ

The 8.4-megabyte skill

The whole tutorial on one balance sheet. Eight billion weights were identified, weighed, and never touched; four million new ones — five in every ten thousand — carried the entire skill, then folded back into the base or snapped on per request.

FROZEN🔒
8,006,464,512
weights · 16 GB @ fp16
gradients stored: none
optimizer states: none
updates received: zero, ever
TRAINED▣ 8.4 MB
00 copy · base frozen·······················0
02 split · W_q factored·······················65,536
03 detour · + W_o wired·······················131,072
04 step · × 32 layers·······················4,194,304
W′ = Wfrozen + (α/r)·B·A— merged: zero added latency · unmerged: hot-swap 8.4 MB
copy 0hunch 0split 65,536detour 131,072step 4.19Mdial 4.19Mmerge 4.19M
BASE · 16 GB · 🔒
supportlegaldeSQL
8.4 MB each

SAVED adapter.safetensors · base untouched