Finishing Schoola hands-on lab

How a raw model gets finished

A pretrained model is a cook who can make anything but has no manners, no taste and no rigor. Three classes finish it: copying worked examples (SFT), comparing two plates (DPO) and sitting a marked exam (GRPO). About 90 minutes of play.

0 · The ladder: three classes, three signals

After pretraining, a model is a young cook who can continue any recipe but rambles, ignores the order and has no taste. That's a base model. The finishing school has three classes, one per floor, and each one teaches from a different kind of signal. Every term with a wavy red underline is tappable: hover or tap it for the plain meaning and its school equivalent.

The model = the cook
can already cook anything; needs finishing
Worked examples = the master's plates
copied in the copying class (SFT)
Chat template = the order ticket
labelled boxes: system, user, assistant, think, tools
Loss mask = the red pen
grades only the answer box
LoRA = sticky notes
a small pad on the recipe book; peel off to undo
DPO = the tasting room
two plates, a finger pointing at the better one
Reference model = the day-one photo
taken on the first day of this class (usually the SFT checkpoint), pinned on the wall
β = the leash
ties the cook to the photo; higher β, shorter leash
GRPO = the exam hall
every answer gets a score; here a thermometer (verifier) reads 0 or 1

Covers smol course Units 1–2 · overview · HF LLM Course ch. 11–12 · intros · RLHF Book ch. 3 (the training overview)

Put each signal on its rung

Tap a signal card, then tap the floor that learns from it. (On a computer you can also drag.) The right floor lights up.

Pick a card first.

One prompt, four cooks (illustrative outputs)

The same cook, after each class. These outputs are written to show the typical behaviour, not generated by a real model.

Guess first!
Which class can run with no human-written answers and no human choices at all, just a program that checks each answer?
GRPO, as used for reasoning (RLVR). There the exam hall scores every answer with a verifier: a program that checks it, such as a math checker, unit tests or running a SQL query. It reads 0 or 1 with no opinions. GRPO itself only needs a score per answer, so it can also use a learned reward model instead (DeepSeekMath, which introduced GRPO, did). SFT only needs answers to copy, and DPO only needs a person's choice between two answers.
Say it out loud
Each class learns from a different signal: copying examples, comparing two answers, or scoring the cook's own answers, often with a checker. They stack; they don't replace each other.

1 · The order ticket: chat templates

A model never sees "messages". It sees one long string of tokens. The chat template is the printed order ticket that turns a conversation into that string, with special tokens as the box borders. Each model family prints its own ticket. Fill one in and watch it render.

Covers smol Unit 1 · Chat Templates · HF LLM Course 11.2 · RLHF Book ch. 4 · SmolLM3-3B model card

System box
User box
Ticket dialect
The ticket as the model sees it · teaching skeleton, not byte-exact
special tokenrole nametemplate's own textyour textthink / toolsthink tag (a special token too)
SmolLM3 thinking
why
special tokens on this ticket
Guess first!
The system prompt says /no_think, but the code passes enable_thinking=True. Does SmolLM3 think?
No. On SmolLM3 the flag in the system prompt beats the keyword (per the model card). The template writes Reasoning Mode: /no_think and ends the ticket with an empty <think></think> box, so the model sees "thinking already happened" and answers directly. Try it above: add /no_think, leave the switch on.
Guess first!
You fine-tune on Llama-3.1-format tickets, then serve the model with ChatML tickets. What happens?
Answers degrade. The model learned that a turn ends at <|eot_id|> and a role sits between header markers. At serving time it sees <|im_start|> markers it never learned to read, so it runs on past the end of its turn, mixes up roles or ignores the system box. Nothing crashes, which is why this bug is easy to miss. Switch the dialect above to compare the two tickets.
Say it out loud
The template is the model's grammar: train and serve on the same one. On SmolLM3, the system-prompt flag beats the keyword.

2 · Grading the answer: loss masking

SFT uses the same loss as pretraining: for each token, how surprised the model was by the right next token (−ln p), averaged. The only new decision is which tokens get graded. With the loss mask on, the teacher's red pen skips the customer's order the cook copied down and grades only the answer. Tap a token to change how likely the cook found it.

Covers smol Unit 1 · Supervised Fine-Tuning · HF LLM Course 11.3 · RLHF Book ch. 4

Customer's order (prompt) · cook's answer (completion). Bar height = surprise, −ln p. Tap a token to cycle its p.
loss (average surprise)
tokens graded
total surprise on graded tokens
Guess first!
Turn on "grade only the answer". Does the loss go up or down?
Down, from 1.38 to 0.77 with the defaults. The two prompt tokens were the most surprising (p = 0.1), and they no longer count. But the lower number isn't "better training". It's measuring a different thing: the cook is no longer graded on guessing the customer's order, only on the answer. Masked and unmasked losses can't be compared with each other.
Say it out loud
SFT is next-token cross-entropy, and the mask decides what the cook is graded on.

3 · Sticky notes: LoRA and training memory

A full fine-tune rewrites the whole recipe book, and every weight being rewritten needs its gradient and optimizer state in memory. LoRA freezes the book and adds a small pad of sticky notes (an adapter) on a few kinds of page. The pad's size is the rank r. Pick a model and a machine budget and see what fits.

Covers smol Unit 1 · LoRA and PEFT · HF LLM Course 11.4 · LoRA paper (Hu et al. 2021) · shapes from each model's config.json

Model
How to train it
Rank r (pad size)
Which pages get notes (target modules)
Sequence length (tokens per example)
Price per trained weight
weights (bf16)2 B
gradients (bf16)2 B
fp32 master copy4 B
AdamW m and v (fp32)8 B
per trainable parameter
a frozen weight (bf16, no grads)
parameters in the model
trainable parameters
of the model trained
Training memory: (ticks = what each machine can use)
frozen weights trainable state (weights + grads + optimizer) activations · teaching estimate
Notes per kind of page, across all layers: r × (d_in + d_out) × layers
Guess first!
A full fine-tune of SmolLM3-3B. Which machine fits it?
None. 3.08 billion parameters × 16 bytes = about 49 GB of weights, gradients and optimizer state before a single activation, which is more than even the 40 GB A100. Switch to LoRA with r = 16 and the same model needs about 7.5 GB: the frozen book at 2 bytes a weight, plus a small pad.
Guess first!
Double r from 16 to 32. What happens to the trainable parameters?
Exactly double. Each adapted matrix gets two thin matrices, d_in × r and r × d_out, so its count is r × (d_in + d_out): linear in r. On Qwen3-1.7B with all seven modules, 17.4M becomes 34.9M. Memory barely moves, because the frozen book dominates.
Say it out loud
LoRA trains about 1% of the weights for a 2–3B model at rank 16 (more for small models or high rank: try it). Full fine-tuning costs about 16 bytes per parameter, which is why a 3B full fine-tune doesn't fit a 12–16 GB card and LoRA does.

4 · The tasting room: DPO

In DPO a taster puts two plates side by side and points at the better one: a preference pair. There's no scorecard. The reward is implicit: β × how much more likely the cook now makes a plate than the day-one photo would have. Each input below is a sequence log-probability (the sum over the answer's tokens, so a negative number).

Covers smol Unit 2 · Direct Preference Optimization · RLHF Book ch. 5 & 8 · DPO paper (Rafailov et al. 2023)

Before the tasting room: the judge's scorecard (a reward model)

The older route to preferences trains a separate reward model: a judge who gives every plate a score. It learns from the same pairs with the Bradley–Terry loss: the chance the chosen plate wins is σ(scorechosen − scorerejected), and the loss is −ln of that chance. Slide the two scores.

Judge's score: chosen plate ★
Judge's score: rejected plate ✗
score gap Δ
P(chosen wins) = σ(Δ)
loss = −ln σ(Δ)
Guess first!
Shift both plates' scores by the same amount. What happens to the loss?
Nothing. Only the difference between the two scores enters the loss, so a judge's scale has no zero point: scores are comparisons, not grades. DPO below keeps this exact loss and swaps the judge's score for β × the log-ratio against the day-one photo. That's why it can drop the judge: the model's own log-ratios already give a score gap.
Cook now: chosen plate ★
Day one: chosen plate ★
Cook now: rejected plate ✗
Day one: rejected plate ✗
β (the leash)
implicit reward, chosen
implicit reward, rejected
margin
P(chosen wins) = σ(margin)
loss = −ln σ(margin)
σ(−margin): the pair's weight in the gradient (times β)
A known conflict. The smol course's Unit 2 table says lower β means closer to the reference. The DPO paper says the opposite: β is the strength of the leash. We follow the paper: higher β = shorter leash.
Guess first!
On the very first step of any DPO run, what's the loss?
0.693 = ln 2, whatever β is. On step one the cook is the day-one photo, so both log-ratios are 0, the margin is 0, σ(0) = 0.5 and −ln 0.5 = ln 2. Press "Back to day one" and move β: the loss doesn't budge. If your first logged loss isn't near 0.693, something is wrong before training starts.
Guess first!
Keep the cook's drift fixed and raise β from 0.1 to 0.5. Does the loss go up or down, and what does that mean for the leash?
Down (0.554 → 0.201 with the defaults). The same drift from day one now counts for five times as much margin, so the taster is satisfied with less drift. The cook reaches a low loss while staying closer to the photo: a shorter leash. That's the paper's reading, and it's why raising β is the fix when DPO outputs drift into odd, repetitive text.

A batch of eight pairs, mid-training

TRL logs two numbers for a DPO batch: reward accuracy (the share of pairs where the chosen plate has the higher implicit reward) and the mean margin. Press the step button to nudge every pair. Pairs that are still wrong push hardest.

Teaching animation, not a real optimizer: each step adds 0.5 × (how hard the pair pushes) to the chosen log-prob and subtracts the same from the rejected one. It uses the β set above.
reward accuracy (rewards/accuracies)
mean margin (rewards/margins)
mean loss
Say it out loud
DPO's reward is implicit: β times how much more likely the cook now makes the plate than on day one. The loss starts at 0.693, and higher β is a shorter leash.

5 · The day-one photo: the reference model and the bill

Every method that measures drift needs the reference model's opinion of each answer, and every opinion is a forward pass. Count the footsteps each training example costs, and how many copies of the model sit in memory.

Covers smol Unit 2 · DPO Hands-on · RLHF Book ch. 8 & 15 (regularization) · TRL docs

Method
Group size G
passes per example (forward + backward + reference)
answers generated per example
model copies in memory
Guess first!
With LoRA on, how many copies of the model does DPO keep in memory?
One. With LoRA, the reference is the same weights with the sticky notes peeled off: switch the adapter off, run the reference forward pass, switch it back on. The two reference passes still run, but on the one copy. Without LoRA (and without precomputing), DPO needs a second full frozen copy. One catch: if your SFT step was itself a LoRA adapter, merge it first (or use TRL's ref_adapter_name), otherwise peeling the notes gives you the base model, not the SFT cook.

What the bill looks like (counted from the loss)

DPO ≈ 2 × SFT per example
Counted from the loss, not timed. Once the reference log-probs are cached, two answers each get a forward and a backward pass, against SFT's one. TRL's precompute_ref_log_probs does the caching.
GRPO ≈ G × SFT plus sampling
Also counted from the loss. Each of the G answers gets a forward and a backward pass, and all G have to be generated first, one token at a time. Generation is usually the bigger bill.
Say it out loud
DPO costs about twice SFT per example once the reference scores are cached, and with LoRA the reference is just the same weights with the notes peeled off.

6 · The exam hall: GRPO

In GRPO the cook plates a group of G answers to the same exam question. A checking machine stamps each one: 1 for the right number, a small extra stamp for neat format. Then each plate is graded against the group's own average, its advantage. There's no second examiner (critic) on the payroll. Scoring with a checker makes this RLVR, the recipe behind reasoning models such as DeepSeek-R1. GRPO itself takes any score per answer, so the stamp could also come from a learned reward model, as in DeepSeekMath, which introduced GRPO.

Covers HF LLM Course 12.3–12.4 · RLHF Book ch. 6–7 · DeepSeekMath (Shao et al. 2024)

Exam question: Solve 2 + 3 × 4. Show your work in <think>, then the answer in <answer>. (Right answer: 14.)
Group size G
Divide by the group's spread?
group mean reward (the chalk line)
sample std (n − 1)
plates that move the cook
Advantage = (reward − group mean) ÷ (sample std + 1e-4): the sample std (n − 1) plus TRL's 1e-4, as TRL computes it. "Worked example" loads a hand-worked example (4 answers, accuracy + format rewards): o1 shows +1.305; without TRL's 1e-4 it would be 1.306. Answer "no" to the spread question and the advantage is just reward − group mean.
Guess first!
All 8 plates are correct and neat. How much does the cook learn from this question?
Nothing. Every reward equals the group mean, so every advantage is 0 (the 1e-4 keeps it from dividing by zero). GRPO only learns from differences inside a group. Questions the cook always gets right, or always gets wrong, teach nothing, which is why reasoning datasets are filtered to questions the model sometimes solves. Set G = 8, then press "Everyone gets it right".

A trivial gap shouts louder: the spread divisor

Two exam questions, four plates each. On the first, every plate is right and one is slightly messier: rewards 1, 1, 1, 0.9. On the second, half are right: 1, 0, 1, 0. Watch each question's lowest plate (outlined) as you flip "Divide by the group's spread?" above. Dividing by the spread makes a trivial 0.1 gap push harder than a real right/wrong gap. That's the difficulty/noise bias Dr. GRPO removes.

Dr. GRPO is two changes, not one. Liu et al. (2025) (a) stop dividing by the group's std and (b) stop normalising each answer's loss by its length, which lets long wrong answers off lightly. In TRL that's scale_rewards="none" plus loss_type="dr_grpo". TRL's current defaults are scale_rewards="group" and loss_type="dapo". This page shows only the std half.

The speed bump: clipping the update (ε)

Each plate's probability under the policy has moved from πold (the policy that sampled it) to πnew. The clip caps the ratio at 1 ± ε inside the objective: the term is min(ratio × A, clipped ratio × A). When the clip changes the term, the "clip bit" lights. Plates o1–o4 of the current group; load the worked example for its numbers.

The clip only bites when a generated batch is reused for more than one update (num_iterations > 1, or several optimizer steps per generation); the numbers here show a reused batch. On TRL's default num_iterations=1, πold = π, the ratio is 1 and the clip never bites.
ε (speed-bump height)

The day-one leash (KL)

TRL's current default β = 0: the day-one leash is unhooked unless you set it, and no reference model is loaded. DeepSeekMath used 0.04. The clip limits each step; the KL term limits total drift. On TRL's defaults neither brake is engaged: β = 0 unhooks the leash, and with num_iterations=1 each generated batch is used for one update, so πold = π, the ratio is 1 and the clip never bites.

PPO vs GRPO: networks to keep

PPOpolicycriticreward model
if learned
reference
GRPOpolicyreward model
if learned
reference
only if β > 0

No critic: the group is the baseline.

Guess first!
Where does GRPO get the baseline that PPO gets from a critic?
From the group. PPO trains a second network to predict how well an answer should do, and subtracts that prediction. GRPO samples G answers to the same prompt and subtracts their average: arithmetic, recomputed every batch, with no second network to train or keep in memory.
Say it out loud
The group is the critic: each plate is graded against its siblings' average. A group that all scores the same teaches nothing, and on current TRL the KL leash is off unless you set β.

★ · Graduation: finish a cook for three clients

Three clients come to hire a graduate. For each, pick the class, the model, LoRA or full, and the machine, then grade the plan. It's scored with the same math as steps 1–6: is it the right class for the signal the client already has, is there enough data, does it fit the machine, and is it within budget? Memory is estimated at r = 16, sequence 1,024, batch 1, with checkpointing.

Covers smol Units 1–2 · HF LLM Course ch. 11–12 · RLHF Book ch. 4, 6–8

Guess first!
The headline client offers only the 50 pairs its editors labelled this week. Can you DPO on those?
No. The smol course's floor is about 1,000 good pairs for a narrow domain, and 10,000+ for robust alignment. With 50 the plan fails whatever β you set. Use all 12,000.
Say it out loud
Pick the class by the signal the client already has: worked examples mean SFT, preference pairs mean DPO, a checker means GRPO. Then check the data is enough, it fits the machine, and the budget allows it.

✓ · Field test

Eight questions, each answered by setting up a widget in steps 2–6 the way the question says and reading off the result. Graded instantly, with rounding tolerance.

Hire all three clients in Graduation and score 6 or better here, and the school issues your diploma.

What's exact and what's a teaching model

Exact: the cross-entropy on the probabilities shown; the parameter and LoRA counts, from each model's config.json on the Hub; the 16-bytes-per-parameter accounting (bf16 weights 2 + bf16 gradients 2 + fp32 master 4 + AdamW m and v 8); the DPO loss, implicit reward, margin and sigmoid; the GRPO advantages (sample std + 1e-4, as TRL computes them) and the clipped term; the pass counts per example.

Teaching models: the token probabilities in step 2 and the log-probs in step 4 are toy numbers; activation memory is a rough allowance, not a measurement; the "training step" in step 4 is an animation, not an optimizer; the four cooks' outputs in step 0 are illustrative, not generated; the πold and πnew values in step 6 are toy numbers for a reused batch; the costs in step 5 are pass counts read off the losses, not timings. The machines' "usable" memory leaves headroom for the framework (and, on a Mac, macOS's default GPU memory cap). GB means 10⁹ bytes.

The formulas are real; the example numbers are chosen to teach, not measured.

Where to go deeper

  • UNIPO from Georgia Tech's Polo Club: a beautiful interactive walk through the GRPO family (REINFORCE, PPO, GRPO, DAPO, Dr. GRPO) on real training runs, token by token. The best next stop after step 6.
  • Hugging Face's a smol course and LLM Course ch. 11–12: free notebooks to run SFT, LoRA, DPO and GRPO yourself on a small model.
  • Nathan Lambert's RLHF Book: the full theory behind every formula here, clearly written and free to read online.

Sources

  • Hugging Face, a smol course, Unit 1 (Chat Templates, Supervised Fine-Tuning, LoRA and PEFT) and Unit 2 (Direct Preference Optimization, DPO Hands-on)
  • Hugging Face, LLM Course, chapter 11 (fine-tuning: templates, SFT, LoRA) and chapter 12 (reasoning models and GRPO, 12.3–12.4)
  • Nathan Lambert, RLHF Book: ch. 3 (training overview), 4 (instruction tuning), 5 (reward models), 6 (policy gradients), 7 (reasoning), 8 (direct alignment), 15 (regularization)
  • Rafailov et al., "Direct Preference Optimization: Your Language Model is Secretly a Reward Model" (2023)
  • Shao et al., "DeepSeekMath: Pushing the Limits of Mathematical Reasoning in Open Language Models" (2024), which introduced GRPO (trained there with a learned reward model)
  • DeepSeek-AI, "DeepSeek-R1: Incentivizing Reasoning Capability in LLMs via Reinforcement Learning" (2025): GRPO with rule-based, checkable rewards
  • Liu et al., "Understanding R1-Zero-Like Training: A Critical Perspective" (2025), which proposed Dr. GRPO
  • Hu et al., "LoRA: Low-Rank Adaptation of Large Language Models" (2021)
  • SmolLM3-3B model card (chat template, enable_thinking, the /think and /no_think flags)
  • TRL documentation and grpo_config.py (GRPOConfig defaults: beta=0.0, epsilon=0.2, num_iterations=1, scale_rewards="group", loss_type="dapo"; DPOConfig: β defaults to 0.1)
  • Model shapes from each model's config.json on the Hugging Face Hub: SmolLM2-135M, Qwen3-1.7B, SmolLM3-3B

The sibling lab, Inference Kitchen, covers what happens after training: how a finished model is served.