Buckets:
| """cwm3/data/build_behaviour_targets.py — DRIVER-BEHAVIOUR event chains B[N,25,3] {hand_return, hand_leave, head_turn_onset} | |
| on the s12 anchor grid, sourced from the CAUSAL kinematics where they exist (no pose work is redone here). | |
| Sources, in priority order per row (recorded in B_source): | |
| 3 causal_routes results/targets_kin_causal_routes/kin_causal_{regime}_{split}.npz (route-level causal pose, all rows — | |
| used only when the full set exists; the 5-route test build is ignored) | |
| 1 causal_clip results/targets_kin_causal/kin_causal_{regime}_{split}.npz (clip-window causal pose, train routes only) | |
| 2 old_noncausal cwm2/results/targets_kin/kin_{regime}_{split}.npz (route-median ROI, whole-route medians incl. | |
| the future — DISCLOSED fallback; the old events agree with the causal ones only at F1 ~ 0.3 on hand events, | |
| qc.json) ; 0 none | |
| The event definitions are those of the source files (hands_on = min_hand_rest_dist < 0.10; head_turned = hysteresis | |
| 0.1941/0.1026 on |head_turn_dev|; onsets = inactive->active of the three chains {hands_on, 1-hands_on, head_turned}). | |
| Outputs results/targets_behaviour/behaviour_{regime}_{split}.npz (row-aligned with s12; uid, t asserted): | |
| B[N,25,3] u8, Bvalid[N,25,3] bool, B0[N,3] f32 (chain state at t; NaN if unknown), Bstate[N,25,2] f32 {hands_on, head_turned}, | |
| Bstate0[N,2] f32, B_first[N,3] int16 (first onset step given inactive & valid at t; -1 none; -2 anchor active / invalid), | |
| B_source[N] u8, Bc_only[N,25,3] u8 / Bc_valid[N,25,3] bool (causal-only copy: False/0 where no causal source), | |
| events, states, uid, t, dongle | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| import json | |
| import os | |
| import sys | |
| import time | |
| from pathlib import Path | |
| os.environ.setdefault("OMP_NUM_THREADS", "8") | |
| import numpy as np # noqa: E402 | |
| ROOT = Path(__file__).resolve().parents[1] | |
| EXPLORE = ROOT.parent | |
| sys.path.insert(0, str(ROOT / "common")) | |
| from runmeta import write_run_json # noqa: E402 | |
| S12 = EXPLORE / "s12_wm" / "results" | |
| KIN_CLIP = ROOT / "results" / "targets_kin_causal" | |
| KIN_ROUTES = ROOT / "results" / "targets_kin_causal_routes" | |
| KIN_OLD = EXPLORE / "cwm2" / "results" / "targets_kin" | |
| OUT = ROOT / "results" / "targets_behaviour" | |
| EVENTS = ["hand_return", "hand_leave", "head_turn_onset"] | |
| STATES = ["hands_on", "head_turned"] | |
| SRC = {"none": 0, "causal_clip": 1, "old_noncausal": 2, "causal_routes": 3} | |
| def _first(B0, B, Bv): | |
| """B0: chain inactive-at-anchor flag (1 = inactive & known); onsets B[N,25] where valid.""" | |
| onset = (B > 0) & Bv | |
| first = np.where(onset.any(1), onset.argmax(1), -1).astype(np.int16) | |
| first[~B0] = -2 | |
| return first | |
| def chain_inactive0(E0): | |
| """E0 = state of each event's chain at the anchor (kin convention: inactive = < 0.5; NaN unknown).""" | |
| return np.isfinite(E0) & (E0 < 0.5) | |
| def build_split(regime, split, use_routes): | |
| z = np.load(S12 / f"targets_{regime}_{split}.npz", allow_pickle=True) | |
| uid, t, dongle, M = z["uid"], z["t"].astype(np.float64), z["dongle"], z["M"] | |
| N = len(t) | |
| B = np.zeros((N, 25, 3), np.uint8) | |
| Bv = np.zeros((N, 25, 3), bool) | |
| B0 = np.full((N, 3), np.nan, np.float32) | |
| Bs = np.full((N, 25, 2), np.nan, np.float32) | |
| Bs0 = np.full((N, 2), np.nan, np.float32) | |
| src = np.zeros(N, np.uint8) | |
| cov = {} | |
| def take(rows, E, EM, E0, S, S0, code): | |
| B[rows] = E[rows] | |
| Bv[rows] = EM[rows] | |
| B0[rows] = E0[rows] | |
| Bs[rows] = S[rows] | |
| Bs0[rows] = S0[rows] | |
| src[rows] = code | |
| # 3 route-level causal (only a complete set) | |
| pr = KIN_ROUTES / f"kin_causal_{regime}_{split}.npz" | |
| if use_routes and pr.exists(): | |
| k = np.load(pr, allow_pickle=True) | |
| assert np.array_equal(k["uid"], uid) and np.allclose(k["t"], t) | |
| rows = np.flatnonzero(k["row_ok"] if "row_ok" in k else k["EM_c"].any((1, 2))) | |
| take(rows, k["E_c"], k["EM_c"], k["E0_c"], k["S_c"], k["S0_c"], SRC["causal_routes"]) | |
| cov["causal_routes"] = int(len(rows)) | |
| # 1 clip-window causal | |
| pc = KIN_CLIP / f"kin_causal_{regime}_{split}.npz" | |
| if pc.exists(): | |
| k = np.load(pc, allow_pickle=True) | |
| assert np.array_equal(k["uid"], uid) and np.allclose(k["t"], t) | |
| rows = np.flatnonzero(k["row_ok"] & (src == 0)) | |
| take(rows, k["E_c"], k["EM_c"], k["E0_c"], k["S_c"], k["S0_c"], SRC["causal_clip"]) | |
| cov["causal_clip"] = int(len(rows)) | |
| Bc, Bcv = B.copy(), Bv.copy() # causal-only copy before the fallback | |
| # 2 old non-causal fallback | |
| po = KIN_OLD / f"kin_{regime}_{split}.npz" | |
| if po.exists(): | |
| k = np.load(po, allow_pickle=True) | |
| assert np.array_equal(k["uid"], uid) and np.allclose(k["t"], t) | |
| EM = k["EM"] & M[:, :, None] | |
| has = EM.any((1, 2)) | np.isfinite(k["E0"]).any(1) | |
| rows = np.flatnonzero(has & (src == 0)) | |
| take(rows, k["E"], EM, k["E0"], k["S"], k["S0"], SRC["old_noncausal"]) | |
| cov["old_noncausal"] = int(len(rows)) | |
| cov["none"] = int((src == 0).sum()) | |
| inact0 = chain_inactive0(B0) | |
| B_first = np.stack([_first(inact0[:, e], B[:, :, e], Bv[:, :, e]) for e in range(3)], 1) | |
| d = dict(B=B, Bvalid=Bv, B0=B0, Bstate=Bs, Bstate0=Bs0, B_first=B_first, B_source=src, Bc_only=Bc, Bc_valid=Bcv, | |
| events=np.array(EVENTS), states=np.array(STATES), uid=uid, t=t, dongle=dongle) | |
| stats = dict(N=N, coverage=cov, coverage_frac={k: v / N for k, v in cov.items()}) | |
| for e, ev in enumerate(EVENTS): | |
| for code, name in ((1, "causal_clip"), (2, "old_noncausal"), (3, "causal_routes")): | |
| r = src == code | |
| if not r.any(): | |
| continue | |
| sel3 = r & (B_first[:, e] != -2) & Bv[:, :15, e].all(1) | |
| y3 = (B_first[sel3, e] >= 0) & (B_first[sel3, e] < 15) | |
| stats[f"{ev}__{name}"] = dict(valid_frac_steps=float(Bv[r, :, e].mean()), onset_rate_steps=float(B[r][:, :, e][Bv[r][:, :, e]].mean()) if Bv[r][:, :, e].any() else float("nan"), | |
| n_inactive_anchors_3s=int(sel3.sum()), onset_anchors_3s=int(y3.sum()), | |
| base_rate_3s=float(y3.mean()) if sel3.any() else float("nan")) | |
| return d, stats | |
| def main(): | |
| ap = argparse.ArgumentParser() | |
| ap.add_argument("--regimes", default="manual,engaged") | |
| ap.add_argument("--splits", default="train,val,test") | |
| ap.add_argument("--force", action="store_true") | |
| ap.add_argument("--use-routes", action="store_true", help="use results/targets_kin_causal_routes when the full set exists") | |
| a = ap.parse_args() | |
| OUT.mkdir(parents=True, exist_ok=True) | |
| t_start = time.time() | |
| summary, files, inputs = {}, [], [] | |
| for regime in a.regimes.split(","): | |
| for split in a.splits.split(","): | |
| d, st = build_split(regime, split, a.use_routes) | |
| p = OUT / f"behaviour_{regime}_{split}.npz" | |
| if p.exists() and not a.force: | |
| raise FileExistsError(f"{p} exists (append-only; --force to overwrite)") | |
| np.savez_compressed(p, **d) | |
| files.append(str(p)) | |
| summary[f"{regime}_{split}"] = st | |
| print(f"[{regime}/{split}] N={st['N']} coverage={st['coverage']}", flush=True) | |
| for k, v in st.items(): | |
| if "__" in k: | |
| print(f" {k:32s} base_rate_3s={v['base_rate_3s']:.5f} ({v['onset_anchors_3s']}/{v['n_inactive_anchors_3s']}) valid={v['valid_frac_steps']:.3f}", flush=True) | |
| for src_dir in (KIN_CLIP, KIN_OLD, KIN_ROUTES if a.use_routes else None): | |
| if src_dir is None: | |
| continue | |
| f = src_dir / (f"kin_causal_{regime}_{split}.npz" if src_dir != KIN_OLD else f"kin_{regime}_{split}.npz") | |
| if f.exists(): | |
| inputs.append(f) | |
| inputs.append(S12 / f"targets_{regime}_{split}.npz") | |
| stamp = time.strftime("%Y%m%dT%H%M%SZ", time.gmtime()) | |
| (OUT / f"build_stats_{stamp}.json").write_text(json.dumps(summary, indent=1)) | |
| (OUT / "build_stats_latest.json").write_text(json.dumps(summary, indent=1)) | |
| write_run_json(OUT, "build_behaviour_targets", [Path(__file__)], sorted(set(inputs)), 0, t_start, | |
| extra=dict(files_written=files, events=EVENTS, states=STATES, source_codes=SRC, use_routes=a.use_routes, dms_fields_used=[])) | |
| print("BEHAVIOUR_DONE", f"{time.time() - t_start:.0f}s", flush=True) | |
| if __name__ == "__main__": | |
| main() | |
Xet Storage Details
- Size:
- 8.52 kB
- Xet hash:
- 1a25a581006d45cdfb2b8a1d0b784a5055a1f958458c92b3079b2c9ba9ee0742
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.