File size: 7,175 Bytes
079e13c | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | """Beam's reasoning-effort dial on the evaluation set, next to Dory-Beam-4B's.
.venv/bin/python -I scripts/beam_effort_study.py # -> data/beam_effort/STUDY.md, data/beam_effort/summary.json
Beam (self-hosted NVFP4, temperature 0.7, top-p 0.99, up to 28k tokens) answered the same 1,836 eval samples at
every reasoning_effort: minimal, low, medium, high, xhigh and max. Medium is data/beam_eval/run-evalbeam2-*, the
others data/beam_eval/run-evaleffort-*. Nothing is selected on correctness. Accuracy gaps against medium are paired by
problem and sample, with 95% bootstrap CIs over problems (4,000 resamples).
"""
import glob
import json
import random
import sys
from collections import defaultdict
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(ROOT / "scripts"))
from verify import check # noqa: E402
LEVELS = ["minimal", "low", "medium", "high", "xhigh", "max"]
BENCHES = ["gpqa", "math500", "aime24", "aime25", "amc23", "heldout"]
NAMES = {"gpqa": "GPQA-D", "math500": "MATH-500", "aime24": "AIME 2024", "aime25": "AIME 2025", "amc23": "AMC 2023",
"heldout": "Held-out", "all": "All"}
DORY = [("low", "rE-t050_loops2-low-64k"), ("medium", "rE-t050_loops2-medium-64k"),
("default", "rE-t050_loops2-default-64k"), ("high", "rE-t050_loops2-high-64k")]
BOOTS = 4000
def load_beam():
bench = {json.loads(l)["id"]: json.loads(l)["bench"] for l in open(ROOT / "data" / "evalsets.jsonl")}
rows = {}
for pattern in ("run-evalbeam2-*.jsonl", "run-evaleffort-*.jsonl"):
for path in sorted(glob.glob(str(ROOT / "data" / "beam_eval" / pattern))):
for line in open(path):
r = json.loads(line)
if "error" in r:
continue
ok, _ = check(r["content"], r["gold"], r["answer_type"])
rows[(r["effort"], r["id"], r["sample_idx"])] = {
"bench": bench[r["id"]], "correct": bool(ok and r["finish_reason"] == "stop"),
"tokens": r["usage"]["completion_tokens"], "truncated": r["finish_reason"] != "stop"}
return rows
def summarize(rows, level, bench):
rs = [v for (e, _, _), v in rows.items() if e == level and (bench == "all" or v["bench"] == bench)]
if not rs:
return None
return {"n": len(rs), "acc": 100 * sum(r["correct"] for r in rs) / len(rs),
"tokens": sum(r["tokens"] for r in rs) / len(rs), "truncated": 100 * sum(r["truncated"] for r in rs) / len(rs)}
def paired_gap(rows, level, ref, bench, rng):
"""Accuracy of level minus ref, on the samples both have; CI by resampling problems."""
per = defaultdict(lambda: [0, 0, 0])
for (e, pid, s), v in rows.items():
if e != level or (bench != "all" and v["bench"] != bench):
continue
o = rows.get((ref, pid, s))
if o is None:
continue
p = per[pid]
p[0] += v["correct"]; p[1] += o["correct"]; p[2] += 1
# sample-weighted like the accuracy column (AIME problems carry 8 samples), resampling whole problems
probs = list(per.values())
if not probs:
return None
gap = lambda ps: 100 * sum(a - b for a, b, _ in ps) / sum(n for _, _, n in ps)
boots = sorted(gap(rng.choices(probs, k=len(probs))) for _ in range(BOOTS))
return gap(probs), boots[BOOTS // 40], boots[BOOTS - BOOTS // 40 - 1]
def dory(tag, bench):
rs = [json.loads(l) for l in open(ROOT / "data" / "eval" / "results" / f"{tag}.jsonl")]
rs = [r for r in rs if bench == "all" or r["bench"] == bench]
return {"acc": 100 * sum(r["correct"] for r in rs) / len(rs), "tokens": sum(r["tokens"] for r in rs) / len(rs)}
def main():
rows = load_beam()
rng = random.Random(0)
summary = {"beam": {}, "dory_beam": {}, "base": {}}
lines = ["# Beam's reasoning-effort dial on the evaluation set", "",
"Accuracy % · mean output tokens. Gap = level minus medium, paired, 95% CI (▲/▼ excludes zero).", "",
"| Level | " + " | ".join(NAMES[b] for b in BENCHES + ["all"]) + " | Gap vs medium (all) | Cut off at 28k |",
"|---" * (len(BENCHES) + 4) + "|"]
for lv in LEVELS:
cells, summary["beam"][lv] = [], {}
for b in BENCHES + ["all"]:
s = summarize(rows, lv, b)
summary["beam"][lv][b] = s
cells.append("—" if s is None else f"{s['acc']:.1f} · {s['tokens'] / 1000:.1f}k")
g = None if lv == "medium" else paired_gap(rows, lv, "medium", "all", rng)
gap = "—" if g is None else f"{g[0]:+.1f} [{g[1]:+.1f}, {g[2]:+.1f}]" + (" ▲" if g[1] > 0 else " ▼" if g[2] < 0 else "")
s = summary["beam"][lv]["all"]
cut = "—" if s is None else f"{s['truncated']:.1f}%"
lines.append(f"| **{lv}** | " + " | ".join(cells) + f" | {gap} | {cut} |")
lines += ["", "Per-benchmark gaps vs medium (paired, 95% CI):", "", "| Level | " + " | ".join(NAMES[b] for b in BENCHES) + " |",
"|---" * (len(BENCHES) + 1) + "|"]
for lv in LEVELS:
if lv == "medium":
continue
cells = []
for b in BENCHES:
g = paired_gap(rows, lv, "medium", b, rng)
cells.append("—" if g is None else f"{g[0]:+.1f} [{g[1]:+.1f}, {g[2]:+.1f}]" + (" ▲" if g[1] > 0 else " ▼" if g[2] < 0 else ""))
lines.append(f"| {lv} | " + " | ".join(cells) + " |")
lines += ["", "Dory-Beam-4B (2 loops, temperature 1.0, 64k) on the same samples:", "",
"| Effort | " + " | ".join(NAMES[b] for b in BENCHES + ["all"]) + " |", "|---" * (len(BENCHES) + 2) + "|"]
for name, tag in DORY:
summary["dory_beam"][name] = {b: dory(tag, b) for b in BENCHES + ["all"]}
lines.append(f"| {name} | " + " | ".join(f"{summary['dory_beam'][name][b]['acc']:.1f} · "
f"{summary['dory_beam'][name][b]['tokens'] / 1000:.1f}k" for b in BENCHES + ["all"]) + " |")
summary["base"] = {b: dory("base_loops2-64k", b) for b in BENCHES + ["all"]}
# grouped points for scripts/make_effort_chart.py: [mean tokens, accuracy]
def pts(rs):
return [sum(r["tokens"] for r in rs) / len(rs), 100 * sum(r["correct"] for r in rs) / len(rs)]
groups = {"all": None, "aime": {"aime24", "aime25"}, "routine": {"math500", "amc23"}}
res = lambda tag: [json.loads(l) for l in open(ROOT / "data" / "eval" / "results" / f"{tag}.jsonl")]
summary["chart"] = {}
for g, bs in groups.items():
keep = lambda r: bs is None or r["bench"] in bs
summary["chart"][g] = {
"beam": {lv: pts([v for (e, _, _), v in rows.items() if e == lv and keep(v)]) for lv in LEVELS},
"dory_beam": {name: pts([r for r in res(tag) if keep(r)]) for name, tag in DORY if name != "default"},
"base": pts([r for r in res("base_loops2-64k") if keep(r)])}
out = ROOT / "data" / "beam_effort"
out.mkdir(parents=True, exist_ok=True)
(out / "STUDY.md").write_text("\n".join(lines) + "\n")
(out / "summary.json").write_text(json.dumps(summary, indent=1))
print("\n".join(lines))
if __name__ == "__main__":
main()
|