XP: 0
⚙️ Part 1 · Module 7

Fine-tuning a Pretrained Model

You built GPT from scratch — but almost nobody does that in practice. Instead, you grab a model that already knows language (like GPT-2) and specialize it on your data. That's fine-tuning: cheaper, faster, and how real projects actually get built.
The smart shortcut

Don't start from zero — stand on a giant's shoulders

Pretraining a model (fundamentals Module 15) costs millions and months. But that model already learned grammar, facts, and reasoning. Fine-tuning takes that pretrained model and continues training it — briefly — on your specific data, so it picks up your style, domain, or task.

❌ Training from scratch

  • Needs a huge dataset (billions of tokens)
  • Costs a fortune, takes months
  • Reinvents grammar & facts from zero
  • Only makes sense for big labs

✓ Fine-tuning a pretrained model

  • Needs a small dataset (hundreds–thousands)
  • Minutes to hours, often on one GPU
  • Reuses everything the model already knows
  • What you'll actually do
Analogy — hiring an expert vs. raising a child

From scratch = raising a child from birth to teach them your business. Fine-tuning = hiring a knowledgeable graduate and giving them a few days of on-the-job training in your way of doing things. Same brain, quick specialization.

🎮 Game 1

Compare the cost: scratch vs fine-tune

Slide the target quality and watch the two approaches' cost/time. Fine-tuning reaches good results for a tiny fraction of the effort — because it starts from something that already works.

Effort to reach a quality target
Drag the desired quality.
target quality: 70%
The recipe

The fine-tuning workflow (it's the training loop again)

Good news: fine-tuning is the Module 3 training loop — just started from pretrained weights instead of random ones, with a small learning rate (you don't want to erase what it knows).

python · fine-tune GPT-2
from transformers import AutoModelForCausalLM, AutoTokenizer

model = AutoModelForCausalLM.from_pretrained("gpt2")   # pretrained! not random
tok   = AutoTokenizer.from_pretrained("gpt2")

optimizer = torch.optim.AdamW(model.parameters(), lr=5e-5)  # small lr!

for epoch in range(3):              # just a few passes
    for batch in your_data_loader:   # YOUR data (Module 4)
        loss = model(**batch).loss    # forward + loss
        loss.backward()               # autograd (Module 2)
        optimizer.step()              # update
        optimizer.zero_grad()
The small-learning-rate rule

Use a much smaller learning rate than training from scratch (e.g. 5e-5 not 1e-3). Big steps would overwrite the model's hard-won knowledge — called catastrophic forgetting. Small steps gently nudge it toward your data while keeping what it knows.

🎮 Game 2

See fine-tuning change the output

Same prompt, same model — but after fine-tuning on a specific style. Pick a target style and watch the "before" (generic GPT-2) become the "after" (your specialized model).

Generic → Specialized
Choose what to fine-tune it into.
✕ Before (base GPT-2)
Prompt: "The weather today"
✓ After fine-tuning
Prompt: "The weather today"
🎮 Game 3

How to format your fine-tuning data

The #1 practical detail: your data must be in the right shape for the task. Different goals need different formats. Click each to see the structure.

Match the format to your goal
Click a goal to see how the data should look.
🎮 Game 4

Freeze layers — train only what you need

A common trick: freeze most of the pretrained layers (keep them fixed) and only train the top few. This is faster, uses less memory, and reduces overfitting on small data. Click layers to freeze/unfreeze them.

❄️ Frozen = fixed · 🔥 Trainable = learns
Click a layer to toggle. Freezing lower layers is the common choice.
python
# freeze everything, then unfreeze just the last block
for p in model.parameters():
    p.requires_grad = False          # ❄️ frozen
for p in model.transformer.h[-1].parameters():
    p.requires_grad = True           # 🔥 train only this
🎮 Game 5

Watch a fine-tune run (starts low!)

Because the model already knows language, fine-tuning loss starts low and drops fast — very different from the high starting loss of training from scratch. Run it and see.

Fine-tune loss vs from-scratch loss
Fine-tune (teal) starts much lower than scratch (amber).
▬ fine-tune▬ from scratch
epoch0
fine-tune loss
🎮 Game 6

Checkpoints — save your progress

Training can crash, or you might overfit (Module 3). So you save checkpoints — snapshots of the model's weights — periodically. Then you can resume, or roll back to the best one. Click a checkpoint to "load" it and see its validation score.

Pick the checkpoint to keep
Each dot = a saved snapshot. The best val loss is your keeper.
👆 Click a checkpoint.
python · save & load
# save a checkpoint
model.save_pretrained("./my-model-epoch3")     # weights + config
tok.save_pretrained("./my-model-epoch3")

# load it back later (or the best one)
model = AutoModelForCausalLM.from_pretrained("./my-model-epoch3")
Save the BEST, not the LAST

Track validation loss (Module 3) and keep the checkpoint where it was lowest — not necessarily the final epoch. The last checkpoint may already be overfitting. This is early stopping + checkpointing working together.

🎯 Check your understanding

Quick challenge

1. What is fine-tuning?
2. Why use a small learning rate when fine-tuning?
3. What does freezing a layer mean?
4. Compared to from-scratch, fine-tuning loss usually…
5. Which checkpoint should you keep?
Takeaway

What you learned

Fine-tuning = take a pretrained model (e.g. GPT-2 via Hugging Face) and continue training it on your small dataset. It's the Module 3 loop, but starting from smart weights with a small learning rate (to avoid catastrophic forgetting). Format your data for the task, optionally freeze lower layers to save resources, watch loss start low and drop fast, and save checkpoints — keeping the one with the best validation loss. This is how most real specialization happens.

Next up → Module 8: LoRA & PEFT — even fine-tuning all of a big model is expensive. LoRA fine-tunes just a tiny set of "adapter" weights (often <1% of the model), and quantization shrinks models to fit one GPU. This is how fine-tuning is actually done today.