#!/usr/bin/env python3 """Portable launcher for the bind2_0 trainer. WHY THIS EXISTS --------------- `src/train_bind2_0_babylm.py` line 20 is: WORK = os.environ["BABYLM_WORK"] a bare subscript at module scope with no default, so merely IMPORTING the module raises an uncaught KeyError when the variable is unset — the failure a newcomer hits first, with no message explaining what to set. It is read at import time, not call time, so it must be set BEFORE the import; rebinding the attribute afterwards is too late. This launcher sets it, checks the two files it derives (tokenizer.json and tokens_u16.bin), and reports clearly if they are absent. The trainer takes bare positional sys.argv (line 26), not argparse, so arguments are passed through verbatim in order. python run_train.py --work -- python run_train.py --work --check HONEST LIMITATION, not worked around: line 30 hardcodes dev = "cuda" with no CPU path, and modeling_bind2_0.py imports flash-linear-attention, whose kernels are CUDA-only. This package cannot run on CPU or on non-NVIDIA hardware. A launcher cannot fix that; only editing the frozen source could, and that is deliberately not done here. """ from __future__ import annotations import argparse import os import sys from pathlib import Path HERE = Path(__file__).resolve().parent def main() -> int: ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) ap.add_argument("--work", default=os.environ.get("BABYLM_WORK", str(HERE / "data")), help="directory holding tokenizer.json and tokens_u16.bin") ap.add_argument("--check", action="store_true", help="resolve inputs and exit") args, passthrough = ap.parse_known_args() if passthrough and passthrough[0] == "--": passthrough = passthrough[1:] work = Path(args.work) os.environ["BABYLM_WORK"] = str(work) # MUST precede the import sys.path.insert(0, str(HERE / "src")) need = {"tokenizer.json": work / "tokenizer.json", "tokens_u16.bin": work / "tokens_u16.bin"} missing = [k for k, v in need.items() if not v.exists()] if args.check or missing: print(f" BABYLM_WORK = {work}") for k, v in need.items(): print(f" {k:16} {'OK ' if v.exists() else 'MISSING'} {v}") if missing: print("\nERROR: tokens_u16.bin is not redistributed inside this package (it is large and " "regenerable). Build it with the bind1 package's tokenizer chain " "(train_tokenizer.py then make_tokens.py), or point --work at a directory that " "already has it. See BUILD.md.", file=sys.stderr) return 2 if args.check: print("\nAll inputs resolve. Re-run without --check to train.") return 0 import train_bind2_0_babylm as T sys.argv = ["train_bind2_0_babylm.py"] + passthrough T.main() return 0 if __name__ == "__main__": raise SystemExit(main())