Tiny GPT Lab II — Train & Sample
- Train the Day-97 character-level transformer on a real corpus with a full training loop
- Verify the initial loss against the cross-entropy prediction for a uniform distribution
- Track train vs validation loss and generate samples at checkpoints to watch quality evolve
- Run controlled experiments on context length and temperature and record their effects
| Spaced-rep warm-up: Week 14 due cards (attention, transformer, tokenization) | 10 min |
| Read the training recipe + sanity-check theory | 15 min |
| Guided: wire the loop, validate initial loss, train | 40 min |
| Guided: sampling + sample diary | 15 min |
| Practice: context-length and temperature ablations | 20 min |
| Ship the repo folder, quiz + flashcards | 15 min |
Builds on: Day 97 — Tiny GPT Lab I — building the model · Day 88 — Training loops & DataLoaders · Day 96 — Tokenization · Day 62 — Entropy & cross-entropy
Yesterday you built a tiny robot that can hold a pen. Today you teach it to write. At first it produces pure static — random letters, like a toddler mashing a keyboard. Then, after a few hundred practice rounds, something eerie happens: spaces start appearing at word-like intervals. Then real short words show up: "the", "and", "of". Then longer words, then sentence-shaped things with capital letters and periods. It is learning to spell, then to imitate style, purely by playing one game millions of times: "given these characters, guess the next one."
Nothing about the robot changed structurally — it is the same machine you assembled on Day 97. What changed is millions of tiny weight adjustments, each one nudged by the gradient of how surprised the model was by the true next character. Watching gibberish become language over twenty minutes of training is the single best intuition-builder for what happened, at incomprehensible scale, inside every large language model you will ever call through an API.
Every LLM you will deploy, prompt, or debug for the rest of this program was trained exactly like this — same loss, same loop, only scaled up a billionfold. Having personally watched loss fall and samples improve gives you conviction that no blog post can: you will explain "it just predicts the next token" to customers with the authority of someone who trained one. It also cements the practical skills — checkpointing, loss curves, sampling — that reappear on Day 128 when you fine-tune a real model with LoRA.
Guided practice
Wire the loop and validate the starting loss
25 min- Download a plain-text corpus (Tiny Shakespeare from the nanoGPT repo works well) as
input.txt. - Paste the starter below into
train.pynext to your Day-97model.py. Adjust the TinyGPT constructor call to your own signature. - Before the loop runs, print the loss of the untrained model on one batch. Compute ln(vocab_size) with
math.logand confirm they match to within ~0.1. Write one sentence in your log explaining WHY (Day 62). - Train 2,000 steps on CPU (or 5,000 on GPU). Record train/val loss every 250 steps in a simple list you print at the end.
- Confirm val loss tracks train loss downward. If train falls and val rises, name the phenomenon (Day 89) and note at what step it started.
Watch it learn to spell
15 min- Add the
generatefunction below and call it every 500 steps during training, printing 300 characters from a newline seed. - Keep a "sample diary": paste the step number, current val loss, and the sample into a markdown file.
- Annotate each entry with what changed: when did spaces appear? First real word? First correctly matched punctuation pair?
- After training, write three sentences connecting loss values to sample quality — this becomes raw material for your Day-105 explainer.
On your own
Two ablations, one table
20 minRun two controlled experiments and record results in a table (setting, final val loss, one-line sample verdict).
(1) Context length: retrain with block_size 32 vs 128. Which produces more coherent long-range structure (character names, matched quotes)? Why would a model that can only see 32 characters back struggle with a quote opened 80 characters ago?
(2) Temperature: from your best checkpoint, sample at temperature 0.3, 0.8, and 1.5 with the same seed. Describe each in one line.
Hints: keep every other hyperparameter fixed — one variable per experiment (Day 81 discipline). Low temperature repeats safe patterns; high temperature increases entropy of each choice (Day 62).
Ship the training run
Turn today's work into a small, reproducible repo folder: train.py, generate.py (loads the checkpoint and takes a --temperature flag via argparse, Day 16 payoff), your sample diary, and a README with the loss table, the ln(vocab_size) sanity-check explanation, and both ablation results. Commit the checkpoint file reference (not the weights if large) and push. This artifact is your proof-of-understanding for Phase 5 — the Day-105 assessment and the Day-128 fine-tuning lab both refer back to it.
Common mistakes & misconceptions
- Skipping the initial-loss check. ln(vocab_size) at step 0 is your free wiring test — a wrong starting loss means broken shapes or targets, and finding that after an hour of training hurts.
- Evaluating with the model in train mode. Dropout stays active and val loss reads noisy-high; wrap evaluation in model.eval() plus torch.no_grad() and switch back.
- Forgetting to crop the context to block_size during generation. Positional embeddings only exist for block_size positions — feeding a longer sequence crashes or silently degrades.
- Judging the model only by loss. Two checkpoints with similar loss can sample very differently; always look at generations, the habit that becomes "look at your outputs" in LLM evals (Day 134).
- Comparing temperature samples from different seeds or checkpoints. Change one variable at a time or the comparison is meaningless.
- Training the tokenizer split before splitting train/val on TEXT order but sampling windows across the boundary — keep val windows strictly out of the training slice.
Q1. Your untrained 65-character model shows an initial loss of about 4.17. Why is that expected?
Q2. During generation you must slice the input to the last block_size tokens because…
Q3. Train loss keeps falling but validation loss starts rising at step 3,000. The model is…
Go deeper — curated resources
- Learning-rate warmup and cosine decay — Real LLM runs warm the LR up over the first steps then decay it. Try adding torch.optim.lr_scheduler.CosineAnnealingLR and compare curves — this reappears in every training-config file you will read.
- Initial loss matched ln(vocab_size) and the explanation is written down
- Final val loss ≥ 40% below baseline with the loss table recorded
- Sample diary shows the gibberish → words → style progression
- generate.py works standalone from the checkpoint; repo pushed
- Quiz ≥ 2/3
← Back: Day 97 built the machine; today Day 88's canonical training loop and Day 62's cross-entropy turned it into a language model. The temperature mechanics you used come straight from the softmax you met on Day 94.
Forward →: Day 100 scales this exact recipe to trillion-token pretraining. Day 102 dissects the sampling knobs you just touched. On Day 128 you will run this loop again — but fine-tuning a real open model with LoRA instead of training from scratch.
Unlocks: D100 How LLMs Are Trained · D101 Scaling Laws, Capabilities & Limits · D102 Decoding & Sampling · D104 Context Windows & Hallucination Deep-Dive