Makemore
- 4 Devlogs
- 27 Total hours
LLM generator practice.
LLM generator practice.
Starting from my GPT-2 124M reproduction and dragging the architecture from 2019 to 2026, one component at a time. The plan is a ladder: swap one thing, understand exactly what it does, keep going. This devlog covers the three architecture swaps.
What changed:
Deliberate: I care more about a stronger model here than a clean ablation, and I can spend the compute.
The swaps are each ~20 to 40 lines. The trap was RoPE. It’s the classic silent bug: get the pairing convention wrong between the cos/sin cache and the apply function and the model still trains fine, it just quietly underperforms and you never find out. So I wrote a unit test instead of trusting the loss curve: shift the whole sequence by k positions and assert the attention scores between the same token pairs are unchanged. Rotation invariance either holds or it doesn’t (like an odometer).
Reproduced GPT-2 124M (the old 2019 model) from scratch, trained on ~10B tokens across 2x RTX 5090 in ~7 hours. Final val loss ~3.10.
GPT-2 124M: embd=768, block_size=1024, weight-tied embeddings (~124M params)
The architecture was basically the char transformer from last devlog, just wider (124M vs ~10M) with BPE instead of 65 chars. The model was the easy part.
The real work was scale engineering: sharding 10B tokens to stream off disk, gradient accumulation to hit a 0.5M-token batch on cards that OOM at batch 8, multi-GPU gradient sync with DDP, mixed precision, and checkpoint/resume so a 7-hour cloud run survives interruptions. That’s what turns a transformer into a trained LM.
makemore — devlog
mlp2-gpu: names MLP
Dataset: Karpathy’s names.txt (32k names, vocab 27)
Architecture:
embed=10 -> flatten -> linear(200) -> tanh -> linear(27)
Training:
Result:
dev loss = 2.20
Samples:
bhuza
fremah
mykeslanna
talee
The model worked because names are short and mostly depend on local character patterns.
mlp3: Tiny Shakespeare (without a guide and with single hidden layer)
Dataset:
Architecture:
embed=32, hidden=400, block_size=16
Training:
Results:
train loss = 1.12
dev loss = 2.02
Samples:
LERCUTIF:
MARCAPUL:
HENRY:
Why it failed:
The model was not too small. It was the wrong architecture.
Next:
WaveNet-style hierarchical MLP from the next lecture.
Instead of flattening all embeddings at once, combine them in stages to preserve locality and expand the receptive field.
Goal:
After that: transformers.