Download code/wp/tables.py from Broyojo/world-pretraining-runs: direct link, hf CLI and curl.
- Browser
- Download file 9.93 kB
-
https://huggingface.co/Broyojo/world-pretraining-runs/resolve/main/code/wp/tables.py
- Command line
-
hf download hf://Broyojo/world-pretraining-runs/code/wp/tables.py
-
curl -L -o tables.py https://huggingface.co/Broyojo/world-pretraining-runs/resolve/main/code/wp/tables.py
9.93 kB
| """LaTeX tables for the report from pulled metrics -> report/tables.tex (one \\newcommand per table).""" | |
| import json | |
| import sys | |
| from collections import defaultdict | |
| from pathlib import Path | |
| import numpy as np | |
| sys.path.insert(0, str(Path(__file__).parent)) | |
| from analyze import EVAL_TASKS, LABELS, load_runs # noqa: E402 | |
| ARMS = ("scratch", "ivgpt", "shuffled", "rescaled", "sp0.1", "sp0.2", "sp0.4", "sp0.7", "spshuf0.4") | |
| NICE = {"scratch": "scratch", "ivgpt": "pretrained", "shuffled": "shuffled", "rescaled": "rescaled", | |
| "sp0.1": r"S\&P $\lambda{=}0.1$", "sp0.2": r"S\&P $\lambda{=}0.2$", "sp0.4": r"S\&P $\lambda{=}0.4$", | |
| "sp0.7": r"S\&P $\lambda{=}0.7$", "spshuf0.4": r"shuffled S\&P $\lambda{=}0.4$"} | |
| def lr_tex(lr): | |
| """Learning rates in the plain e-notation common in ML papers, e.g. 3e-3.""" | |
| e = int(np.floor(np.log10(lr) + 1e-9)) | |
| return f"{lr / 10 ** e:g}e-{abs(e)}" | |
| def sweep_table(runs, budget, freeze): | |
| """Rows = arms, cols = LRs, final val loss of seed-0 runs; the LR used for all further runs in bold.""" | |
| grid = defaultdict(dict) | |
| for r in runs: | |
| if r["budget"] == budget and r["freeze"] == freeze and r["done"] and r["seed"] == 0: | |
| grid[r["init"]][r["lr"]] = r["val"][-1] | |
| lrs = sorted({lr for g in grid.values() for lr in g}) | |
| if not lrs: | |
| return "" | |
| lines = [r"\begin{tabular}{l" + "c" * len(lrs) + "}", r"\toprule", | |
| "initialization & " + " & ".join(lr_tex(lr) for lr in lrs) + r" \\", r"\midrule"] | |
| for a in ARMS: | |
| if a not in grid: | |
| continue | |
| chosen = chosen_lr(runs, budget, freeze, a) | |
| cells = [] | |
| for lr in lrs: | |
| v = grid[a].get(lr) | |
| cells.append("--" if v is None else (rf"\textbf{{{v:.3f}}}" if lr == chosen else f"{v:.3f}")) | |
| lines.append(NICE[a] + " & " + " & ".join(cells) + r" \\") | |
| lines += [r"\bottomrule", r"\end{tabular}"] | |
| return "\n".join(lines) | |
| def chosen_lr(runs, budget, freeze, init): | |
| """The LR with the most seeds, then the lowest mean final loss over seeds (same rule as replicate_table).""" | |
| groups = defaultdict(list) | |
| for r in runs: | |
| if r["budget"] == budget and r["freeze"] == freeze and r["init"] == init and r["done"]: | |
| groups[r["lr"]].append(r["val"][-1]) | |
| return min(groups, key=lambda l: (-len(groups[l]), np.mean(groups[l]))) if groups else None | |
| def best_lr(runs, budget, freeze, init): | |
| c = [(r["val"][-1], r["lr"]) for r in runs if r["budget"] == budget and r["freeze"] == freeze | |
| and r["init"] == init and r["done"] and r["seed"] == 0] | |
| return min(c)[1] if c else None | |
| def replicate_table(runs, budget): | |
| """Best-LR runs with all seeds: per-seed finals, mean, and the gap to scratch.""" | |
| rows, ref = [], None | |
| for a in ARMS: | |
| groups = defaultdict(list) | |
| for r in runs: | |
| if r["budget"] == budget and r["freeze"] == "none" and r["init"] == a and r["done"]: | |
| groups[r["lr"]].append((r["seed"], r["val"][-1])) | |
| if not groups: | |
| continue | |
| # prefer the LR with the most seeds, then the lowest mean | |
| lr = min(groups, key=lambda l: (-len(groups[l]), np.mean([v for _, v in groups[l]]))) | |
| reps = sorted(groups[lr]) | |
| vals = [v for _, v in reps] | |
| mean = float(np.mean(vals)) | |
| if a == "scratch": | |
| ref = mean | |
| rows.append((a, lr, vals, mean)) | |
| lines = [r"\begin{tabular}{llccc}", r"\toprule", r"initialization & chosen LR & seeds & mean & $\Delta$ vs scratch \\", r"\midrule"] | |
| for a, lr, vals, mean in rows: | |
| d = "--" if a == "scratch" or ref is None else f"{mean - ref:+.3f}" | |
| lines.append(f"{NICE[a]} & {lr_tex(lr)} & {', '.join(f'{v:.3f}' for v in vals)} & {mean:.3f} & {d}" + r" \\") | |
| lines += [r"\bottomrule", r"\end{tabular}"] | |
| return "\n".join(lines), {a: {"lr": lr, "vals": vals, "mean": mean} for a, lr, vals, mean in rows} | |
| def eval_table(runs): | |
| """Main conditions at their replicated best LR, accuracies averaged over seeds.""" | |
| rows, ses = [], [] | |
| for budget in ("500M", "2000M"): | |
| for a in ("scratch", "ivgpt", "sp0.4", "spshuf0.4"): | |
| groups = defaultdict(list) | |
| for r in runs: | |
| if r["budget"] == budget and r["freeze"] == "none" and r["init"] == a and r["done"] and r["evals"]: | |
| groups[r["lr"]].append(r) | |
| if not groups: | |
| continue | |
| lr = min(groups, key=lambda l: (-len(groups[l]), np.mean([r["val"][-1] for r in groups[l]]))) | |
| reps = groups[lr] | |
| acc = {t: np.mean([r["evals"][t]["v"] for r in reps]) for t in EVAL_TASKS} | |
| ses += [r["evals"][t]["se"] or 0 for r in reps for t in EVAL_TASKS] | |
| rows.append((budget, a, lr, len(reps), acc)) | |
| if not rows: | |
| return "" | |
| short = {"piqa": "PIQA", "hellaswag": "HellaSwag", "arc_easy": "ARC-E", "sciq": "SciQ", "winogrande": "Wino.", "lambada_openai": "LAMBADA"} | |
| tasks = list(EVAL_TASKS) | |
| lines = [r"\begin{tabular}{llc" + "c" * (len(tasks) + 1) + "}", r"\toprule", | |
| "tokens & initialization & seeds & " + " & ".join(short[t] for t in tasks) + r" & mean \\", r"\midrule"] | |
| last = None | |
| for budget, a, lr, n, acc in rows: | |
| if last and budget != last: | |
| lines.append(r"\midrule") | |
| tok = budget.replace("2000M", "2B") if budget != last else "" | |
| last = budget | |
| vals = [100 * acc[t] for t in tasks] | |
| lines.append(f"{tok} & {NICE[a]} & {n} & " + " & ".join(f"{v:.1f}" for v in vals) + f" & {np.mean(vals):.1f}" + r" \\") | |
| lines += [r"\bottomrule", r"\end{tabular}"] | |
| return "\n".join(lines), float(np.mean(ses)) | |
| def adapt_table(runs): | |
| """Frozen backbones at 500M tokens: rows = backbone, cols = adaptation, best LR per cell (seed 0).""" | |
| adapts = ("body", "lora", "top4") | |
| cell = {} | |
| for b in ("ivgpt", "scratch", "shuffled"): | |
| for a in adapts: | |
| v = [r["val"][-1] for r in runs if r["init"] == b and r["freeze"] == a and r["budget"] == "500M" | |
| and r["done"] and r["seed"] == 0] | |
| cell[b, a] = min(v) if v else None | |
| best = {a: min(v for (b, aa), v in cell.items() if aa == a and v is not None) for a in adapts} | |
| fmt = lambda v, a: "--" if v is None else (rf"\textbf{{{v:.3f}}}" if v == best[a] else f"{v:.3f}") | |
| lines = [r"\begin{tabular}{lccc}", r"\toprule", | |
| r"frozen backbone & frozen & frozen + LoRA & frozen + 4 layers \\", r"\midrule"] | |
| for b in ("ivgpt", "scratch", "shuffled"): | |
| lines.append(f"{NICE[b]} & " + " & ".join(fmt(cell[b, a], a) for a in adapts) + r" \\") | |
| small = [r["val"][-1] for r in runs if r["init"] == "nobody" and r["budget"] == "500M" and r["done"]] | |
| if small: | |
| lines += [r"\midrule", f"none (small 4-layer model) & -- & -- & {min(small):.3f}" + r" \\"] | |
| lines += [r"\bottomrule", r"\end{tabular}"] | |
| return "\n".join(lines) | |
| DOMAINS = [("ssv2", "SSv2 actions"), ("droid", "DROID instructions"), ("piqa", "PIQA"), | |
| ("fineweb", "FineWeb-Edu"), ("wiki", "WikiText-103"), ("gsm8k", "GSM8K")] | |
| def domain_table(probe): | |
| """Per-domain validation loss (mean over seeds) after 500M and 2B tokens; best per row and budget in bold.""" | |
| import re | |
| g = defaultdict(list) | |
| for name, r in probe.items(): | |
| m = re.search(r"-(scratch|ivgpt|sp0\.4|spshuf0\.4)-none-lr[0-9e.-]+-(\d+M)", name) | |
| if m: | |
| g[m.group(2), m.group(1)].append(r) | |
| cols = [("500M", k) for k in ("scratch", "ivgpt", "sp0.4", "spshuf0.4")] + [("2000M", k) for k in ("scratch", "ivgpt", "sp0.4")] | |
| cols = [c for c in cols if g[c]] | |
| short = {"scratch": "scratch", "ivgpt": "pretrained", "sp0.4": r"S\&P", "spshuf0.4": r"shuf.\ S\&P"} | |
| n5 = sum(c[0] == "500M" for c in cols) | |
| lines = [r"\begin{tabular}{l" + "c" * n5 + "c" * (len(cols) - n5) + "}", r"\toprule", | |
| rf" & \multicolumn{{{n5}}}{{c}}{{after 500M tokens}} & \multicolumn{{{len(cols) - n5}}}{{c}}{{after 2B tokens}} \\", | |
| rf"\cmidrule(lr){{2-{n5 + 1}}}\cmidrule(lr){{{n5 + 2}-{len(cols) + 1}}}", | |
| "text & " + " & ".join(short[k] for _, k in cols) + r" \\", r"\midrule"] | |
| for d, lab in DOMAINS: | |
| vals = {c: float(np.mean([r[d] for r in g[c]])) for c in cols} | |
| best = {b: min(v for c, v in vals.items() if c[0] == b) for b in ("500M", "2000M")} | |
| lines.append(lab + " & " + " & ".join( | |
| rf"\textbf{{{vals[c]:.3f}}}" if vals[c] == best[c[0]] else f"{vals[c]:.3f}" for c in cols) + r" \\") | |
| lines += [r"\bottomrule", r"\end{tabular}"] | |
| return "\n".join(lines) | |
| def main(): | |
| runs = load_runs(["results/ice", "results/dm_backup"]) | |
| out = {} | |
| tex = [] | |
| for key, (budget, freeze) in {"SweepFull": ("500M", "none"), "PilotFull": ("100M", "none"), | |
| "PilotFrozen": ("100M", "body"), "SweepFrozen": ("500M", "body")}.items(): | |
| t = sweep_table(runs, budget, freeze) | |
| if t: | |
| tex.append(rf"\newcommand{{\Table{key}}}{{%" + "\n" + t + "}") | |
| for budget, key in (("500M", "RepFive"), ("2000M", "RepTwoB")): | |
| t, data = replicate_table(runs, budget) | |
| if data: | |
| tex.append(rf"\newcommand{{\Table{key}}}{{%" + "\n" + t + "}") | |
| out[key] = data | |
| et = eval_table(runs) | |
| if et: | |
| tex.append(r"\newcommand{\TableEval}{%" + "\n" + et[0] + "}") | |
| out["eval_mean_stderr"] = et[1] | |
| tex.append(r"\newcommand{\TableAdapt}{%" + "\n" + adapt_table(runs) + "}") | |
| pf = Path("report/probe.json") | |
| if pf.exists(): | |
| tex.append(r"\newcommand{\TableDomains}{%" + "\n" + domain_table(json.loads(pf.read_text())) + "}") | |
| Path("report/tables.tex").write_text("\n\n".join(tex) + "\n") | |
| Path("report/key_numbers.json").write_text(json.dumps(out, indent=1)) | |
| print(json.dumps(out, indent=1)) | |
| if __name__ == "__main__": | |
| main() | |