Chris Leo commited on
Commit
190efc0
·
verified ·
1 Parent(s): cb80d51

scorevision: push artifact

Browse files
Files changed (1) hide show
  1. training/export_onnx.py +65 -0
training/export_onnx.py ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Export a trained YOLOv11 .pt to ONNX with NMS baked in -> output shape [1, max_det, 6].
3
+
4
+ The default chute miner.py decode path expects [1, N, 6] (NMS-baked). The king's own
5
+ weights.onnx is raw-YOLO [1, 10, 8400] without NMS — our exported model does NOT match
6
+ that, but our miner.py handles both formats. NMS-baked is preferred because:
7
+ - chute startup is faster (less graph work),
8
+ - the decode path is simpler (no fallback to raw YOLO numpy NMS),
9
+ - p95 latency is more stable (no Python-NMS spike on busy frames).
10
+
11
+ Usage:
12
+ python export_onnx.py --weights runs/detect/crime_b/weights/best.pt --imgsz 1280 \
13
+ --out ../weights.onnx
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ import argparse
19
+ import shutil
20
+ from pathlib import Path
21
+
22
+ from ultralytics import YOLO
23
+
24
+
25
+ def main() -> int:
26
+ ap = argparse.ArgumentParser()
27
+ ap.add_argument("--weights", required=True)
28
+ ap.add_argument("--imgsz", type=int, default=1280)
29
+ ap.add_argument("--out", default=None,
30
+ help="destination path for weights.onnx (defaults next to source .pt)")
31
+ ap.add_argument("--max-det", type=int, default=300)
32
+ ap.add_argument("--opset", type=int, default=17)
33
+ ap.add_argument("--half", action="store_true",
34
+ help="export FP16 (smaller, faster on CUDA, marginal accuracy delta)")
35
+ args = ap.parse_args()
36
+
37
+ weights = Path(args.weights).resolve()
38
+ model = YOLO(str(weights))
39
+
40
+ onnx_path = model.export(
41
+ format="onnx",
42
+ imgsz=args.imgsz,
43
+ nms=True,
44
+ max_det=args.max_det,
45
+ opset=args.opset,
46
+ dynamic=False,
47
+ half=args.half,
48
+ simplify=True,
49
+ agnostic_nms=False, # class-aware NMS (must match miner.py expectations)
50
+ device="cpu",
51
+ )
52
+
53
+ src = Path(onnx_path)
54
+ if args.out:
55
+ dst = Path(args.out).resolve()
56
+ dst.parent.mkdir(parents=True, exist_ok=True)
57
+ shutil.move(str(src), str(dst))
58
+ print(f"[export] {src} -> {dst}")
59
+ else:
60
+ print(f"[export] {src}")
61
+ return 0
62
+
63
+
64
+ if __name__ == "__main__":
65
+ raise SystemExit(main())