|
| 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