"""Blocksworld STaR labeling with the frozen model (direct vs CoT plan).""" import json import os import sys import time from pathlib import Path import torch from bw_common import make_dataset, verify_plan from prep_mbpp import batch_generate 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")) DIRECT_SUFFIX = "\n\nGive only the numbered list of moves, nothing else." COT_SUFFIX = ("\n\nFirst think step by step about which blocks must move " "and in what order (briefly), then give the numbered list of " "moves.") def chat(tok, it, suffix): return tok.apply_chat_template( [{"role": "user", "content": it["question"] + suffix}], tokenize=False, add_generation_prompt=True) def main(): model, tok = load_model(dtype=torch.bfloat16) tok.padding_side = "left" items = make_dataset(n_train=400, n_test=200, seed=0) print(f"{len(items)} instances", flush=True) for tag, suffix, mx in (("direct", DIRECT_SUFFIX, 200), ("cot", COT_SUFFIX, 500)): t0 = time.time() gens = batch_generate(model, tok, [chat(tok, it, suffix) for it in items], max_new_tokens=mx, batch_size=24) oks = [verify_plan(it, g) for it, g in zip(items, gens)] for it, g, ok in zip(items, gens, oks): it[f"{tag}_ok"] = bool(ok) it[f"{tag}_plan"] = g if ok else None print(f"{tag}: acc={sum(oks)/len(items):.3f} " f"({time.time()-t0:.0f}s)", flush=True) for it in items: it["label"] = ("easy" if it["direct_ok"] else "hard" if it["cot_ok"] else "drop") it["sol_plan"] = (it["direct_plan"] if it["direct_ok"] else it["cot_plan"]) for split in ("train", "test"): sub = [it for it in items if it["split"] == split] print(f"{split}: 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) json.dump(items, open(OUT / "bw_data.json", "w"), indent=1) print("wrote", OUT / "bw_data.json") if __name__ == "__main__": main()