4.3.8 · D4Pretraining & Fine-Tuning LLMs

Exercises — LoRA and QLoRA

2,573 words12 min readBack to topic

This page is your self-test for LoRA and QLoRA. Cover the solution, try the problem cold, then reveal. Difficulty climbs from "do you recognize the idea?" to "can you design with it?".

Every symbol below is built in the parent note. Quick reminder of the cast so you never have to leave this page:


Level 1 — Recognition

L1.1 — Count the parameters

A linear layer has , . You apply LoRA with rank . (a) How many parameters does full fine-tuning update for this matrix? (b) How many does LoRA train? (c) What is the reduction factor?

Recall Solution

(a) Full update is the same shape as : M. (b) LoRA trains () plus (): . (c) . A 256× reduction. WHAT we did: just plugged into "full = , LoRA = ". WHY: and are the only trainable tensors; the rest is frozen.

L1.2 — Which parts are frozen?

In the LoRA forward pass , state for each of , , : is it frozen or trained, and its initial value.

Recall Solution
Tensor Frozen or trained? Initialization
Frozen (no gradient) pretrained values
Trained random Gaussian
Trained all zeros

Because at the start, , so and the model behaves exactly like the pretrained one on step 0.


Level 2 — Application

L2.1 — Real layer, two projections

A transformer layer has . You apply rank- LoRA to the and projections only (2 matrices). See Attention Q K V Projections. (a) LoRA params per matrix? (b) Total LoRA params? (c) As a percentage of full fine-tuning those two matrices, how much do you train?

Recall Solution

(a) per matrix. (b) Two matrices: . (c) Full for two matrices: M. Ratio — about 0.3%.

L2.2 — The scaling factor

You run with , . (a) What is the effective scale ? (b) You now raise to but forget to change . What is the new scale, and did the update get stronger or weaker? (c) Using the rule of thumb , what should you have chosen for ?

Recall Solution

(a) . (b) New scale . The multiplier dropped from to , so the effective update is halved — weaker. This is the classic "my rank-16 run felt worse" bug. (c) , which restores .

L2.3 — QLoRA base storage

You want to fine-tune a 7B model with QLoRA. The base is stored in 4-bit NF4. (a) How many bytes per parameter is 4-bit? (b) How many GB does the frozen base occupy? (Use bytes.)

Recall Solution

(a) bits bytes per parameter. See Quantization of Neural Networks. (b) bytes GB. That is why a 7B QLoRA fine-tune squeezes onto a consumer GPU.


Level 3 — Analysis

L3.1 — Why can only reach rank

Show that (with , ) can have rank at most , and connect this to why LoRA "restricts" the update. Reference the figure.

Figure — LoRA and QLoRA
Recall Solution

WHAT: the product is a sum of outer products — one per shared index: where is the -th column of (a -vector) and is the -th row of (a -vector). Each outer product is a rank-1 matrix (a single "direction"). WHY at most : a sum of rank-1 matrices has rank . The column space of is spanned by — at most vectors — so . WHAT IT LOOKS LIKE (figure): the full is a fat block; and are thin strips whose product fills the same block but is constrained to lie in an -dimensional column space. We deliberately throw away the ability to represent higher-rank changes — that is the low-rank bet, discussed in Matrix Rank and Low-Rank Approximation.

L3.2 — Break-even rank

For a square matrix , at what rank does LoRA stop saving parameters (i.e. )?

Recall Solution

Set : For LoRA trains at least as many parameters as full fine-tuning — no saving. Interpretation: LoRA only helps when is well below this break-even. In practice , so the saving is enormous. Beyond that you'd be better off just doing full FT.

L3.3 — Where does QLoRA's memory actually go?

List the four memory consumers when fine-tuning and say, for a QLoRA run, which are small and which are large, and why.

Recall Solution
  1. Base weights — LARGE count, but stored 4-bit → compressed (e.g. 3.5 GB for 7B). Frozen.
  2. Optimizer state (Adam: momentum + variance + master copy) — normally the killer at 12 bytes/param. In QLoRA it exists only for , which are tiny → negligible. See Adam Optimizer memory cost.
  3. Gradients — also only for → tiny.
  4. Activations — depend on batch/sequence length, unrelated to LoRA; handled by Paged Optimizers during spikes. Key point: LoRA kills consumers 2 and 3 (they scale with trainable params, not total params); NF4 shrinks consumer 1.

Level 4 — Synthesis

L4.1 — Design a memory budget

You have a 24 GB GPU and want to fine-tune a 7B model. Base (NF4) = 3.5 GB. Activations + overhead ≈ 6 GB. Adam keeps 3 fp32 copies per trainable param (momentum, variance, master = 12 bytes/param). How many trainable LoRA parameters can you afford so total stays under 24 GB? (Ignore the sub-GB gradient term.)

Recall Solution

Budget left for optimizer state: GB bytes. Each trainable param costs bytes of optimizer state: That is astronomically more than any realistic LoRA config needs (typically tens of millions), so you are nowhere near the limit — activations, not adapters, dominate. This is exactly why QLoRA fits a 7B on 24 GB with room to spare.

L4.2 — Merge vs serve-many

You trained 3 different LoRA adapters (one per task) on the same base. (a) If you serve one task, what should you do at inference to get zero added latency, and write the merged weight formula. (b) If you must serve all three tasks live from one model, why can't you merge, and what's the cost?

Recall Solution

(a) Merge the chosen adapter into the base: Now is a single ordinary matrix — the forward pass is identical to the base, zero extra latency. This is LoRA's edge over Adapter Layers. (b) You can't bake three different corrections into one simultaneously — merging is per-adapter. So you keep unmerged and add at runtime per request, paying a small extra matmul (two skinny mults). Trade-off: flexibility (swap adapters per request) vs the merged zero-latency win.

L4.3 — Why NF4 beats int4 here

Explain, using the shape of the weight distribution, why 4-bit NormalFloat places its levels better than uniform int4 for LLM weights.

Recall Solution

Neural-net weights are approximately normally distributed — a bell curve, dense near , sparse in the tails. See the figure.

Figure — LoRA and QLoRA
  • Uniform int4 spaces its levels equally along the axis. Many levels land far out in the tails where almost no weights live — wasted precision — and too few land near where weights cluster → coarse rounding exactly where it matters.
  • NF4 places its levels at the quantiles of the normal distribution: closely packed near , spread out in the tails. Each bin then holds roughly equal probability mass, which is information-theoretically optimal for Gaussian data. Result: lower average quantization error for the same 4 bits, so the frozen base is a more faithful copy of the original.

Level 5 — Mastery

L5.1 — Full QLoRA memory audit

7B model. Apply rank-16 LoRA to all projections across 32 layers, each projection . Adam state = 12 bytes per trainable param. Base NF4 = 0.5 byte/param. (a) Trainable params per projection. (b) Total trainable params (4 projections × 32 layers). (c) Optimizer state size (GB). (d) Base storage (GB). Does it all fit in 16 GB alongside ~6 GB activations?

Recall Solution

(a) per projection. (b) M trainable params. (c) bytes GB. (d) Base: GB. Total GB GB. Yes, it fits comfortably, with headroom.

L5.2 — Compare full FT vs QLoRA optimizer memory

For the same 7B model, full fine-tuning keeps Adam state for all 7B params at 12 bytes each. QLoRA keeps it only for the 16.8M trainable params from L5.1. (a) Full-FT optimizer memory (GB). (b) Ratio of full-FT to QLoRA optimizer memory.

Recall Solution

(a) bytes GB. (This alone won't fit on a single common GPU — the core problem LoRA solves.) (b) From L5.1(c), QLoRA optimizer GB. Ratio . QLoRA uses roughly 400× less optimizer memory.

L5.3 — Why and not ? (design justification)

LoRA sets and random. Suppose you instead set and random. Would training start cleanly? Would the first gradient step be able to move both matrices? Analyze.

Recall Solution

Clean start: either choice gives at step 0 (a zero times anything is zero), so the model starts undisturbed either way. That condition alone doesn't decide it. Gradient flow at step 0 is the deciding factor. The gradient of the loss w.r.t. depends on ; the gradient w.r.t. depends on (product rule through ):

  • With : , so can move immediately; once , also gets gradient. Training unlocks. ✓
  • With : symmetric — , so moves first, then . This also works. Conclusion: both zero-init-one-side schemes start cleanly and unlock. The convention is ; the essential, non-negotiable requirement is that exactly one of them is zero so at start while the non-zero side keeps the gradient path alive. Initializing both to zero would freeze training (both gradients zero forever); initializing both random corrupts the output at step 0.

Recall One-line self-check

Effective LoRA update strength is controlled by which quantity? ::: The ratio , not or alone. Full-FT vs QLoRA optimizer memory for 7B (L5.2)? ::: GB vs GB, roughly .

Related: LoRA and QLoRA · Instruction Tuning · Matrix Rank and Low-Rank Approximation · Quantization of Neural Networks