Download scripts/probe_all.py from quinnlue/mae-cross-objective: direct link, hf CLI and curl.
- Browser
- Download file 4.33 kB
-
https://huggingface.co/quinnlue/mae-cross-objective/resolve/main/scripts/probe_all.py
- Command line
-
hf download hf://quinnlue/mae-cross-objective/scripts/probe_all.py
-
curl -L -o probe_all.py https://huggingface.co/quinnlue/mae-cross-objective/resolve/main/scripts/probe_all.py
4.33 kB
| """Probe every final export under a run root, in parallel across GPUs. | |
| Reports AS-20K probe mAP against the patching's own random-init floor. That | |
| ratio -- not reconstruction loss -- is the gate. This project has twice been | |
| burned by treating MAE val_loss as a quality signal: cluster-weight-channels.md | |
| measures it at rho=0.72 with the train/eval distribution-match channel, and | |
| regmix-regression-256.md found it uncorrelated with downstream score at | |
| rho=-0.034 over 256 mixtures. | |
| """ | |
| import argparse | |
| import json | |
| import queue | |
| import subprocess | |
| import threading | |
| from pathlib import Path | |
| REPO = "/workspace/code/eat-map-regmix" | |
| FLOORS = {"p16": 0.03861, "p4x64": 0.04867} | |
| def latest_export(run: Path) -> Path | None: | |
| exports = sorted((run / "exports").glob("step_*")) if (run / "exports").exists() else [] | |
| return exports[-1] if exports else None | |
| def main(): | |
| ap = argparse.ArgumentParser() | |
| ap.add_argument("root") | |
| ap.add_argument("--gpus", default="0,1,2,3") | |
| ap.add_argument("--all-steps", action="store_true", help="probe every export, not just the last") | |
| # The probe is CPU-bound, not GPU-bound: feature extraction is ~15 s but the | |
| # ridge solve and the 527-class mAP run on BLAS, which by default grabs one | |
| # thread per core. Four concurrent probes then ask for 512 threads on 128 | |
| # cores and spend 90% of wall time descheduling. Capping threads and raising | |
| # concurrency is worth ~8x here. | |
| ap.add_argument("--per-gpu", type=int, default=2, help="concurrent probes per GPU") | |
| ap.add_argument("--threads", type=int, default=12, help="BLAS threads per probe") | |
| args = ap.parse_args() | |
| jobs: queue.Queue = queue.Queue() | |
| for run in sorted(Path(args.root).iterdir()): | |
| if not run.is_dir(): | |
| continue | |
| exports = (sorted((run / "exports").glob("step_*")) if args.all_steps | |
| else [latest_export(run)]) | |
| for exp in [e for e in exports if e]: | |
| if not (exp / "probe.json").exists(): | |
| jobs.put((run.name, exp)) | |
| total = jobs.qsize() | |
| print(f"{total} exports to probe") | |
| lock = threading.Lock() | |
| def worker(gpu): | |
| while True: | |
| try: | |
| name, exp = jobs.get_nowait() | |
| except queue.Empty: | |
| return | |
| threads = str(args.threads) | |
| proc = subprocess.run( | |
| ["python", "-m", "eatmap.cli.probe", "--export", str(exp)], | |
| cwd=REPO, capture_output=True, | |
| env={**__import__("os").environ, "CUDA_VISIBLE_DEVICES": str(gpu), | |
| "PYTHONPATH": REPO, | |
| "OMP_NUM_THREADS": threads, "OPENBLAS_NUM_THREADS": threads, | |
| "MKL_NUM_THREADS": threads, "NUMEXPR_NUM_THREADS": threads}, | |
| ) | |
| with lock: | |
| if proc.returncode: | |
| print(f" FAIL {name} {exp.name}: {proc.stderr.decode()[-200:]}") | |
| jobs.task_done() | |
| threads = [threading.Thread(target=worker, args=(int(g),)) | |
| for g in args.gpus.split(",") for _ in range(args.per_gpu)] | |
| for t in threads: | |
| t.start() | |
| for t in threads: | |
| t.join() | |
| rows = [] | |
| for run in sorted(Path(args.root).iterdir()): | |
| if not run.is_dir(): | |
| continue | |
| for exp in sorted((run / "exports").glob("step_*")): | |
| pj = exp / "probe.json" | |
| if not pj.exists(): | |
| continue | |
| d = json.loads(pj.read_text()) | |
| tag = "p4x64" if "p4x64" in run.name else "p16" | |
| floor = FLOORS[tag] | |
| status = json.loads((run / "status.json").read_text()) if (run / "status.json").exists() else {} | |
| rows.append((run.name, int(exp.name.split("_")[1]), d["probe/map"], | |
| d["probe/map"] / floor, status.get("val/loss", float("nan")))) | |
| print(f"\n{'run':<24}{'step':>8}{'probe mAP':>12}{'x floor':>10}{'val loss':>10}") | |
| for name, step, m, ratio, vl in sorted(rows, key=lambda r: -r[2]): | |
| print(f"{name:<24}{step:>8}{m:>12.5f}{ratio:>10.2f}{vl:>10.4f}") | |
| Path(args.root, "probe_summary.json").write_text(json.dumps( | |
| [{"run": n, "step": s, "probe_map": m, "x_floor": r, "val_loss": v} | |
| for n, s, m, r, v in rows], indent=1)) | |
| if __name__ == "__main__": | |
| main() | |