Add new regression and ensemble experiment configurations for V2-M and OrthoBridge

- 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.
This commit is contained in:
rpotter6298
2026-06-11 15:08:20 +02:00
parent 32a801a572
commit 280060db82
343 changed files with 8558 additions and 57747 deletions
+17 -9
View File
@@ -39,14 +39,20 @@ def find_rep_summaries(run_dir: Path) -> list[tuple[int, Path]]:
def load_rep(summary_path: Path) -> dict:
"""Extract the fields we summarise from one rep's summary.json."""
"""Extract the fields we summarise from one rep's summary.json.
Uses `primary_metric` if present (for regression runs e.g. neg_mse),
falling back to AUC for legacy classification runs.
"""
d = json.loads(summary_path.read_text())
pm = d.get("primary_metric", "auc")
return {
"val_mean": float(d.get("mean_val_auc", float("nan"))),
"val_std": float(d.get("std_val_auc", float("nan"))),
"test_mean": float(d.get("mean_test_auc", float("nan"))),
"test_std": float(d.get("std_test_auc", float("nan"))),
"elapsed_s": float(d.get("elapsed_s", float("nan"))),
"primary": pm,
"val_mean": float(d.get(f"mean_val_{pm}", d.get("mean_val_auc", float("nan")))),
"val_std": float(d.get(f"std_val_{pm}", d.get("std_val_auc", float("nan")))),
"test_mean": float(d.get(f"mean_test_{pm}", d.get("mean_test_auc", float("nan")))),
"test_std": float(d.get(f"std_test_{pm}", d.get("std_test_auc", float("nan")))),
"elapsed_s": float(d.get("elapsed_s", float("nan"))),
"eval_stage": d.get("eval_stage", "?"),
}
@@ -63,6 +69,7 @@ def summarise(run_dir: Path) -> dict:
"run": str(run_dir),
"n_reps": len(rows),
"eval_stage": rows[0][1]["eval_stage"],
"primary": rows[0][1]["primary"],
"val_mean": float(np.mean(val)),
"val_std": float(np.std(val)),
"val_min": float(np.min(val)),
@@ -83,12 +90,13 @@ def render(s: dict, per_rep: bool = False) -> str:
if s["n_reps"] == 0:
return f"Run: {s['run']}\n no reps with summary.json found."
metric = s.get("primary", "auc")
lines = [
f"Run: {s['run']}",
f"Reps: {s['n_reps']} (eval_stage={s['eval_stage']})",
f"Val AUC: {s['val_mean']:.4f} ± {s['val_std']:.4f} "
f"Reps: {s['n_reps']} (eval_stage={s['eval_stage']}, metric={metric})",
f"Val {metric}: {s['val_mean']:.4f} ± {s['val_std']:.4f} "
f"[min={s['val_min']:.4f} max={s['val_max']:.4f}]",
f"Test AUC: {s['test_mean']:.4f} ± {s['test_std']:.4f} "
f"Test {metric}: {s['test_mean']:.4f} ± {s['test_std']:.4f} "
f"[min={s['test_min']:.4f} max={s['test_max']:.4f}]",
]
if s.get("elapsed_total_s") is not None: