AsianPlayer/TriDrive / code /probes /own_readout_check.py
AsianPlayer's picture
download
raw
5.24 kB
"""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.