Dory-Beam-4B / code /scripts /build_pool.py
ProCreations's picture
Dory-Beam-4B weights, config, tokenizer, license and code
f0975ca verified
Raw History Blame Contribute Delete
5.08 kB
"""Build a decontaminated, verifiable prompt pool for Beam -> Dory distillation.
Sources (train splits only):
math zwhe99/DeepMath-103K difficulty >= 5, closed-form final answers
science nvidia/OpenScienceReasoning-2 multiple choice, single-letter answers
Decontamination: drop any prompt sharing a 13-gram with MATH-500, AIME 2024/2025,
AMC 2023 or GPQA-style eval questions we can access without auth.
"""
import argparse
import hashlib
import json
import random
import re
from pathlib import Path
import duckdb
ROOT = Path(__file__).resolve().parent.parent
SOURCES = ROOT / "data" / "sources"
EVAL_SETS = [
("read_json_auto('hf://datasets/HuggingFaceH4/MATH-500/test.jsonl')", "problem"),
("'hf://datasets/HuggingFaceH4/aime_2024/**/*.parquet'", "problem"),
("'hf://datasets/yentinglin/aime_2025/**/*.parquet'", "problem"),
("'hf://datasets/math-ai/amc23/**/*.parquet'", "question"),
]
MCQ_PREFIX = (
"Solve the following problem. Make sure to put the answer (and only answer) "
"inside \\boxed{}.\n\n"
)
MATH_SUFFIX = "\n\nPut your final answer within \\boxed{}."
def norm_words(text):
return re.sub(r"[^a-z0-9 ]+", " ", text.lower()).split()
def ngrams(text, n=13):
w = norm_words(text)
return {" ".join(w[i : i + n]) for i in range(max(0, len(w) - n + 1))}
def eval_ngrams(con):
grams = set()
for src, col in EVAL_SETS:
repo = src.split("datasets/")[1].split("/", 2)[:2]
repo = "/".join(repo)
try:
rows = con.execute(f"SELECT {col} FROM {src}").fetchall()
except Exception as e: # missing/gated eval set: report, keep going
print(f" decontam: skipped {repo}: {str(e)[:120]}")
continue
for (q,) in rows:
grams |= ngrams(q or "")
print(f" decontam: {repo}: {len(rows)} questions")
return grams
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--math", type=int, default=6000)
ap.add_argument("--science", type=int, default=4000)
ap.add_argument("--seed", type=int, default=20261022)
ap.add_argument("--out", default=str(ROOT / "data" / "pool.jsonl"))
args = ap.parse_args()
con = duckdb.connect()
con.execute("INSTALL httpfs; LOAD httpfs;")
rng = random.Random(args.seed)
print("loading eval sets for decontamination")
bad = eval_ngrams(con)
print("loading DeepMath-103K (difficulty >= 5)")
math_rows = con.execute(
"""SELECT question, final_answer, difficulty, topic
FROM 'hf://datasets/zwhe99/DeepMath-103K/**/*.parquet'
WHERE difficulty >= 5"""
).fetchall()
print(f" {len(math_rows)} candidates")
print("loading OpenScienceReasoning-2 (single-letter MCQ)")
sci_rows = con.execute(
"""SELECT input, expected_answer
FROM 'hf://datasets/nvidia/OpenScienceReasoning-2/**/*.parquet'
WHERE length(expected_answer) = 1 AND expected_answer BETWEEN 'A' AND 'J'"""
).fetchall()
print(f" {len(sci_rows)} candidates")
pool, seen, dropped = [], set(), 0
def add(item):
nonlocal dropped
key = hashlib.sha1(" ".join(norm_words(item["prompt"])).encode()).hexdigest()
if key in seen:
return False
if ngrams(item["prompt"]) & bad:
dropped += 1
return False
seen.add(key)
item["id"] = f"{item['source']}-{key[:12]}"
pool.append(item)
return True
# Math: stratify by difficulty band so harder problems aren't swamped.
bands = {}
for q, a, d, t in math_rows:
if not a or len(a) > 80:
continue
bands.setdefault(min(int(d), 9), []).append((q, a, d, t))
per_band = args.math // len(bands)
for band, rows in sorted(bands.items()):
rng.shuffle(rows)
taken = 0
for q, a, d, t in rows:
if taken >= per_band:
break
taken += add(
{
"source": "deepmath",
"domain": "math",
"prompt": q.strip() + MATH_SUFFIX,
"answer": a,
"answer_type": "math",
"difficulty": d,
"topic": t,
}
)
print(f" math band {band}: {taken}")
rng.shuffle(sci_rows)
taken = 0
for q, a in sci_rows:
if taken >= args.science:
break
prompt = q if q.startswith(MCQ_PREFIX) else MCQ_PREFIX + q
taken += add(
{
"source": "openscience2",
"domain": "science",
"prompt": prompt.strip(),
"answer": a,
"answer_type": "mcq",
}
)
print(f" science: {taken}")
rng.shuffle(pool)
with open(args.out, "w") as f:
for item in pool:
f.write(json.dumps(item, ensure_ascii=False) + "\n")
print(f"wrote {len(pool)} prompts to {args.out} (decontam dropped {dropped})")
if __name__ == "__main__":
main()