Source: docs/experiments/EXP-3D-CAJU3D-FUSENET-V1/analysis/fn_describe.py · Plain text

docs/experiments/EXP-3D-CAJU3D-FUSENET-V1/analysis/fn_describe.py

"""EXP-3D-CAJU3D-FUSENET-V1 descriptive analysis after the confirmation (no decision depends on it):
  per-seed place means of every FuseNet on both confirmation cohorts;
  the AbsRel of covered (alpha >= 0.5) and uncovered pixels, and the uncovered split by near7, for CORE_B / KF_BASE /
  FUSE_BASE (ensemble);
  the uncovered correction r of FUSE_BASE: mean, share of |r| > 0.6 (near the 0.7 bound), sign;
  the per-place gain CORE_B - FUSE_BASE against the place's CORE_B error (Spearman) and its quartiles.
Run from the repository root with the DepthSplat environment, CUDA hidden (PYTHONPATH=src):
  python fn_describe.py ROOT > ROOT/results/describe.txt
"""

import json
import sys
from pathlib import Path

import numpy as np
import torch

ROOT = Path(sys.argv[1]).resolve()
sys.path.insert(0, str(ROOT / "code"))
import fn_data as D  # noqa: E402
import fn_model as M  # noqa: E402
import fn_score as FS  # noqa: E402

K, S = FS.K, D.S


def rank(x):
    return np.argsort(np.argsort(x)).astype(float)


def main():
    tables = json.loads(FS.TABLES.read_text())
    models = FS.load_models(ROOT)
    out = {}
    for cohort in FS.CONF:
        access = []
        queries = D.load_cohort(ROOT, cohort, access, with_jepa=True)
        per_seed_rows, rows = [], []
        acc = {k: [0.0, 0] for k in ("cov_CORE_B", "cov_KF_BASE", "cov_FUSE_BASE", "unc_CORE_B", "unc_FUSE_BASE",
                                     "uncnear_CORE_B", "uncnear_FUSE_BASE", "uncfar_CORE_B", "uncfar_FUSE_BASE")}
        r_all = []
        for q in queries:
            valid = q["gt"] > 0
            gt = q["gt"][valid]
            base = torch.tensor(q["base"][None])
            jepa = torch.tensor(q["jepa"][None])
            seed_preds = {}
            with torch.no_grad():
                for arm, ms in models.items():
                    for i, m in enumerate(ms):
                        logit, r = m(base, jepa if m.use_jepa else None)
                        seed_preds[f"{arm}_{i}"] = np.exp(M.log_prediction(base, logit, r)[0].double().numpy())[valid]
                        if arm == "BASE":
                            r_all.append(r[0].numpy()[(q["base"][6] < 0.5) & valid])
                fuse = np.exp(FS.ensemble_log(models["BASE"], base, jepa, True)[0].double().numpy())[valid]
            per_seed_rows.append({"place": q["place"], "episode": q["episode"], "query": q["key"],
                                  "core_b": {k: float(np.mean(np.abs(v - gt) / gt)) for k, v in seed_preds.items()}})
            core = K.readout(q["kf"], "CORE_B", tables)
            kfb = K.readout(q["kf"], "KF_BASE", tables)
            cov = q["kf"]["alpha"] >= 0.5
            near = q["kf"]["near"]
            for name, pred in (("CORE_B", core), ("KF_BASE", kfb), ("FUSE_BASE", fuse)):
                err = np.abs(pred - gt) / gt
                for key, mask in (("cov", cov), ("unc", ~cov), ("uncnear", ~cov & near), ("uncfar", ~cov & ~near)):
                    if f"{key}_{name}" in acc:
                        acc[f"{key}_{name}"][0] += float(err[mask].sum())
                        acc[f"{key}_{name}"][1] += int(mask.sum())
            rows.append({"place": q["place"], "episode": q["episode"], "query": q["key"],
                         "core_b": {"CORE_B": float(np.mean(np.abs(core - gt) / gt)),
                                    "FUSE_BASE": float(np.mean(np.abs(fuse - gt) / gt))}})
        seed_table = S.place_table(per_seed_rows)
        table = S.place_table(rows)
        places = sorted(table["CORE_B"])
        core_err = np.array([table["CORE_B"][p] for p in places])
        gain = np.array([table["CORE_B"][p] - table["FUSE_BASE"][p] for p in places])
        r_cat = np.concatenate(r_all)
        total_pixels = sum(v[1] for k, v in acc.items() if k.startswith("cov_CORE_B") or k.startswith("unc_CORE_B"))
        out[cohort] = {
            "per_seed_means": {k: round(S.mean(v), 5) for k, v in seed_table.items()},
            "pixel_absrel": {k: round(v[0] / max(v[1], 1), 5) for k, v in acc.items()},
            "uncovered_pixel_share": round(acc["unc_CORE_B"][1] / max(total_pixels, 1), 4),
            "uncovered_far_share_of_uncovered": round(acc["uncfar_CORE_B"][1] / max(acc["unc_CORE_B"][1], 1), 4),
            "r": {"mean": round(float(r_cat.mean()), 4), "share_positive": round(float((r_cat > 0).mean()), 4),
                  "share_abs_gt_0.6": round(float((np.abs(r_cat) > 0.6).mean()), 4)},
            "gain_vs_core_b_error_spearman": round(float(np.corrcoef(rank(core_err), rank(gain))[0, 1]), 3),
            "gain_quartiles": [round(float(x), 5) for x in np.quantile(gain, [0, 0.25, 0.5, 0.75, 1])],
            "worse_places": int((gain < 0).sum()), "places": len(places),
        }
        print(cohort, json.dumps(out[cohort], indent=1))
    (ROOT / "results/describe.json").write_text(json.dumps(out, indent=1, sort_keys=True) + "\n")


if __name__ == "__main__":
    main()