Download methods/run.py from skyuu72/kibble-pythia-1b: direct link, hf CLI and curl.
- Browser
- Download file 5.91 kB
-
https://huggingface.co/skyuu72/kibble-pythia-1b/resolve/main/methods/run.py
- Command line
-
hf download hf://skyuu72/kibble-pythia-1b/methods/run.py
-
curl -L -o run.py https://huggingface.co/skyuu72/kibble-pythia-1b/resolve/main/methods/run.py
5.91 kB
| # one runner for every method, so they all face the same protocol. | |
| # usage: python methods/run.py --exp E05 --method baselines:MEMIT --proto scale,seq [--hp layers=[2,3,4,5,6] lam=15000] | |
| # protos: tune (100 tune facts, light eval) | scale (1/10/100/800 eval facts) | seq (10 batches of 80) | |
| # | heldout (final report only: 200 held-out facts, then all 1000 at once) | |
| import argparse, ast, importlib, threading, sys, os | |
| sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) | |
| from common import * | |
| from harness import Judge, brief | |
| from values import req | |
| def avg(ms): | |
| keys = {k for m in ms for k in m} | |
| return {k: sum(m[k] for m in ms if k in m) / sum(1 for m in ms if k in m) for k in keys | |
| if all(isinstance(m.get(k, 0), (int, float)) for m in ms)} | |
| def watchdog(minutes, path, payload): | |
| def boom(): | |
| payload["status"] = f"KILLED: over {minutes} min, too costly"; jdump(payload, path) | |
| print(payload["status"], flush=True); os._exit(3) | |
| t = threading.Timer(minutes * 60, boom); t.daemon = True; t.start() | |
| def main(): | |
| ap = argparse.ArgumentParser() | |
| ap.add_argument("--exp", required=True); ap.add_argument("--method", required=True) | |
| ap.add_argument("--proto", default="scale,seq"); ap.add_argument("--hp", nargs="*", default=[]) | |
| ap.add_argument("--seed", type=int, default=0); ap.add_argument("--tag", default="") | |
| ap.add_argument("--n_tune", type=int, default=100); ap.add_argument("--judge_bs", type=int, default=16); ap.add_argument("--minutes", type=float, default=45) | |
| a = ap.parse_args() | |
| hp = {} | |
| for kv in a.hp: | |
| k, v = kv.split("=", 1) | |
| try: hp[k] = ast.literal_eval(v) | |
| except Exception: hp[k] = v | |
| torch.manual_seed(a.seed); import random; random.seed(a.seed) | |
| mod, cls = a.method.split(":") | |
| name = f"{a.exp}_{cls}{('_' + a.tag) if a.tag else ''}"; path = os.path.join(RES, name + ".json") | |
| out = jload(path) if os.path.exists(path) else {} | |
| out.update(exp=a.exp, method=cls, hp=hp, seed=a.seed, status="running") | |
| watchdog(a.minutes, path, out) | |
| meta = jload(os.path.join(ROOT, "data", "meta.json")); model, tok = load_model(meta["model"]) | |
| J = Judge(tok, bs=a.judge_bs); M = getattr(importlib.import_module(mod), cls)(model, tok, **hp) | |
| protos = a.proto.split(",") | |
| ev, tune = J.facts("eval"), J.facts("tune")[:a.n_tune] | |
| if a.seed: random.Random(a.seed).shuffle(ev) # fresh seed = fresh fact order, so different batches and different N-subsets | |
| used = (tune if "tune" in protos else []) + (ev if ("scale" in protos or "seq" in protos) else []) | |
| if "heldout" in protos: used = used + ev + J.facts("heldout") | |
| used = list({f["id"]: f for f in used}.values()) | |
| J.prepare(model, used) | |
| t0 = time.time(); M.precompute([req(f) for f in used]); out["precompute_sec"] = round(time.time() - t0, 1) | |
| def one(facts, full): | |
| M.reset(); t = time.time() | |
| M.edit([req(f) for f in facts]); es = time.time() - t | |
| m = J.evaluate(model, facts, full=full, **M.eval_kwargs()); m["edit_sec"] = round(es, 2); return m | |
| def save(): | |
| out["peak_vram_mb"] = peak_mb(); out["method_stats"] = getattr(M, "stats", {}); jdump(out, path) | |
| try: | |
| if "tune" in protos: | |
| out["tune"] = one(tune, False); print("tune ", brief(out["tune"]), flush=True); save() | |
| if "scale" in protos: | |
| out.setdefault("scale", {}) | |
| groups = {1: [[f] for f in ev[:10]], 10: [ev[0:10], ev[10:20], ev[20:30]], 100: [ev[:100]], 800: [ev[:800]]} | |
| for N, gs in groups.items(): | |
| if str(N) in out["scale"]: continue | |
| try: | |
| ms = [one(g, i == 0) for i, g in enumerate(gs)] | |
| out["scale"][str(N)] = avg(ms); print(f"scale {N:4d}", brief(out["scale"][str(N)]), flush=True) | |
| except Skip as e: | |
| out["scale"][str(N)] = dict(skipped=str(e)); print(f"scale {N} skipped: {e}", flush=True) | |
| save() | |
| if "seq" in protos and "seq" not in out and hp.get("mode") == "all": | |
| out["seq"] = dict(skipped="800 facts do not fit in the context window"); save() | |
| if "seq" in protos and "seq" not in out: | |
| M.reset(); B = [ev[i * 80:(i + 1) * 80] for i in range(10)]; curve = []; t = time.time() | |
| for i, b in enumerate(B): | |
| M.edit([req(f) for f in b]) | |
| m = J.evaluate(model, B[0], full=False, **M.eval_kwargs()) | |
| curve.append({k: m[k] for k in ("efficacy_em", "para_em", "hop_em", "loc_kl", "loc_qa_em", "nbr_real_em")}) | |
| print(f"seq after batch {i + 1}: batch1", brief(m), flush=True) | |
| es = time.time() - t | |
| final = J.evaluate(model, ev[:800], full=True, **M.eval_kwargs()); final["edit_sec"] = round(es, 1) | |
| per_batch = [J.evaluate(model, b, full=False, **M.eval_kwargs())["efficacy_em"] for b in B] | |
| out["seq"] = dict(final=final, batch1_curve=curve, final_eff_per_batch=per_batch) | |
| print("seq final", brief(final), "| eff per batch", [round(x, 2) for x in per_batch], flush=True); save() | |
| if "heldout" in protos: | |
| held = J.facts("heldout") | |
| out["heldout_200"] = one(held, True); print("heldout ", brief(out["heldout_200"]), flush=True); save() | |
| try: | |
| out["all_1000"] = one(ev + held, True); print("all 1000 ", brief(out["all_1000"]), flush=True) | |
| except Skip as e: | |
| out["all_1000"] = dict(skipped=str(e)) | |
| save() | |
| out["status"] = "ok" | |
| except Exception as e: | |
| import traceback; traceback.print_exc() | |
| out["status"] = "FAILED: " + repr(e)[:300] | |
| out["total_sec"] = round(time.time() - t0, 1); save(); print(f"[saved] results/{name}.json status={out['status']} peak={out['peak_vram_mb']}MB") | |
| if __name__ == "__main__": | |
| main() | |