update 3-19
This commit is contained in:
+28
-83
@@ -56,6 +56,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "6a600aed",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
@@ -84,6 +85,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "d1ea8b19",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 1) Build UNet Manifest"
|
||||
@@ -92,6 +94,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "b07b3e69",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
@@ -108,21 +111,28 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "dgglybgo5wg",
|
||||
"source": "## 2) Build Refugelike Backbone\n\nThe `refugelike` backbone is a ResNet-50 pre-trained on REFUGE as an optic disc/cup classifier, then stripped of its classification head and used as a frozen or partially-frozen feature extractor in the HyperTower image tower.\n\n**Steps:**\n1. Train the REFUGE classifier (`--train-clf`)\n2. Export its backbone weights to `models/v2/refuge/refugelike_backbone.pt` (`--export-backbone`)\n\nThe classifier checkpoint is saved to `models/v2/refuge/classifier/resnet50/refuge_classifier_best.pt` by default. \nThe exported backbone is what `--backbone refugelike` loads at runtime (see `classes/v2/backbones.py`).",
|
||||
"metadata": {}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"id": "b7jt033ul4v",
|
||||
"source": "BACKBONE_PATH = \"models/v2/refuge/refugelike_backbone.pt\"\n\n# Step 1: train the REFUGE classifier (ResNet-50, 30 epochs by default)\n!python3 scripts/main/refuge/refuge_build.py \\\n --train-clf \\\n --manifest manifest.csv \\\n --device cuda\n\n# Step 2: strip the head and export backbone weights\n!python3 scripts/main/refuge/refuge_build.py \\\n --export-backbone {BACKBONE_PATH} \\\n --manifest manifest.csv \\\n --device cuda",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 2) Train UNet Segmenter (per-image normalization)\n",
|
||||
"\n",
|
||||
"Current tuned baseline:\n",
|
||||
"- `--device cuda`\n",
|
||||
"- `--batch-size 8`\n",
|
||||
"- `--loader-workers 14`\n",
|
||||
"- `--in-memory-cache`\n",
|
||||
"- `--cache-workers 4`"
|
||||
]
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "8df524a2",
|
||||
"metadata": {},
|
||||
"source": "## 2b) Train UNet Segmenter (per-image normalization)\n\nCurrent tuned baseline:\n- `--device cuda`\n- `--batch-size 8`\n- `--loader-workers 14`\n- `--in-memory-cache`\n- `--cache-workers 4`"
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"id": "be2b499a",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
@@ -1270,6 +1280,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "a2a3bd04",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 5) Run Pipeline Experiments\n",
|
||||
@@ -1283,6 +1294,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "e395f268",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -1301,41 +1313,18 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "125f35c6",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 3b) GT crop — expert segmentation masks crop the optic disc region\n",
|
||||
"!python scripts/main/v2/multirun_hypertower.py \\\n",
|
||||
" --tower-modes single ensemble \\\n",
|
||||
" --eval-modes binary multiclass \\\n",
|
||||
" --epochs 40 --n-splits 5 \\\n",
|
||||
" --backbone refugelike \\\n",
|
||||
" --img-crop-gt \\\n",
|
||||
" --warmup-md-epochs 50 \\\n",
|
||||
" --fused-head \\\n",
|
||||
" --run-name pipeline_gt"
|
||||
]
|
||||
"source": "# 3b) GT crop — expert segmentation masks crop the optic disc region\n!python scripts/main/v2/multirun_hypertower.py \\\n --tower-modes single ensemble \\\n --eval-modes binary multiclass \\\n --epochs 40 --n-splits 5 \\\n --backbone refugelike \\\n --img-crop-manifest manifest.csv \\\n --img-crop-gt \\\n --warmup-md-epochs 50 \\\n --fused-head \\\n --run-name pipeline_gt"
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "83df73ac",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 3c) UNet crop — trained segmenter crops the optic disc region\n",
|
||||
"!python scripts/main/v2/multirun_hypertower.py \\\n",
|
||||
" --tower-modes single ensemble \\\n",
|
||||
" --eval-modes binary multiclass \\\n",
|
||||
" --epochs 40 --n-splits 5 \\\n",
|
||||
" --backbone refugelike \\\n",
|
||||
" --img-crop-manifest analysis_data/unet_manifest.csv \\\n",
|
||||
" --img-crop-weights models/v2/refuge/segmentation/per_image/best.pt \\\n",
|
||||
" --img-crop-normalize per_image \\\n",
|
||||
" --img-crop-cache analysis_data/v2_crops_unet_refuge \\\n",
|
||||
" --warmup-md-epochs 50 \\\n",
|
||||
" --fused-head \\\n",
|
||||
" --run-name pipeline_unet"
|
||||
]
|
||||
"source": "# 3c) UNet crop — trained segmenter crops the optic disc region\n!python scripts/main/v2/multirun_hypertower.py \\\n --tower-modes single ensemble \\\n --eval-modes binary multiclass \\\n --epochs 40 --n-splits 5 \\\n --backbone refugelike \\\n --img-crop-manifest manifest.csv \\\n --img-crop-weights models/v2/refuge/segmentation/per_image/best.pt \\\n --img-crop-normalize per_image \\\n --img-crop-cache analysis_data/v2_crops_unet_refuge \\\n --warmup-md-epochs 50 \\\n --fused-head \\\n --run-name pipeline_unet"
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
@@ -1353,51 +1342,7 @@
|
||||
"id": "7yrcfu0bv1w",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import subprocess\n",
|
||||
"from pathlib import Path\n",
|
||||
"\n",
|
||||
"RUN_DIRS = {\n",
|
||||
" \"nocrop\": Path(\"analysis_data/pipeline_nocrop\"),\n",
|
||||
" \"gt\": Path(\"analysis_data/pipeline_gt\"),\n",
|
||||
" \"unet\": Path(\"analysis_data/pipeline_unet\"),\n",
|
||||
"}\n",
|
||||
"EVAL_MODES = [\"binary\", \"multiclass\"]\n",
|
||||
"TOWER_MODES = [\"single\", \"ensemble\"]\n",
|
||||
"\n",
|
||||
"for run_name, run_dir in RUN_DIRS.items():\n",
|
||||
" for eval_mode in EVAL_MODES:\n",
|
||||
" for tower_mode in TOWER_MODES:\n",
|
||||
" mode_dir = run_dir / eval_mode / tower_mode\n",
|
||||
" if not mode_dir.exists():\n",
|
||||
" print(f\" skip (not found): {mode_dir}\")\n",
|
||||
" continue\n",
|
||||
" print(f\"--- {run_name} / {eval_mode} / {tower_mode} ---\")\n",
|
||||
"\n",
|
||||
" # ROC curves\n",
|
||||
" subprocess.run([\n",
|
||||
" \"python\", \"scripts/output_analysis/visualizations/plot_run_roc_v2.py\",\n",
|
||||
" \"--run-dir\", str(run_dir),\n",
|
||||
" \"--eval-mode\", eval_mode,\n",
|
||||
" \"--tower-mode\", tower_mode,\n",
|
||||
" ], check=True)\n",
|
||||
"\n",
|
||||
" # Probability strips — binary only\n",
|
||||
" if eval_mode == \"binary\":\n",
|
||||
" subprocess.run([\n",
|
||||
" \"python\", \"scripts/output_analysis/visualizations/plot_prob_strips.py\",\n",
|
||||
" \"--run-dir\", str(mode_dir),\n",
|
||||
" \"--head\", \"fused\", \"--style\", \"strips\",\n",
|
||||
" ], check=True)\n",
|
||||
"\n",
|
||||
" # Probability triangle-3D — multiclass only\n",
|
||||
" if eval_mode == \"multiclass\":\n",
|
||||
" subprocess.run([\n",
|
||||
" \"python\", \"scripts/output_analysis/visualizations/plot_prob_strips.py\",\n",
|
||||
" \"--run-dir\", str(mode_dir),\n",
|
||||
" \"--head\", \"fused\", \"--style\", \"triangle3d\",\n",
|
||||
" ], check=True)"
|
||||
]
|
||||
"source": "import subprocess\nfrom pathlib import Path\n\nRUN_DIRS = {\n \"nocrop\": (Path(\"analysis_data/pipeline_nocrop\"), [\"single\", \"ensemble\"]),\n \"gt\": (Path(\"analysis_data/pipeline_gt\"), [\"single\", \"ensemble\"]),\n \"unet\": (Path(\"analysis_data/pipeline_unet\"), [\"single\", \"ensemble\"]),\n \"imgonly_nocrop\":(Path(\"analysis_data/pipeline_imgonly_nocrop\"),[\"single\"]),\n \"imgonly_gt\": (Path(\"analysis_data/pipeline_imgonly_gt\"), [\"single\"]),\n \"imgonly_unet\": (Path(\"analysis_data/pipeline_imgonly_unet\"), [\"single\"]),\n}\nEVAL_MODES = [\"binary\", \"multiclass\"]\n\nfor run_name, (run_dir, tower_modes) in RUN_DIRS.items():\n for eval_mode in EVAL_MODES:\n for tower_mode in tower_modes:\n mode_dir = run_dir / eval_mode / tower_mode\n if not mode_dir.exists():\n print(f\" skip (not found): {mode_dir}\")\n continue\n print(f\"--- {run_name} / {eval_mode} / {tower_mode} ---\")\n\n # ROC curves (auto-detects all available probs stems)\n subprocess.run([\n \"python\", \"scripts/output_analysis/visualizations/plot_run_roc_v2.py\",\n \"--run-dir\", str(run_dir),\n \"--eval-mode\", eval_mode,\n \"--tower-mode\", tower_mode,\n ], check=True)\n\n # Probability strips — binary only (auto-detects all heads)\n if eval_mode == \"binary\":\n subprocess.run([\n \"python\", \"scripts/output_analysis/visualizations/plot_prob_strips.py\",\n \"--run-dir\", str(mode_dir),\n \"--style\", \"strips\",\n ], check=True)\n\n # Probability triangle-3D — multiclass only (auto-detects all heads)\n if eval_mode == \"multiclass\":\n subprocess.run([\n \"python\", \"scripts/output_analysis/visualizations/plot_prob_strips.py\",\n \"--run-dir\", str(mode_dir),\n \"--style\", \"triangle3d\",\n ], check=True)"
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
@@ -1458,4 +1403,4 @@
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ Usage examples (after activating .venv_refuge):
|
||||
python refuge_build.py --eval --with-ttt
|
||||
|
||||
The script expects the REFUGE folder and writes checkpoints under
|
||||
models/refuge/segmentation and models/refuge/classifier.
|
||||
models/v2/refuge/segmentation and models/v2/refuge/classifier.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -46,7 +46,7 @@ from classes.papila_builders import build_papila_clinical
|
||||
|
||||
REFUGE_ROOT = Path("REFUGE")
|
||||
SEG_CKPT = Path("models/refuge/segmentation/refuge_segmentation_best.pt")
|
||||
CLF_DIR = Path("models/refuge/classifier")
|
||||
CLF_DIR = Path("models/v2/refuge/classifier")
|
||||
UNET_WEIGHT_CANDIDATES = (
|
||||
Path("models/v2/refuge/segmentation/per_image/best.pt"),
|
||||
Path("models/v2/refuge/segmentation/best.pt"),
|
||||
@@ -820,7 +820,7 @@ def parse_args() -> argparse.Namespace:
|
||||
"--clf-checkpoint-path",
|
||||
type=Path,
|
||||
default=None,
|
||||
help="Optional explicit path for the classifier checkpoint (defaults to models/refuge/classifier/<backbone>/refuge_classifier_best.pt)",
|
||||
help="Optional explicit path for the classifier checkpoint (defaults to models/v2/refuge/classifier/<backbone>/refuge_classifier_best.pt)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--eval-datasets",
|
||||
|
||||
@@ -7,7 +7,7 @@ from pathlib import Path
|
||||
import sys
|
||||
import argparse
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[2]
|
||||
REPO_ROOT = Path(__file__).resolve().parents[3]
|
||||
if str(REPO_ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(REPO_ROOT))
|
||||
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
10× repeated 5-fold CV runner for the best hypertower configuration
|
||||
(nocrop, ensemble mode, both binary and multiclass).
|
||||
|
||||
Each repetition uses a different fold-seed so the 5 folds are split
|
||||
differently, giving 50 folds per eval-mode total. Holdout composition
|
||||
is kept identical across repetitions (same --holdout-seed).
|
||||
|
||||
Results land under:
|
||||
{output-root}/rep{N:02d}/{eval_mode}/ensemble/fold{K}/
|
||||
|
||||
Usage
|
||||
-----
|
||||
python scripts/main/v2/run_10x5cv.py \
|
||||
--n-reps 10 \
|
||||
--eval-modes binary multiclass \
|
||||
--output-root analysis_data/pipeline_10x5 \
|
||||
--epochs 40 --fused-head \
|
||||
--backbone refugelike
|
||||
|
||||
Any extra flags are forwarded directly to V2HyperTower.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[3]
|
||||
if str(REPO_ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(REPO_ROOT))
|
||||
|
||||
from classes.v2.v2_hypertower import V2HyperTower
|
||||
|
||||
# Base fold seed for rep 0; rep N uses BASE_SEED + N * SEED_STRIDE
|
||||
_BASE_SEED = 100
|
||||
_SEED_STRIDE = 100
|
||||
|
||||
|
||||
def _parse_own(argv=None):
|
||||
ap = argparse.ArgumentParser(
|
||||
description=__doc__,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
add_help=False,
|
||||
)
|
||||
ap.add_argument("--n-reps", type=int, default=10,
|
||||
help="Number of repetitions (default: 10).")
|
||||
ap.add_argument("--eval-modes", nargs="+",
|
||||
choices=["binary", "multiclass"],
|
||||
default=["binary", "multiclass"])
|
||||
ap.add_argument("--output-root", default="analysis_data/pipeline_10x5",
|
||||
help="Parent directory for all rep sub-runs.")
|
||||
ap.add_argument("-h", "--help", action="store_true")
|
||||
return ap.parse_known_args(argv)
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
own, remaining = _parse_own(argv)
|
||||
|
||||
if own.help:
|
||||
print(__doc__)
|
||||
base_parser = V2HyperTower.build_parser()
|
||||
base_parser.print_help()
|
||||
return
|
||||
|
||||
base_parser = V2HyperTower.build_parser()
|
||||
output_root = Path(own.output_root)
|
||||
first_run = True
|
||||
|
||||
for rep in range(own.n_reps):
|
||||
fold_seed = _BASE_SEED + rep * _SEED_STRIDE
|
||||
rep_label = f"rep{rep:02d}"
|
||||
|
||||
for eval_mode in own.eval_modes:
|
||||
tower_mode = "ensemble"
|
||||
|
||||
# Skip if already fully complete
|
||||
tm_dir = output_root / rep_label / eval_mode / tower_mode
|
||||
if (tm_dir / "summary.json").exists():
|
||||
print(f"[10x5cv] {rep_label} {eval_mode}:{tower_mode} — already done, skipping.")
|
||||
first_run = False
|
||||
continue
|
||||
|
||||
cli = list(remaining) + [
|
||||
"--eval-mode", eval_mode,
|
||||
"--tower-mode", tower_mode,
|
||||
"--fold-seed", str(fold_seed),
|
||||
"--run-name", rep_label,
|
||||
"--output-root", str(output_root),
|
||||
]
|
||||
|
||||
# Reuse crop cache across runs after the first
|
||||
if not first_run:
|
||||
cli.append("--persist-img-crop-cache")
|
||||
|
||||
print(f"\n[10x5cv] Starting {rep_label} {eval_mode}:{tower_mode} "
|
||||
f"(fold_seed={fold_seed})")
|
||||
args = base_parser.parse_args(cli)
|
||||
V2HyperTower(args).run()
|
||||
first_run = False
|
||||
|
||||
print(f"\n[10x5cv] All done. Results in: {output_root}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,90 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Run single-mode binary + multiclass for each IOP correction method and
|
||||
collect all results under one output root for easy comparison.
|
||||
|
||||
Output layout:
|
||||
analysis_data/iop_corr_comparison/
|
||||
ratio/binary/single/ ratio/multiclass/single/
|
||||
ols/binary/single/ ols/multiclass/single/
|
||||
lad/binary/single/ lad/multiclass/single/
|
||||
multi/binary/single/ multi/multiclass/single/
|
||||
|
||||
Usage
|
||||
-----
|
||||
python scripts/main/v2/run_iop_corr_comparison.py [V2HyperTower args...]
|
||||
|
||||
Any extra args (backbone, epochs, img-crop-*, etc.) are forwarded to every run.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[3]
|
||||
if str(REPO_ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(REPO_ROOT))
|
||||
|
||||
from classes.v2.v2_hypertower import V2HyperTower
|
||||
|
||||
IOP_METHODS = ["ratio", "ols", "lad", "multi"]
|
||||
EVAL_MODES = ["binary", "multiclass"]
|
||||
OUTPUT_ROOT = "analysis_data/iop_corr_comparison"
|
||||
|
||||
|
||||
def main() -> None:
|
||||
base_parser = V2HyperTower.build_parser()
|
||||
# Consume only the remaining (forwarded) args — iop-corr-method and
|
||||
# run-name are set by this script; eval-mode and tower-mode likewise.
|
||||
_, remaining = base_parser.parse_known_args()
|
||||
|
||||
first_run = True
|
||||
for method in IOP_METHODS:
|
||||
for eval_mode in EVAL_MODES:
|
||||
run_name = method # one sub-folder per method
|
||||
tm_dir = (Path(OUTPUT_ROOT) / run_name / eval_mode / "single")
|
||||
if (tm_dir / "summary.json").exists():
|
||||
print(f"[iop_corr] {method}/{eval_mode}/single — already done, skipping.")
|
||||
first_run = False
|
||||
continue
|
||||
|
||||
cli = list(remaining) + [
|
||||
"--eval-mode", eval_mode,
|
||||
"--tower-mode", "single",
|
||||
"--iop-corr-method", method,
|
||||
"--output-root", OUTPUT_ROOT,
|
||||
"--run-name", run_name,
|
||||
]
|
||||
if not first_run:
|
||||
cli.append("--persist-img-crop-cache")
|
||||
|
||||
print(f"\n[iop_corr] Starting {method}/{eval_mode}/single ...")
|
||||
args = base_parser.parse_args(cli)
|
||||
V2HyperTower(args).run()
|
||||
first_run = False
|
||||
|
||||
# ── summary table ──────────────────────────────────────────────────────
|
||||
import json
|
||||
print("\n" + "=" * 60)
|
||||
print("IOP correction method comparison — single mode")
|
||||
print("=" * 60)
|
||||
header = f"{'Method':<8} {'Mode':<12} {'Val AUC':>10} {'Hld AUC':>10}"
|
||||
print(header)
|
||||
print("-" * len(header))
|
||||
for method in IOP_METHODS:
|
||||
for eval_mode in EVAL_MODES:
|
||||
p = Path(OUTPUT_ROOT) / method / eval_mode / "single" / "summary.json"
|
||||
if not p.exists():
|
||||
print(f"{method:<8} {eval_mode:<12} {'missing':>10} {'missing':>10}")
|
||||
continue
|
||||
ms = json.loads(p.read_text()).get("mode_summary", {})
|
||||
val = ms.get("classic_best_val", {})
|
||||
hld = ms.get("classic_holdout", {})
|
||||
val_s = f"{val['auc_mean']:.3f}±{val['auc_std']:.3f}" if val.get("auc_mean") else "—"
|
||||
hld_s = f"{hld['auc_mean']:.3f}±{hld['auc_std']:.3f}" if hld.get("auc_mean") else "—"
|
||||
print(f"{method:<8} {eval_mode:<12} {val_s:>10} {hld_s:>10}")
|
||||
print("=" * 60)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -323,6 +323,7 @@ def main() -> None:
|
||||
best_epoch = 0
|
||||
best_phase = ""
|
||||
best_state = None
|
||||
epoch_log_rows = []
|
||||
|
||||
print(
|
||||
f"\n[fold {fold_idx+1}/{args.n_splits}] "
|
||||
@@ -350,6 +351,14 @@ def main() -> None:
|
||||
aggregate_patient=aggregate_patient,
|
||||
)
|
||||
|
||||
hld_auc_ep = float("nan")
|
||||
hld_acc_ep = float("nan")
|
||||
if holdout_loader is not None:
|
||||
_, _, hld_auc_ep, hld_acc_ep = _evaluate_single(
|
||||
model, holdout_loader, device, num_classes,
|
||||
aggregate_patient=aggregate_patient,
|
||||
)
|
||||
|
||||
is_main = phase == "main"
|
||||
if is_main and (not np.isnan(val_auc)) and val_auc > best_auc:
|
||||
best_auc = float(val_auc)
|
||||
@@ -357,6 +366,17 @@ def main() -> None:
|
||||
best_epoch = ep + 1
|
||||
best_phase = phase
|
||||
|
||||
epoch_log_rows.append({
|
||||
"epoch": ep + 1,
|
||||
"phase": phase,
|
||||
"train_loss": float(tr_loss),
|
||||
"train_acc": float(tr_acc),
|
||||
"val_auc": float(val_auc),
|
||||
"val_acc": float(val_acc),
|
||||
"hld_auc": float(hld_auc_ep),
|
||||
"hld_acc": float(hld_acc_ep),
|
||||
})
|
||||
|
||||
if ep == 0 or (ep + 1) % 10 == 0 or (ep + 1) == total_epochs:
|
||||
print(
|
||||
f" ep {ep+1:>3}/{total_epochs} [{phase}:{main_ep}/{args.epochs}] "
|
||||
@@ -366,6 +386,9 @@ def main() -> None:
|
||||
flush=True,
|
||||
)
|
||||
|
||||
import pandas as _pd
|
||||
_pd.DataFrame(epoch_log_rows).to_csv(fold_dir / "epoch_log.csv", index=False)
|
||||
|
||||
if best_state is not None:
|
||||
model.load_state_dict(best_state)
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ from __future__ import annotations
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[1]
|
||||
REPO_ROOT = Path(__file__).resolve().parents[3]
|
||||
if str(REPO_ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(REPO_ROOT))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user