Phase 05 — PEFT: LoRA, QLoRA & Knowledge Distillation
The phase where adaptation stops being a luxury. Phase 00 taught you that a full fine-tune holds the weights + gradients + optimizer state + activations in memory —
~16 bytes/param, so a 7B model needs~112 GBbefore activations, and a 65B model is hopeless on commodity hardware. This phase is how the industry got around that: don't move the giant weights — freeze them and learn a tiny correction. LoRA, QLoRA, and distillation are the three techniques that turn "fine-tuning needs a cluster" into "fine-tuning needs one GPU and an afternoon."
Why this phase exists
A Senior AI Engineer is asked, constantly: "We need this model to do our task — how?" The naive answer (full fine-tune) is usually wrong on cost, and the lazy answer ("just prompt it harder") is usually wrong on quality. The senior answer is a menu:
- LoRA — freeze
W, learn a rank-rupdateΔW=(α/r)·A·B. You trainr·(d+k)params instead ofd·k— often <1% of the model — and at inference youmerge()the delta back so there is zero added latency. One base, many cheap swappable adapters. - QLoRA — store the frozen base in 4-bit NF4, keep the small LoRA adapters in 16-bit, and you can fine-tune a 65B model on a single 48 GB GPU. The base never trains, so its quantization error never compounds.
- Distillation — when you want a permanently smaller model, train a small student on a big teacher's softened logits. The student inherits the teacher's "dark knowledge" (the relative probabilities of the wrong answers), often matching it at a fraction of the inference cost — which, recall Phase 00, is the bill you pay forever.
These are not interchangeable. LoRA/QLoRA adapt a frozen model cheaply; distillation shrinks one permanently. Knowing which lever a problem wants — and being able to defend it with the param-count and memory math — is the skill this phase installs.
What to recall from earlier phases
- Phase 00 (cost math). Training memory ≈
16 bytes/param(weights + gradients + Adam moments + fp32 master), and inference cost is2N/token paid forever. Both facts are the reason PEFT and distillation exist; this phase is their direct payoff. - Phase 00 (quantization). Weights at
0.5 bytes/param(int4) vs2(fp16) is the difference between two GPUs and one — QLoRA puts that lever under fine-tuning. - Phase 02/03 (the transformer & autograd). You know a block is attention projections
(
q,k,v,o) plus an MLP, and what a gradient/optimizer step costs — PEFT decides which of those weights get gradients at all.
Concept map
┌──────────────────────────────────────────────┐
│ Full fine-tune is too expensive (P00 math): │
│ weights + grads + Adam state ≈ 16 B/param │
└──────────────────────────────────────────────┘
│ │
ADAPT a frozen model SHRINK to a new model
│ │
┌─────────────┴─────────────┐ ▼
▼ ▼ DISTILLATION
LoRA QLoRA teacher → student
ΔW = (α/r)·A·B 4-bit NF4 base softmax(z/T)
A:(d×r) gauss + 16-bit LoRA L = T²·KL(t‖s)
B:(r×k) ZERO ─── start = pretrained + α·CE(s, y)
train r·(d+k) ≪ d·k double-quant "dark knowledge"
│ paged optimizer │
▼ │ ▼
merge() ⇒ 0 latency ▼ smaller N ⇒ less
swappable adapters 65B on one GPU inference cost forever
└──────────────┬───────────┴─────────────────┘
▼
THE PEFT DECISION (recall: inference cost is forever)
which layers? what rank? adapt-and-serve, or distill-and-replace?
The lab
| Lab | You build | Difficulty | Time |
|---|---|---|---|
| lab-01 — LoRA / QLoRA Delta + Distillation | matrix helpers, LoRALinear (zero-init B, delta/merge/forward), param counts, NF4-style blockwise quantize/dequantize with a bounded error, and the distillation kit (softmax_T, stable kl_divergence, distillation_loss = T²·KL + α·CE) | ⭐⭐⭐☆☆ math / ⭐⭐⭐⭐⭐ invariants | 3–4 h |
The lab is a runnable, test-verified miniature — see the lab standard.
Run it red (pytest test_lab.py), make it green, then read solution.py.
Integrated scenario ideas
- Size a LoRA fine-tune: for a 7B model, count the trainable params if you adapt
q,vatr=8across 32 layers; show it is well under 1% and that the optimizer state shrinks by the same factor — the reason it fits one GPU. - Defend QLoRA on a 65B: compute the 4-bit base footprint (
~35 GB) vs the fp16 base (130 GB), add the tiny adapter, and show why one 48 GB GPU now works. - Adapter zoo: one frozen base + 20 task adapters at a few MB each vs 20 full fine-tuned copies; compute the storage and the swap cost.
- Distill, don't scale (Phase 00 callback): a 70B teacher vs a distilled 7B student
at your QPS — compute the perpetual
$/1Mgap and the breakeven volume. - Pick the lever: given "we need 5 niche tasks on shared infra" vs "we need one task served at 50k QPS forever," argue LoRA-zoo vs distillation with numbers.
Deliverables checklist
-
lab.pypassespytest test_lab.py -v(andLAB_MODULE=solutiondoes too). -
You can derive
ΔW=(α/r)·A·Band explain the orientation (A:d×r,B:r×k). -
You can explain why
Bis zero-initialized in one sentence and what breaks if it is not. -
You can compute the LoRA trainable fraction for a given
(d,k,r)in your head. - You can explain QLoRA's three tricks (NF4, double quantization, paged optimizer) and why the base never training is what makes 4-bit safe.
-
You can write the distillation loss from memory and explain
Tand theT²factor.
Key takeaways
- Adapt the update, not the weights. Weight updates during fine-tuning are
empirically low-rank, so a rank-
rA·Bcaptures most of the gain atr·(d+k)params. This is the whole hypothesis behind LoRA — and why it works at all. Bzero-init is the design, not a detail. It makes the adapted model identical to the pretrained one at step 0, so training only ever adds skill from a known-good starting point. Lose this and you start from a randomly corrupted model.- QLoRA decouples storage precision from training precision. The base is frozen, so its 4-bit error is fixed and never compounds; only the high-precision adapters learn. That decoupling is what fits a 65B fine-tune on one GPU.
- Distillation moves capability into a smaller
N. Softened logits carry far more signal than hard labels, so the student learns the teacher's function, not just its answers — and a smallerNis cheaper to serve on every request, forever (P00). - The lever depends on lifetime, not vibes. Many cheap swappable tasks → LoRA zoo. One task served at huge scale → distill and replace. Memory-constrained training → QLoRA. Defend it with the math, not the hype.