summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--README.md69
-rw-r--r--design/preregistration.md50
3 files changed, 101 insertions, 20 deletions
diff --git a/.gitignore b/.gitignore
index a0b7284..c986bc4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,5 +2,7 @@ __pycache__/
*.pyc
.venv/
runs/
+!runs/*/
+!runs/*/summary.csv
.pytest_cache/
report/
diff --git a/README.md b/README.md
index bae6cf7..3216e2d 100644
--- a/README.md
+++ b/README.md
@@ -1,34 +1,63 @@
# Prime Grokking
-Can minimal architectures learn the next-prime function — or *grok* it rather than memorize it?
+**Can a minimal architecture learn the next-prime function — or *grok* it rather than memorize it?**
-Experiment 1 (seed 0): weight-tied 2-layer RNN cell (K=20 tied steps, ACT learned halting)
-vs. a fixed-d_model transformer baseline, range n ∈ [2, 100], 30% holdout.
+The grokking literature studies almost exclusively group-structured tasks (modular arithmetic).
+Next-prime supplies the missing **non-group-structured case**. Results so far (phases 1–4,
+range [2, 100]): **no grokking observed** — memorization, partial in-range generalization, and a
+decomposition surprise (is-prime generalizes ~2.5x better than next-prime), but no delayed
+transition. That negative-class result is the point of the project; E6 (range [2, 1000]) and a
+long-horizon follow-up are in flight.
-## Layout
+**The unusual bit:** every batch is **pre-registered**. Before each run, the outcome →
+interpretation matrix is committed to the private research repo (the commit hash is the lock),
+and results are interpreted *only* against that lock. The complete record, addenda 1–6, is
+mirrored in [`design/preregistration.md`](design/preregistration.md).
-```
-design/experiment-spec.md design doc (copied from the research repo, provenance noted)
-design/preregistration.md pre-registered outcome→interpretation matrix (LOCK: commit 00c696d in research repo)
-src/ config, data, model API, models, train, eval
-tests/ pytest suite (data correctness, model shapes, halting)
-scripts/ run_experiment.sh, plot.py
-runs/ metrics CSVs + plots (gitignored)
-```
+## Contents
+
+- `design/` — experiment spec, full pre-registration, external review passes (Gemini, Codex) including rejected points and why
+- `src/` — config, data (sieve + bisect), weight-tied ACT-GRU RNN, GPT-style transformer baseline, train, eval (chunked, probe reports)
+- `tests/` — 48-test pytest suite (data correctness, weight-tying, batch invariance, device handling, scaling)
+- `scripts/` — idempotent sweep runner, experiment launcher, plots
+- `NOTES-*.md` — per-phase analyses written against the lock, not after the fact
+- `runs/*/summary.csv` — headline numbers per phase (raw run dirs are gitignored; everything is regenerable)
## Quick start
+CPU (no GPU needed, ~35 min/run on 2 cores):
+
```bash
python3 -m venv .venv
-.venv/bin/pip install torch --index-url https://download.pytorch.org/whl/cpu numpy matplotlib pytest
+.venv/bin/pip install torch --index-url https://download.pytorch.org/whl/cpu
+.venv/bin/pip install numpy matplotlib pytest
.venv/bin/pytest tests/ -q
-scripts/run_experiment.sh rnn 0 # full run, ~35 min on 2 cores
-scripts/run_experiment.sh transformer 0
-scripts/plot.py
+.venv/bin/python -m src.train rnn 0
```
-## Notes
+CUDA (AMP fp16 is on by default on CUDA; Turing tensor cores):
+
+```bash
+.venv/bin/pip install torch --index-url https://download.pytorch.org/whl/cu126
+.venv/bin/python -m src.train transformer 0 --range_end 1000 --max_steps 32 --device cuda
+```
+
+Notes: `--max_steps` is K (the tied-iteration cap — it must exceed the max prime gap of the
+range: 20 below 1000, 36 below 10^4, 72 below 10^5). `--compile_model True` roughly doubles the
+transformer on CUDA but hurts the RNN (dynamic halting breaks graph capture). Full flag surface
+(weight decay, train fraction, task mode, vocab mode, halting ablation, cosine decay) lives in
+`src/config.py`.
+
+## Research discipline
+
+- Outcome (O1–O4), probe-signature (P1–P6), and halting (H1–H4) codes locked before runs; no post-hoc reinterpretation — `NOTES-*.md` compares measurements against the lock and reports whichever branch fired.
+- Seed replication for headline cells; no hyperparameter tuning on the validation split.
+- Pre-registered interpretation matrices were reviewed by external models (Gemini, Codex) before locking.
+
+## Blog
+
+The experiment is covered in a multi-part series on [jayrup.me](https://jayrup.me/) (parts 1–3, Aug 2026).
+
+## License
-- Results are interpreted ONLY against `design/preregistration.md` (outcome codes O1–O8, H1–H4, P1–P4).
-- Seed-0 runs are anecdotes until seeds {1, 2}; no hyperparameter tuning on the val set.
-- Remote: `ssh://meru/~/projects/prime-grokking.git` (private; MIT license included for future publishing).
+[MIT](LICENSE)
diff --git a/design/preregistration.md b/design/preregistration.md
index 7efa8ad..07d0791 100644
--- a/design/preregistration.md
+++ b/design/preregistration.md
@@ -261,3 +261,53 @@ interpretation per Addendum 4 E5, unchanged.
Batch = 11 runs: e4 (2), e3 (2), ints (3), isp (4). 2-way parallel, one thread per child,
same eval cadence, metrics, and early stop as all previous phases.
+
+---
+
+## Addendum 6 — E6: dataset extension to [2, 1000] (locked 2026-08-17, pre-run)
+
+**Question (Q3c):** does increasing the dataset 10× (range_end 100 → 1000) change the outcome
+class of next-prime learning? Power et al. (2201.02177): "smaller datasets require increasing
+amounts of optimization for generalization" — the inverse prediction: more data should pull any
+grokking transition earlier. E6 is the SAME protocol as phases 1–3 (E1+E2 replication) with
+exactly one variable changed: range_end 100 → 1000.
+
+**Protocol (all cells):** digits mode, task next_prime, train_frac 0.7, lr 1e-3 const,
+max_train_steps 200_000, eval_every 200, ACT halting on (halt_penalty 0.01), d_model 128.
+**Changed vs phases 1–3 (recorded, unavoidable):**
+- `--max_steps 32` (K). Max prime gap below 1000 is 20 (887→907), so K=20 is the exact worst
+ case with zero margin. K=32 covers every in-range target. Rationale logged pre-run.
+- `--device cuda` + AMP fp16 autocast (T1000, ichi). fp16 numerics differ from the CPU fp32
+ baseline. The O/P/H classification is precision-robust; if any cell lands within ±2 points of
+ a classification boundary, the tiebreak re-run is fp32 on ichi CPU.
+- Outputs up to 4 digits: covered by max_out_len 6; global layout is range-derived (bisect +
+ margin code, tested to 100k).
+
+**Cells (16):**
+- wd sweep {0.01, 0.1, 0.3, 1.0, 3.0} × {rnn, transformer}, seed 0 (10)
+- wd 1.0 replication × seeds {1, 2} × {rnn, transformer} (4)
+- batch-size ablation: wd 1.0, seed 0, batch 128 × {rnn, transformer} (2)
+
+**Interpretation matrix — O/P/H codes unchanged (locked Addenda 1–4). Probe range is now
+[1001, 2000]. New P-ladder (sieve-rank estimation, replaces the single P1 signature):**
+- A model that internalized a k-prime sieve misses exactly the composites whose prime factors
+ all exceed p_k; the smallest missed composite in probe range identifies k unambiguously:
+ 1147→k=10, 1369→k=11, 1681→k=12, 1849→k=13, none→k≥14 (exact trial division to √n).
+- In-range discriminator: the 960→961 case (961=31² is the ONLY composite below 1000 with all
+ factors ≥ 31) separates k=10 from k=11.
+- P5(k) = errors concentrated on the rank-k signature set; P6 = exact (no probe misses).
+- P3 threshold for the [1001, 2000] probe: ≥90% (a rank-10 sieve scores ~97% there).
+- Locked reading: P5(k=10) would confirm the "first-10-primes heuristic" hypothesis; P6 would
+ show full divisibility transfer; P4/P2 keep their existing meanings.
+- E6 outcome vs phase 1–3: an O1 anywhere = data pressure unlocked grokking; same codes =
+ the task's walls are algorithmic, not data-bound.
+
+**Compute:** ichi (T1000 + i7-8700), tmux batch, run_sweep concurrency 4, GPU jobs only.
+Benchmarks pre-run: transformer 66 steps/s (AMP), rnn 31 steps/s → batch est. 2.5–4 h.
+
+**E7 (next, after E6 analysis):** long-horizon test — 20× budget (4M steps) on the best E6
+cells, per user decision; protocol locked in Addendum 7 post-E6.
+
+---
+
+*Publication note (2026-08-17): this file is mirrored verbatim from the private research repo (prime-grokking/preregistration.md) at the moment the experiment repo went public; hashes cited above are research-repo commits. The experiment repo commit history preserves each mirror step.*