moved_repo_first_update

This commit is contained in:
rpotter6298
2026-02-24 10:39:48 +01:00
commit 9894a23f09
98 changed files with 35387 additions and 0 deletions
+145
View File
@@ -0,0 +1,145 @@
#!/usr/bin/env python3
import argparse, subprocess, sys, time, json
from pathlib import Path
# Backbones in the paper that torchvision supports
BACKBONES = [
"efficientnet_b0",
"resnet50",
"densenet121",
"vgg16",
"mobilenet_v2",
"inception_v3",
# (Xception omitted; not in torchvision — add via timm later if needed)
]
MODES = [
("multiclass", ["Healthy", "Glaucoma", "Suspect"]),
("binary", ["Healthy", "Glaucoma"]),
]
def run(cmd):
print("\n$ " + " ".join(map(str, cmd)))
res = subprocess.run(cmd, check=True)
return res.returncode
def main():
ap = argparse.ArgumentParser(description="Run all paper CNNs across folds in multiclass + binary, then compile plots.")
ap.add_argument("--epochs", type=int, default=5, help="Epochs per fold (fast sanity first).")
ap.add_argument("--shortname", type=str, default="papergrid", help="Prefix for run IDs.")
ap.add_argument("--n-splits", type=int, default=5, help="Number of folds.")
ap.add_argument("--fusion-mode", type=str, default="fused", choices=["image_only","fused","metadata_only","vote"],
help="Paper CNNs are image-only; leave as image_only unless youre testing others.")
ap.add_argument("--freeze-ratio", type=float, default=0.0, help="0.0 = full fine-tune (as in the paper).")
# You can override data roots if needed
ap.add_argument("--image-dir", default="Papila/FundusImages")
ap.add_argument("--clinical-dir", default="Papila/ClinicalData")
ap.add_argument("--label-col", default="Diagnosis")
ap.add_argument("--cat-cols", nargs="*", default=["Gender", "Phakic/Pseudophakic"])
args = ap.parse_args()
ts = time.strftime("%Y%m%d_%H%M%S")
master_tag = f"{args.shortname}_{ts}"
master_dir = Path("analysis_data") / master_tag
master_dir.mkdir(parents=True, exist_ok=True)
# Keep a log of all subruns for the master report
index = []
for backbone in BACKBONES:
for eval_mode, class_names in MODES:
# build a child shortname per (backbone, mode)
sub_prefix = f"{args.shortname}_{backbone}_{eval_mode}"
cmd = [
sys.executable, "scripts/run_multifold.py",
"--backbone", backbone,
"--freeze-ratio", str(args.freeze_ratio),
"--fusion-mode", args.fusion_mode,
"--epochs", str(args.epochs),
"--n-splits", str(args.n_splits),
"--shortname", sub_prefix,
"--eval_mode", eval_mode,
"--image-dir", args.image_dir,
"--clinical-dir", args.clinical_dir,
"--label-col", args.label_col,
]
# class names by mode (ensures plot legends are correct)
cmd += ["--class-names", *class_names]
plot_head_map = {
"image_only": "image",
"fused" : "fused",
"metadata_only": "metadata",
"vote": "fused",
}
# We always aggregate/plot the image head for paper CNNs
cmd += ["--plot-head", plot_head_map.get(args.fusion_mode)]
# Delegate the whole run to run_multifold.py
run(cmd)
# Discover the child run folder (the newest folder matching the shortname prefix)
# We do this because run_multifold appends its own timestamp.
adir = Path("analysis_data")
children = sorted([p for p in adir.glob(f"{sub_prefix}_*") if p.is_dir()])
if not children:
print(f"[WARN] No analysis_data folder found for {sub_prefix}; skipping index entry.")
continue
run_dir = children[-1]
summary_json = run_dir / "summary.json"
plots_dir = run_dir / "plots"
# Record entry
entry = {
"backbone": backbone,
"eval_mode": eval_mode,
"run_dir": str(run_dir),
"summary_json": str(summary_json) if summary_json.exists() else None,
"plots": {
"mean": str(plots_dir / "roc_image_mean_ovr.png"),
"overlay": str(plots_dir / "roc_image_perfold_overlay.png"),
}
}
# Try to read AUCs
try:
if summary_json.exists():
entry.update(json.loads(summary_json.read_text()))
except Exception:
pass
index.append(entry)
# Write a master JSON + markdown report
(master_dir / "index.json").write_text(json.dumps(index, indent=2), encoding="utf-8")
# Simple markdown table of results with links
lines = [
f"# Multimodel grid — {master_tag}",
"",
f"- Epochs per fold: **{args.epochs}**",
f"- Folds: **{args.n_splits}**",
f"- Fusion mode: **{args.fusion_mode}** (paper CNNs = image-only)",
f"- Freeze ratio: **{args.freeze_ratio}**",
"",
"| Backbone | Mode | Mean AUC (macro/mc or ROC-AUC/bin) | Plots | Run folder |",
"|---|---|---:|---|---|",
]
for e in index:
auc_mean = e.get("macro_ovr_auc_mean", None)
if auc_mean is not None:
auc_str = f"{auc_mean:.3f}"
else:
auc_str = ""
mean_png = e["plots"]["mean"]
overlay_png = e["plots"]["overlay"]
plots_md = f"[mean]({mean_png}) / [overlay]({overlay_png})"
lines.append(
f"| `{e['backbone']}` | `{e['eval_mode']}` | {auc_str} | {plots_md} | `{e['run_dir']}` |"
)
(master_dir / "README.md").write_text("\n".join(lines) + "\n", encoding="utf-8")
print(f"\nAll done.\n- Master index: {master_dir/'index.json'}\n- Report: {master_dir/'README.md'}")
print(f"- Individual runs live under analysis_data/<shortname_backbone_mode_*> with plots and summaries.")
if __name__ == "__main__":
main()