"""STaR-style difficulty labeling of MBPP with the frozen base model. Two passes per item: direct code generation vs plan-first-then-code, each executed against MBPP's unit tests (sandboxed subprocess). Labels: easy (direct passes), hard (plan-only passes), drop (neither). The model's own passing code is kept as the training target (in-distribution supervision). """ import json import os import re import subprocess import sys import tempfile import time from concurrent.futures import ThreadPoolExecutor from pathlib import Path import torch from datasets import load_dataset sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) from jlens.core import load_model # noqa: E402 OUT = Path(os.environ.get("LOOP_OUT", Path(__file__).resolve().parent.parent / "results-loop")) OUT.mkdir(exist_ok=True) DIRECT_SUFFIX = ("\n\nWrite only the Python function in a ```python code " "block. No explanation.") PLAN_SUFFIX = ("\n\nFirst write a very brief plan: at most 4 short bullet " "lines, no headings, no math notation. Then write the complete " "Python function in a ```python code block.") CODE_RE = re.compile(r"```(?:python)?\s*\n(.*?)```", re.S) def mbpp_prompt(tok, item, suffix): tests = "\n".join(item["test_list"]) msg = (f"{item['text']}\nYour code should pass these tests:\n\n{tests}" f"{suffix}") return tok.apply_chat_template([{"role": "user", "content": msg}], tokenize=False, add_generation_prompt=True) def extract_code(text): m = CODE_RE.findall(text) return m[-1].strip() if m else None def run_tests(code, item, timeout=10): if not code: return False script = (item.get("test_setup_code") or "") + "\n" + code + "\n" + \ "\n".join(item["test_list"]) try: with tempfile.TemporaryDirectory() as td: r = subprocess.run([sys.executable, "-c", script], cwd=td, capture_output=True, timeout=timeout) return r.returncode == 0 except (subprocess.TimeoutExpired, OSError): return False @torch.no_grad() def batch_generate(model, tok, prompts, max_new_tokens, batch_size=24): outs = [] for i in range(0, len(prompts), batch_size): chunk = prompts[i : i + batch_size] enc = tok(chunk, return_tensors="pt", padding=True, add_special_tokens=False).to("cuda") gen = model.generate(**enc, max_new_tokens=max_new_tokens, do_sample=False, pad_token_id=tok.pad_token_id or 0) for j in range(len(chunk)): outs.append(tok.decode(gen[j, enc["input_ids"].shape[1]:], skip_special_tokens=True)) print(f" {min(i+batch_size, len(prompts))}/{len(prompts)}", flush=True) return outs def main(): model, tok = load_model(dtype=torch.bfloat16) tok.padding_side = "left" ds = load_dataset("google-research-datasets/mbpp", "full") items = [] for split, tag in (("train", "train"), ("validation", "train"), ("test", "test")): for row in ds[split]: items.append({"split": tag, "task_id": row["task_id"], "text": row["text"], "test_list": row["test_list"], "test_setup_code": row["test_setup_code"]}) print(f"{len(items)} items", flush=True) for tag, suffix, mx in (("direct", DIRECT_SUFFIX, 220), ("plan", PLAN_SUFFIX, 700)): t0 = time.time() print(f"{tag} pass", flush=True) gens = batch_generate(model, tok, [mbpp_prompt(tok, it, suffix) for it in items], mx) codes = [extract_code(g) for g in gens] with ThreadPoolExecutor(8) as ex: oks = list(ex.map(lambda ci: run_tests(ci[0], ci[1]), zip(codes, items))) for it, c, ok in zip(items, codes, oks): it[f"{tag}_ok"] = bool(ok) it[f"{tag}_code"] = c if ok else None print(f"{tag} pass done in {time.time()-t0:.0f}s " f"pass@1={sum(oks)/len(items):.3f}", flush=True) for it in items: it["label"] = ("easy" if it["direct_ok"] else "hard" if it["plan_ok"] else "drop") it["sol_code"] = it["direct_code"] if it["direct_ok"] else it["plan_code"] for split in ("train", "test"): sub = [it for it in items if it["split"] == split] n = len(sub) print(f"{split}: n={n} direct={sum(i['direct_ok'] for i in sub)/n:.3f} " f"plan={sum(i['plan_ok'] for i in sub)/n:.3f} " f"easy={sum(i['label']=='easy' for i in sub)} " f"hard={sum(i['label']=='hard' for i in sub)} " f"drop={sum(i['label']=='drop' for i in sub)}", flush=True) with open(OUT / "mbpp_data.json", "w") as f: json.dump(items, f, indent=1) print("wrote", OUT / "mbpp_data.json") if __name__ == "__main__": main()