File size: 6,000 Bytes
079e13c f698686 079e13c f698686 079e13c f698686 079e13c f698686 079e13c f698686 079e13c f9d4a1a 0052e99 f698686 079e13c f698686 0052e99 079e13c f698686 079e13c f698686 0052e99 f698686 0052e99 079e13c f698686 079e13c 0052e99 079e13c f698686 | 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 | """Build space/data.json for the side-by-side Space: base Dory vs Dory-Beam-4B vs Beam (the teacher) on the same
eval problems.
.venv/bin/python -I scripts/build_space_data.py [--loops 2] [--seed 0]
Problems are a seeded random sample per benchmark (not hand-picked); every answer is that model's first sample
for the problem from the eval runs. Also writes per-benchmark summary stats over the full eval.
Beam's side ("teacher") is Beam-1.0-501B-A23B itself: self-hosted NVFP4, temperature 0.7, top-p 0.99, up to 28k
tokens, on the same 1,836 samples at each reasoning effort (data/beam_eval/, graded with verify.check as in cascade.py
and beam_effort_study.py). It follows the page's effort control via TEACHER_EFFORT: Dory-Beam low -> Beam low,
default (no effort tag) -> Beam medium (Beam's own default), high -> Beam high.
"""
import argparse
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
RES = ROOT / "data" / "eval" / "results"
# Beam at medium, then at every other level (minimal, low, high, xhigh, max)
TEACHER = [ROOT / "data" / "beam_eval" / "run-evalbeam2-20261030-200821.jsonl",
ROOT / "data" / "beam_eval" / "run-evaleffort-20261101-183703.jsonl"]
# Dory-Beam effort on the page -> the Beam level shown beside it
TEACHER_EFFORT = {"low": "low", "default": "medium", "high": "high"}
# No GPQA examples: its authors ask that questions not appear online in plain text. GPQA stays in the stats table.
QUOTA = {"math500": 10, "aime24": 5, "aime25": 5, "amc23": 5, "heldout": 9}
EFFORTS = ("low", "default", "high")
NAMES = {"gpqa": "GPQA-Diamond", "math500": "MATH-500", "aime24": "AIME 2024", "aime25": "AIME 2025",
"amc23": "AMC 2023", "heldout": "Held-out"}
def load(tag):
by = defaultdict(dict)
for line in open(RES / f"{tag}.jsonl"):
r = json.loads(line)
by[r["id"]].setdefault(r["sample"], r)
return by
def load_teacher():
"""Beam's answers per level, each in the same {id: {sample: record}} shape as load(); graded like
scripts/cascade.py and scripts/beam_effort_study.py. Only the levels the page shows are kept."""
by = {lvl: defaultdict(dict) for lvl in TEACHER_EFFORT.values()}
for path in TEACHER:
for line in open(path):
r = json.loads(line)
if "error" in r or r["effort"] not in by:
continue
ok, pred = check(r["content"], r["gold"], r["answer_type"])
by[r["effort"]][r["id"]].setdefault(r["sample_idx"], {
"bench": r["domain"], "tokens": r["usage"]["completion_tokens"], "pred": pred,
"correct": bool(ok and r["finish_reason"] == "stop"), "finish": r["finish_reason"],
"reasoning": (r["reasoning"] or "").strip(), "answer": (r["content"] or "").strip()})
return by
def teacher_side(r):
return {"reasoning": r["reasoning"], "answer": r["answer"], "tokens": r["tokens"], "correct": r["correct"],
"pred": r["pred"], "truncated": r["finish"] == "length"}
def side(r):
reasoning, _, answer = r["text"].partition("</think>")
return {"reasoning": reasoning.strip(), "answer": answer.strip(), "tokens": r["tokens"],
"correct": r["correct"], "pred": r["pred"], "truncated": r["finish"] == "length"}
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--loops", type=int, default=2)
ap.add_argument("--seed", type=int, default=0)
args = ap.parse_args()
base = load(f"base_loops{args.loops}-64k")
# Dory-Beam-4B v2 at each reasoning effort ("default" = no effort tag)
beam = {e: load(f"rE-t050_loops{args.loops}-{e}-64k") for e in EFFORTS}
teacher = load_teacher()
for lvl, runs in teacher.items():
assert sum(map(len, runs.values())) == sum(map(len, base.values())), f"Beam {lvl} should cover every sample"
probs = [json.loads(l) for l in open(ROOT / "data" / "evalsets.jsonl")]
rng = random.Random(args.seed)
items = []
for bench, k in QUOTA.items():
pool = [p for p in probs if p["bench"] == bench]
for p in sorted(rng.sample(pool, k), key=lambda p: p["id"]):
items.append({"id": p["id"], "bench": NAMES[bench], "prompt": p["prompt"], "gold": p["answer"],
"base": side(base[p["id"]][0]), "beam": {e: side(beam[e][p["id"]][0]) for e in EFFORTS},
"teacher": {lvl: teacher_side(runs[p["id"]][0]) for lvl, runs in teacher.items()}})
stats = []
for bench, name in NAMES.items():
row = {"bench": name}
def agg(runs):
rs = [r for pid, samples in runs.items() for r in samples.values() if r["bench"] == bench]
return {"acc": round(100 * sum(r["correct"] for r in rs) / len(rs), 1),
"tokens": round(sum(r["tokens"] for r in rs) / len(rs))}
row["base"] = agg(base)
row["beam"] = {e: agg(beam[e]) for e in EFFORTS}
row["teacher"] = {lvl: agg(runs) for lvl, runs in teacher.items()}
stats.append(row)
out = ROOT / "space" / "data.json"
out.parent.mkdir(exist_ok=True)
out.write_text(json.dumps({"loops": args.loops, "seed": args.seed, "teacher_effort": TEACHER_EFFORT,
"stats": stats, "items": items}, ensure_ascii=False))
both = sum(i["base"]["correct"] and i["beam"]["default"]["correct"] for i in items)
right = {lvl: sum(i["teacher"][lvl]["correct"] for i in items) for lvl in teacher}
print(f"{len(items)} problems ({both} both Dory sides correct; Beam correct {right}) -> {out} "
f"({out.stat().st_size / 1e6:.2f} MB)")
for lvl in teacher:
print(f" Beam {lvl:<6} " + " | ".join(
f"{s['bench']} {s['teacher'][lvl]['acc']:.1f} · {s['teacher'][lvl]['tokens'] / 1000:.1f}k" for s in stats))
if __name__ == "__main__":
main()
|