Genesis is a GPT-2 language model implemented entirely from scratch — from the multi-head attention mechanism to the byte-pair tokenizer wrapper to the production training loop. This is my first deep learning project, built to truly understand how large language models work under the hood.
"The French Revolution began in 1866. The Spanish were the last
two-year-old boyhood – the Spanish-speaking War of 1878..."
— Genesis at step 91k. Grammatically fluent, factually hilarious.
Architecture
Genesis follows the GPT-2 architecture (Radford et al., 2019):
Why 163M instead of 124M? GPT-2 ties its input embedding and output head weights (saving ~38.6M params). Genesis keeps them separate — a deliberate choice to understand the full parameter space.
Sample Generation — Prints model outputs during training for qualitative monitoring
WikiText Forgetting Check (Phase 2) — Monitors whether new data causes catastrophic forgetting
Sample Outputs
At Step 91,000 (Phase 1 — WikiText)
>> The French Revolution began in
The French Revolution began in 1866. The Spanish were the last
two-year-old boyhood – the Spanish-speaking War of 1878.
>> Albert Einstein discovered that
Albert Einstein discovered that he was pregnant with the car.
According to the New York Times, "the first time a young man
would have been the first time he had a"...
The model has learned fluent English grammar and Wikipedia-style structure — but factual accuracy is, shall we say, creative. This is expected for a 163M model at this training stage.
Key Implementation Details
What I built from scratch
Multi-head causal self-attention with parallel head processing via reshape (not head loops)
Pre-LayerNorm transformer blocks matching GPT-2 paper
Tanh-approximated GELU activation
Sliding-window dataset with configurable stride for next-token prediction
Production training loop with all the bells and whistles (AMP, cosine LR, gradient accumulation, checkpointing)
Inference engine with temperature, top-k, and top-p (nucleus) sampling
Auto config detection — generate.py inspects checkpoint weight dimensions to reconstruct model config without needing the config dict
HuggingFace datasets — Dataset downloading for Phase 2
Lessons Learned
Data quality > quantity — WikiText-103 alone teaches grammar but not coherent multi-sentence output. Adding TinyStories dramatically improves narrative flow.
Small models hallucinate confidently — 163M parameters is enough for fluent English but not for factual accuracy. Einstein being "pregnant with the car" is a feature, not a bug (at this scale).
Checkpoint everything — Colab disconnects are inevitable. Saving to Drive every 500 steps saved me dozens of hours.
Weight tying matters — The difference between 124M and 163M params is entirely the un-tied embedding weights. Something to fix in v2.
Learning rate is everything — Phase 2 uses 1e-4 (not 3e-4) to avoid catastrophic forgetting of Phase 1 knowledge.