AsianPlayer/TriDrive / code /aide /eval /report_arch_attribution.py
AsianPlayer's picture
download
raw
30.4 kB
"""cwm3/aide/eval/report_arch_attribution.py — AIDE architecture-attribution fair experiments (docs/decisions.md 2026-09-14, row
"AIDE 架构归因公平实验"; rules fixed before the runs) -> aide/results/tables/arch_attribution.md (+ .json).
Reads ONLY run outputs: pred_test.npz (paired per-clip bootstraps recomputed here with aide/eval/metrics.paired_diff, 10k resamples, seed 0 —
the same procedure as baton_pretrain.md), metrics_test.json (level values + clip-bootstrap CIs written once per run by the harness), the run json
files (best epoch / epochs / stop / GPU minutes / init report / params) and the pretraining history. Nothing is typed by hand.
(1) matched BATON in-cabin pose pretraining for the keypoint baselines: A = <model>_batonpre_trunkp123_s<k>_v2 (trunk-only init from
<model>_batonpre_pretrain_s123) vs B = the EXISTING seed-init runs <model>_s<k>_v2, seeds 42 / 123 / 456; Δ = A − B per clip; verdict as
baton_pretrain.md: BEATS / WORSE = Δ CI excl. 0 on >= 2/3 seeds with the same sign on every seed; NOT_WORSE = all CIs cover 0 and |Δ| < 0.25;
else INCONCLUSIVE. The gain is shown next to K's trunk-only gain (cwm3d_kp_batonpre_trunkp123 vs cwm3d_kp, recomputed from the same files);
descriptive only, no cross-architecture test.
(2) Driver-WM-kp (driverwm_kp_s<k>_v2) vs K (cwm3d_kp_s<k>_v2) and vs MotionBERT-kp (motionbert_kp_s<k>_v2), seed-matched paired Δ. Reading
(decisions row): (a) every seed's Δ All (Driver-WM-kp − K) has a CI containing 0 and |Δ| < 1 px -> the lead belongs to the keypoint
formulation; (b) K significantly better (Δ > 0 with CI excl. 0 on >= 2/3 seeds) -> supports an architecture advantage under the keypoint
formulation; (c) Driver-WM-kp better (Δ < 0 with CI excl. 0 on >= 2/3 seeds) -> reported as is; anything else -> none of the three readings.
(3) MotionBERT-kp at 5 seeds (42 / 123 / 456 + 789 / 1011 = K's 5-seed set): per-seed paired Δ = K − MotionBERT-kp; verdict by the beats rule
generalised to n seeds (CI excl. 0 on >= ceil(2n/3) seeds, same sign on all; NOT_WORSE / INCONCLUSIVE as above), reported for the 5 seeds
and for the locked 3; 5-seed mean ± sd of both models.
python aide/eval/report_arch_attribution.py [--n-boot 10000] [--out aide/results/tables/arch_attribution.md]
Output policy: if --out already exists the new content is APPENDED as a dated block (append-only tables); existing sections are never edited.
"""
from __future__ import annotations
import argparse
import glob
import json
import math
import sys
import time
from pathlib import Path
import numpy as np
ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(ROOT))
from aide.data import protocol as P # noqa: E402
from aide.eval import metrics as M # noqa: E402
from aide.eval.harness import align, load_split # noqa: E402
from common.runmeta import write_run_json # noqa: E402
RUNS = P.RESULTS / "runs"
OUT = P.RESULTS / "tables" / "arch_attribution.md"
SEEDS3, SEEDS5 = (42, 123, 456), (42, 123, 456, 789, 1011)
TOL_NOT_WORSE = 0.25
LEVEL_COLS = [("mpjpe_all", "All", 2), ("dn_mpjpe", "d-n", 3), ("mpjpe_hm", "HM", 2), ("pck05", "PCK@0.05", 2), ("hm_h5", "HM h=5", 2)]
MAIN_CELLS = ("All-MPJPE", "d-n", "HM-MPJPE", "PCK@0.05", "HM h=5")
# ----------------------------------------------------------------------------- io
def run_json(name):
fs = sorted(glob.glob(str(RUNS / name / f"run_{name}_2*.json")))
return json.load(open(fs[-1])) if fs else None
def metrics_test(name):
p = RUNS / name / "metrics_test.json"
return json.load(open(p))["metrics"] if p.exists() else None
def load_pred(name, d):
p = RUNS / name / "pred_test.npz"
if not p.exists():
return None
z = np.load(p, allow_pickle=False)
return np.asarray(z["pred"], dtype=np.float64)[align(z, d["clip_id"])]
def per_clip_cells(pred, gt, hm, full=False):
"""-> {cell: (per-clip values, higher_better)} — baton_pretrain.md's cells (+ d-n)."""
err = M.joint_errors(pred, gt)
clip = err.mean((1, 2))
cells = {"All-MPJPE": (clip, False), "d-n": (100.0 * clip / P.DIAG, False), "HM-MPJPE": (err[hm].mean((1, 2)), False),
"PCK@0.05": (100.0 * (err <= P.pck_threshold_px(0.05)).mean((1, 2)), True), "HM h=5": (err[hm][:, 4].mean(1), False)}
if full:
for k, idx in P.PARTS.items():
cells[f"All {k}"] = (err[:, :, idx].mean((1, 2)), False)
for h in range(P.T_PRED):
cells[f"All h={h + 1}"] = (err[:, h].mean(1), False)
return cells
def paired(a_name, b_name, d, gt, hm, n_boot, full=False):
pa, pb = load_pred(a_name, d), load_pred(b_name, d)
if pa is None or pb is None:
return None
ca, cb = per_clip_cells(pa, gt, hm, full), per_clip_cells(pb, gt, hm, full)
return {c: {"a": float(ca[c][0].mean()), "b": float(cb[c][0].mean()), **M.paired_diff(ca[c][0], cb[c][0], n_boot, 0), "higher_better": ca[c][1]} for c in ca}
def verdict(rows, higher_better, n_req=None):
"""baton_pretrain.md rule; n_req = number of seeds whose CI must exclude 0 (default ceil(2n/3), i.e. 2 of 3, 4 of 5)."""
n = len(rows)
if n == 0:
return "INSUFFICIENT"
n_req = math.ceil(2 * n / 3) if n_req is None else n_req
d = np.array([r["mean"] for r in rows]); lo = np.array([r["ci_lo"] for r in rows]); hi = np.array([r["ci_hi"] for r in rows])
improving = (d > 0) if higher_better else (d < 0)
excl = (lo > 0) | (hi < 0)
same = np.all(np.sign(d) == np.sign(d.mean())) and d.mean() != 0
if excl.sum() >= n_req and same and improving.all():
return "BEATS"
if excl.sum() >= n_req and same and (~improving).all():
return "WORSE"
if np.all((lo <= 0) & (hi >= 0)) and np.all(np.abs(d) < TOL_NOT_WORSE):
return "NOT_WORSE"
return "INCONCLUSIVE"
def fmt_ci(r, nd=2):
return f"{r['mean']:+.{nd}f} [{r['ci_lo']:+.{nd}f},{r['ci_hi']:+.{nd}f}]"
def ms(vals, nd):
v = np.asarray([x for x in vals if x is not None], float)
if not len(v):
return "—"
return f"{v.mean():.{nd}f} ± {v.std(ddof=1):.{nd}f}" if len(v) > 1 else f"{v[0]:.{nd}f}"
def level_row(name, cols=LEVEL_COLS):
m = metrics_test(name)
if m is None:
return None
return " | ".join(f"{m[c]['value']:.{nd}f} [{m[c]['ci_lo']:.{nd}f}, {m[c]['ci_hi']:.{nd}f}]" for c, _, nd in cols)
def run_meta(name):
r = run_json(name) or {}
return r.get("best_epoch", "—"), r.get("epochs_run", "—"), r.get("stop_reason", "—"), r.get("gpu_minutes"), r.get("n_params")
def delta_table(per_seed, label_a, label_b, cells=None, n_req=None):
seeds = list(per_seed)
cells = cells or list(next(iter(per_seed.values())))
L = ["| cell | " + " | ".join(f"{label_a} s{k}" for k in seeds) + " | " + " | ".join(f"{label_b} s{k}" for k in seeds) + " | "
+ " | ".join(f"Δ s{k} [CI]" for k in seeds) + " | mean Δ ± sd | verdict |", "|---|" + "---|" * (3 * len(seeds)) + "---|---|"]
res = {}
for c in cells:
rows = [per_seed[k][c] for k in seeds]
v = verdict(rows, rows[0]["higher_better"], n_req)
dm = np.array([r["mean"] for r in rows])
nd = 3 if c == "d-n" else 2
L.append(f"| {c} | " + " | ".join(f"{r['a']:.{nd}f}" for r in rows) + " | " + " | ".join(f"{r['b']:.{nd}f}" for r in rows) + " | "
+ " | ".join(fmt_ci(r, nd) for r in rows) + f" | {dm.mean():+.{nd}f} ± {(dm.std(ddof=1) if len(dm) > 1 else float('nan')):.{nd}f} | {v} |")
res[c] = {"verdict": v, "mean": float(dm.mean()), "sd": float(dm.std(ddof=1)) if len(dm) > 1 else None, "per_seed": {str(k): per_seed[k][c] for k in seeds}}
return L, res
# ----------------------------------------------------------------------------- main
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--n-boot", type=int, default=10000)
ap.add_argument("--out", default=str(OUT))
a = ap.parse_args()
t0 = time.time()
d = load_split("test")
gt = d["S10"][:, P.T_OBS:]
hm, thr, _ = M.hm_mask(gt)
stamp = time.strftime("%Y%m%dT%H%M%SZ", time.gmtime())
gpu = {} # run -> GPU minutes (from run json)
summary = {}
def note_gpu(name):
r = run_json(name)
if r is not None and r.get("gpu_minutes") is not None:
gpu[name] = float(r["gpu_minutes"])
L = ["# AIDE architecture attribution — fair experiments (owner-approved 2026-09-14; rules fixed before the runs) — AIDE test, n = 609, paired per-clip bootstrap (10k)", "",
f"Generated {stamp} by `aide/eval/report_arch_attribution.py` from pred_test.npz / metrics_test.json / run json / pretraining history files only (locked protocol: driver `first`, "
f"grid `floor`, HM top {int(hm.sum())} (threshold {thr:.2f} px), PCK @ {P.pck_threshold_px(0.05):.0f} px; every run selected on val All-MPJPE only, test evaluated once by the harness). "
"Δ = paired per-clip difference (negative = better for errors, positive = better for PCK), CI = 10k clip-bootstrap percentile interval. "
f"**Verdict rule (as `baton_pretrain.md`): BEATS / WORSE = Δ CI excl. 0 on ≥ 2/3 of the seeds (n = 3: 2; n = 5: 4) with the same sign on every seed; NOT_WORSE = all CIs cover 0 and |Δ| < {TOL_NOT_WORSE}; else INCONCLUSIVE.**", "",
"Pre-specified readings (docs/decisions.md 2026-09-14 row \"AIDE 架构归因公平实验\"): (1) Δ All-MPJPE BEATS / INCONCLUSIVE per baseline, gains listed next to K's −0.62 ± 0.17 (descriptive, no cross-architecture test); "
"(2) Driver-WM-kp vs K per seed: CI ∋ 0 and |Δ| < 1 px on every seed → \"领先属于关键点表述\" (the lead belongs to the keypoint formulation); K significantly better on ≥ 2/3 seeds → "
"\"支持架构在关键点表述下的优势\" (supports an architecture advantage under the keypoint formulation); Driver-WM-kp better → \"如实报告\" (reported as is); "
"(3) K − MotionBERT-kp per seed over the 5-seed set, beats rule. **论文措辞按结果改:现有\"领先来自关键点锚定表述\"只在 (2)(3) 支持时才可改写为架构优势。**", ""]
# ------------------------------------------------------------------ (1) matched pretraining
L += ["## 1. Matched BATON in-cabin pose pretraining for the keypoint baselines (trunk-only init, pretraining seed 123) vs their EXISTING seed-init runs", ""]
sec1 = {}
k_pair = {k: paired(f"cwm3d_kp_batonpre_trunkp123_s{k}_v2", f"cwm3d_kp_s{k}_v2", d, gt, hm, a.n_boot) for k in SEEDS3}
k_pair = {k: v for k, v in k_pair.items() if v}
for model, label in (("motionbert_kp", "MotionBERT-kp"), ("stgcn_kp", "ST-GCN-kp")):
pre = f"{model}_batonpre_pretrain_s123"
pr = run_json(pre)
L += [f"### 1.{1 if model == 'motionbert_kp' else 2} {label}", ""]
if pr is None:
L += [f"_(pretraining run `{pre}` not finished — no numbers)_", ""]
sec1[model] = {"status": "PRETRAIN_MISSING"}
continue
note_gpu(pre)
hist = pr.get("history", [])
zs = pr.get("zeroshot") or {}
L += [f"- Pretraining `{pre}` (`aide/train/pretrain_cwm3d_baton.py --model {model} --seed 123`: same corpus sha256 {pr['corpus']['corpus_sha256'][:16]}, {pr['corpus']['n_windows'] - pr['corpus']['n_windows_val']:,} fit windows, "
f"same task / augmentation / optimiser / schedule / EMA / held-out-route selection as `cwm3d_kp_batonpre_pretrain_s123`; active loss terms {pr.get('loss_terms_active')} — the tensor-output baselines have no "
f"Laplace / bone / jerk terms, exactly as in their AIDE recipe): {pr['n_params']:,} params, bs {pr['config']['bs']}, lr {pr['config']['lr']}, {pr['epochs_run']} epochs run, best epoch {pr['best_epoch']} "
f"(held-out-route All-MPJPE {pr['best_corpus_val_all']:.2f} px), stop = {pr['stop_reason']}; **{pr['ms_per_step_mean']:.1f} ms/step, {pr['gpu_minutes']:.1f} GPU-min**.",
"", "| epoch | ms/step | samples/s | train loss | corpus held-out All | corpus held-out HM | AIDE val zero-shot All | AIDE val zero-shot HM |", "|---|---|---|---|---|---|---|---|"]
for h in hist:
L.append(f"| {h['epoch']} | {h['ms_per_step']:.1f} | {h['samples_per_s']:.0f} | {h.get('train_total', float('nan')):.3f} | {h['corpus_val_all']:.2f} | {h['corpus_val_hm']:.2f} | {h['aide_val_zeroshot_all']:.3f} | {h['aide_val_zeroshot_hm']:.2f} |")
if zs:
L += ["", f"- Zero-shot run `{zs['name']}` (pretrained model on AIDE without any AIDE training, test once): test All {zs['test'].get('mpjpe_all', float('nan')):.3f} / HM {zs['test'].get('mpjpe_hm', float('nan')):.2f} / "
f"PCK@0.05 {zs['test'].get('pck05', float('nan')):.2f} / HM h=5 {zs['test'].get('hm_h5', float('nan')):.2f}; Δ vs zero-velocity All {zs['test'].get('diff_vs_ref_all', float('nan')):+.2f}."]
per_seed = {k: paired(f"{model}_batonpre_trunkp123_s{k}_v2", f"{model}_s{k}_v2", d, gt, hm, a.n_boot, full=True) for k in SEEDS3}
per_seed = {k: v for k, v in per_seed.items() if v}
if not per_seed:
L += ["", f"_(no finished fine-tune pairs `{model}_batonpre_trunkp123_s<k>_v2` vs `{model}_s<k>_v2` yet)_", ""]
sec1[model] = {"status": "FINETUNE_MISSING"}
continue
L += ["", "| seed | A run (trunk init) | A best epoch / epochs / stop / GPU min | init (tensors loaded / kept at seed init; kept keys) | B run (existing seed init, not retrained) | B best epoch / epochs / GPU min |", "|---|---|---|---|---|---|"]
for k in per_seed:
an, bn = f"{model}_batonpre_trunkp123_s{k}_v2", f"{model}_s{k}_v2"
ra, rb = run_json(an) or {}, run_json(bn) or {}
ini = ra.get("init") or {}
note_gpu(an)
L.append(f"| {k} | {an} | {ra.get('best_epoch', '—')} / {ra.get('epochs_run', '—')} / {ra.get('stop_reason', '—')} / {ra.get('gpu_minutes', '—')} | "
f"{ini.get('parts', '—')}: {ini.get('n_loaded', '—')} / {ini.get('n_missing_or_kept', '—')} (ckpt epoch {ini.get('ckpt_epoch', '—')}; kept {', '.join(ini.get('kept_keys', [])[:6])}) | "
f"{bn} | {rb.get('best_epoch', '—')} / {rb.get('epochs_run', '—')} / {rb.get('gpu_minutes', '—')} |")
rows, res = delta_table(per_seed, "A", "B")
L += [""] + rows
v_all = res["All-MPJPE"]["verdict"]
L += ["", f"**Reading (1) for {label}: Δ All-MPJPE = {v_all} (mean {res['All-MPJPE']['mean']:+.2f} ± {res['All-MPJPE']['sd']:.2f} px over {len(per_seed)} seeds); "
f"HM-MPJPE {res['HM-MPJPE']['verdict']} ({res['HM-MPJPE']['mean']:+.2f}), PCK@0.05 {res['PCK@0.05']['verdict']} ({res['PCK@0.05']['mean']:+.2f}), HM h=5 {res['HM h=5']['verdict']} ({res['HM h=5']['mean']:+.2f}).**", ""]
sec1[model] = {"status": "DONE", "n_seeds": len(per_seed), "verdict_all": v_all, "cells": {c: {kk: vv for kk, vv in r.items() if kk != "per_seed"} for c, r in res.items()}, "per_seed_all": res["All-MPJPE"]["per_seed"]}
if k_pair:
rows_k, res_k = delta_table(k_pair, "A", "B", cells=list(MAIN_CELLS))
L += ["### 1.3 Reference: K (CWM3-D-kp) trunk-only init from the same pretraining seed (`cwm3d_kp_batonpre_trunkp123_s<k>_v2` vs `cwm3d_kp_s<k>_v2`, recomputed from the same files; `baton_pretrain.md` §6)", ""] + rows_k
L += ["", "### 1.4 Gain from matched pretraining, side by side (mean Δ All-MPJPE ± sd over seeds; DESCRIPTIVE — no cross-architecture test is performed)", "",
"| model | params | Δ All-MPJPE (A − B) per seed | mean ± sd | verdict | Δ HM-MPJPE mean ± sd | Δ HM h=5 mean ± sd |", "|---|---|---|---|---|---|---|"]
for model, label in (("cwm3d", "K = CWM3-D-kp"), ("motionbert_kp", "MotionBERT-kp"), ("stgcn_kp", "ST-GCN-kp")):
if model == "cwm3d":
res, rjs = res_k, run_json("cwm3d_kp_s42_v2")
else:
if sec1.get(model, {}).get("status") != "DONE":
L.append(f"| {label} | — | (not finished) | — | — | — | — |")
continue
res = {c: {**sec1[model]["cells"][c], "per_seed": None} for c in sec1[model]["cells"]}
res["All-MPJPE"]["per_seed"] = sec1[model]["per_seed_all"]
rjs = run_json(f"{model}_s42_v2")
ps = res["All-MPJPE"]["per_seed"]
L.append(f"| {label} | {(rjs or {}).get('n_params', 0):,} | " + " / ".join(f"{ps[str(k)]['mean']:+.2f}" for k in SEEDS3 if str(k) in ps) + f" | {res['All-MPJPE']['mean']:+.2f} ± {res['All-MPJPE']['sd']:.2f} | {res['All-MPJPE']['verdict']} | "
f"{res['HM-MPJPE']['mean']:+.2f} ± {res['HM-MPJPE']['sd']:.2f} | {res['HM h=5']['mean']:+.2f} ± {res['HM h=5']['sd']:.2f} |")
summary["k_trunk_gain_all"] = {"mean": res_k["All-MPJPE"]["mean"], "sd": res_k["All-MPJPE"]["sd"], "verdict": res_k["All-MPJPE"]["verdict"]}
L.append("")
summary["exp1"] = sec1
# ------------------------------------------------------------------ (2) Driver-WM-kp
L += ["## 2. Driver-WM-kp (Driver-WM reproduction with K's keypoint part tokens in the internal stream, exterior stream as in the reproduction, shared recipe; `aide/docs/driverwm_kp_port.md`) vs K and vs MotionBERT-kp, seed-matched", ""]
dwm = {k: f"driverwm_kp_s{k}_v2" for k in SEEDS3}
have2 = [k for k in SEEDS3 if metrics_test(dwm[k]) is not None and run_json(dwm[k]) is not None]
sec2 = {"status": "MISSING"}
if not have2:
L += ["_(no finished `driverwm_kp_s<k>_v2` run yet)_", ""]
else:
L += ["| seed | run | params | best epoch / epochs / stop | GPU min | " + " | ".join(f"{lab} [CI]" for _, lab, _ in LEVEL_COLS) + " |", "|---|---|---|---|---|" + "---|" * len(LEVEL_COLS)]
for k in have2:
for name in (dwm[k], f"cwm3d_kp_s{k}_v2", f"motionbert_kp_s{k}_v2"):
be, ep, st, gm, npar = run_meta(name)
if name == dwm[k]:
note_gpu(name)
L.append(f"| {k} | {name} | {npar:,} | {be} / {ep} / {st} | {gm} | {level_row(name)} |")
pk = {k: paired(dwm[k], f"cwm3d_kp_s{k}_v2", d, gt, hm, a.n_boot) for k in have2}
pm = {k: paired(dwm[k], f"motionbert_kp_s{k}_v2", d, gt, hm, a.n_boot) for k in have2}
pk = {k: v for k, v in pk.items() if v}; pm = {k: v for k, v in pm.items() if v}
rows, res_k2 = delta_table(pk, "DWM-kp", "K")
L += ["", "### 2.1 Paired Δ = Driver-WM-kp − K (cwm3d_kp_s<k>_v2), per seed", ""] + rows
rows, res_m2 = delta_table(pm, "DWM-kp", "MB")
L += ["", "### 2.2 Paired Δ = Driver-WM-kp − MotionBERT-kp (motionbert_kp_s<k>_v2), per seed", ""] + rows
# pre-specified reading on Δ All vs K
r_all = [res_k2["All-MPJPE"]["per_seed"][str(k)] for k in pk]
d_ = np.array([r["mean"] for r in r_all]); lo = np.array([r["ci_lo"] for r in r_all]); hi = np.array([r["ci_hi"] for r in r_all])
cover = (lo <= 0) & (hi >= 0)
n_req = math.ceil(2 * len(r_all) / 3)
k_sig_better = int(((lo > 0)).sum()) >= n_req # Δ (DWM − K) > 0 with CI excl. 0 -> K better
dwm_sig_better = int(((hi < 0)).sum()) >= n_req
reading_a = bool(np.all(cover & (np.abs(d_) < 1.0)))
if reading_a:
reading = "(a) 领先属于关键点表述 — every seed's Δ All CI contains 0 and |Δ| < 1 px: the lead over the published Driver-WM belongs to the keypoint formulation, not to the CWM3-D architecture"
elif k_sig_better:
reading = "(b) 支持架构在关键点表述下的优势 — K is significantly better than Driver-WM-kp on ≥ 2/3 seeds (Δ All CI excl. 0, K lower)"
elif dwm_sig_better:
reading = "(c) Driver-WM-kp 更好,如实报告 — Driver-WM-kp is significantly better than K on ≥ 2/3 seeds (Δ All CI excl. 0)"
else:
reading = "none of the three pre-specified readings obtained (mixed: neither all-seeds-within-1-px-with-CI∋0 nor a ≥ 2/3-seed significant direction)"
L += ["", f"**Reading (2): Δ All (Driver-WM-kp − K) per seed = " + "; ".join(f"s{k} {fmt_ci(res_k2['All-MPJPE']['per_seed'][str(k)])}" for k in pk)
+ f" (CI ∋ 0 on {int(cover.sum())}/{len(r_all)} seeds; |Δ| < 1 px on {int((np.abs(d_) < 1.0).sum())}/{len(r_all)}; K significantly better on {int((lo > 0).sum())}/{len(r_all)}; Driver-WM-kp significantly better on {int((hi < 0).sum())}/{len(r_all)}) → {reading}. "
f"Verdicts (beats rule, sign from Driver-WM-kp's side): All {res_k2['All-MPJPE']['verdict']}, HM {res_k2['HM-MPJPE']['verdict']}, PCK {res_k2['PCK@0.05']['verdict']}, HM h=5 {res_k2['HM h=5']['verdict']}; vs MotionBERT-kp: All {res_m2['All-MPJPE']['verdict']}, HM {res_m2['HM-MPJPE']['verdict']}.**", ""]
sec2 = {"status": "DONE", "n_seeds": len(pk), "reading": reading, "reading_key": "a" if reading_a else "b" if k_sig_better else "c" if dwm_sig_better else "none",
"vs_k": {c: {kk: vv for kk, vv in r.items()} for c, r in res_k2.items()}, "vs_mb": {c: {kk: vv for kk, vv in r.items()} for c, r in res_m2.items()}}
summary["exp2"] = sec2
# ------------------------------------------------------------------ (3) MotionBERT-kp 5 seeds
L += ["## 3. MotionBERT-kp at 5 seeds (unchanged hardening-D recipe; seeds 789 / 1011 new) — paired K − MotionBERT-kp per seed", ""]
mb = {k: f"motionbert_kp_s{k}_v2" for k in SEEDS5}
kk_ = {k: f"cwm3d_kp_s{k}_v2" for k in SEEDS5}
have3 = [k for k in SEEDS5 if metrics_test(mb[k]) is not None and metrics_test(kk_[k]) is not None]
cols5 = LEVEL_COLS[:3] + [("dn_mpjpe_hm", "HM d-n", 3)] + LEVEL_COLS[3:4] + [("pck10", "PCK@0.10", 2)] + LEVEL_COLS[4:]
L += ["| seed | status | model | run | best epoch / epochs / stop | GPU min | val All | " + " | ".join(lab for _, lab, _ in cols5) + " |", "|---|---|---|---|---|---|---|" + "---|" * len(cols5)]
vals = {"K": {c: [] for c, _, _ in cols5}, "MB": {c: [] for c, _, _ in cols5}}
for k in SEEDS5:
for tag, name in (("K", kk_[k]), ("MB", mb[k])):
mt = metrics_test(name)
if mt is None:
L.append(f"| {k} | {'locked' if k in SEEDS3 else 'NEW'} | {tag} | {name} | (not finished) | | | " + " | ".join("—" for _ in cols5) + " |")
continue
be, ep, st, gm, _ = run_meta(name)
if tag == "MB" and k not in SEEDS3:
note_gpu(name)
mv = json.load(open(RUNS / name / "metrics_val.json"))["metrics"] if (RUNS / name / "metrics_val.json").exists() else {}
L.append(f"| {k} | {'locked' if k in SEEDS3 else 'NEW'} | {tag} | {name} | {be} / {ep} / {st} | {gm} | {mv.get('mpjpe_all', {}).get('value', float('nan')):.3f} | "
+ " | ".join(f"{mt[c]['value']:.{nd}f}" for c, _, nd in cols5) + " |")
if k in have3:
for c, _, _ in cols5:
vals[tag][c].append(mt[c]["value"])
L += ["", f"### 3.1 Seed means (n = {len(have3)} seeds with both runs finished: {have3})", "", "| model | n | " + " | ".join(lab for _, lab, _ in cols5) + " |", "|---|---|" + "---|" * len(cols5)]
for tag, label in (("K", "CWM3-D-kp (K)"), ("MB", "MotionBERT-kp")):
L.append(f"| {label} | {len(have3)} | " + " | ".join(ms(vals[tag][c], nd) for c, _, nd in cols5) + " |")
loc = [k for k in have3 if k in SEEDS3]
if len(loc) != len(have3):
L.append(f"| {label}, locked 3 seeds only | {len(loc)} | " + " | ".join(ms([metrics_test(kk_[k] if tag == 'K' else mb[k])[c]['value'] for k in loc], nd) for c, _, nd in cols5) + " |")
sec3 = {"status": "MISSING"}
p5 = {k: paired(kk_[k], mb[k], d, gt, hm, a.n_boot) for k in have3}
p5 = {k: v for k, v in p5.items() if v}
if p5:
rows5, res5 = delta_table(p5, "K", "MB")
L += ["", f"### 3.2 Paired Δ = K − MotionBERT-kp per seed ({len(p5)} seeds; verdict threshold = CI excl. 0 on ≥ {math.ceil(2 * len(p5) / 3)}/{len(p5)} seeds, same sign on all)", ""] + rows5
loc = {k: v for k, v in p5.items() if k in SEEDS3}
res3 = None
if loc and len(loc) != len(p5):
rows3, res3 = delta_table(loc, "K", "MB")
L += ["", "### 3.3 The same on the locked 3 seeds only (42 / 123 / 456; CI excl. 0 on ≥ 2/3)", ""] + rows3
v_all5 = res5["All-MPJPE"]["verdict"]
r_all = [res5["All-MPJPE"]["per_seed"][str(k)] for k in p5]
n_k_better = int(sum(r["ci_hi"] < 0 for r in r_all)); n_mb_better = int(sum(r["ci_lo"] > 0 for r in r_all))
if v_all5 == "BEATS":
reading3 = "K BEATS MotionBERT-kp on All-MPJPE (supports an architecture advantage under the keypoint formulation)"
elif v_all5 == "WORSE":
reading3 = "MotionBERT-kp BEATS K on All-MPJPE (the architecture advantage is NOT supported; reported as is)"
else:
reading3 = f"{v_all5}: no seed-consistent significant difference between K and MotionBERT-kp on All-MPJPE — the architecture advantage is NOT supported by (3)"
L += ["", f"**Reading (3) over {len(p5)} seeds: Δ All (K − MotionBERT-kp) = " + "; ".join(f"s{k} {fmt_ci(res5['All-MPJPE']['per_seed'][str(k)])}" for k in p5)
+ f"; mean {res5['All-MPJPE']['mean']:+.2f} ± {res5['All-MPJPE']['sd']:.2f} px; K significantly better on {n_k_better}/{len(p5)} seeds, MotionBERT-kp significantly better on {n_mb_better}/{len(p5)} → {reading3}. "
f"HM-MPJPE {res5['HM-MPJPE']['verdict']} ({res5['HM-MPJPE']['mean']:+.2f} ± {res5['HM-MPJPE']['sd']:.2f}), PCK@0.05 {res5['PCK@0.05']['verdict']} ({res5['PCK@0.05']['mean']:+.2f}), HM h=5 {res5['HM h=5']['verdict']} ({res5['HM h=5']['mean']:+.2f}).**", ""]
sec3 = {"status": "DONE", "n_seeds": len(p5), "seeds": list(p5), "verdict_all_5": v_all5, "reading": reading3, "cells": {c: {kk: vv for kk, vv in r.items()} for c, r in res5.items()},
"locked3": None if res3 is None else {c: {"verdict": r["verdict"], "mean": r["mean"], "sd": r["sd"]} for c, r in res3.items()},
"means": {tag: {c: {"mean": float(np.mean(v)), "sd": float(np.std(v, ddof=1)) if len(v) > 1 else None, "n": len(v)} for c, v in vals[tag].items() if v} for tag in vals}}
summary["exp3"] = sec3
# ------------------------------------------------------------------ outcome + GPU minutes
L += ["## 4. Outcome (decisions-row wording)", ""]
e1 = "; ".join(f"{m}: {'Δ All ' + v['verdict_all'] if v.get('status') == 'DONE' else v.get('status')}" for m, v in sec1.items())
L.append(f"- (1) matched pretraining — {e1}; K's trunk-only gain (same pretraining seed): {summary.get('k_trunk_gain_all', {}).get('mean', float('nan')):+.2f} ± {summary.get('k_trunk_gain_all', {}).get('sd', float('nan')):.2f} "
f"({summary.get('k_trunk_gain_all', {}).get('verdict', '—')}). Descriptive comparison of gain magnitudes only.")
L.append(f"- (2) Driver-WM-kp — {sec2.get('reading', sec2.get('status'))}.")
L.append(f"- (3) MotionBERT-kp 5 seeds — {sec3.get('reading', sec3.get('status'))}.")
arch_supported = (sec2.get("reading_key") == "b") and (sec3.get("verdict_all_5") == "BEATS")
L.append(f"- **Paper wording: the existing claim \"the lead comes from the keypoint-anchored formulation\" may be rewritten as an ARCHITECTURE advantage only if (2) AND (3) support it → "
f"{'SUPPORTED by both (2) and (3): may be rewritten' if arch_supported else 'NOT supported (' + ('(2) reading ' + str(sec2.get('reading_key')) + ', (3) ' + str(sec3.get('verdict_all_5'))) + '): the formulation wording stays'}.**")
summary["architecture_advantage_supported"] = bool(arch_supported)
L += ["", "## 5. Runs and GPU minutes (from the run json files; existing runs were not retrained)", "", "| run | GPU min |", "|---|---|"]
for name, g in gpu.items():
L.append(f"| {name} | {g:.2f} |")
L += [f"| **total (new runs)** | **{sum(gpu.values()):.1f}** |", "",
"## Provenance", "", "- New run dirs only (`aide/results/runs/{motionbert_kp,stgcn_kp}_batonpre_pretrain_s123`, `*_batonpre_zeroshot_s123_v2`, `*_batonpre_trunkp123_s<k>_v2`, `motionbert_kp_s{789,1011}_v2`, `driverwm_kp_s<k>_v2`); "
"the comparison runs `cwm3d_kp_s*_v2`, `motionbert_kp_s{42,123,456}_v2`, `stgcn_kp_s{42,123,456}_v2`, `cwm3d_kp_batonpre_trunkp123_s*_v2` are the existing ones.",
"- Pretraining corpus: BATON train-split, train-only-device routes (no val / test device or route); AIDE side: TRAIN statistics only. No AIDE test clip entered any training or selection.",
"- Launch gate before every job (free VRAM ≥ need + 4 GB, MemAvailable ≥ 28 GB, < 4 trainers, OMP/MKL 4): `aide/train/run_arch_attribution.sh`; pids in `aide/results/arch_attribution/pids.txt`.", ""]
out = Path(a.out)
out.parent.mkdir(parents=True, exist_ok=True)
text = "\n".join(L)
if out.exists(): # append-only: never edit an existing table
with open(out, "a") as f:
f.write(f"\n\n---\n\n<!-- appended regeneration {stamp} -->\n\n" + text)
mode = "appended"
else:
out.write_text(text)
mode = "written"
js = out.with_suffix(".json")
rec = {"stamp": stamp, "n_boot": a.n_boot, "summary": summary, "gpu_minutes": gpu}
if js.exists():
old = json.load(open(js))
old = old if isinstance(old, list) else [old]
js.write_text(json.dumps(old + [rec], indent=1, default=str))
else:
js.write_text(json.dumps([rec], indent=1, default=str))
write_run_json(P.RESULTS / "tables", "report_arch_attribution", [Path(__file__), M.__file__, P.__file__], [P.CACHE_NPZ], seed=0, t_start=t0, input_listing=False,
extra={"out": str(out), "mode": mode, "summary": {k: (v if k != "exp1" else {m: {kk: vv for kk, vv in s.items() if kk not in ("cells", "per_seed_all")} for m, s in v.items()}) for k, v in summary.items()},
"gpu_minutes": gpu, "dms_fields_used": []})
print(text)
print(f"\n[{mode}] {out}")
if __name__ == "__main__":
main()

Xet Storage Details

Size:
30.4 kB
·
Xet hash:
47c7e6da14f10245e5c01804a89ae0e424fbb9706b29f7c938f04d2e040de600

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.