Part IV Β· Ch. 17 β€” LoRA

Part IV Β· Chapter 17 of 20

LoRA

Teaching a giant model new tricks by training 1% of it


The price of a tweak

Chapter 16 ended with a tempting recipe. Want a radar-systems tutor instead of a generic assistant? Fine-tune it: keep training the model on your own examples. It sounds cheap β€” a little extra practice on top of a finished model. Now do the accounting the recipe quietly skipped. A mid-size open model holds about 7 billion learned numbers, and full fine-tuning nudges every single one of them.

Here is the bill, in three plain lines:

  • Memory. Every trainable weight needs its own gradient β€” the backward blame signal from Chapter 14 β€” plus the optimizer's running bookkeeping for each weight. The training footprint balloons to several times the size of the model itself.
  • Storage. The result of your fine-tune is a complete second copy of all 7 billion numbers β€” roughly 14 GB at standard 16-bit storage. That is one full copy per project, per experiment.
  • Hardware. This is rack-of-GPUs territory, not laptop territory.

Fine-tuning for a narrow job β€” a tone, a format, a specialty β€” feels like it should be a small change. So here is the question the rest of this chapter answers: is there a way to make the change literally small β€” to write it down in far fewer numbers than the model itself? There is. It is called LoRA, low-rank adaptation, and by the last paragraph its one formula will read like arithmetic.

Don't rewrite β€” learn the change

One move unlocks everything: fine-tuning never needs to replace a weight grid β€” it can learn a correction that gets added on. Pick any one grid $\mathbf{W}$ in the model (one attention lens from Chapter 10, say). After fine-tuning it has become some new grid $\mathbf{W}'$ β€” read that "W-prime, the updated grid" β€” and we can always write the update as the old grid plus a grid of changes. Writing $\Delta$ for that change (the Greek letter delta, the traditional symbol for "a change"):

$$\mathbf{W}' = \mathbf{W} + \Delta\mathbf{W}$$

In words: the new grid is the old grid plus a grid of changes, added cell by cell.

And adding two grids is a move you already own. We have added vectors component by component since Chapter 1; adding two grids is the same move β€” matching cells add.

On its own, though, this reframe saves nothing, and honesty demands we say so. The change $\Delta\mathbf{W}$ has exactly as many cells as $\mathbf{W}$ β€” a million-cell grid still needs a million-cell correction. Writing the update as "old plus change" only pays off if the change can be described more cheaply than the original. So the real question becomes: how complicated is the change that fine-tuning actually needs?

Picture what you do when you personalize a textbook. You don't reprint the book β€” you write in the margins. The book (billions of numbers, the pretrained $\mathbf{W}$) stays exactly as it was; your notes are tiny, because what you add is narrow and consistent. LoRA is the mathematical version of writing in the margins β€” and "how complicated is a change" turns out to have a precise mathematical name: rank.

Rank: how complicated is a change?

Picture before symbols. Chapter 3 taught that a $2\times 2$ grid takes in any arrow on the plane and hands back another arrow β€” and in general its outputs can land anywhere on the plane. Now meet a grid that can't. Here is the chapter's toy change-grid, $\begin{bmatrix} 6 & 2 \\ 3 & 1 \end{bmatrix}$, and we'll feed it three inputs by Chapter 3's recipe (each output column is a column of the grid; a general input has the rows dot it):

  • Feed it $\begin{bmatrix} 1 \\ 0 \end{bmatrix}$: out comes the first column, $\begin{bmatrix} 6 \\ 3 \end{bmatrix}$.
  • Feed it $\begin{bmatrix} 0 \\ 1 \end{bmatrix}$: out comes the second column, $\begin{bmatrix} 2 \\ 1 \end{bmatrix}$.
  • Feed it $\begin{bmatrix} 1 \\ 1 \end{bmatrix}$: the rows dot the input β€” $6+2 = 8$ on top, $3+1 = 4$ below β€” out comes $\begin{bmatrix} 8 \\ 4 \end{bmatrix}$.

Now look at the three answers together: $[6, 3]$, $[2, 1]$, $[8, 4]$. Every one of them lies on the same line through the origin β€” the line of the direction $[2, 1]$. Each is just some number of copies of $[2, 1]$: three copies, one copy, four copies. And this is true for every possible input. This grid's whole world of outputs is one single line.

A quadrant plot. Three thin blue input arrows leave the origin to (1,0), (0,1) and (1,1), labeled in [1,0], in [0,1], in [1,1]. Three thicker amber output arrows also leave the origin, to (2,1), (6,3) and (8,4), labeled out [2,1], out [6,3], out [8,4]. A mint dashed line runs from the origin through the direction [2,1], and all three amber arrowheads sit exactly on it. An annotation reads: every output lands on this one line β€” rank 1.
A grid that only knows one direction. The change-grid $\begin{bmatrix} 6 & 2 \\ 3 & 1 \end{bmatrix}$ sends $[1, 0] \to [6, 3]$, $[0, 1] \to [2, 1]$, and $[1, 1] \to [8, 4]$ β€” three different inputs, and every answer is some number of copies of $[2, 1]$. Its whole world of outputs is one line: rank 1, the simplest possible change.

That is the idea we needed a name for. The rank of a grid is how many independent directions its outputs can span. A generic $2\times 2$ grid fills the plane: rank 2. Our toy only ever draws one line: rank 1 β€” the simplest possible non-zero change. Low rank means a change with few independent moves in it. The grid still holds four numbers; it is the behavior that is simple.

And here is the secret that makes rank useful: a rank-1 grid factors. It is a skinny column times a flat row.

$$\Delta\mathbf{W} = \begin{bmatrix} 6 & 2 \\ 3 & 1 \end{bmatrix} = \underbrace{\begin{bmatrix} 2 \\ 1 \end{bmatrix}}_{\mathbf{B}} \underbrace{\begin{bmatrix} 3 & 1 \end{bmatrix}}_{\mathbf{A}}$$

In words: the whole change-grid is one column, $\mathbf{B} = [2, 1]$ standing up, multiplied by one row, $\mathbf{A} = [3, 1]$ lying flat.

Check a cell so the product isn't magic β€” grid times grid is rows-dotting-columns from Chapter 3. Cell in row 1, column 1 is $2\times 3 = 6$; cell in row 2, column 2 is $1\times 1 = 1$. (The other two are yours to verify.) These two factors keep their names all chapter: $\mathbf{B}$, the column, $d$ numbers tall, and $\mathbf{A}$, the row, $d$ numbers wide.

Now watch why the factored form is stuck on one line β€” the bottleneck, worked with the chapter's spine numbers. Take the input $[1, 1]$. The row $\mathbf{A}$ hits it first and squashes it to a single number; then the column $\mathbf{B}$ stretches that number back into an arrow:

$$\mathbf{A}\begin{bmatrix} 1 \\ 1 \end{bmatrix} = 3 \times 1 + 1 \times 1 = 4 \qquad \mathbf{B} \cdot 4 = \begin{bmatrix} 8 \\ 4 \end{bmatrix}$$

In words: $\mathbf{A}$ squashes the whole input down to a single number, and $\mathbf{B}$ turns that number into some amount of one fixed direction. Everything must squeeze through a one-number bottleneck β€” and that is why every output sits on one line.

Want a slightly richer change? Give the bottleneck more lanes. Let $r$ numbers pass through instead of 1: $\mathbf{B}$ becomes $d \times r$ (that many skinny columns), $\mathbf{A}$ becomes $r \times d$ (that many flat rows), and now the outputs can span up to $r$ independent directions. That dial $r$ β€” "r, the rank you choose" β€” is LoRA's central knob: 1, 4, 8, 64… always tiny next to $d$.

The LoRA move: a skinny detour

Now assemble the method in one breath, then spend the section proving it works. Freeze the pretrained grid $\mathbf{W}$ β€” training never touches it again. Bolt a detour onto it: the input also flows through $\mathbf{A}$ (down to $r$ numbers), then through $\mathbf{B}$ (back up to full size), and that detour's answer β€” scaled by a volume knob β€” is added onto $\mathbf{W}$'s answer. Train only $\mathbf{B}$ and $\mathbf{A}$.

A left-to-right diagram. An input chip x splits into two paths. The upper path enters a large violet box labeled W with a padlock, captioned pretrained β€” frozen, never trained again. The lower path enters a small mint box A (squash to r numbers), narrows through a pinched bottleneck labeled r, enters a small mint box B (stretch back up), passes an ×α⁄r label, then rises. Both paths meet at a plus junction and continue to an output chip. A mint label over the lower path reads: trained β€” the only moving parts. A note below reads: B starts all-zero, so training begins at exactly the pretrained behavior.
The LoRA move. The input flows through the frozen pretrained grid $\mathbf{W}$ (violet, padlocked) as always β€” and through a skinny trained detour: $\mathbf{A}$ squashes it down to $r$ numbers, $\mathbf{B}$ stretches it back up, $\alpha/r$ sets the volume, and the $\oplus$ adds the detour's answer on. Training moves only the mint parts. Because $\mathbf{B}$ starts at zero, day one of fine-tuning behaves exactly like the base model.

Here is the formula, with every symbol re-introduced in words. The rank you chose is $r$, and $\alpha$ β€” "alpha, the LoRA scale" β€” is a volume knob for how loudly the detour speaks:

$$\mathbf{W}' = \mathbf{W} + \frac{\alpha}{r}\,\mathbf{B}\mathbf{A}$$

In words: the working grid is the frozen grid plus alpha-over-r times the learned detour.

Why divide by $r$? One honest sentence: if you later double the rank, the product $\mathbf{B}\mathbf{A}$ picks up roughly twice as many contributions, so dividing by $r$ keeps the detour's overall volume comparable β€” and your other settings survive a change of rank.

Worked example

Every digit, on the chapter's full toy. The frozen grid is a plain doubling machine from Chapter 3's family, $\mathbf{W} = \begin{bmatrix} 2 & 0 \\ 0 & 2 \end{bmatrix}$; our column and row are $\mathbf{B} = [2, 1]$ and $\mathbf{A} = [3, 1]$ from the last section; and we set $\alpha = 2$, $r = 1$, so $\alpha/r = 2$. Push $\mathbf{x} = \begin{bmatrix} 1 \\ 1 \end{bmatrix}$ through the detour route and add:

  • Frozen path: $\mathbf{W}\mathbf{x} = \begin{bmatrix} 2 \\ 2 \end{bmatrix}$.
  • Detour path: $\mathbf{A}\mathbf{x} = 4$, then $\mathbf{B}\cdot 4 = \begin{bmatrix} 8 \\ 4 \end{bmatrix}$, then scaled by 2 to $\begin{bmatrix} 16 \\ 8 \end{bmatrix}$.
  • Add them: $\begin{bmatrix} 2 \\ 2 \end{bmatrix} + \begin{bmatrix} 16 \\ 8 \end{bmatrix} = \begin{bmatrix} 18 \\ 10 \end{bmatrix}$.

Now the payoff. Instead of running the detour live, pre-add the two grids once β€” $\mathbf{W}' = \mathbf{W} + 2\cdot\mathbf{B}\mathbf{A}$, where $2\cdot\mathbf{B}\mathbf{A} = \begin{bmatrix} 12 & 4 \\ 6 & 2 \end{bmatrix}$ β€” and push the same input through the single merged grid:

$$\mathbf{W}' = \begin{bmatrix} 2 & 0 \\ 0 & 2 \end{bmatrix} + 2\begin{bmatrix} 6 & 2 \\ 3 & 1 \end{bmatrix} = \begin{bmatrix} 14 & 4 \\ 6 & 4 \end{bmatrix} \qquad \mathbf{W}'\begin{bmatrix} 1 \\ 1 \end{bmatrix} = \begin{bmatrix} 18 \\ 10 \end{bmatrix}$$

In words: you can run the detour live, or fold it into the grid once and throw the scaffolding away β€” the merged grid gives identical outputs, $[18, 10]$ both ways.

That equality is why a merged LoRA costs nothing extra at inference: once you have added the detour into $\mathbf{W}$, the model is just… a model.

One detail practitioners rely on, and it is elegant. At the very start of training, $\mathbf{B}$ is set to all zeros β€” so $\mathbf{B}\mathbf{A} = 0$, the change $\Delta\mathbf{W}$ is zero, and the fine-tune begins exactly at the pretrained model's behavior. Training then grows the change outward from "no change at all." Chapter 13's downhill walk starts from the best base camp there is.

A closing note on our toy's volume, because it matters. Our detour shouts: it changes the doubler's output from $[2, 2]$ to $[18, 10]$. That is on purpose β€” every digit stays visible. Real fine-tuning updates are gentle nudges, not shouts. And, pleasingly, our knob is honest anyway: $\alpha = 2$ with $r = 1$ gives a multiplier of 2, and the field's everyday default of $\alpha = 16$ with $r = 8$ gives… the same 2.

Why so little is enough

A careful reader should be uneasy right now. A rank-1 change only draws a line β€” surely a real fine-tune needs the full plane (well, the full 4,096-dimensional space)? The empirical answer, honestly attributed: the 2021 paper that introduced LoRA (Microsoft researchers) found that for adapting a big pretrained model, ranks as small as 1 to 8 matched full fine-tuning on many tasks. Not "almost as good on a budget" β€” matched.

The intuition for why, in this site's own language: a fine-tune for a narrow job is a consistent, repeated adjustment. "Lean the outputs toward radar-systems vocabulary." "Always answer in the house format." The same few directions of change, applied across many different situations β€” and that is precisely what a low-rank grid is: a few directions, applied everywhere. The pretraining already built the library (Chapter 15); the fine-tune is margin notes, and margin notes are low-rank.

Say the limit out loud, because this is a bet, not a law. Low rank fits changes of style, format, tone, and light specialization. Teaching the model a genuinely new body of knowledge β€” a language it never saw, a private field of facts β€” is not a few consistent directions, and low rank can genuinely fall short there. Then you crank $r$ up, or full fine-tune, or don't put facts in the weights at all (retrieval, two chapters ahead). A method's honest boundary is part of understanding it.

Counting the savings

Now the arithmetic that made LoRA famous, on one honest mid-size grid: a $d \times d$ weight grid with $d = 1{,}000$. A full change $\Delta\mathbf{W}$ is $1{,}000 \times 1{,}000 = 1{,}000{,}000$ numbers. LoRA at $r = 8$ replaces it with two slivers: $\mathbf{B}$ is $1{,}000 \times 8 = 8{,}000$ numbers, $\mathbf{A}$ is $8 \times 1{,}000 = 8{,}000$ numbers β€” 16,000 in all.

$$\underbrace{1{,}000 \times 1{,}000}_{\text{full } \Delta\mathbf{W}} = 1{,}000{,}000 \qquad \text{vs} \qquad \underbrace{(1{,}000 \times 8)}_{\mathbf{B}} + \underbrace{(8 \times 1{,}000)}_{\mathbf{A}} = 16{,}000$$

In words: sixteen thousand trainable numbers stand in for a million β€” 1.6 percent.

Left: a large violet square filled with a faint lattice, labeled Ξ”W β€” 1,000 Γ— 1,000, 1,000,000 numbers. A large 'vs'. Right: two thin mint slivers drawn to true scale forming an L β€” a tall one labeled B β€” 1,000 Γ— 8 and a flat one labeled A β€” 8 Γ— 1,000 β€” with a dashed zoom-inset circle magnifying the tall sliver Γ—40 so it is visible. Beneath: 8,000 + 8,000 = 16,000 numbers, = 1.6% of the square.
The whole argument, to scale. A full change to a $1{,}000 \times 1{,}000$ grid is the violet square: one million numbers. LoRA's rank-8 detour is the two mint slivers β€” $\mathbf{B}$ and $\mathbf{A}$, 16,000 numbers, 1.6% β€” drawn here at true scale (with a zoom inset so you can find them at all). That sliver is what your GPU trains and what your fine-tune saves to disk.

Scale that to a real model. In practice you attach detours to a subset of grids β€” classically the attention lenses $\mathbf{W}_Q$ and $\mathbf{W}_V$ (Chapter 10's violet grids) in every layer β€” and a 7-billion-parameter model ends up with a few million trainable numbers: well under 1% of the model. The saved training memory β€” no gradients, no optimizer bookkeeping for the frozen 99%-and-then-some β€” is exactly what moves fine-tuning off a rack of data-center GPUs and onto one consumer graphics card.

And the storage win becomes a workflow win. Your finished fine-tune is just $\mathbf{B}$ and $\mathbf{A}$ for each adapted grid β€” an adapter β€” a file measured in megabytes, riding on a base model measured in gigabytes. Keep a shelf of them: a radar-systems tutor, a contract summarizer, a pirate-speak toy β€” one frozen base model, many cheap personalities.

A large violet box labeled W β€” base model, 7 billion numbers, frozen, ~14 GB, with a padlock and a small slot cut into its right edge. Three mint-bordered chips float to the right β€” radar systems tutor Β· 8 MB, contract summarizer Β· 8 MB, pirate speak Β· 8 MB β€” and the top one is docking into the slot, a mint arrow pointing it in. A caption reads: swap in milliseconds β€” or merge: W + (α⁄r)BA becomes one grid, and the slot disappears.
One frozen base model, a shelf of cheap personalities. Each adapter is just the trained $\mathbf{B}$ and $\mathbf{A}$ grids β€” megabytes riding on gigabytes β€” so you can keep many, swap them per request, or fold a favorite into $\mathbf{W}$ permanently. This is how a single shared model serves a thousand different fine-tunes. (Sizes are typical, not exact.)

That leaves one honest choice at serving time. Either run the detour live β€” a tiny bit of extra arithmetic per token, and adapters can be hot-swapped between requests, which is how one provider serves thousands of customers' fine-tunes on shared hardware β€” or merge, folding $\frac{\alpha}{r}\mathbf{B}\mathbf{A}$ into $\mathbf{W}$ once (exactly as our worked example proved is lossless) for zero added cost, at the price of baking that one personality in.

See it move

You've built this on paper; now watch it move. The video takes the change-grid $\begin{bmatrix} 6 & 2 \\ 3 & 1 \end{bmatrix}$, eats three different inputs, and drops every answer on one line; splits the grid into a column times a row; and shrinks a million-number square down to two 16,000-number slivers β€” the very same numbers as this chapter.

Watch (1:59): what to notice β€” every one of the three amber outputs landing on the single mint line, the grid splitting into $\mathbf{B}$ times $\mathbf{A}$ with a one-number bottleneck between them, and the million-number square collapsing to two hairline slivers.

Why the LLM cares

Here is where this shows up in the wild. When you hear "I fine-tuned a 7B model on my gaming PC overnight," you are hearing LoRA (or a close cousin). When an API offers cheap fine-tunes with instant switching between them, you are hearing adapters being hot-swapped on a shared base model. This one technique is a large part of why customized models went from a corporate luxury to a hobbyist weekend.

Tie it back to the machine we built. Chapter 11 said everything a model knows lives in how its violet grids transform vectors. LoRA is surgical editing of that behavior β€” a few learned directions added to chosen grids β€” without disturbing the library underneath. It is the gentlest possible answer to "change what the machine does."

One beat of breadth, names only: the same trick escaped LLMs entirely. Image-generation models take LoRA adapters too β€” an adapter that draws in your art style is a few megabytes riding a frozen giant β€” and "parameter-efficient fine-tuning" is now a whole family of methods, of which LoRA is the famous member.

You can now decode a sentence like "a rank-16 LoRA on the attention layers, alpha 32" the way you decode arithmetic β€” and you know exactly which numbers move, which stay frozen, and why the file is small.

What you now know

  • Fine-tuning never has to rewrite a weight grid β€” it can learn a change added on top, $\mathbf{W}' = \mathbf{W} + \Delta\mathbf{W}$, and the whole game is describing that change cheaply.
  • Rank measures how complicated a change is: our toy grid $\begin{bmatrix} 6 & 2 \\ 3 & 1 \end{bmatrix}$ sends every input onto the single line of direction $[2, 1]$ β€” rank 1 β€” because it secretly factors into a column times a row, $\mathbf{B}\mathbf{A}$, with a one-number bottleneck between them.
  • LoRA freezes $\mathbf{W}$ and trains only the skinny detour, $\mathbf{W}' = \mathbf{W} + \frac{\alpha}{r}\mathbf{B}\mathbf{A}$, where $r$ is the bottleneck width you choose and $\alpha$ is a volume knob; $\mathbf{B}$ starts at zero so training begins exactly at the pretrained behavior.
  • The detour can run live or be merged β€” our toy's bypass ($[2, 2] + 2\cdot[8, 4]$) and merged grid $\begin{bmatrix} 14 & 4 \\ 6 & 4 \end{bmatrix}$ both send $[1, 1]$ to $[18, 10]$ β€” which is why a merged LoRA adds zero inference cost.
  • The arithmetic that changed the industry: a $1{,}000 \times 1{,}000$ change is $1{,}000{,}000$ numbers, but rank-8 $\mathbf{B}$ and $\mathbf{A}$ are 16,000 β€” about 1.6%, and under 1% on a full model β€” small enough for one consumer GPU and an adapter file of megabytes.
  • Low rank fits narrow, consistent changes (style, format, specialization) and genuinely can fall short for whole new bodies of knowledge β€” for fresh facts, retrieval (Chapter 19) is the honest tool.

Where we're headed. Your model is trained, tuned, and wearing exactly the personality you gave it β€” and now it has to actually run. Every word you generate re-awakens the whole tower from Chapter 11, and served naively, the machine would redo mountains of work it finished one token ago. Next chapter is the engineering of running: why the first word of a reply takes longest, the clever cache that remembers every key and value so attention never computes the same thing twice, what a context window really is β€” and how a weight like 0.34 survives being squeezed into four bits so the whole model fits on a phone.