summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/campaign/FW135M_BP_BASELINE.md89
-rw-r--r--ep_run/baseline_configs/fw135m_matched_bp.json42
-rw-r--r--ep_run/fw135m_baseline.py117
3 files changed, 248 insertions, 0 deletions
diff --git a/docs/campaign/FW135M_BP_BASELINE.md b/docs/campaign/FW135M_BP_BASELINE.md
new file mode 100644
index 0000000..3f81ba8
--- /dev/null
+++ b/docs/campaign/FW135M_BP_BASELINE.md
@@ -0,0 +1,89 @@
+# FW135M BP Twin Run Sheet
+
+Source of truth: `docs/BASELINE_SPEC.md`.
+
+Status: commands configured on branch `xiang`; no training has started.
+
+## First width-only rung
+
+- Shape: `L12/C768/H12/T256`
+- Head dimension: `64`
+- Exact local parameter count: `135,303,936`
+- Data: existing FineWeb-Edu 32k bins
+- Batch: `B24`
+- Target: `20N = 2,706,078,720` tokens
+- Complete-batch exposure: `2,706,081,792` tokens
+- Trainer argument: `--steps 440442` (440,443 inclusive updates)
+
+## What changes from 72M
+
+- Width: `512 -> 768`
+- Heads: `8 -> 12`
+- Parameters: `72.11M -> 135.30M`
+- Run length: increases to preserve approximately 20 tokens/parameter
+
+## What stays identical
+
+- L12 depth and 64-dimensional heads
+- T256 and B24
+- FineWeb-Edu data and 32k tokenizer
+- OLMo2-style model implementation
+- Muon hybrid optimizer and cosine schedule
+- Weight decay 0.1 and BF16 autocast
+- Seed list and validation cadence
+- Existing `casc_bp_train.py` code path
+
+## LR sweep
+
+At this smallest new rung only:
+
+- `7e-4`
+- `1e-3`
+- `1.4e-3`
+
+Only Adam-side LR changes. Carry the winner to larger rungs.
+
+No result may be quoted with fewer than two seeds. Record best validation CE, final-step CE, and tail median. Save every 5,000 steps and log validation every 100 steps.
+
+## Dry-run launcher
+
+From `ep_run/`:
+
+```bash
+python -m py_compile fw135m_baseline.py
+python fw135m_baseline.py --mode smoke
+python fw135m_baseline.py --mode sweep
+python fw135m_baseline.py --mode full
+```
+
+Commands print by default. Add `--execute` only when ready.
+
+Smoke:
+
+```bash
+python fw135m_baseline.py --mode smoke --execute
+```
+
+LR sweep:
+
+```bash
+python fw135m_baseline.py --mode sweep --execute
+```
+
+Selected full run:
+
+```bash
+python fw135m_baseline.py --mode full --lr <selected-lr> --seed 1 --execute
+python fw135m_baseline.py --mode full --lr <selected-lr> --seed 2 --execute
+```
+
+W&B remains off until configured. Later:
+
+```bash
+python fw135m_baseline.py --mode full --lr <selected-lr> \
+ --wandb_project <project> --execute
+```
+
+## Final EP/BP comparison
+
+The EP arm must use the same shape, data, B/T, steps, optimizer family, selected shared settings, seeds, and evaluation cadence. Only the training rule and EP-specific `β` controls differ.
diff --git a/ep_run/baseline_configs/fw135m_matched_bp.json b/ep_run/baseline_configs/fw135m_matched_bp.json
new file mode 100644
index 0000000..0e22686
--- /dev/null
+++ b/ep_run/baseline_configs/fw135m_matched_bp.json
@@ -0,0 +1,42 @@
+{
+ "source_of_truth": "docs/BASELINE_SPEC.md",
+ "purpose": "First approximately 2x BP twin rung after the completed 72M FineWeb model",
+ "changed_from_72m": {
+ "width": "512 -> 768",
+ "heads": "8 -> 12",
+ "parameters": "72,114,688 -> 135,303,936",
+ "training_updates": "440,443 updates to preserve approximately 20 tokens/parameter"
+ },
+ "held_fixed_from_72m": {
+ "layers": 12,
+ "head_dim": 64,
+ "context": 256,
+ "global_sequence_batch": 24,
+ "data": "fineweb_edu",
+ "vocab": 32768,
+ "architecture": "local OLMo2-style",
+ "optimizer": "Muon on hidden matrices plus AdamW on remaining parameters",
+ "muon_lr": 0.02,
+ "adam_side_lr_center": 0.001,
+ "weight_decay": 0.1,
+ "warmup_steps": 500,
+ "schedule": "cosine to 0.1 of peak",
+ "precision": "bf16 autocast with fp32 parameters/states"
+ },
+ "locked_run": {
+ "tag": "fw135m_bp",
+ "layers": 12,
+ "width": 768,
+ "heads": 12,
+ "head_dim": 64,
+ "context": 256,
+ "batch": 24,
+ "parameters": 135303936,
+ "target_tokens_20N": 2706078720,
+ "trainer_steps_argument": 440442,
+ "actual_updates": 440443,
+ "actual_tokens": 2706081792
+ },
+ "bp_lr_sweep_smallest_rung_only": [0.0007, 0.001, 0.0014],
+ "minimum_seeds_before_reporting": 2
+}
diff --git a/ep_run/fw135m_baseline.py b/ep_run/fw135m_baseline.py
new file mode 100644
index 0000000..ddcc5c0
--- /dev/null
+++ b/ep_run/fw135m_baseline.py
@@ -0,0 +1,117 @@
+"""Dry-run-by-default launcher for BASELINE_SPEC.md's first BP twin rung."""
+from __future__ import annotations
+
+import argparse
+import subprocess
+import sys
+
+
+VOCAB = 32768
+LAYERS = 12
+WIDTH = 768
+HEADS = 12
+CONTEXT = 256
+BATCH = 24
+PARAMETERS = 135303936
+FULL_STEPS_ARG = 440442 # casc_bp_train.py loops inclusively: 440,443 updates
+LR_SWEEP = ("7e-4", "1e-3", "1.4e-3")
+
+
+def parameter_count(vocab=VOCAB, layers=LAYERS, width=WIDTH):
+ hidden = ((8 * width // 3) + 63) // 64 * 64
+ return 2 * vocab * width + width + layers * (
+ 4 * width * width + 3 * width * hidden + 4 * width
+ )
+
+
+def command(tag, lr, steps, warmup, seed, wandb_project):
+ return [
+ sys.executable,
+ "casc_bp_train.py",
+ "--tag",
+ tag,
+ "--L",
+ str(LAYERS),
+ "--C",
+ str(WIDTH),
+ "--H",
+ str(HEADS),
+ "--T",
+ str(CONTEXT),
+ "--B",
+ str(BATCH),
+ "--steps",
+ str(steps),
+ "--lr",
+ lr,
+ "--warmup",
+ str(warmup),
+ "--amp",
+ "--olmo2",
+ "--wd",
+ "0.1",
+ "--opt",
+ "muon",
+ "--muon_lr",
+ "0.02",
+ "--cosine",
+ "--lr_min_ratio",
+ "0.1",
+ "--data",
+ "fineweb_edu",
+ "--seed",
+ str(seed),
+ "--save_every",
+ "5000",
+ "--log",
+ "100",
+ "--wandb",
+ wandb_project,
+ "--wandb_run",
+ tag if wandb_project else "",
+ ]
+
+
+def main():
+ ap = argparse.ArgumentParser()
+ ap.add_argument("--mode", choices=("smoke", "sweep", "full"), default="smoke")
+ ap.add_argument("--execute", action="store_true", help="run commands; default only prints")
+ ap.add_argument("--lr", default="1e-3", help="selected LR for --mode full")
+ ap.add_argument("--seed", type=int, default=1)
+ ap.add_argument("--sweep_steps", type=int, default=FULL_STEPS_ARG)
+ ap.add_argument("--wandb_project", default="")
+ args = ap.parse_args()
+
+ count = parameter_count()
+ if count != PARAMETERS:
+ raise RuntimeError(f"parameter formula returned {count}, expected {PARAMETERS}")
+
+ if args.mode == "smoke":
+ runs = [(f"fw135m_bp_smoke_s{args.seed}", args.lr, 400, 50)]
+ elif args.mode == "sweep":
+ runs = [
+ (
+ f"fw135m_bp_lr{lr.replace('-', 'm').replace('.', 'p')}_s{args.seed}",
+ lr,
+ args.sweep_steps,
+ 500,
+ )
+ for lr in LR_SWEEP
+ ]
+ else:
+ runs = [(f"fw135m_bp_s{args.seed}", args.lr, FULL_STEPS_ARG, 500)]
+
+ print(
+ f"# L{LAYERS} C{WIDTH} H{HEADS} T{CONTEXT} B{BATCH} "
+ f"| {PARAMETERS:,} params | target 20N={20 * PARAMETERS:,} tokens",
+ flush=True,
+ )
+ for tag, lr, steps, warmup in runs:
+ cmd = command(tag, lr, steps, warmup, args.seed, args.wandb_project)
+ print(" ".join(f'"{item}"' if item == "" else item for item in cmd), flush=True)
+ if args.execute:
+ subprocess.run(cmd, check=True)
+
+
+if __name__ == "__main__":
+ main()