Skip to content

Commit 7459e2b

Browse files
Add one-head FineWeb-Edu nanoGPT baselines
1 parent e3e1937 commit 7459e2b

29 files changed

Lines changed: 4580 additions & 2 deletions

README.md

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ architectures and modalities rather than against a single toy model.
1313
| --- | --- | --- | --- |
1414
| **MLP3 / MNIST** | `784 -> 512 -> 512 -> 10` MLP on MNIST | SGD + momentum, AdamW, SGD + momentum + Muon | Cheap, tightly controlled optimizer and spectral debugging |
1515
| **Small ViT / CIFAR-10** | 6-block, 192-wide Vision Transformer with 4x4 patches | SGD + Nesterov, AdamW, Muon + auxiliary AdamW | Transformer optimization on vision data with residual/attention structure |
16+
| **One-head nanoGPT / FineWeb-Edu** | 1 block, 1 attention head, width 128, context 256 on a pinned document-disjoint FineWeb-Edu corpus | SGD + Nesterov, AdamW, Muon + auxiliary AdamW | Smallest realistic language-model optimizer baseline with MPS restart support and per-epoch spectral diagnostics |
1617
| **nanochat d12** | 12-layer, 768-wide, 2048-context nanochat language model | Native nanochat Muon + AdamW recipe | Modern small-LLM reference baseline with tuned initialization, parameter groups, scaling rules, and schedules |
1718

1819
### MLP3 / MNIST
@@ -37,6 +38,23 @@ auxiliary AdamW. It uses three seeds, optimizer-specific tuned hyperparameters,
3738
warmup/cosine schedules, CIFAR-10 augmentation, checkpoint persistence, and
3839
WeightWatcher spectral diagnostics.
3940

41+
### One-head nanoGPT / FineWeb-Edu
42+
43+
[`baseline/nanogpt_one_head/`](baseline/nanogpt_one_head) contains the smallest
44+
realistic language-model control. It trains a one-block, one-attention-head
45+
nanoGPT on a pinned FineWeb-Edu `sample-10BT` stream rather than Tiny
46+
Shakespeare. Exact document-disjoint 10M/1M/1M-token train/validation/test
47+
splits are shared across SGD + Nesterov, AdamW, and Muon + auxiliary AdamW.
48+
49+
The suite uses optimizer-specific warmup/cosine schedules, three independent
50+
seeds, restartable full checkpoints, Apple-MPS execution, per-epoch
51+
train/validation/test loss, next-token accuracy and perplexity, fixed held-out
52+
continuation BLEU, and WeightWatcher calls with `ERG=True` and
53+
`randomize=True`. Raw per-matrix `alpha`, `ERG_gap`, and `num_traps` are
54+
retained without fallbacks or proxy counts. Four notebooks produce run-level
55+
95% Student-t confidence intervals and a fixed color map for the six
56+
transformer matrices.
57+
4058
### nanochat d12
4159

4260
`baseline/notebooks/NanoChat_D12_Reference_Baseline.ipynb` is the modern
@@ -58,8 +76,8 @@ The reusable runner lives at:
5876

5977
- `baseline/rg_baselines/nanochat_reference.py`
6078

61-
See [`baseline/README.md`](baseline/README.md) for detailed run instructions,
62-
output layouts, metrics, and reproducibility conventions.
79+
See [`baseline/README.md`](baseline/README.md) for the shared baseline
80+
conventions and the experiment-specific READMEs for exact run instructions.
6381

6482
## Optimizer variants
6583

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
.venv-one-head/
2+
__pycache__/
3+
.pytest_cache/
4+
*.pyc
5+
runs/
6+
data/
7+
plots/
8+
*.log
9+
.ipynb_checkpoints/
Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
# One-head nanoGPT optimizer baselines
2+
3+
This experiment is the smallest realistic language-model baseline in
4+
`CalculatedContent/rg_optimizers`. It was adapted from the restart, data,
5+
measurement, and multi-seed conventions in
6+
`CalculatedContent/nanogpt-experiments`, but is kept isolated here so RG
7+
optimizer variants can use it as a clean control.
8+
9+
It trains the same **one-block, one-attention-head nanoGPT** with:
10+
11+
1. **SGD + Nesterov momentum**;
12+
2. **AdamW**;
13+
3. **Muon on hidden transformer matrices + auxiliary AdamW**.
14+
15+
The experiment does **not** use Tiny Shakespeare. It streams a pinned revision
16+
of FineWeb-Edu, creates exact document-disjoint train/validation/test splits,
17+
and tokenizes them with GPT-2 BPE.
18+
19+
## Reference protocol
20+
21+
| Component | Value |
22+
|---|---:|
23+
| Dataset | `HuggingFaceFW/fineweb-edu`, `sample-10BT` |
24+
| Dataset revision | `593b3a867298afb8ce42625a270ef20ddcad28f9` |
25+
| Tokenizer | GPT-2 BPE, vocabulary 50,257 |
26+
| Training split | 10,000,000 tokens |
27+
| Validation split | 1,000,000 tokens |
28+
| Test split | 1,000,000 tokens |
29+
| Split construction | Document-disjoint |
30+
| Transformer blocks | **1** |
31+
| Attention heads | **1** |
32+
| Embedding width | 128 |
33+
| Context length | 256 |
34+
| MLP width | 512 |
35+
| Dropout | 0.0 |
36+
| Bias | false |
37+
| Token embedding / LM head | tied |
38+
| Micro-batch | 4 sequences |
39+
| Gradient accumulation | 8 |
40+
| Tokens per optimizer step | 8,192 |
41+
| Target training horizon | 5 passes over the fixed train split |
42+
| Optimizer steps | 6,104 |
43+
| Seeds | 1337, 2027, 4099 |
44+
| Preferred device | Apple MPS |
45+
| Numerical precision | float32 |
46+
47+
The model uses nanoGPT-style `N(0, 0.02)` initialization and scales the two
48+
residual-output matrices by `1/sqrt(2 * n_layer)`. With one block, WeightWatcher
49+
sees exactly six matrices:
50+
51+
```text
52+
W_Q, W_K, W_V, W_O, W_MLP_IN, W_MLP_OUT
53+
```
54+
55+
## Optimizer profiles
56+
57+
The profiles are intentionally optimizer-specific. Forcing the same numerical
58+
learning rate across SGD, AdamW, and Muon would not be a meaningful control.
59+
60+
| Optimizer | Peak LR | LR floor | Warm-up | Schedule | Decay / momentum |
61+
|---|---:|---:|---:|---|---|
62+
| SGD + Nesterov | 0.05 | 0.005 | 10% | linear warm-up + cosine decay | momentum 0.90, weight decay 0.01 |
63+
| AdamW | 6e-4 | 6e-5 | 1% | linear warm-up + cosine decay | betas (0.90, 0.95), weight decay 0.10 |
64+
| Muon matrices | 0.02 | 0.002 | 5% | linear warm-up + cosine decay | momentum 0.95, Nesterov, 5 Newton-Schulz steps, weight decay 0.01 |
65+
| Muon auxiliary AdamW | 3e-4 | 3e-5 | 5% | same progress as Muon | betas (0.90, 0.95), weight decay 0.01 |
66+
67+
AdamW follows the canonical nanoGPT pretraining values. Muon follows the
68+
reference Muon partition: only hidden two-dimensional transformer matrices use
69+
Muon; embeddings, tied output parameters, normalization gains, and other
70+
non-Muon parameters use AdamW. The SGD profile is a conservative transformer
71+
baseline with a longer warm-up because it lacks AdamW's coordinate-wise
72+
normalization. These are strong preregistered reference settings, not a claim
73+
that a finite grid search has proven global optimality.
74+
75+
## WeightWatcher contract
76+
77+
At epoch zero and every nominal epoch, the code copies the six transformer
78+
matrices to CPU and calls:
79+
80+
```python
81+
watcher.analyze(
82+
ERG=True,
83+
randomize=True,
84+
plot=False,
85+
min_evals=20,
86+
)
87+
```
88+
89+
The raw result is saved. Required direct outputs include:
90+
91+
- per-matrix `alpha`;
92+
- per-matrix `ERG_gap`;
93+
- per-matrix `num_traps` from randomized MP diagnostics;
94+
- `detX_num`, `num_pl_spikes`, fit distance `D`, stable rank, MP soft rank,
95+
spectral/log norms, entropy, and all other returned WeightWatcher columns.
96+
97+
There is no fallback alpha, no proxy trap count, and no synthesized ERG gap.
98+
The reference configuration is strict: a WeightWatcher version that does not
99+
return `alpha`, `ERG_gap`, and `num_traps` fails visibly.
100+
101+
## Metrics and plots
102+
103+
Each epoch checkpoint records:
104+
105+
```text
106+
train / validation / test cross-entropy
107+
train / validation / test perplexity
108+
train / validation / test next-token top-1 accuracy
109+
fixed-continuation test BLEU
110+
validation and test generalization gaps
111+
learning rates
112+
gradient norms
113+
weight norm and update-to-weight ratio
114+
MPS memory usage
115+
```
116+
117+
The BLEU value is a deterministic secondary diagnostic. For 16 fixed held-out
118+
test segments, the model receives a 64-token prompt and greedily predicts the
119+
next 32 tokens. Corpus BLEU compares those continuations with the exact held-out
120+
continuations. It is **not** a translation benchmark and should not replace
121+
cross-entropy or perplexity.
122+
123+
The notebooks plot individual seed trajectories, the across-seed mean, and a
124+
two-sided **95% Student-t confidence interval**. Matrix plots use one invariant
125+
color map for `W_Q`, `W_K`, `W_V`, `W_O`, `W_MLP_IN`, and `W_MLP_OUT` across all
126+
optimizers.
127+
128+
## Checkpoints and restart behavior
129+
130+
Every run writes:
131+
132+
```text
133+
results/<optimizer>/seed_<seed>/
134+
manifest.json
135+
metrics.csv
136+
epoch_metrics.csv
137+
checkpoint_latest.pt
138+
checkpoint_best.pt
139+
checkpoint_final.pt
140+
epoch_checkpoints/
141+
model_epoch_000p000_step_0000000.pt
142+
model_epoch_001p000_....pt
143+
...
144+
spectral/
145+
layers.csv
146+
summary.csv
147+
raw/weightwatcher_step_*.csv
148+
test_results.json
149+
run_complete.json
150+
```
151+
152+
`checkpoint_latest.pt` contains the model, optimizer state, data-sampling RNG,
153+
Python/NumPy/Torch RNG state, elapsed time, and a protocol fingerprint. Rerunning
154+
the same command resumes an incomplete compatible run. A mismatched config,
155+
data identity, optimizer, or seed is rejected rather than silently resumed.
156+
Completed runs are skipped.
157+
158+
Test measurements are monitoring-only. Validation loss selects
159+
`checkpoint_best.pt`; test loss, test accuracy, test perplexity, and BLEU never
160+
change optimizer updates, schedules, early stopping, or checkpoint selection.
161+
162+
## MacBook MPS workflow
163+
164+
From the repository root:
165+
166+
```bash
167+
cd baseline/nanogpt_one_head
168+
bash scripts/setup_mac.sh
169+
bash scripts/prepare_data.sh
170+
bash scripts/smoke_test.sh
171+
172+
export RG_NANOGPT_ONE_HEAD_ROOT="$HOME/rg-nanogpt-one-head"
173+
caffeinate -dimsu bash scripts/run_all_baselines.sh \
174+
2>&1 | tee "$RG_NANOGPT_ONE_HEAD_ROOT/run_all.log"
175+
```
176+
177+
The setup script prints:
178+
179+
```text
180+
MPS built: True
181+
MPS available: True
182+
```
183+
184+
When MPS is available, `--device auto` selects it. Unsupported individual MPS
185+
operations may use PyTorch's CPU fallback because
186+
`PYTORCH_ENABLE_MPS_FALLBACK=1` is set by the scripts. WeightWatcher always runs
187+
on CPU copies of the matrices so its SVD/RMT path does not depend on MPS support.
188+
189+
The first data-preparation run requires internet access. Later runs reuse the
190+
exact token files and metadata under:
191+
192+
```text
193+
$RG_NANOGPT_ONE_HEAD_ROOT/data
194+
```
195+
196+
## Notebook order
197+
198+
```text
199+
notebooks/01_sgd_momentum_baseline.ipynb
200+
notebooks/02_adamw_baseline.ipynb
201+
notebooks/03_muon_baseline.ipynb
202+
notebooks/04_compare_baselines.ipynb
203+
```
204+
205+
The first three notebooks can run or resume their three seeds. The comparison
206+
notebook requires all nine runs and produces optimizer overlays plus final and
207+
validation-selected 95% confidence-interval tables.
208+
209+
Launch Jupyter with:
210+
211+
```bash
212+
.venv-one-head/bin/jupyter lab notebooks
213+
```
214+
215+
## Smaller development runs
216+
217+
The committed `configs/reference.yaml` defines the scientific reference.
218+
Temporary smoke or pilot changes should be written to a separate YAML file and
219+
must not overwrite the reference results directory.
220+
221+
Run one optimizer manually:
222+
223+
```bash
224+
.venv-one-head/bin/python -m rg_nanogpt_one_head.training \
225+
--config configs/reference.yaml \
226+
--optimizer adamw \
227+
--device auto
228+
```
229+
230+
Run one seed:
231+
232+
```bash
233+
.venv-one-head/bin/python -m rg_nanogpt_one_head.training \
234+
--config configs/reference.yaml \
235+
--optimizer muon \
236+
--seeds 1337 \
237+
--device auto
238+
```
239+
240+
## Validation
241+
242+
```bash
243+
bash scripts/smoke_test.sh
244+
```
245+
246+
The test suite checks the one-head architecture, all three optimizer update
247+
paths, exact document-disjoint split writing, checkpoint round-tripping,
248+
Student-t intervals, direct `ERG_gap`/`num_traps` handling, tiny CPU training,
249+
and notebook structure.

0 commit comments

Comments
 (0)