Worked examples — Full fine-tuning vs feature extraction
This page is the exercise gym for the parent note. There we built the two anchor strategies. Here we walk every case class the decision can throw at you — tiny data, huge data, domain shift, memory limits, degenerate inputs — and work each one fully.
Before we start, one reminder of the notation so nobody is lost from line one:
The scenario matrix
Every real fine-tuning decision is a combination of a few axes. Think of the matrix below as "all the dials". Each worked example lights up specific cells so that, together, they cover every cell at least once.
| Axis | Extreme A | Middle | Extreme B |
|---|---|---|---|
| Dataset size | tiny (hundreds) | medium (thousands) | huge (100k+) |
| Domain shift vs pretraining | none / close | some | large / "legalese" |
| Trainable params | head only (feat. extr.) | top- layers | everything (full FT) |
| Compute budget | 1 small GPU | 1 big GPU | cluster |
| Degenerate inputs | data or trainable params | LR (no step) | LR huge (overshoot) |
The "degenerate" row is the equivalent of checking every sign and the zero case in a geometry problem: what happens at the boundaries where a formula could blow up or silently do nothing. Its Middle column is not "less degenerate" — it is the intermediate boundary where a step is taken but its size is exactly , sitting between "nothing to train" (left) and "step too big" (right). We hit all three columns in Examples 5–7 and 10.
The picture below is the same matrix as a map — read it top to bottom to pick a strategy:

Coverage map (fill it in as you read):
| Cell | Example |
|---|---|
| Tiny data · close domain · head only | Ex 1 |
| Huge data · big shift · full FT | Ex 2 |
| Medium data · some shift · top- | Ex 3 |
| Memory math (why full FT is heavy) | Ex 4 |
| Degenerate: LR (Middle column) | Ex 5 |
| Degenerate: LR far too large (right) | Ex 6 |
| Degenerate: trainable params (left) | Ex 7 |
| Real-world word problem: serving many tasks | Ex 8 |
| Exam twist: forgetting curve limit | Ex 9 |
| Degenerate: data (left) | Ex 10 |
Example 1 — Tiny data, close domain (head only)
- Count head params. A linear layer from inputs to outputs has a weight matrix of plus one bias per output: Why this step? Trainable-parameter count is our proxy for overfitting risk. on examples is modest — good.
- Precompute embeddings once. Because is frozen, never changes, so run the backbone once per review: forward passes total, cached forever. Why this step? A frozen function of a fixed input is a constant — recomputing it every epoch would be pure waste. This is the Transfer Learning free lunch.
- Train the head fast. Logistic regression on cached -vectors trains in seconds. Why this step? No backward pass through the backbone means near-zero cost.
Verify: . Backbone forward passes (once each), backbone backward passes . Sanity on data-vs-params: here we train more parameters () than we have examples () — ratio examples per parameter. That is under-determined, which is exactly why we lean on a linear head (a highly constrained shape) plus regularization; if we had instead unfrozen the whole M-param backbone the mismatch would be catastrophic, so the Bias-Variance Tradeoff says freeze. ✓
Example 2 — Huge data, big domain shift (full fine-tuning)
- Diagnose the regime. 200k examples is plenty to constrain a big model → variance is not the bottleneck. But frozen generic features cannot represent "legalese" → high bias. Why this step? The Bias-Variance Tradeoff tells you which knob to turn: here, reduce bias by giving the model capacity to reshape features.
- Unfreeze , use a small . Update both, pushing each weight downhill on the loss : Why a small ? The model already sits near a good optimum; a large step would overwrite good features — Catastrophic Forgetting. Small steps nudge rather than bulldoze.
- Add warmup + weight decay. Start near and ramp up over the first few hundred steps. Why this step? Early gradients through deep layers can be large; warmup (Learning Rate Schedules) prevents a destructive first jump.
Verify: , which sits in the recommended full-FT band . Data-to-shift logic: huge data ⇒ variance safe ⇒ full FT justified. No arithmetic to fail here, but the LR is inside band: . ✓
Example 3 — Medium data, some shift (top- partial fine-tuning)
- Recall the layer hierarchy. In Layer-wise Representations in Deep Nets, shallow layers learn generic patterns; deep (later) layers learn task/domain-specific ones. Why this step? It tells you where to spend your limited retraining budget.
- Unfreeze the top 2 layers only. Now — far less than full FT. Why this step? You adapt the specific part while protecting the general part from forgetting.
- Read the payoff. Accuracy climbs . Why this step? This is a point on the spectrum between the two anchors — cheaper than full FT, more flexible than pure feature extraction.
Verify: improvement percentage points. Fraction of trainable layers strictly between the two anchors (), confirming it is a genuine middle point. ✓
Example 4 — Memory math: why full FT is heavy
- Full FT trainable count. Why this step? Memory scales with the number of things Adam must track.
- Full FT memory. Using : Why this step? numbers bytes bytes per trainable param — the constant that makes full FT painful.
- Feature-extraction memory. Why this step? Only the head is trainable, so the optimizer footprint nearly vanishes — you pay just the forward pass on the backbone.
Verify: ratio . Full FT's optimizer state is ~ times heavier. Units: bytes GB by dividing by . ✓ (PEFT and LoRA exists precisely to kill this term.)
Example 5 — Degenerate: learning rate = 0
- Apply the update rule. For any weight : Why this step? Multiplying the gradient by erases the step no matter how large the gradient — the compass still points, but you take a step of length zero.
- Interpret. and both stay fixed → nothing learns, not even the head. Why this step? This is worse than feature extraction: feature extraction freezes but still trains with a real . Zero LR freezes everything.
Verify: with , exactly for both and . So the model output equals the untrained head's output — no learning occurs. ✓ Boundary confirmed: ≠ feature extraction.
Example 6 — Degenerate: learning rate far too large
- Compare to the safe band. Recommended full-FT range is . Why this step? Quantifies just how far outside safe territory you are — the top of the band.
- Predict the damage. A step too big overshoots the good optimum and overwrites pretrained features → severe Catastrophic Forgetting. Why this step? The model was near a minimum; a giant step throws it out of the basin entirely.
Verify: , and , so is above the safe ceiling. Clearly out of band. ✓ Fix: use – or discriminative LRs.
Example 7 — Degenerate: no head, backbone frozen
- Count trainable params. Why this step? If nothing is trainable, gradient descent has nothing to move.
- Interpret. The pipeline is a pure fixed function . It computes embeddings but cannot map them to your labels. Why this step? This is not even feature extraction — feature extraction needs the head () to learn the label mapping.
- Fix. Add a trainable head: at minimum a linear layer, giving for features and classes. Why this step? Restores a nonzero trainable set so learning can happen.
Verify: with , no weight satisfies with a nonzero move, so accuracy stays at the random/fixed-mapping baseline. For the minimal fix gives trainable params. ✓
Example 8 — Real-world word problem: serving 12 tasks on one GPU
- Full FT cost. 12 separate fine-tuned models: params to store. Why this step? Full FT changes , so each task needs its own full weight set — unaffordable.
- Feature extraction / PEFT cost. Share one frozen backbone; store only per-task heads. With -param heads: trainable params total. Why this step? A frozen backbone is task-agnostic, so it is stored once; only tiny heads differ. See PEFT and LoRA for the adapter version.
- Decide. Close domain + tiny per-task data + shared serving ⇒ feature extraction (or PEFT) wins on every axis. Why this step? Matches the matrix: small data → freeze; many tasks → share backbone.
Verify: storage ratio vs . Feature extraction stores essentially one backbone, so ~ cheaper. ✓
Example 9 — Exam twist: the forgetting limit
- Limit . Why this step? No step ⇒ no overwrite ⇒ perfect retention. This is the feature-extraction / frozen extreme: nothing is nudged, so nothing pretrained is lost.
- Safe LR . Why this step? We plug the actual recommended LR into the retention formula to see what "safe" buys you: about of pretrained knowledge survives while the model still adapts. This is precisely why Example 2 chose — small enough to remember, nonzero enough to learn.
- Limit . Why this step? We check the far boundary: an unbounded step size drives retention to — total Catastrophic Forgetting, the exact failure mode of Example 6's oversized LR. Covering both limits ( and ) shows the whole curve, not just one end.

Verify: ; ; . Monotonic decreasing, matching intuition "bigger LR forgets more". ✓
Example 10 — Degenerate: zero training data
- Look at where gradients come from. The loss is an average over training examples. With examples there is nothing to average, so is undefined and no gradient can be formed. Why this step? The whole update rule needs a gradient built from data; no data ⇒ no gradient ⇒ no legitimate step for either or .
- Interpret both strategies. Feature extraction: the head stays at its random initialization → predictions are chance-level. Full FT: also never moves → the model is exactly the pretrained model with a random head. Why this step? Zero data collapses both anchor strategies to "no learning", regardless of what you froze — the data axis dominates.
- Contrast with (Ex 5). Ex 5 had data but a zero step size; here we have a nonzero but no data. Both give "no learning", but for different reasons — one kills the step, the other kills the gradient. Why this step? Distinguishing the two zero-cases prevents the mistake of thinking "the model didn't learn" always means "bad learning rate".
Verify: number of gradient terms number of examples , so the summed/averaged gradient is empty and every satisfies . A binary head at random init sits at chance accuracy . ✓
Recall Quick self-test
- Why can Example 1 cache embeddings but Example 2 cannot? ::: Ex 1 freezes so is constant; Ex 2 changes every step.
- What makes worse than feature extraction? ::: Zero LR freezes the head too, so nothing learns; feature extraction still trains the head.
- How is "zero data" different from ""? ::: Zero data means no gradient can be formed at all; means the gradient exists but the step length is .
- Why is full FT ~ heavier in optimizer memory here? ::: It tracks params vs for the head alone.
- What retention does the safe LR give in the toy model? ::: , about .