Buckets:
| """cwm3/probes/own_readout_check.py — supplementary check for innovation 3 (b2): decode the t+k STATE bits from each run's predicted F_hat(t+k) with the run's OWN | |
| trained `f_state` read-out (models/identity.FS_NAMES) on the TEST probe rows, and place the PR-AUC next to the frozen actual-future read-out (A) and copy-current (C) | |
| of the pre-registered protocol (probes/future_vs_predicted.py --space v2, same rows: aligned & Fok[k]). Motivation: `pooled_P_fsonly` drops the F cosine, so its F_hat | |
| no longer lives in the F space and the frozen actual-F read-out cannot read it — the own read-out is the fair decoder for that arm; for `pooled_P_fs` both decoders apply. | |
| -> results/probes/own_readout_fs_v2.csv + a section appended to results/tables/state_supervised_E.md by probes/report_state_sup.py --own. CPU / small GPU; no DMS field. | |
| python probes/own_readout_check.py --runs E0_pooled_P_fs_s0_v2 ... [--tag fs_v2] | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| import csv | |
| import json | |
| import os | |
| import sys | |
| from pathlib import Path | |
| os.environ.setdefault("OMP_NUM_THREADS", "4") | |
| import numpy as np # noqa: E402 | |
| import torch # noqa: E402 | |
| sys.path.insert(0, str(Path(__file__).resolve().parent)) | |
| import common as C # noqa: E402 | |
| import future_vs_predicted as FVP # noqa: E402 | |
| from models import identity as idn # noqa: E402 | |
| EV_OF = {f"P_{c}": f"P_{c}_active" for c in idn.P_CHAINS} | |
| EV_OF.update({"brake": "veh_brake_pressed", "gas": "veh_gas_pressed"}) # R_any / R_hard have no protocol event -> reported alone | |
| def main(): | |
| ap = argparse.ArgumentParser() | |
| ap.add_argument("--runs", nargs="+", required=True) | |
| ap.add_argument("--tag", default="fs_v2") | |
| ap.add_argument("--n-boot", type=int, default=300) | |
| ap.add_argument("--regimes", default="manual,engaged") | |
| a = ap.parse_args() | |
| out = C.OUT / f"own_readout_{a.tag}.csv" | |
| proto = {} | |
| with open(C.OUT / f"future_vs_predicted_{a.tag}.csv") as fh: | |
| rows = list(csv.DictReader(fh)) | |
| last = max(r["stamp"] for r in rows) | |
| for r in rows: | |
| if r["stamp"] == last and r["probe"] == "ridge" and r["subset"] == "all": | |
| proto[(r["regime"], r["run"], r["event"], int(r["k"]))] = r | |
| new = not out.exists() | |
| f = open(out, "a", newline="") | |
| cols = ["stamp", "regime", "run", "state", "event", "k", "n_te", "npos_te", "ap_own", "ci_own", "ap_actual", "ap_pred_frozen", "ap_copy", "share_own", "share_frozen", "d_own_minus_copy", "d_ci"] | |
| w = csv.DictWriter(f, fieldnames=cols) | |
| if new: | |
| w.writeheader() | |
| stamp = C.stamp() | |
| for regime in a.regimes.split(","): | |
| D = FVP.Data(regime, "test", "v2", a.runs) | |
| for run in a.runs: | |
| z = torch.load(C.RUNS / run / (C.RUNS / run / "BEST").read_text().strip(), map_location="cpu", weights_only=False) | |
| W, b = z["model"]["f_state.weight"].float().numpy(), z["model"]["f_state.bias"].float().numpy() | |
| Fh = D.F_hat[run] # [n,5,256] (raw, un-normalised: the head reads the raw F_hat) | |
| for k in range(1, 6): | |
| rows_k = D.rows(k) | |
| ev = FVP.events_at(D.raw, k) | |
| logit = Fh[rows_k, k - 1] @ W.T + b # [n_k, 10] | |
| dte = D.raw["dongle"][rows_k] | |
| for j, st in enumerate(idn.FS_NAMES): | |
| evn = EV_OF.get(st) | |
| if evn is None or evn not in ev: | |
| continue | |
| y, m, _ = ev[evn] | |
| y, m = y[rows_k], m[rows_k] | |
| if m.sum() < 100 or y[m].sum() < 10 or (~y[m]).sum() < 10: | |
| continue | |
| pr = proto.get((regime, run, evn, k)) | |
| Zc = FVP.unit(D.F_cur[rows_k]) # copy-current score for the paired Δ: the protocol's copy value is a ridge read-out; here we | |
| res = C.cluster_boot(y[m], logit[m, j], dte[m], n_boot=a.n_boot) # report the own-read-out AP with its CI and the protocol's A / P / C levels on the same rows | |
| A_, P_, Cc = (float(pr["ap_actual"]), float(pr["ap_pred"]), float(pr["ap_copy"])) if pr else (np.nan, np.nan, np.nan) | |
| share_own = (res["ap"] - Cc) / (A_ - Cc) if pr and abs(A_ - Cc) > 0.01 else np.nan | |
| share_fr = (P_ - Cc) / (A_ - Cc) if pr and abs(A_ - Cc) > 0.01 else np.nan | |
| w.writerow({"stamp": stamp, "regime": regime, "run": run, "state": st, "event": evn, "k": k, "n_te": int(m.sum()), "npos_te": int(y[m].sum()), | |
| "ap_own": round(res["ap"], 5), "ci_own": f"{res['ci'][0]:.3f},{res['ci'][1]:.3f}", "ap_actual": A_, "ap_pred_frozen": P_, "ap_copy": Cc, | |
| "share_own": round(share_own, 4) if np.isfinite(share_own) else "", "share_frozen": round(share_fr, 4) if np.isfinite(share_fr) else "", | |
| "d_own_minus_copy": round(res["ap"] - Cc, 5) if pr else "", "d_ci": ""}) | |
| f.flush() | |
| print(f"{regime} {run}: done", flush=True) | |
| f.close() | |
| print(f"-> {out}") | |
| if __name__ == "__main__": | |
| main() | |
Xet Storage Details
- Size:
- 5.24 kB
- Xet hash:
- c59ab4ec95276c4bdef2941000fb4627abb1b25096db8009f4fb3e4b54bf9ad1
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.