Code Architecture: Chinchilla Scaling Laws Notebook
Overview
The notebook implements a simplified but complete reproduction of the Chinchilla scaling law analysis. It trains several small character-level transformer language models at different parameter counts and training-token combinations, records the final cross-entropy loss for each, and fits the parametric scaling law L(N,D) = E + A/N^α + B/D^β to the collected data. It then derives the compute-optimal allocation N_opt(C) and D_opt(C), compares it to the Kaplan et al. (2020) allocation, and visualizes the scaling-law frontier — exactly as the paper does with its 400+ models, but at a miniature scale runnable on a single GPU within 30 minutes.
Section-by-Section Breakdown
1. Setup & Imports
- Import PyTorch, numpy, scipy (for curve fitting), matplotlib.
- Set random seeds for reproducibility.
- Configure device (GPU/CPU).
- Define hyperparameter grid: list of model configurations (n_layer, n_embd, n_head) and token counts to sweep.
2. Toy Text Corpus
- Generate or load a small text corpus (Shakespeare-like or synthetic structured text).
- Build a character-level tokenizer (vocab ~65 characters).
- Data shapes: Input
(batch, seq_len), target(batch, seq_len)— standard next-token prediction. - The corpus is large enough to train on varying numbers of tokens without repetition issues.
3. Small Transformer Language Model
- Key class:
MiniTransformer(nn.Module)— a minimal GPT-style decoder with:- Token + positional embeddings
- N Transformer decoder blocks (causal multi-head self-attention + feedforward + residual + layer norm)
- LM head (tied weights optional)
- Configurable
n_embd(embedding dim),n_layer(depth),n_head(attention heads),vocab_size,max_seq_len=256. - Model sizes in the sweep: ~10K, ~50K, ~100K, ~200K, ~500K parameters (small enough to train many variants quickly).
- Forward shapes:
(batch, seq_len)→ embeddings(batch, seq_len, n_embd)→ blocks(batch, seq_len, n_embd)→ logits(batch, seq_len, vocab_size). - Parameter counting: A helper
count_parameters(model)returns total non-embedding params, matching the paper’s convention (N excludes embedding/token tables where possible).
4. Training Sweep — Multiple (N, D) Combinations
- Key function:
train_model(config, n_tokens, ...)— trains one model with the given config for n_tokens tokens and returns the final validation loss. - Sweep over a grid of model sizes × token counts:
- 5 model sizes (varying n_embd and n_layer)
- 4-5 token counts per model (e.g., 1M, 2M, 5M, 10M, 20M tokens)
- Total: ~20-25 training runs
- Each run: AdamW optimizer, cosine LR schedule, ~short training (just enough to reach the loss curve’s smooth region for that token count).
- Record: (N_params, D_tokens, final_loss, compute_flops) for each run.
- Compute: FLOPs ≈ 6 * N * D (forward + backward, as in the paper).
- Data shapes: Each training step processes
(batch_size, seq_len)wherebatch_size * seq_len = tokens_per_step.
5. Fitting the Parametric Scaling Law
- Key function:
fit_scaling_law(loss_data)— usesscipy.optimize.curve_fitto fit:L(N, D) = E + A / N^alpha + B / D^betawhere (E, A, B, alpha, beta) are free parameters fitted to the (N, D, loss) data.
- Initial guesses: E~1.0, A~100, B~100, alpha~0.3, beta~0.3 (based on paper’s values).
- Report fitted parameters and compare to paper’s values (E=1.69, A=406.4, B=410.7, alpha=0.34, beta=0.28).
- Loss landscape visualization: 3D or contour plot of L(N, D) surface with fitted parameters.
6. Deriving Compute-Optimal Allocation
- Key function:
compute_optimal_ND(C, E, A, B, alpha, beta)— given compute budget C, minimize L(N,D) subject to 6ND = C.- Using Lagrange multipliers or numerical optimization (scipy.optimize.minimize with constraint).
- Derive: N_opt(C) ∝ C^(beta/(alpha+beta)), D_opt(C) ∝ C^(alpha/(alpha+beta)).
- For alpha=beta: N_opt ∝ C^0.5, D_opt ∝ C^0.5 (equal scaling — the Chinchilla result).
- Plot N_opt and D_opt as functions of C on a log-log scale.
- Compare to Kaplan et al.’s prediction: N_opt ∝ C^0.73, D_opt ∝ C^0.27.
7. IsoFLOP Analysis (Approach 2)
- For a fixed compute budget C, select several model sizes and train each for the token count D = C / (6*N).
- Plot final loss vs model size for each IsoFLOP curve.
- Find the minimum of each curve → optimal N for that C.
- Repeat for 3-4 compute levels and show the optimal N scales as C^0.5.
8. Visualization & Comparison
- Plot 1: Loss vs FLOPs for all training runs, colored by model size. Show the compute-optimal frontier (envelope of minimum-loss points).
- Plot 2: Log-log plot of N_opt(C) and D_opt(C) vs C, with fitted power laws. Overlay Kaplan et al.’s prediction for contrast.
- Plot 3: Parametric loss surface L(N, D) with the compute-optimal curve overlaid.
- Plot 4: Bar chart comparing Chinchilla allocation (equal N/D scaling) vs Kaplan allocation (N-heavy) at a representative compute budget.
- Summary table: Fitted parameters vs paper’s parameters, and predicted optimal N/D ratio.
Key Functions/Classes
| Component | Class/Function | Purpose |
|---|---|---|
| Tokenizer | CharTokenizer | Character-level tokenizer for the toy corpus |
| Language Model | MiniTransformer | GPT-style decoder for language modeling |
| Param Counter | count_parameters() | Count non-embedding model parameters |
| Training | train_model() | Train one model for N tokens, return final loss |
| Sweep | run_sweep() | Train models across the (N, D) grid |
| Scaling Law Fit | fit_scaling_law() | Fit L = E + A/N^α + B/D^β via scipy curve_fit |
| Optimal Allocation | compute_optimal_ND() | Derive N_opt, D_opt for a given compute budget C |
| IsoFLOP Analysis | run_isoflop() | Train at fixed FLOPs, varying model size |
| Visualization | plot_results() | Generate all comparison plots |
Data Flow
Toy Corpus → CharTokenizer → Training Grid (N × D)
↓
train_model() for each (N, D)
↓
(N, D, loss, FLOPs) records
↓
┌───────────┴───────────┐
↓ ↓
fit_scaling_law() run_isoflop()
(parametric fit) (Approach 2)
↓ ↓
E, A, B, α, β N_opt per FLOP level
↓ ↓
compute_optimal_ND() compare approaches
↓ ↓
└───────────┬───────────┘
↓
plot_results()
(frontier, N_opt vs C, Kaplan comparison)
Deliberate Simplifications vs Full Paper
| Aspect | Paper | This Notebook |
|---|---|---|
| Model sizes | 70M to 16B+ parameters | ~10K to ~500K parameters |
| Training data | 5B to 500B tokens (MassiveText) | 1M to 20M tokens (toy corpus) |
| Number of models | 400+ training runs | ~20-25 training runs |
| Tokenizer | SentencePiece/byte-level BPE | Character-level (~65 vocab) |
| Architecture | Full GPT-style transformer (Gopher-like) | Mini GPT (2-6 layers, 64-256 embd) |
| Compute budget | ~10^21 to 10^25 FLOPs | ~10^8 to 10^11 FLOPs |
| FLOP formula | 6ND (same) | 6ND (same) |
| Scaling law params | E=1.69, A=406.4, B=410.7, α=0.34, β=0.28 | Fitted from toy data (values will differ) |
| IsoFLOP curves | Trained at 9 FLOP levels | 3-4 FLOP levels |
| Chinchilla model | 70B params, 1.4T tokens | Not trained (too large); inferred from scaling law |
| Evaluation | MMLU, BIG-bench, etc. | Validation loss only |
These simplifications keep the notebook runnable within Kaggle’s 30-minute GPU limit while faithfully implementing all three scaling-law estimation approaches and the parametric loss fitting from the paper.