Guide

Karpathy's recipe is a disciplined debugging loop: become one with the data, overfit one batch, set a sensible learning rate, then add regularization.

Concept

For a balanced K-way classifier with a near-zero last layer, softmax is about 1/K, so loss should start near ln K. If it does not, something is wrong before you blame the optimizer.

The big idea

L ≈ −log(1/K) = ln K
Kln K (nats)
20.69
102.30
10006.91
50,000 (big BPE vocab)≈ 10.8

If your LM loss starts at 4 with a 50k vocab, the head is already oddly peaked or labels are wrong. If it starts at 25, logits are exploding. Check residual scales and init. Log this number on every new run before celebrating a "fast" drop from a broken start.

Walking through the recipe

  1. Become one with the data — visualize labels, find duplicates, check imbalance.
  2. Overfit one batch — train until loss ~0 on 1–2 batches. If you cannot, the bug is in code, loss or shapes, not hyperparameters.
  3. Set a sensible LR — range test, or start from known defaults (1e-3 AdamW for small nets, 3e-4 class for many transformers).
  4. Generalize — add regularization gradually. Do not jump from nothing to heavy dropout plus decay plus aug.
  5. Measure — plot train/val curves. Distrust vibes.

Also: confirm decreasing train loss before trusting validation, and change one thing at a time.

PatternLikely causeTry
Loss → NaN / explodesLR too high, bad init, div by zeroCut LR 10×, grad clip, check the loss API
Flat from step 0LR too low, forgot train(), grads blockedRaise LR, check requires_grad, zero_grad order
Train ↓ val ↑OverfittingMore data/aug, weight decay, early stop
Both flat after progressPlateauLR schedule, longer train, data diversity
Val << trainData leak or aug-only train difficultyAudit splits. Eval without heavy aug

The table's "try" column is the underfitting and overfitting checklist. See overfitting for the bias–variance version. If both curves look stuck, check shuffle, constant labels, a scheduler that set LR to 0, or eval using train-mode BatchNorm.

Train loss is noisy even with correct code. Smooth with an exponential moving average. Do not change LR because of one spiky step. A 50-example val set will jitter more than your real gains.

Mismatching "scheduler step per batch" versus "per epoch" is a classic way to accidentally use 100× fewer decay steps than you intended. Plot opt.param_groups[0]["lr"] over time on every serious run.

Example

Multiclass net, K=1000, init loss ≈ 6.9. You measure 0.4 at step 0: labels may be wrong or the head is over-confidently init. You measure 40: logits exploding — check weight init scale or input normalization.

Common mistakes

  • Tuning the optimizer before you can overfit one batch. If one batch will not go to ~0, the code is wrong.
  • Celebrating a drop from loss 25. You started broken.
  • Changing three knobs after one spiky step. Smooth the curve first.

Check yourself

  1. A 10-way classifier starts at loss 0.01. What is wrong? Answer: Init loss should be about ln 10 ≈ 2.3. 0.01 means the head is already peaked or labels leak.
  2. You cannot drive loss to ~0 on two batches. Is the learning rate the first suspect? Answer: No. Shapes, loss, labels or blocked grads come first.

Key takeaways

  • Verify loss ≈ ln K at step 0.
  • Overfit one batch before you tune hyperparameters.
  • Read train versus val as a table of patterns, not a vibe.
  • Change one thing at a time. Plot the learning rate as well as the loss.

Further learning

Karpathy's recipe is short and worth re-reading before every new training run.

A Recipe for Training Neural NetworksMusings of a Computer Scientist.karpathy.github.io Neural Networks: Zero to HeroNeural Networks: Zero To Herokarpathy.ai