The notebook
Run the sweep yourself
The experiment ran on Google Colab GPUs from one notebook. Here it is, as published: read it below, download it, or open it in Colab.
The copy here is colab/run_sweep.ipynb at commit b1f62d3 (SHA-256 14193656b6d6…). Colab opens the repository's main branch.
A short guide
Which GPU
Colab assigns the GPU, and may give a different one from the one you asked for, so check: the notebook's test cell prints device, and every run log records it in its first line ("hardware": {… "device": …}). The experiment's 33 runs used:
- NVIDIA A100-SXM4-40GB: 27 runs
- NVIDIA L4: 3 runs
- NVIDIA A100-SXM4-80GB: 2 runs
- Tesla T4: 1 run
Drive copies and resuming
The work happens on Colab's local disk; results, checkpoints and the tokenised data are copied to MyDrive/DeMo_Fixed_Band_Experiment_state with rsync every 10 minutes and when the sweep ends, and restored from there at the start of each session. If the session disconnects, reconnect and run all again: finished runs are skipped and an interrupted run resumes from its last checkpoint. To stop early, interrupt the sweep cell and run save_to_drive() before disconnecting.
How long each configuration took
Wall time per run of 3,000 steps, mean over seeds, from the run logs (results.json's seconds), with the GPUs the runs used. Times vary with the GPU.
| Configuration | Seeds | Minutes per run | GPU |
|---|---|---|---|
| A · AdamW | 3 | 9.7 | A100-SXM4-40GB, L4 |
| B · top-k | 3 | 16.0 | A100-SXM4-40GB, L4 |
| C · low band, 1-D 256 | 3 | 13.4 | A100-SXM4-40GB, A100-SXM4-80GB |
| C · low band, 1-D 64 | 1 | 12.8 | A100-SXM4-40GB |
| C · low band, 2-D 64×64 | 3 | 14.8 | A100-SXM4-40GB, L4 |
| D · calibrated band | 3 | 13.3 | A100-SXM4-40GB, A100-SXM4-80GB |
| E · perfect optics (control) | 1 | 35.8 | Tesla T4 |
| E · ENOB 8, 8 planes, full scale fixed | 1 | 15.1 | A100-SXM4-40GB |
| E · ENOB 8, 4 planes | 1 | 14.9 | A100-SXM4-40GB |
| E · ENOB 6, 8 planes | 1 | 15.5 | A100-SXM4-40GB |
| E · ENOB 8, 8 planes | 1 | 15.5 | A100-SXM4-40GB |
| E · ENOB 10, 8 planes | 1 | 15.7 | A100-SXM4-40GB |
| E · ENOB 12, 8 planes | 1 | 15.6 | A100-SXM4-40GB |
| E · ENOB 8, 12 planes | 1 | 16.8 | A100-SXM4-40GB |
| F · high band | 1 | 13.5 | A100-SXM4-40GB |
| F · random band | 1 | 13.5 | A100-SXM4-40GB |
| F · zigzag band | 1 | 13.7 | A100-SXM4-40GB |
The notebook
DeMo fixed-band experiment on a Colab GPU
Runs the experiment in DeMo_Fixed_Band_Experiment on a GPU, at the
tinystories-gpusize (about 16M parameters, 3,000 steps per run).- Runtime > Change runtime type > GPU (T4 is free; an A100 is faster).
- Runtime > Run all. The first cells check the GPU, run the tests and a smoke run, and time the model; the sweep cell then runs the whole grid.
- If the session disconnects, reconnect and *Run all* again. Each session pulls the latest code from GitHub and restores the finished runs from Drive; the timing cell is skipped once the sweep has started.
- To stop early, interrupt the sweep cell and run
save_to_drive()in a new cell before disconnecting, so the last few minutes are kept.
The work happens on Colab's local disk (training directly on the Drive mount made the mount drop). Results, checkpoints and the tokenised data are copied to
MyDrive/DeMo_Fixed_Band_Experiment_stateevery 10 minutes and when the sweep ends, and restored from there at the start of each session, so finished runs are skipped and an interrupted run resumes from its last checkpoint.Optional: to push results to GitHub as each run finishes, add a Colab secret (key icon, left) named
GH_TOKENholding a fine-grained token with write access to this repository's contents.In [1]
!nvidia-smi --query-gpu=name,memory.total --format=csvIn [2]
from google.colab import drive import os, subprocess, threading, time drive.mount('/content/drive') REPO = '/content/DeMo_Fixed_Band_Experiment' STORE = '/content/drive/MyDrive/DeMo_Fixed_Band_Experiment_state' if not os.path.exists(REPO): !git clone -q https://github.com/BrendanJamesLynskey/DeMo_Fixed_Band_Experiment.git {REPO} %cd {REPO} !git config user.name "Colab sweep" && git config user.email "colab-sweep@users.noreply.github.com" # fetch and reset rather than pull: results committed to the repository would otherwise clash with # the same files restored from Drive, and the pull would fail, leaving the old code in place !git fetch -q origin && git reset -q --hard origin/main !git log --oneline -1 !which rsync > /dev/null || apt-get -qq install -y rsync > /dev/null os.makedirs(STORE, exist_ok=True) # restore what earlier sessions saved: results, checkpoints and the tokenised data !rsync -a {STORE}/results/ results/ 2>/dev/null; rsync -a {STORE}/data/ data/ 2>/dev/null; true import glob print('restored from Drive:', len(glob.glob('results/tinystories-gpu/*.jsonl')), 'run logs,', len(glob.glob('results/ckpt/*.pt')), 'checkpoints') def save_to_drive(): """Copy results, checkpoints and tokenised data to Drive (not the raw text downloads).""" if not os.path.isdir(STORE): print('Drive is not mounted; skipping the copy') return # a finished run deletes its checkpoint locally, but rsync does not propagate deletions: # remove checkpoints of finished runs from both copies, or they fill the Drive quota import glob, json as _json for ck in glob.glob('results/ckpt/*.pt') + glob.glob(f'{STORE}/results/ckpt/*.pt'): stem = os.path.basename(ck)[:-3] for log in glob.glob(f'results/*/{stem}.jsonl'): lines = open(log).read().strip().splitlines() if lines and _json.loads(lines[-1]).get('type') == 'done': os.remove(ck) break for src in ('results', 'data'): if os.path.isdir(src): subprocess.run(['rsync', '-a', '--exclude', '*.txt', '--exclude', '*.part', src + '/', f'{STORE}/{src}/']) def _saver(period=600): while True: time.sleep(period) try: save_to_drive() except Exception as e: print('Drive copy failed:', e) if not globals().get('_saver_started'): threading.Thread(target=_saver, daemon=True).start() _saver_started = TrueIn [3]
# PyTorch with CUDA is preinstalled on Colab; add the rest !pip -q install tokenizers ruff pytest einopsIn [4]
# Tests (they run on the CPU) and a short run of every variant on synthetic data, on the GPU !python -m pytest -q tests !python experiment/sweep.py --grid ci --dataset synthetic !python -c "import json,glob; f=sorted(glob.glob('results/synthetic/*.jsonl'))[0]; print('device:', json.loads(open(f).readline())['hardware']['device'])"In [5]
# Timing: 30 steps of AdamW and of DeMo with a fixed band, then an estimate for the whole grid. # Skipped once the sweep has started (set FORCE_TIMING = True to run it anyway). FORCE_TIMING = False if FORCE_TIMING or not os.path.isdir('results/tinystories-gpu'): import json, sys, time, dataclasses sys.path.insert(0, 'experiment') import sweep, train from pathlib import Path prof = sweep.SIZES['tinystories-gpu'] rate = {} for v in ('adamw', 'band', 'optics'): cfg = train.RunConfig(**{**prof, 'variant': v, 'steps': 30, 'eval_every': 30, 'diag_every': 30, 'ckpt_every': 1000, 'chunk_mode': '1d' if v == 'optics' else '2d', 'chunk': 256 if v == 'optics' else 64}) out = Path('/content/timing') / f'{v}.jsonl' if out.exists(): out.unlink() train.run(cfg, out) ev = [json.loads(l) for l in out.read_text().splitlines() if '"eval"' in l][-1] rate[v] = ev['seconds'] / 30 print(f'{v}: {rate[v]:.2f} s/step') total = 0 for stage in ('lr', 'core', 'optics', 'shapes'): for c in sweep.grid(stage, 'tinystories-gpu'): total += c.steps * rate['adamw' if c.variant == 'adamw' else 'optics' if c.variant == 'optics' else 'band'] print(f'estimated time for the whole grid: {total / 3600:.1f} h') else: print('sweep already started: timing skipped')In [6]
# The whole experiment: learning-rate sweep, then the core, optics and band-shape stages. # Long-running. Finished runs are skipped on a rerun; an interrupted one resumes. FLAGS = '' try: from google.colab import userdata token = userdata.get('GH_TOKEN') !git remote set-url origin "https://x-access-token:{token}@github.com/BrendanJamesLynskey/DeMo_Fixed_Band_Experiment.git" FLAGS = '--commit --push' print('results will be committed and pushed after each run') except Exception: print('no GH_TOKEN secret: results stay in Drive') !python experiment/sweep.py --grid all --dataset tinystories-gpu $FLAGS 2>&1 | tee -a results/colab_sweep.log save_to_drive()In [7]
!python experiment/analyse.py --dataset tinystories-gpu from IPython.display import Image, display for f in ('loss_vs_steps_and_bytes.png', 'enob_tolerance.png'): p = f'results/tinystories-gpu/{f}' if os.path.exists(p): display(Image(p))