File size: 6,845 Bytes
1a8377a 1742ac7 1a8377a 1742ac7 1a8377a 1742ac7 1a8377a 1742ac7 1a8377a 1742ac7 1a8377a 1742ac7 1a8377a 1742ac7 1a8377a 1742ac7 1a8377a 1742ac7 1a8377a 1742ac7 1a8377a 1742ac7 1a8377a 1742ac7 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | """Phase 6 pre-flight on free CPU, second pass: how do we get a working lm-eval without moving the image?
The first pass (12:13Z) answered a question nobody had asked and killed two assumptions at once:
* `pip install --user --no-deps lm-eval==0.4.13` **cannot be imported at all** -- `lm_eval/api/metrics.py:11`
does `import sacrebleu` at module scope, so `--tasks list` exits 1 with `ModuleNotFoundError`. The
`--no-deps` flag was E-045/12's answer to "a resolving install might drop a different transformers into
~/.local"; it bought that safety at the price of a harness that does not start. Review-found, CPU-proved.
* The rest of this file's own first draft then died on `%`-formatting a template that contains `%s` specs.
So the real question is which install keeps the image's `transformers 5.0.0` and `torch` *and* gets the
metric libraries. lm-eval declares `transformers>=4.1`, which 5.0.0 already satisfies -- pip leaves a
satisfied requirement alone -- so a resolving install may be safe here. This measures it rather than
arguing: it snapshots the versions and file locations of the packages Phase 6 depends on, installs with
deps, snapshots again, and only then parses `--tasks list` and dumps the nine task configs.
**No eval data is touched and none can be:** installing, listing task ids and reading YAML configs never
calls `datasets.load_dataset`; that happens only when a task is requested against a model, which is
Phase 6's own step (§3.3).
"""
import json
import os
import re
import subprocess
import sys
os.chdir("/kaggle/working")
PIN = "0.4.13"
TASKS = ["arc_challenge", "arc_easy", "hellaswag", "mmlu", "piqa", "truthfulqa_mc1",
"truthfulqa_mc2", "winogrande", "gsm8k"]
PRIMARY_METRIC = {"arc_challenge": "acc,none", "arc_easy": "acc,none", "hellaswag": "acc,none",
"mmlu": "acc,none", "piqa": "acc,none", "truthfulqa_mc1": "acc,none",
"truthfulqa_mc2": "acc,none", "winogrande": "acc,none",
"gsm8k": "exact_match,flexible-extract"}
WATCH = ["transformers", "torch", "numpy", "pandas", "datasets", "evaluate", "accelerate", "scipy",
"sympy", "sacrebleu", "lm_eval"]
SNAPSHOT = """
import importlib.metadata as md, json, os, sys
out = {}
for name in %s:
try:
mod = __import__(name)
where = getattr(mod, "__file__", None) or "?"
except Exception:
where = None
try:
ver = md.version(name.replace("_", "-"))
except Exception:
ver = getattr(__import__(name), "__version__", None) if where else None
out[name] = {"version": str(ver) if ver else None,
"file": where, "user_dir": bool(where and "/.local/" in where)}
print("SNAPSHOT " + json.dumps(out, default=str))
""" % (WATCH,)
def sh(argv, label, timeout=2400):
print("=== " + label, flush=True)
p = subprocess.run(argv, capture_output=True, text=True, timeout=timeout)
out = (p.stdout or "") + (p.stderr or "")
print(label, "rc", p.returncode, "chars", len(out), flush=True)
return p.returncode, out
def snapshot(label):
open("snap.py", "w").write(SNAPSHOT)
rc, out = sh([sys.executable, "snap.py"], "snapshot_" + label, 600)
line = next((l for l in out.splitlines() if l.startswith("SNAPSHOT ")), "")
d = json.loads(line[len("SNAPSHOT "):]) if line else {}
for k, v in sorted(d.items()):
print(" %-12s %-10s %s" % (k, v["version"], ("<USER>" if v["user_dir"] else v["file"])),
flush=True)
return d
def parse_ids(text):
return set(re.findall(r"^\s*(?:-\s*)?([a-z][a-z0-9_]{2,})\s*$", text, re.M))
before = snapshot("before")
rc, out = sh([sys.executable, "-m", "pip", "install", "--user", "--quiet",
"lm-eval==" + PIN], "pip_install_with_deps", 2400)
print(" ", out.strip()[-400:], flush=True)
after = snapshot("after")
moved = {k: (before.get(k, {}).get("version"), v["version"])
for k, v in after.items() if before.get(k, {}).get("version") != v["version"]
and k != "lm_eval"}
print("PIP_MOVED", json.dumps(moved, default=str), flush=True)
assert after["transformers"]["version"] == "5.0.0", "transformers moved off 5.0.0"
assert after["transformers"]["file"] == before["transformers"]["file"], "transformers moved location"
rc, listed = sh([sys.executable, "-m", "lm_eval", "--tasks", "list"], "tasks_list", 1200)
ids = parse_ids(listed)
print("PARSED_IDS", len(ids), "all nine present:", all(t in ids for t in TASKS), flush=True)
if not ids:
print("RAW_TAIL", repr(listed[-1500:]), flush=True)
open("taskconfig.py", "w").write("""
import json
from lm_eval.tasks import TaskManager
tm = TaskManager()
try:
out = {"index_type": str(type(next(iter(tm.task_index.values()))))}
except Exception as e:
out = {"index_type": "empty or unreachable: " + type(e).__name__}
recs = {}
for t in %s:
r = {"registered": t in tm.task_index}
try:
item = tm.task_index[t]
cfg = item if isinstance(item, dict) else getattr(item, "config", {})
r["keys"] = sorted(cfg)[:14]
r["num_fewshot"] = cfg.get("num_fewshot")
r["metric_list"] = [(m.get("metric_uri") if isinstance(m, dict) else m)
for m in (cfg.get("metric_list") or [])]
r["dataset_path"] = cfg.get("dataset_path")
r["dataset_name"] = cfg.get("dataset_name")
r["test_split"] = cfg.get("test_split")
r["validation_split"] = cfg.get("validation_split")
r["fewshot_split"] = cfg.get("fewshot_split")
except Exception as e:
r["error"] = "%%s: %%s" %% (type(e).__name__, str(e)[:220])
recs[t] = r
print("TASKCONFIG " + json.dumps({"meta": out, "tasks": recs}, default=str))
""" % (TASKS,))
rc, tc = sh([sys.executable, "taskconfig.py"], "task_configs", 1200)
line = next((l for l in tc.splitlines() if l.startswith("TASKCONFIG ")), "")
info = json.loads(line[len("TASKCONFIG "):]) if line else {"meta": {}, "tasks": {}}
cfgs = info.get("tasks", {})
print("TASKCONFIG_META", json.dumps(info.get("meta"), default=str), flush=True)
for t in TASKS:
c = cfgs.get(t, {})
m = PRIMARY_METRIC[t]
print("TASK %-16s fewshot=%-6s test=%-10s val=%-8s metric %-34s declared=%s" % (
t, c.get("num_fewshot"), c.get("test_split"), c.get("validation_split"), m,
m in (c.get("metric_list") or [])), flush=True)
print("HARNESS_PROBE_JSON", json.dumps({
"pip_moved": moved, "tasks_listed": len(ids), "all_present": all(t in ids for t in TASKS),
"primary_declared": {t: PRIMARY_METRIC[t] in (cfgs.get(t) or {}).get("metric_list", [])
for t in TASKS}, "configs": cfgs}, default=str)[:6000], flush=True)
ok = bool(ids) and all(t in ids for t in TASKS) and bool(cfgs)
print("VERDICT P6_HARNESS_PROBE", "OK" if ok else "PROBLEM", flush=True)
raise SystemExit(0 if ok else 6)
|