Instructions to use Lien-Feng/Lightweight-2-5D-LUNA16 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- ultralytics
How to use Lien-Feng/Lightweight-2-5D-LUNA16 with ultralytics:
# Couldn't find a valid YOLO version tag. # Replace XX with the correct version. from ultralytics import YOLOvXX model = YOLOvXX.from_pretrained("Lien-Feng/Lightweight-2-5D-LUNA16") source = 'http://images.cocodataset.org/val2017/000000039769.jpg' model.predict(source=source, save=True) - Notebooks
- Google Colab
- Kaggle
File size: 6,238 Bytes
c3f98a1 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | """Run the official 10-fold training matrix.
Every ``(configuration, fold)`` pair is trained with the same pinned schedule.
A run counts as complete only when it wrote ``summary.json`` - Ultralytics
emits ``weights/best.pt`` from the first epoch, so a checkpoint alone does not
mean the schedule finished. The matrix is therefore resumable across
invocations without silently keeping a half-trained fold.
Usage
-----
python scripts/03_train.py # everything still missing
python scripts/03_train.py --groups main # one group
python scripts/03_train.py --exp Exp4_2p5D_Strict --folds 0
python scripts/03_train.py --dry-run # just print the plan
"""
from __future__ import annotations
import argparse
import json
import sys
import time
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
from luna_rev import config as cfg
from luna_rev import splits
from luna_rev.train import is_complete
LOG_PATH = cfg.RESULTS_DIR / "training_log.jsonl"
#: Seconds to idle after each run so Windows can reap the dataloader workers
#: before the next run starts allocating.
COOLDOWN_S = 8
def run_in_subprocess(exp, fold, force: bool = False, epochs: int | None = None) -> dict:
"""Train one pair in a fresh interpreter and return its record.
Isolating each run guarantees that workers, pinned buffers and the CUDA
context are released before the next one begins; sharing one interpreter
across 120 runs exhausted page-locked host memory partway through.
"""
import subprocess
cmd = [sys.executable, "-m", "luna_rev._train_worker", exp.name, str(fold.index)]
if force:
cmd.append("--force")
if epochs:
cmd += ["--epochs", str(epochs)]
proc = subprocess.run(cmd, cwd=str(cfg.ROOT), capture_output=True, text=True,
encoding="utf-8", errors="replace")
time.sleep(COOLDOWN_S)
for line in reversed((proc.stdout or "").splitlines()):
if line.startswith("TRAIN_RECORD "):
return json.loads(line[len("TRAIN_RECORD "):])
tail = "\n".join((proc.stderr or "").strip().splitlines()[-12:])
print(f" subprocess exit {proc.returncode}\n{tail}", flush=True)
return {"exp": exp.name, "fold": fold.index, "status": "failed",
"returncode": proc.returncode, "stderr_tail": tail}
def build_plan(groups, exp_names, fold_filter) -> list[tuple]:
"""Expand the requested selection into ``(exp, fold)`` pairs."""
folds = {f.index: f for f in splits.get_folds("official")}
experiments = cfg.experiments_for_group(*groups) if groups else list(cfg.ALL_EXPERIMENTS)
if exp_names:
wanted = set(exp_names)
experiments = [e for e in experiments if e.name in wanted]
unknown = wanted - {e.name for e in experiments}
if unknown:
raise SystemExit(f"Unknown experiment(s): {sorted(unknown)}")
plan = []
for exp in experiments:
for k in cfg.folds_for(exp):
if fold_filter is not None and k not in fold_filter:
continue
plan.append((exp, folds[k]))
return plan
def main() -> int:
ap = argparse.ArgumentParser()
ap.add_argument("--groups", nargs="*", default=None,
help="main r_sweep w_sweep neg_ablation seeds yolo26")
ap.add_argument("--exp", nargs="*", default=None, help="explicit configuration names")
ap.add_argument("--folds", nargs="*", type=int, default=None)
ap.add_argument("--force", action="store_true", help="retrain even if weights exist")
ap.add_argument("--dry-run", action="store_true")
ap.add_argument("--epochs", type=int, default=None, help="override the schedule (benchmarking)")
args = ap.parse_args()
plan = build_plan(args.groups, args.exp, set(args.folds) if args.folds else None)
pending = [(e, f) for e, f in plan if args.force or not is_complete(e, f.index)]
print(f"planned runs : {len(plan)}")
print(f"already done : {len(plan) - len(pending)}")
print(f"to train : {len(pending)}")
if args.dry_run:
for e, f in pending:
print(f" {e.name:28s} fold{f.index} [{e.model}, r={e.r_sample}, "
f"w_min={e.w_min_px}, neg={e.negatives}, seed={e.seed}]")
return 0
if not pending:
return 0
t_start = time.time()
failures: list[tuple] = []
for i, (exp, fold) in enumerate(pending, 1):
t0 = time.time()
print(f"\n[{i}/{len(pending)}] {exp.name} fold{fold.index} "
f"(elapsed {(time.time() - t_start) / 3600:.2f} h)", flush=True)
rec = run_in_subprocess(exp, fold, force=args.force, epochs=args.epochs)
rec["wall_seconds"] = round(time.time() - t0, 1)
with LOG_PATH.open("a", encoding="utf-8") as fh:
fh.write(json.dumps(rec) + "\n")
if rec["status"] == "failed":
failures.append((exp, fold))
print(f" -> FAILED after {rec['wall_seconds'] / 60:.1f} min "
f"(continuing; will retry at the end)", flush=True)
continue
rate = (time.time() - t_start) / i
print(f" -> {rec['status']} in {rec['wall_seconds'] / 60:.1f} min "
f"| ETA {(len(pending) - i) * rate / 3600:.1f} h", flush=True)
# One retry pass: the failures we have seen are transient resource
# exhaustion, which a fresh process after an idle gap usually clears.
if failures:
print(f"\nRetrying {len(failures)} failed run(s) ...", flush=True)
still_failing = []
for exp, fold in failures:
time.sleep(30)
rec = run_in_subprocess(exp, fold, force=True, epochs=args.epochs)
with LOG_PATH.open("a", encoding="utf-8") as fh:
fh.write(json.dumps({**rec, "retry": True}) + "\n")
if rec["status"] == "failed":
still_failing.append(f"{exp.name} fold{fold.index}")
if still_failing:
print("PERMANENT FAILURES: " + ", ".join(still_failing), flush=True)
return 1
print(f"\nAll done in {(time.time() - t_start) / 3600:.2f} h")
return 0
if __name__ == "__main__":
raise SystemExit(main())
|