A frame to help you reason through the assignment — the mental model, the loop diagram, and the map of which cell does what. It deliberately does not contain the answers or write-ups for you. Instead it gives you the questions to ask yourself and the cells to go inspect. The work — and the learning — is in running the training, watching the reward move, and writing your own conclusions.
Notebook:
01_Reasoning_Fine_Tuning_Unsloth_GRPO.ipynbModel:meta-llama/Llama-3.2-3B-Instruct(gated — accept the license andhf auth login, or use the ungatedunsloth/mirror). Dataset:openai/gsm8k. One idea to hold onto while you read: we never show the model examples of good reasoning — we only reward it. Keep asking yourself what, exactly, is being rewarded, and what that pressures the model to become.
| You want to… | Reach for | Where to look |
|---|---|---|
| Load base model (16-bit) | FastLanguageModel.from_pretrained |
Task 2 — note the load_in_4bit value and ask why |
| Attach LoRA adapters | get_peft_model |
Task 3 — then read print(model) (you need it for Q2) |
| GSM8K → prompts + gold | get_gsm8k_questions() |
Task 4 — what does the system prompt force? what does #### mark? |
| Score a completion | 5 reward functions | Task 5 — which one is worth the most, and why do the others exist? |
| Configure the RL run | GRPOConfig |
Task 6 — num_generations, warmup_ratio, learning_rate, scheduler |
| Train | GRPOTrainer(...).train() |
Task 7 — watch the reward column |
| Generate base vs tuned | fast_generate(lora_request=...) |
Task 8/9 — None vs the saved adapter |
One sentence to keep in mind: GRPO scores each completion relative to the group's average reward. That single design choice is what lets it skip a piece of machinery PPO needs — figure out which piece, and why the group average can stand in for it. That's the heart of the video explanation.
flowchart TD
P[GSM8K prompt] --> G[sample a GROUP of completions<br/>num_generations=?]
G --> R[score each with the reward stack]
R --> A[group-relative advantage<br/>reward vs group average]
A --> U[policy update<br/>+ KL penalty]
U --> P
U -.only the adapter moves.-> W[which weights actually change?]
ASCII fallback:
prompt ─► sample a group of completions ─► reward each ─► advantage = reward vs GROUP AVERAGE
▲ │
└─────────────── policy update (only the LoRA matrices?) ◄───────────┘
Orientation, not answer: the notebook's intro (Cell 0) states the loop in five arrows and makes one claim about why no value network / critic is needed. Find that claim and make sure you can say it in your own words — it's exactly what the video asks for. Then, as you read Tasks 3–9, keep a running answer to: which weights actually change during training, and which stay frozen?
uv sync # from 15_Reasoning_Model_Fine_Tuning; Linux/WSL2 + Ampere+ GPU only
hf auth login # Llama-3.2 is gated — or swap to the unsloth/ mirror in the notebookThis session trains a model on your own GPU — Ampere+ (compute ≥8.0), 16GB+ VRAM, Linux/WSL2. If you
hit out-of-memory, the README lists the knobs (gpu_memory_utilization, num_generations,
gradient_accumulation_steps). Before you change num_generations, read Task 6's note about which two
numbers have to stay divisible — changing one without the other is the classic crash. No suitable GPU?
Use the ColabVersion__…ipynb on a Colab-Pro L4/A100.
These are what Questions #1–4 ask you to explain in your own words. Below is where to look and what to compare — not the conclusion. Form your own read first, then check it against the notebook's callouts.
Find where Task 2 sets load_in_4bit and read Cell 0's note on why this session trains 16-bit. Then
recall the QLoRA paper's double quantization: what exactly gets quantized the second time — the
weights again, or something else the 4-bit packing created? Ask: given that GRPO spends most of its time
generating 8 completions per step, what would 4-bit cost you on that path? And flip it — when would
4-bit (QLoRA) be the right call?
Read Cell 8's description and the get_peft_model call in Task 3. For a weight matrix W, what two small
matrices get introduced, and what is the effective weight during training? Which parameters receive
gradients — all of W, or just the new pieces? Write your own one-sentence definition of LoRA before
you read the notebook's, then compare.
Run Task 3 and study the printout. The diagram in Q2 gives you Layer Norm as a worked example
(LlamaRMSNorm). For each remaining label — Feed Forward, Masked Multi Self-Attention, Text & Position
Embed, Text Prediction — find the matching module name in the printout. One of them is a trap: does Llama
store positions in a learned embedding table, or does it get position information some other way?
Check where lora_A/lora_B appear and connect that back to target_modules.
Read Task 5's table and the five functions. Which single reward is worth the most? The others give only 0.5 or less — so why include them at all? Ask yourself: at step 0, before the model ever gets an answer right, is there anything it can do to earn a non-zero reward? What would training look like if the only reward were correctness?
Open the GRPOConfig in Task 6. For warmup_ratio, learning_rate, and lr_scheduler_type: which one
sets how big each step is, which sets how the step size ramps up at the start, and which sets how it
decays afterward? The TRL TrainingArguments docs (linked in Q4) are fair game. Then ask why an RL
fine-tune in particular wants a gentle warmup.
Read Task 8's note: vLLM is still holding the frozen base weights, so the same engine can generate two ways. What argument flips generation between the base model and your trained adapter? Plan to run the same prompt both ways so your comparison is controlled.
In the QLoRA scheme, what does 4-bit packing create that itself costs memory — and is that what double quantization compresses? Roughly how much does it save per parameter? Then: given GRPO samples 8 completions every step, why does this notebook stay 16-bit — and when would you still pick QLoRA?
Match each diagram label to a module in your print(model) output. Which block holds gate/up/down?
Which holds q/k/v/o? Is "Text & Position Embed" really two learned tables here, or does Llama get
positions another way? Which module turns the final hidden state into vocabulary logits?
For a frozen weight W, what does LoRA add, and what is the effective weight while training? Which
parameters actually update? Why does this make fine-tuning a 3B model feasible on one GPU? (Careful not to
describe QLoRA's quantization here — that's a different idea.)
Which of the three is the step size, which is the ramp-up, and which is the decay shape? Tie each to training stability: what goes wrong with no warmup, or with too large a learning rate, on a noisy RL signal?
Deliverable: an executed GRPOTrainer.train() (Task 7) with the reward logs kept (README:
"especially the training reward logs"), plus your own note on what you observed.
Method: let it run and watch the reward column. Cell 27 warns about an "Aha" moment — reward hovers
near ~0, then climbs. Keep evidence of the trajectory, not just a final number. The
correctness_reward_func prints a sample completion each batch — watching those go from rambling to
structured is exactly the story to capture. Modest movement in a short run is expected; don't chase a big
number.
Deliverable: the same prompt run through the base model and your fine-tuned adapter (Task 8/9), plus a written observation on what changed. Method: generate once with the base (frozen weights) and once with your trained adapter, using the same prompt so it's a fair comparison. Describe the behavior difference — format, structure, reasoning — not just "the second one is better." Ask yourself: did the format change, the correctness, or both?
The learning is in running the training, watching the reward actually move, comparing base vs. tuned on the same prompt, and writing your own conclusions. The notebook's callouts (Cell 0's loop, Cell 27's "Aha" note, the Breakout Room summaries) are there to check your reasoning against — read them after you've formed your own answer, not instead of forming one.