280060db82
- Introduced multiple regression experiment configurations targeting vf_md, including: - cd_solo_reg_set.json: CD tower only regression setup. - img_solo_reg_set.json: Image tower only regression setup. - reg_head_epoch_sweep.json: Baseline regression sweeps at different epochs (50, 75, 100). - reg_head_set.json: Various regression setups including baseline and OrthoBridge configurations. - single_eye_reg.json: Single-eye regression setup for worst-eye aggregation analysis. - Added ensemble configurations for OrthoBridge with different inner bridges: - ortho_alts_ensemble.json: Ensemble tests with ConcatBridge, PairwiseAdditiveBridge, and GatedAdditiveBridge. - ortho_alts_tritower.json: Tritower tests with the same inner bridges. - Created V2-M specific configurations: - baseline_reg_nt50.json: Regression baseline with V2-M backbone. - geom_vec_gt.json and geom_vec_unet.json: Geometry vector injection experiments with V2-M. - single_l1_bridges.json: Single-eye ensemble experiments with various bridge types. - tritower_geom_gt.json: Tritower setup with GT contour-rasterized masks. - Promoted existing experiments to higher repetitions for robustness.
56 lines
1.9 KiB
Python
56 lines
1.9 KiB
Python
"""Shared loaders/aggregators for v4 figure scripts."""
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from pathlib import Path
|
|
from typing import Optional
|
|
|
|
import numpy as np
|
|
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parents[3]
|
|
RESULTS_ROOT = REPO_ROOT / "v4" / "results" / "experiments"
|
|
|
|
|
|
def summarise_run(run_path: Path, primary_hint: Optional[str] = None) -> Optional[dict]:
|
|
"""Aggregate val/test primary-metric mean & std across reps for one run folder.
|
|
|
|
Returns dict with n, val_mean, val_std, test_mean, test_std, metric_name, or None if no reps."""
|
|
val, test = [], []
|
|
metric_name = primary_hint
|
|
for rep in sorted(run_path.glob("rep*")):
|
|
s = next(iter(rep.rglob("summary.json")), None)
|
|
if not s:
|
|
continue
|
|
d = json.loads(s.read_text())
|
|
pm = d.get("primary_metric") or metric_name or "auc"
|
|
metric_name = metric_name or pm
|
|
v = d.get(f"mean_val_{pm}")
|
|
t = d.get(f"mean_test_{pm}")
|
|
if v is None or t is None or not np.isfinite(v) or not np.isfinite(t):
|
|
continue
|
|
val.append(float(v)); test.append(float(t))
|
|
if not val:
|
|
return None
|
|
return {
|
|
"n": len(val),
|
|
"metric": metric_name or "auc",
|
|
"val_mean": float(np.mean(val)),
|
|
"val_std": float(np.std(val)),
|
|
"test_mean": float(np.mean(test)),
|
|
"test_std": float(np.std(test)),
|
|
"val_arr": np.array(val),
|
|
"test_arr": np.array(test),
|
|
}
|
|
|
|
|
|
def summarise_many(name_to_path: dict[str, Path], primary_hint: Optional[str] = None) -> dict[str, Optional[dict]]:
|
|
"""Apply summarise_run to a dict of labelled run folders."""
|
|
return {label: summarise_run(p, primary_hint) for label, p in name_to_path.items()}
|
|
|
|
|
|
def fmt_status(s: Optional[dict]) -> str:
|
|
if s is None:
|
|
return "pending"
|
|
return f"n={s['n']:>2d} test={s['test_mean']:.4f}±{s['test_std']:.4f}"
|