apocaliss92 commited on
Commit
90c9878
·
verified ·
1 Parent(s): c1e01ae

docs: notices, licences and source/ after the plate detector swap (D718)

Browse files

Licence files, notices, model cards and the source/ folder (AGPL Corresponding Source scripts) from the CamStack repository. Only files that differ from the Hub are included. No weight file is touched.

LICENSES/AGPL-3.0.txt CHANGED
@@ -1,6 +1,6 @@
1
  Source: https://www.gnu.org/licenses/agpl-3.0.txt
2
  Fetched: 2026-09-26 (verbatim below the line; nothing edited)
3
- Applies to: Ultralytics weights: objectDetection/yolo26, objectDetection/yolov9, segmentation/yolo26-seg, plateDetection/yolov8-plate
4
  Note: byte-identical to https://raw.githubusercontent.com/ultralytics/ultralytics/main/LICENSE, fetched the same day.
5
  --------------------------------------------------------------------------------
6
  GNU AFFERO GENERAL PUBLIC LICENSE
 
1
  Source: https://www.gnu.org/licenses/agpl-3.0.txt
2
  Fetched: 2026-09-26 (verbatim below the line; nothing edited)
3
+ Applies to: Ultralytics weights: objectDetection/yolo26, objectDetection/yolov9, segmentation/yolo26-seg
4
  Note: byte-identical to https://raw.githubusercontent.com/ultralytics/ultralytics/main/LICENSE, fetched the same day.
5
  --------------------------------------------------------------------------------
6
  GNU AFFERO GENERAL PUBLIC LICENSE
LICENSES/Apache-2.0.txt CHANGED
@@ -1,7 +1,7 @@
1
  Source: https://www.apache.org/licenses/LICENSE-2.0.txt
2
  Fetched: 2026-09-26 (verbatim below the line; nothing edited)
3
- Applies to: RF-DETR (Roboflow), AuraFace v1 (fal.ai), U-2-Net (Xuebin Qin et al.), YAMNet (tensorflow/models), AIY Vision Birds V1 and the Coral Edge TPU models (google-coral/test_data), timm EfficientNet-Lite0, Qwen2.5 / Qwen3-VL / Qwen3.6
4
- Note: none of those upstream repositories carries a NOTICE file (checked 2026-09-26 via the GitHub contents API and the HF file list), so Apache-2.0 section 4(d) adds nothing to reproduce.
5
  --------------------------------------------------------------------------------
6
 
7
  Apache License
 
1
  Source: https://www.apache.org/licenses/LICENSE-2.0.txt
2
  Fetched: 2026-09-26 (verbatim below the line; nothing edited)
3
+ Applies to: RF-DETR (Roboflow), AuraFace v1 (fal.ai), U-2-Net (Xuebin Qin et al.), YAMNet (tensorflow/models), AIY Vision Birds V1 and the Coral Edge TPU models (google-coral/test_data), timm EfficientNet-Lite0, Qwen2.5 / Qwen3-VL / Qwen3.6, open-lpr YOLOX-tiny plate detector (faisalthaheem/open-lpr-models, added 2026-10-06)
4
+ Note: none of those upstream repositories carries a NOTICE file (checked 2026-09-26 via the GitHub contents API and the HF file list), so Apache-2.0 section 4(d) adds nothing to reproduce, except open-lpr models, whose NOTICE is reproduced in NOTICE-open-lpr.txt. Its LICENSE is this text (checked 2026-10-06).
5
  --------------------------------------------------------------------------------
6
 
7
  Apache License
LICENSES/NOTICE-open-lpr.txt ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Source: https://huggingface.co/faisalthaheem/open-lpr-models/resolve/aed0df35ec2891c5a90437041ebeadb592cc516b/NOTICE
2
+ Fetched: 2026-10-06 (verbatim below the line; nothing edited)
3
+ Applies to: plateDetection/yolox-tiny-plate (open-lpr YOLOX-tiny plate detector, Apache-2.0; licence text: Apache-2.0.txt). Apache-2.0 section 4(d) requires this NOTICE to accompany redistribution.
4
+ --------------------------------------------------------------------------------
5
+ open-lpr models
6
+ Copyright the open-lpr contributors
7
+
8
+ This product includes software developed by third parties. The artifacts in
9
+ this repository are NOT all ours; per-artifact provenance is recorded in
10
+ manifest.json and summarised below.
11
+
12
+ --------------------------------------------------------------------------------
13
+ plate_yolox_tiny_640.onnx and best_ckpt.pth
14
+ --------------------------------------------------------------------------------
15
+ Produced by this project. Architecture from YOLOX (Megvii-BaseDetection/YOLOX),
16
+ which is licensed Apache-2.0 for both its code and its same-repository release
17
+ weights. Pretrained from COCO (yolox_tiny.pth), then fine-tuned on an annotated
18
+ licence-plate corpus plus community-contributed images pseudo-labelled by a
19
+ teacher model.
20
+
21
+ The training imagery is not published. It consists of user-contributed
22
+ photographs containing real licence plates, faces and vehicles, uploaded without
23
+ consent obtained. Publishing it would create a searchable index of real vehicle
24
+ registration numbers.
25
+
26
+ Ultralytics YOLO weights are licensed AGPL-3.0 and are deliberately NOT used,
27
+ redistributed, or derived from anywhere in this project.
28
+
29
+ --------------------------------------------------------------------------------
30
+ plate_ocr_ppocrv5_mobile.onnx and plate_ocr_dict.json
31
+ --------------------------------------------------------------------------------
32
+ NOT produced by this project. These are conversions of an upstream recognition
33
+ model from PaddleOCR (https://github.com/PaddlePaddle/PaddleOCR), which is
34
+ licensed under Apache-2.0.
35
+
36
+ The specific upstream release was never recorded and cannot be recovered from
37
+ the artifacts: the ONNX graph carries no producer, producer_version or
38
+ doc_string, and no PaddlePaddle installation, wheel or shell history survives on
39
+ the build host. The Apache-2.0 licence is therefore asserted at project level
40
+ and is NOT pinned to a verified release.
41
+
42
+ These two files are a MATCHED PAIR and must be used together. Decoding assumes
43
+ len(dictionary) + 2 output classes; substituting either without the other
44
+ produces silently incorrect text rather than an error.
README.md CHANGED
@@ -18,7 +18,7 @@ library_name: onnx
18
 
19
  This repository is a **mirror of third-party models** converted by
20
  [CamStack](https://camstack-docs.zentik.app) into the formats its inference
21
- engines run (ONNX, OpenVINO IR, CoreML, TFLite). **Nothing here is relicensed.**
22
  Each folder stays under the licence of the model it was made from, stated in the
23
  folder's `README.md` and in the table below, with the full text in
24
  [`LICENSES/`](LICENSES). The repository as a whole has no single licence; see
@@ -35,9 +35,8 @@ fetched from other repositories, with the attributions each licence requires.
35
 
36
  ## AGPL-3.0 models (Ultralytics)
37
 
38
- `objectDetection/yolo26`, `objectDetection/yolov9`, `segmentation/yolo26-seg`,
39
- and `plateDetection/yolov8-plate` hold
40
- Ultralytics weights under **AGPL-3.0** ([`LICENSES/AGPL-3.0.txt`](LICENSES/AGPL-3.0.txt)).
41
  Their Corresponding Source is set out in
42
  [Source offer for the AGPL-3.0 weights](THIRD_PARTY_MODELS.md#source-offer-for-the-agpl-30-weights).
43
 
@@ -50,8 +49,12 @@ This **may not be used commercially**. See the folder's card.
50
 
51
  ## Required attributions
52
 
53
- - **Ultralytics YOLO26, YOLOv9, YOLOv8**: © Ultralytics, AGPL-3.0. YOLOv9
54
  architecture: Chien-Yao Wang, I-Hau Yeh, Hong-Yuan Mark Liao, GPL-3.0.
 
 
 
 
55
  - **fast-plate-ocr**: Copyright (c) 2024 ankandrew, MIT.
56
  - **Open Images V7** (animal-classifier training data): annotations © Google
57
  LLC, CC BY 4.0.
@@ -77,7 +80,7 @@ marks an entry kept resolvable for a saved selection but no longer offered.
77
  | `packageDetection/rfdetr-package` | `rfdetr-package` (default) | Roboflow RF-DETR | Apache-2.0 | [`Apache-2.0.txt`](LICENSES/Apache-2.0.txt) | RF-DETR-M fine-tuned to 2 classes at 576; exported to ONNX, OpenVINO IR and CoreML; training checkpoint .pth also published |
78
  | `faceDetection/yunet` | `yunet-2023mar` (default) | OpenCV Zoo YuNet | MIT | [`MIT-yunet-reference.txt`](LICENSES/MIT-yunet-reference.txt), [`BSD-3-Clause.txt`](LICENSES/BSD-3-Clause.txt) | input contract baked into the graph (the pool RGB /255 becomes the upstream BGR 0..255: Mul(255) plus a channel Gather); internal tensor names cleared in the OpenVINO IR; ONNX fp32, OpenVINO IR fp32, CoreML fp16 (scripts/build-yunet-model.py) |
79
  | `faceRecognition/auraface` | `auraface-r100` (default) | fal.ai AuraFace v1 (glintr100.onnx only) | Apache-2.0 | [`Apache-2.0.txt`](LICENSES/Apache-2.0.txt) | input scaling y = 2x - 1 baked ahead of the first Conv (scripts/build-auraface-model.py); converted to OpenVINO IR and CoreML FP16 |
80
- | `plateDetection/yolov8-plate` | `yolov8n-plate` (default) | ml-debi/yolov8-license-plate-detection (ONNX, OpenVINO) and Koushim/yolov8-license-plate-detection (CoreML), YOLOv8n fine-tunes | AGPL-3.0 | [`AGPL-3.0.txt`](LICENSES/AGPL-3.0.txt) | ONNX redistributed unmodified; converted to OpenVINO IR from the ONNX, and exported to CoreML and TFLite from the checkpoint (scripts/build-camstack-models.py) |
81
  | `plateRecognition/cct-s-v2-global` | `cct-s-v2-global` (default) | ankandrew/fast-plate-ocr | MIT | [`MIT-fast-plate-ocr.txt`](LICENSES/MIT-fast-plate-ocr.txt) | input head removed (recorded in the ONNX doc_string); converted to OpenVINO IR and CoreML |
82
  | `animalClassification/animal-classifier` | `animal-classifier` (default) | timm EfficientNet-Lite0, fine-tuned by CamStack | Apache-2.0 | [`Apache-2.0.txt`](LICENSES/Apache-2.0.txt) | fine-tuned by CamStack on the Open Images V7 animal subset (8 classes); exported to ONNX, OpenVINO IR and CoreML |
83
  | `animalClassification/bird-classifier` | `bird-classifier` (default) | Google AIY Vision birds_V1 | Apache-2.0 | [`Apache-2.0.txt`](LICENSES/Apache-2.0.txt) | converted from TensorFlow with tf2onnx; OpenVINO IR and CoreML derived from it |
@@ -90,6 +93,6 @@ marks an entry kept resolvable for a saved selection but no longer offered.
90
 
91
  This mirror holds only the models CamStack offers. Models it no longer offers
92
  (SCRFD, ArcFace, Inception-ResNet, VGG-English, MobileCLIP S1/S2,
93
- YOLOv8n-package, SSDLite MobileDet, and earlier a third-party face, PaddleOCR,
94
  animals-10, NABirds and EfficientNet folders) were removed, and the repository
95
  history was squashed on 2026-10-06.
 
18
 
19
  This repository is a **mirror of third-party models** converted by
20
  [CamStack](https://camstack-docs.zentik.app) into the formats its inference
21
+ engines run (ONNX, OpenVINO IR, CoreML). **Nothing here is relicensed.**
22
  Each folder stays under the licence of the model it was made from, stated in the
23
  folder's `README.md` and in the table below, with the full text in
24
  [`LICENSES/`](LICENSES). The repository as a whole has no single licence; see
 
35
 
36
  ## AGPL-3.0 models (Ultralytics)
37
 
38
+ `objectDetection/yolo26`, `objectDetection/yolov9` and `segmentation/yolo26-seg`
39
+ hold Ultralytics weights under **AGPL-3.0** ([`LICENSES/AGPL-3.0.txt`](LICENSES/AGPL-3.0.txt)).
 
40
  Their Corresponding Source is set out in
41
  [Source offer for the AGPL-3.0 weights](THIRD_PARTY_MODELS.md#source-offer-for-the-agpl-30-weights).
42
 
 
49
 
50
  ## Required attributions
51
 
52
+ - **Ultralytics YOLO26, YOLOv9**: © Ultralytics, AGPL-3.0. YOLOv9
53
  architecture: Chien-Yao Wang, I-Hau Yeh, Hong-Yuan Mark Liao, GPL-3.0.
54
+ - **open-lpr models** (plate detector): Copyright the open-lpr contributors,
55
+ Apache-2.0; YOLOX architecture and COCO pretraining by Megvii, Apache-2.0.
56
+ The upstream `NOTICE` is in the folder and in
57
+ [`LICENSES/NOTICE-open-lpr.txt`](LICENSES/NOTICE-open-lpr.txt).
58
  - **fast-plate-ocr**: Copyright (c) 2024 ankandrew, MIT.
59
  - **Open Images V7** (animal-classifier training data): annotations © Google
60
  LLC, CC BY 4.0.
 
80
  | `packageDetection/rfdetr-package` | `rfdetr-package` (default) | Roboflow RF-DETR | Apache-2.0 | [`Apache-2.0.txt`](LICENSES/Apache-2.0.txt) | RF-DETR-M fine-tuned to 2 classes at 576; exported to ONNX, OpenVINO IR and CoreML; training checkpoint .pth also published |
81
  | `faceDetection/yunet` | `yunet-2023mar` (default) | OpenCV Zoo YuNet | MIT | [`MIT-yunet-reference.txt`](LICENSES/MIT-yunet-reference.txt), [`BSD-3-Clause.txt`](LICENSES/BSD-3-Clause.txt) | input contract baked into the graph (the pool RGB /255 becomes the upstream BGR 0..255: Mul(255) plus a channel Gather); internal tensor names cleared in the OpenVINO IR; ONNX fp32, OpenVINO IR fp32, CoreML fp16 (scripts/build-yunet-model.py) |
82
  | `faceRecognition/auraface` | `auraface-r100` (default) | fal.ai AuraFace v1 (glintr100.onnx only) | Apache-2.0 | [`Apache-2.0.txt`](LICENSES/Apache-2.0.txt) | input scaling y = 2x - 1 baked ahead of the first Conv (scripts/build-auraface-model.py); converted to OpenVINO IR and CoreML FP16 |
83
+ | `plateDetection/yolox-tiny-plate` | `yolox-tiny-plate` (default) | open-lpr models (faisalthaheem/open-lpr-models), YOLOX-tiny | Apache-2.0 | [`Apache-2.0.txt`](LICENSES/Apache-2.0.txt) | input contract baked into the graph (static 1x3x640x640 RGB /255 becomes the upstream BGR 0..255: Mul(255) plus a channel Gather) and the output reshaped to the YOLOv8 layout (cx, cy, w, h, obj*cls); ONNX fp32, OpenVINO IR fp16, CoreML fp16 (scripts/build-yolox-plate-model.py) |
84
  | `plateRecognition/cct-s-v2-global` | `cct-s-v2-global` (default) | ankandrew/fast-plate-ocr | MIT | [`MIT-fast-plate-ocr.txt`](LICENSES/MIT-fast-plate-ocr.txt) | input head removed (recorded in the ONNX doc_string); converted to OpenVINO IR and CoreML |
85
  | `animalClassification/animal-classifier` | `animal-classifier` (default) | timm EfficientNet-Lite0, fine-tuned by CamStack | Apache-2.0 | [`Apache-2.0.txt`](LICENSES/Apache-2.0.txt) | fine-tuned by CamStack on the Open Images V7 animal subset (8 classes); exported to ONNX, OpenVINO IR and CoreML |
86
  | `animalClassification/bird-classifier` | `bird-classifier` (default) | Google AIY Vision birds_V1 | Apache-2.0 | [`Apache-2.0.txt`](LICENSES/Apache-2.0.txt) | converted from TensorFlow with tf2onnx; OpenVINO IR and CoreML derived from it |
 
93
 
94
  This mirror holds only the models CamStack offers. Models it no longer offers
95
  (SCRFD, ArcFace, Inception-ResNet, VGG-English, MobileCLIP S1/S2,
96
+ YOLOv8n-package, SSDLite MobileDet, the YOLOv8n plate detector, and earlier a third-party face, PaddleOCR,
97
  animals-10, NABirds and EfficientNet folders) were removed, and the repository
98
  history was squashed on 2026-10-06.
THIRD_PARTY_MODELS.md CHANGED
@@ -36,7 +36,7 @@ under [Non-commercial models](#non-commercial-models).
36
  - RF-DETR © Roboflow, Apache-2.0. https://github.com/roboflow/rf-detr
37
  - YuNet weights Copyright (c) 2020 Shiqi Yu, MIT. Training code: ShiqiYu/libfacedetection.train, BSD-3-Clause. https://github.com/opencv/opencv_zoo/tree/main/models/face_detection_yunet
38
  - AuraFace v1 by fal.ai, Apache-2.0. https://huggingface.co/fal/AuraFace-v1
39
- - © Ultralytics, AGPL-3.0 (YOLOv8n base). Fine-tuned for licence plates by third parties: the ONNX file is best.onnx of https://huggingface.co/ml-debi/yolov8-license-plate-detection, redistributed unmodified (its author published no checkpoint); the CoreML and TFLite files are exported from best.pt of https://huggingface.co/Koushim/yolov8-license-plate-detection. Both cards say MIT; the Ultralytics base keeps them AGPL-3.0. Corresponding source: build-camstack-models.py at https://huggingface.co/camstack/camstack-models/tree/main/source. https://huggingface.co/ml-debi/yolov8-license-plate-detection
40
  - fast-plate-ocr, MIT License, copyright (c) 2024 ankandrew (full notice: licenses/models/MIT-fast-plate-ocr.txt). https://github.com/ankandrew/fast-plate-ocr
41
  - EfficientNet-Lite0 via timm (Ross Wightman), Apache-2.0. Open Images V7 annotations © Google LLC, CC BY 4.0; images listed by Google as CC BY 2.0, without warranty. https://github.com/huggingface/pytorch-image-models
42
  - torchvision MobileNetV3, BSD-3-Clause. Trained on the Vehicle classification dataset by DrBimmer (https://huggingface.co/datasets/DrBimmer/vehicle-classification), CC BY-NC 4.0. https://github.com/pytorch/vision
@@ -62,7 +62,7 @@ Training data under attribution terms:
62
  cards link here instead of repeating it.
63
  -->
64
 
65
- The folders `objectDetection/yolo26`, `objectDetection/yolov9`, `plateDetection/yolov8-plate` and `segmentation/yolo26-seg` of the model mirror hold Ultralytics weights,
66
  modified by CamStack and distributed under AGPL-3.0. Their Corresponding Source
67
  is published in the mirror itself, in its **`source/`** folder,
68
  **https://huggingface.co/camstack/camstack-models/tree/main/source**, together
@@ -70,15 +70,7 @@ with the upstream checkpoints it starts from:
70
 
71
  1. **The upstream checkpoints.** Ultralytics publishes
72
  `yolo26{n,s,m,l,x}.pt`, `yolov9{t,s,m,c}.pt` and `yolo26{n,s,m}-seg.pt` at
73
- https://github.com/ultralytics/assets/releases. `yolov8n-plate` is two
74
- third-party YOLOv8n licence-plate fine-tunes, neither trained by CamStack:
75
- its ONNX file is `best.onnx` of
76
- https://huggingface.co/ml-debi/yolov8-license-plate-detection (SHA-256
77
- `85d23628…15bd50`, hosted unmodified), and its CoreML and TFLite files are
78
- exported from `best.pt` of
79
- https://huggingface.co/Koushim/yolov8-license-plate-detection. Both cards
80
- say MIT; the Ultralytics base weights keep both AGPL-3.0, as their own
81
- metadata states.
82
  2. **The build script** in `source/`: `build-camstack-models.py`, with
83
  `convert_lib.py` (the ONNX to OpenVINO / INT8 converter it calls, the same
84
  file CamStack's Model Studio runs) and `requirements.txt`. It holds one
@@ -106,11 +98,6 @@ Limits of a rebuild:
106
  - **INT8 calibration.** An IR records how many images calibrated it, not
107
  which ones. Calibrating on the same COCO images gives the documented build;
108
  a different set gives an equivalent, not bit-identical, INT8 model.
109
- - **`yolov8n-plate` ONNX has no checkpoint.** Its author published only the
110
- ONNX file, so that file is the preferred form of the work that exists, and
111
- CamStack redistributes it unmodified. CamStack's modification is the
112
- OpenVINO conversion of it, which the script reproduces. The training data of
113
- both plate fine-tunes is not published.
114
 
115
  ## Non-commercial models
116
 
@@ -159,7 +146,7 @@ entry kept resolvable for a saved selection but no longer offered.
159
 
160
  | Catalog ids | Upstream | Code / weights | Training data | CamStack changes | Downloaded from |
161
  | --- | --- | --- | --- | --- | --- |
162
- | `yolov8n-plate` (default) | [ml-debi/yolov8-license-plate-detection (ONNX, OpenVINO) and Koushim/yolov8-license-plate-detection (CoreML), YOLOv8n fine-tunes](https://huggingface.co/ml-debi/yolov8-license-plate-detection) | AGPL-3.0 / AGPL-3.0 (`AGPL-3.0.txt`) | undisclosed licence-plate datasets of the two third-party fine-tunes (ml-debi, trained 2023-12-05; Koushim, trained 2025-05-25): UNKNOWN | ONNX redistributed unmodified; converted to OpenVINO IR from the ONNX, and exported to CoreML and TFLite from the checkpoint (scripts/build-camstack-models.py) | mirror `plateDetection/yolov8-plate` |
163
 
164
  ### Licence plate reading
165
 
 
36
  - RF-DETR © Roboflow, Apache-2.0. https://github.com/roboflow/rf-detr
37
  - YuNet weights Copyright (c) 2020 Shiqi Yu, MIT. Training code: ShiqiYu/libfacedetection.train, BSD-3-Clause. https://github.com/opencv/opencv_zoo/tree/main/models/face_detection_yunet
38
  - AuraFace v1 by fal.ai, Apache-2.0. https://huggingface.co/fal/AuraFace-v1
39
+ - open-lpr models, Copyright the open-lpr contributors, Apache-2.0 (https://huggingface.co/faisalthaheem/open-lpr-models, tag detector-2026.10.1). YOLOX architecture and COCO pretraining by Megvii (https://github.com/Megvii-BaseDetection/YOLOX), Apache-2.0. The upstream NOTICE is reproduced verbatim (`NOTICE-open-lpr.txt`). https://huggingface.co/faisalthaheem/open-lpr-models
40
  - fast-plate-ocr, MIT License, copyright (c) 2024 ankandrew (full notice: licenses/models/MIT-fast-plate-ocr.txt). https://github.com/ankandrew/fast-plate-ocr
41
  - EfficientNet-Lite0 via timm (Ross Wightman), Apache-2.0. Open Images V7 annotations © Google LLC, CC BY 4.0; images listed by Google as CC BY 2.0, without warranty. https://github.com/huggingface/pytorch-image-models
42
  - torchvision MobileNetV3, BSD-3-Clause. Trained on the Vehicle classification dataset by DrBimmer (https://huggingface.co/datasets/DrBimmer/vehicle-classification), CC BY-NC 4.0. https://github.com/pytorch/vision
 
62
  cards link here instead of repeating it.
63
  -->
64
 
65
+ The folders `objectDetection/yolo26`, `objectDetection/yolov9` and `segmentation/yolo26-seg` of the model mirror hold Ultralytics weights,
66
  modified by CamStack and distributed under AGPL-3.0. Their Corresponding Source
67
  is published in the mirror itself, in its **`source/`** folder,
68
  **https://huggingface.co/camstack/camstack-models/tree/main/source**, together
 
70
 
71
  1. **The upstream checkpoints.** Ultralytics publishes
72
  `yolo26{n,s,m,l,x}.pt`, `yolov9{t,s,m,c}.pt` and `yolo26{n,s,m}-seg.pt` at
73
+ https://github.com/ultralytics/assets/releases.
 
 
 
 
 
 
 
 
74
  2. **The build script** in `source/`: `build-camstack-models.py`, with
75
  `convert_lib.py` (the ONNX to OpenVINO / INT8 converter it calls, the same
76
  file CamStack's Model Studio runs) and `requirements.txt`. It holds one
 
98
  - **INT8 calibration.** An IR records how many images calibrated it, not
99
  which ones. Calibrating on the same COCO images gives the documented build;
100
  a different set gives an equivalent, not bit-identical, INT8 model.
 
 
 
 
 
101
 
102
  ## Non-commercial models
103
 
 
146
 
147
  | Catalog ids | Upstream | Code / weights | Training data | CamStack changes | Downloaded from |
148
  | --- | --- | --- | --- | --- | --- |
149
+ | `yolox-tiny-plate` (default) | [open-lpr models (faisalthaheem/open-lpr-models), YOLOX-tiny](https://huggingface.co/faisalthaheem/open-lpr-models) | Apache-2.0 / Apache-2.0 (`Apache-2.0.txt`) | Simanno annotated plate corpus plus community-contributed photographs, pseudo-labelled by a teacher model (not published; the upstream NOTICE says the photographs were uploaded without consent obtained): UNKNOWN | input contract baked into the graph (static 1x3x640x640 RGB /255 becomes the upstream BGR 0..255: Mul(255) plus a channel Gather) and the output reshaped to the YOLOv8 layout (cx, cy, w, h, obj*cls); ONNX fp32, OpenVINO IR fp16, CoreML fp16 (scripts/build-yolox-plate-model.py) | mirror `plateDetection/yolox-tiny-plate` |
150
 
151
  ### Licence plate reading
152
 
source/README.md CHANGED
@@ -4,13 +4,13 @@
4
 
5
  This folder is the **Corresponding Source** under the GNU AGPL-3.0 for the
6
  Ultralytics-derived weights in this mirror (`objectDetection/yolo26`,
7
- `objectDetection/yolov9`, `segmentation/yolo26-seg`, `plateDetection/yolov8-plate`).
8
  The full source offer is in
9
  [`THIRD_PARTY_MODELS.md`](../THIRD_PARTY_MODELS.md#source-offer-for-the-agpl-30-weights).
10
 
11
  | File | What it is |
12
  | --- | --- |
13
- | `build-camstack-models.py` | Rebuilds every file in the four folders above. One recipe per hosted file stem: upstream checkpoint, input size, the Ultralytics `export()` arguments, the OpenVINO precisions and the INT8 calibration count. Each value is what the hosted file records about itself in its metadata. |
14
  | `convert_lib.py` | The converter `build-camstack-models.py` calls for OpenVINO: ONNX to IR (`ov.convert_model`, FP32 or FP16-compressed), NNCF INT8 post-training quantisation, and validation of every IR. It is the same file CamStack's Model Studio runs. |
15
  | `requirements.txt` | Python dependencies of `convert_lib.py`, with per-platform markers. |
16
  | `export-models.py` | An older bulk exporter for YOLOv8 / YOLOv9 / YOLO11 ids. No file in this mirror needs it. |
@@ -32,8 +32,7 @@ python build-camstack-models.py --all --formats onnx,openvino # some formats
32
  Results go to `./exported-models/<mirror path>`, for example
33
  `exported-models/objectDetection/yolo26/openvino/camstack-yolo26n-320-int8.xml`.
34
  Each build step runs in its own Python process: on macOS, CoreML, OpenVINO and
35
- TensorFlow crash one another when they share one. CoreML needs macOS. TFLite
36
- needs `tensorflow` and `onnx2tf`.
37
 
38
  What the recipes encode (the hosted files record each of these):
39
 
@@ -43,13 +42,11 @@ What the recipes encode (the hosted files record each of these):
43
  | `objectDetection/yolo26` | `camstack-yolo26{n,s,m,l}-{320,256}` | dynamic axes, opset 17 | flexible batch 1..16, FP16 | FP32 `<stem>.xml`; INT8 `<stem>-int8.xml` (128 images) |
44
  | `objectDetection/yolov9` | `camstack-yolov9{t,s,m,c}-{320,640}` | static, opset 13 | static, batch 1 | FP16 `<stem>-fp16.xml`; INT8 `<stem>-int8.xml` (300 images) |
45
  | `segmentation/yolo26-seg` | `camstack-yolo26{n,s,m}-seg` @640 | static, opset 17 | static, batch 1 | FP16 `<stem>.xml` |
46
- | `plateDetection/yolov8-plate` | `camstack-yolov8n-plate` @640 | third-party file, unmodified | static, batch 1 | FP16 `<stem>.xml` (from the ONNX); also TFLite float32 |
47
 
48
  Recorded tool versions (Ultralytics / PyTorch / coremltools / OpenVINO):
49
  YOLO26 @640 and YOLO26-seg 8.4.24 / 2.10.0 / 9.0 / 2026.2.1; YOLO26 @320 and
50
  @256 8.4.92 / 2.13.0 for ONNX, 2.5.1 for CoreML / 8.3.0 / 2026.2.1; YOLOv9
51
- 8.4.98 / 2.13.0 / 9.0 / 2026.2.1; plate CoreML 8.4.24 / 2.10.0 / 9.0, plate IR
52
- OpenVINO 2026.0.0. The script warns when the installed Ultralytics differs.
53
  With these versions a rebuild gives the hosted weights. Other versions give the
54
  same weights in a possibly different graph. The flexible-batch CoreML exports
55
  need coremltools 8.3 with PyTorch 2.5.1, the macOS pins in `requirements.txt`;
@@ -74,24 +71,6 @@ not record WHICH images calibrated it, so a different set gives an equivalent
74
  INT8 model, not a bit-identical one. Without calibration images the INT8 files
75
  are skipped and the run says so.
76
 
77
- ### `yolov8n-plate`
78
-
79
- Two third-party YOLOv8n licence-plate fine-tunes, neither trained by CamStack:
80
-
81
- - `onnx/camstack-yolov8n-plate.onnx` is `best.onnx` of
82
- [ml-debi/yolov8-license-plate-detection](https://huggingface.co/ml-debi/yolov8-license-plate-detection)
83
- (revision `8062e8e8`, SHA-256 `85d236280a1301ad98907947d284951dd2b20c23a6786ff50f7e6a8ec515bd50`),
84
- hosted unmodified. Its author published no checkpoint, so the ONNX is the
85
- only form of that model that exists. CamStack's modification is the OpenVINO
86
- conversion, which the script reproduces from it.
87
- - `coreml/` and `tflite/` are Ultralytics exports of `best.pt` of
88
- [Koushim/yolov8-license-plate-detection](https://huggingface.co/Koushim/yolov8-license-plate-detection)
89
- (revision `9aaa5cd4`, SHA-256 `2d95861825bb4184404344c9cf809f40fd31dba785fe54e8ba5b9a3583789822`).
90
- The script downloads and verifies both files.
91
-
92
- Both model cards say MIT. The Ultralytics YOLOv8n base weights keep both
93
- AGPL-3.0, as their own metadata states. Neither publishes its training data.
94
-
95
  ## Licences
96
 
97
  - **These scripts** (`build-camstack-models.py`, `convert_lib.py`,
 
4
 
5
  This folder is the **Corresponding Source** under the GNU AGPL-3.0 for the
6
  Ultralytics-derived weights in this mirror (`objectDetection/yolo26`,
7
+ `objectDetection/yolov9`, `segmentation/yolo26-seg`).
8
  The full source offer is in
9
  [`THIRD_PARTY_MODELS.md`](../THIRD_PARTY_MODELS.md#source-offer-for-the-agpl-30-weights).
10
 
11
  | File | What it is |
12
  | --- | --- |
13
+ | `build-camstack-models.py` | Rebuilds every file in the three folders above. One recipe per hosted file stem: upstream checkpoint, input size, the Ultralytics `export()` arguments, the OpenVINO precisions and the INT8 calibration count. Each value is what the hosted file records about itself in its metadata. |
14
  | `convert_lib.py` | The converter `build-camstack-models.py` calls for OpenVINO: ONNX to IR (`ov.convert_model`, FP32 or FP16-compressed), NNCF INT8 post-training quantisation, and validation of every IR. It is the same file CamStack's Model Studio runs. |
15
  | `requirements.txt` | Python dependencies of `convert_lib.py`, with per-platform markers. |
16
  | `export-models.py` | An older bulk exporter for YOLOv8 / YOLOv9 / YOLO11 ids. No file in this mirror needs it. |
 
32
  Results go to `./exported-models/<mirror path>`, for example
33
  `exported-models/objectDetection/yolo26/openvino/camstack-yolo26n-320-int8.xml`.
34
  Each build step runs in its own Python process: on macOS, CoreML, OpenVINO and
35
+ TensorFlow crash one another when they share one. CoreML needs macOS.
 
36
 
37
  What the recipes encode (the hosted files record each of these):
38
 
 
42
  | `objectDetection/yolo26` | `camstack-yolo26{n,s,m,l}-{320,256}` | dynamic axes, opset 17 | flexible batch 1..16, FP16 | FP32 `<stem>.xml`; INT8 `<stem>-int8.xml` (128 images) |
43
  | `objectDetection/yolov9` | `camstack-yolov9{t,s,m,c}-{320,640}` | static, opset 13 | static, batch 1 | FP16 `<stem>-fp16.xml`; INT8 `<stem>-int8.xml` (300 images) |
44
  | `segmentation/yolo26-seg` | `camstack-yolo26{n,s,m}-seg` @640 | static, opset 17 | static, batch 1 | FP16 `<stem>.xml` |
 
45
 
46
  Recorded tool versions (Ultralytics / PyTorch / coremltools / OpenVINO):
47
  YOLO26 @640 and YOLO26-seg 8.4.24 / 2.10.0 / 9.0 / 2026.2.1; YOLO26 @320 and
48
  @256 8.4.92 / 2.13.0 for ONNX, 2.5.1 for CoreML / 8.3.0 / 2026.2.1; YOLOv9
49
+ 8.4.98 / 2.13.0 / 9.0 / 2026.2.1. The script warns when the installed Ultralytics differs.
 
50
  With these versions a rebuild gives the hosted weights. Other versions give the
51
  same weights in a possibly different graph. The flexible-batch CoreML exports
52
  need coremltools 8.3 with PyTorch 2.5.1, the macOS pins in `requirements.txt`;
 
71
  INT8 model, not a bit-identical one. Without calibration images the INT8 files
72
  are skipped and the run says so.
73
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
  ## Licences
75
 
76
  - **These scripts** (`build-camstack-models.py`, `convert_lib.py`,
source/build-camstack-models.py CHANGED
@@ -8,7 +8,6 @@ https://huggingface.co/camstack/camstack-models in
8
  objectDetection/yolo26 yolo26{n,s,m,l,x} @640, yolo26{n,s,m,l} @320 and @256
9
  objectDetection/yolov9 yolov9{t,s,m,c} @320 and @640
10
  segmentation/yolo26-seg yolo26{n,s,m}-seg @640
11
- plateDetection/yolov8-plate yolov8n-plate (third-party fine-tune, see below)
12
 
13
  Every hosted file is one output of ONE recipe in `RECIPES` below, and the recipe
14
  holds exactly the settings that file records about itself: the Ultralytics
@@ -40,7 +39,6 @@ Formats:
40
  int8 convert_lib.quantize_openvino_int8: NNCF post-training quantisation
41
  of the ONNX, calibrated on the first N images (sorted by file name)
42
  of --calib-dir (default $CAMSTACK_CALIB_DIR or ./calibration-images)
43
- tflite Ultralytics export(format="tflite") (needs tensorflow + onnx2tf)
44
 
45
  INT8 calibration: the hosted INT8 IRs record subset_size 128 (YOLO26) and 300
46
  (YOLOv9), drawn from COCO; an IR does not record WHICH images. The documented
@@ -62,7 +60,6 @@ convert_lib's). convert_lib.py is found next to this script (the mirror's
62
  from __future__ import annotations
63
 
64
  import argparse
65
- import hashlib
66
  import json
67
  import os
68
  import shutil
@@ -86,15 +83,6 @@ DEFAULT_CALIB_DIR = Path(os.environ.get('CAMSTACK_CALIB_DIR', 'calibration-image
86
  # --- Recipe model ------------------------------------------------------------
87
 
88
 
89
- @dataclass(frozen=True)
90
- class Download:
91
- """A third-party file fetched by URL and verified by SHA-256."""
92
-
93
- url: str
94
- sha256: str
95
- filename: str
96
-
97
-
98
  @dataclass(frozen=True)
99
  class OnnxExport:
100
  """Ultralytics export(format="onnx") arguments, as the hosted ONNX records them."""
@@ -139,28 +127,24 @@ class Recipe:
139
  imgsz: int
140
  toolchain: Toolchain
141
  # The PyTorch checkpoint: an Ultralytics asset id (`yolo26n` -> yolo26n.pt,
142
- # auto-downloaded by Ultralytics) or a third-party Download.
143
- checkpoint: str | Download
144
- onnx: Optional[OnnxExport] # None: the ONNX is `onnx_verbatim`, not exported
145
  coreml: Optional[CoremlExport]
146
  openvino: tuple[OpenvinoOutput, ...] = ()
147
  calib_samples: int = 0
148
- tflite: bool = False
149
- onnx_verbatim: Optional[Download] = None # a third-party ONNX hosted unmodified
150
  note: str = ''
151
 
152
  def outputs(self) -> list[str]:
153
  """Mirror paths this recipe produces (an .mlpackage is a directory)."""
154
  out: list[str] = []
155
- if self.onnx is not None or self.onnx_verbatim is not None:
156
  out.append(f'{self.folder}/onnx/{self.name}.onnx')
157
  if self.coreml is not None:
158
  out.append(f'{self.folder}/coreml/{self.name}.mlpackage/')
159
  for ov in self.openvino:
160
  stem = f'{self.folder}/openvino/{self.name}{ov.suffix}'
161
  out.extend([f'{stem}.xml', f'{stem}.bin'])
162
- if self.tflite:
163
- out.append(f'{self.folder}/tflite/{self.name}_float32.tflite')
164
  return out
165
 
166
 
@@ -171,7 +155,6 @@ class Recipe:
171
  TC_2604 = Toolchain('8.4.24', '2.10.0', '9.0', '2026.2.1')
172
  TC_2607_REDUCED = Toolchain('8.4.92', 'onnx 2.13.0, coreml 2.5.1', '8.3.0', '2026.2.1')
173
  TC_2607_YOLOV9 = Toolchain('8.4.98', '2.13.0', '9.0', '2026.2.1')
174
- TC_PLATE = Toolchain('8.4.24 (CoreML, TFLite)', '2.10.0', '9.0', '2026.0.0')
175
 
176
  FP16_IR = OpenvinoOutput('', 'fp16')
177
 
@@ -226,53 +209,19 @@ def _yolo26_seg(tier: str) -> Recipe:
226
  )
227
 
228
 
229
- # yolov8n-plate is TWO third-party YOLOv8n licence-plate fine-tunes, neither
230
- # trained by CamStack (both declare MIT on their model cards; the Ultralytics
231
- # base weights make them AGPL-3.0, and their own metadata says so):
232
- # - the ONNX (and the OpenVINO IR converted from it) is ml-debi's `best.onnx`,
233
- # hosted byte-identical. Its author published no .pt; the ONNX is the only
234
- # form that exists. CamStack's modification is the IR conversion below.
235
- # - the CoreML package and the TFLite file are Ultralytics exports of
236
- # Koushim's `best.pt`, saved as `yolov8n-plate.pt` (the file stem is what
237
- # the export metadata calls the model). The .pt is public.
238
- _PLATE_ONNX = Download(
239
- url='https://huggingface.co/ml-debi/yolov8-license-plate-detection/resolve/'
240
- '8062e8e86734e272c60fa9a819433327ebdb66d7/best.onnx',
241
- sha256='85d236280a1301ad98907947d284951dd2b20c23a6786ff50f7e6a8ec515bd50',
242
- filename='camstack-yolov8n-plate.onnx',
243
- )
244
- _PLATE_PT = Download(
245
- url='https://huggingface.co/Koushim/yolov8-license-plate-detection/resolve/'
246
- '9aaa5cd490abe0c165882ba87f4f62658ab54d01/best.pt',
247
- sha256='2d95861825bb4184404344c9cf809f40fd31dba785fe54e8ba5b9a3583789822',
248
- filename='yolov8n-plate.pt',
249
- )
250
-
251
- PLATE = Recipe(
252
- name='camstack-yolov8n-plate', folder='plateDetection/yolov8-plate', imgsz=640,
253
- toolchain=TC_PLATE, checkpoint=_PLATE_PT,
254
- onnx=None, onnx_verbatim=_PLATE_ONNX,
255
- coreml=CoremlExport(dynamic=False, batch=1, half=False),
256
- openvino=(FP16_IR,), tflite=True,
257
- note='ONNX + IR: ml-debi/yolov8-license-plate-detection; CoreML + TFLite: '
258
- 'Koushim/yolov8-license-plate-detection (different fine-tunes)',
259
- )
260
-
261
  RECIPES: tuple[Recipe, ...] = (
262
  *(_yolo26_full(t) for t in 'nsmlx'),
263
  *(_yolo26_reduced(t, r) for t in 'nsml' for r in (320, 256)),
264
  *(_yolov9(t, r) for t in ('t', 's', 'm', 'c') for r in (320, 640)),
265
  *(_yolo26_seg(t) for t in 'nsm'),
266
- PLATE,
267
  )
268
 
269
  FAMILIES = {
270
  'yolo26': 'objectDetection/yolo26',
271
  'yolov9': 'objectDetection/yolov9',
272
  'yolo26-seg': 'segmentation/yolo26-seg',
273
- 'yolov8-plate': 'plateDetection/yolov8-plate',
274
  }
275
- ALL_FORMATS = ('onnx', 'coreml', 'openvino', 'tflite')
276
 
277
  # --- Helpers ----------------------------------------------------------------
278
 
@@ -283,27 +232,6 @@ def size_mb(path: Path) -> float:
283
  return sum(f.stat().st_size for f in path.rglob('*') if f.is_file()) / 1_048_576
284
 
285
 
286
- def sha256_of(path: Path) -> str:
287
- h = hashlib.sha256()
288
- with path.open('rb') as fh:
289
- for chunk in iter(lambda: fh.read(1 << 20), b''):
290
- h.update(chunk)
291
- return h.hexdigest()
292
-
293
-
294
- def fetch(dl: Download, cache: Path) -> Path:
295
- """Download a third-party file once and refuse it if the SHA-256 differs."""
296
- cache.mkdir(parents=True, exist_ok=True)
297
- dest = cache / dl.filename
298
- if not dest.is_file():
299
- print(f' → downloading {dl.url}')
300
- urllib.request.urlretrieve(dl.url, dest)
301
- got = sha256_of(dest)
302
- if got != dl.sha256:
303
- raise RuntimeError(f'{dest} has sha256 {got}, expected {dl.sha256}')
304
- return dest
305
-
306
-
307
  def warn_toolchain(recipe: Recipe) -> None:
308
  try:
309
  import ultralytics
@@ -324,9 +252,7 @@ def place(src: Path, dest: Path) -> Path:
324
  return dest
325
 
326
 
327
- def checkpoint_path(recipe: Recipe, cache: Path) -> str:
328
- if isinstance(recipe.checkpoint, Download):
329
- return str(fetch(recipe.checkpoint, cache))
330
  return f'{recipe.checkpoint}.pt' # Ultralytics downloads its own assets
331
 
332
 
@@ -408,27 +334,24 @@ def ultralytics_export(checkpoint: str, **kwargs: object) -> Path:
408
  # --- Format steps -------------------------------------------------------------
409
 
410
 
411
- def build_onnx(recipe: Recipe, out: Path, cache: Path) -> Path:
412
  dest = out / recipe.folder / 'onnx' / f'{recipe.name}.onnx'
413
- if recipe.onnx_verbatim is not None:
414
- print(' → ONNX: third-party file, hosted unmodified')
415
- return place(fetch(recipe.onnx_verbatim, cache), dest)
416
  assert recipe.onnx is not None
417
  print(f' → ONNX (imgsz={recipe.imgsz}, dynamic={recipe.onnx.dynamic}, opset={recipe.onnx.opset})')
418
  src = ultralytics_export(
419
- checkpoint_path(recipe, cache), format='onnx', imgsz=recipe.imgsz,
420
  dynamic=recipe.onnx.dynamic, simplify=True, opset=recipe.onnx.opset,
421
  nms=False, batch=1, half=False,
422
  )
423
  return place(src, dest)
424
 
425
 
426
- def build_coreml(recipe: Recipe, out: Path, cache: Path, verify: bool) -> Path:
427
  assert recipe.coreml is not None
428
  c = recipe.coreml
429
  print(f' → CoreML (imgsz={recipe.imgsz}, dynamic={c.dynamic}, batch={c.batch}, half={c.half})')
430
  src = ultralytics_export(
431
- checkpoint_path(recipe, cache), format='coreml', imgsz=recipe.imgsz,
432
  dynamic=c.dynamic, batch=c.batch, half=c.half, nms=False,
433
  )
434
  dest = place(src, out / recipe.folder / 'coreml' / f'{recipe.name}.mlpackage')
@@ -459,16 +382,6 @@ def build_openvino(recipe: Recipe, onnx_path: Path, out: Path, calib_dir: Path,
459
  return skipped
460
 
461
 
462
- def build_tflite(recipe: Recipe, out: Path, cache: Path) -> Path:
463
- print(f' → TFLite float32 (imgsz={recipe.imgsz})')
464
- saved = ultralytics_export(checkpoint_path(recipe, cache), format='tflite', imgsz=recipe.imgsz)
465
- stem = Path(checkpoint_path(recipe, cache)).stem
466
- src = next(saved.rglob(f'{stem}_float32.tflite'), None) if saved.is_dir() else saved
467
- if src is None:
468
- raise RuntimeError(f'no {stem}_float32.tflite under {saved}')
469
- return place(src, out / recipe.folder / 'tflite' / f'{recipe.name}_float32.tflite')
470
-
471
-
472
  def verify_coreml_batch(mlpackage: Path, imgsz: int) -> None:
473
  """Predict with N=1 then N=4 on a flexible-batch package, in a throwaway child.
474
 
@@ -503,29 +416,27 @@ def run_step(report: Report, label: str, step: Callable[[], object]) -> object:
503
  return None
504
 
505
 
506
- def build(recipe: Recipe, formats: set[str], out: Path, cache: Path, calib_dir: Path,
507
  calib_samples: Optional[int], verify_coreml: bool, report: Report) -> None:
508
  print('\n' + '=' * 70 + f'\n{recipe.name} ({recipe.folder}, {recipe.imgsz}×{recipe.imgsz})\n' + '=' * 70)
509
  if recipe.note:
510
  print(f' {recipe.note}')
511
  warn_toolchain(recipe)
512
  onnx_path: Optional[Path] = None
513
- if formats & {'onnx', 'openvino'} and (recipe.onnx or recipe.onnx_verbatim):
514
- result = run_step(report, f'{recipe.name} onnx', lambda: build_onnx(recipe, out, cache))
515
  onnx_path = result if isinstance(result, Path) else None
516
  if 'coreml' in formats and recipe.coreml is not None:
517
  if sys.platform != 'darwin':
518
  print(' ⊘ CoreML needs macOS')
519
  report.skipped.append(f'{recipe.name} coreml')
520
  else:
521
- run_step(report, f'{recipe.name} coreml', lambda: build_coreml(recipe, out, cache, verify_coreml))
522
  if 'openvino' in formats and recipe.openvino and onnx_path is not None:
523
  samples = calib_samples or recipe.calib_samples or 300
524
  skipped = run_step(report, f'{recipe.name} openvino',
525
  lambda: build_openvino(recipe, onnx_path, out, calib_dir, samples))
526
  report.skipped.extend(skipped if isinstance(skipped, list) else [])
527
- if 'tflite' in formats and recipe.tflite:
528
- run_step(report, f'{recipe.name} tflite', lambda: build_tflite(recipe, out, cache))
529
 
530
 
531
  def adhoc_recipe(args: argparse.Namespace) -> Recipe:
@@ -584,15 +495,13 @@ def check_hosted() -> int:
584
  def list_recipes() -> None:
585
  for r in RECIPES:
586
  ov = ','.join(f'{o.precision}{"→" + o.suffix if o.suffix else ""}' for o in r.openvino)
587
- src = r.checkpoint if isinstance(r.checkpoint, str) else r.checkpoint.url
588
- onnx = 'verbatim' if r.onnx_verbatim else (
589
- f'{"dynamic" if r.onnx and r.onnx.dynamic else "static"} opset{r.onnx.opset if r.onnx else ""}')
590
  cm = (f'{"flex≤" + str(r.coreml.batch) if r.coreml.dynamic else "static"}'
591
  f'{" fp16" if r.coreml.half else ""}') if r.coreml else '-'
592
  int8 = f' int8 N={r.calib_samples}' if any(o.precision == 'int8' for o in r.openvino) else ''
593
  print(f'{r.name:30s} {r.folder:28s} {r.imgsz:4d} onnx[{onnx}] coreml[{cm}] '
594
- f'openvino[{ov}]{int8}{" tflite" if r.tflite else ""} '
595
- f'ultralytics {r.toolchain.ultralytics} from {src}')
596
 
597
 
598
  def parse_args(argv: list[str]) -> argparse.Namespace:
@@ -606,10 +515,8 @@ def parse_args(argv: list[str]) -> argparse.Namespace:
606
  sel.add_argument('--check-hosted', action='store_true',
607
  help='compare the recipes with the live mirror and exit (non-zero on a gap)')
608
  sel.add_argument('--dry-run', action='store_true', help='print the files that would be built')
609
- p.add_argument('--formats', default=','.join(ALL_FORMATS), help='subset of onnx,coreml,openvino,tflite')
610
  p.add_argument('--out', type=Path, default=Path('exported-models'))
611
- p.add_argument('--cache', type=Path, default=Path('exported-models/.downloads'),
612
- help='where third-party checkpoints are downloaded')
613
  p.add_argument('--calib-dir', type=Path, default=DEFAULT_CALIB_DIR)
614
  p.add_argument('--verify-coreml', action='store_true',
615
  help='predict N=1 and N=4 on each flexible-batch CoreML package (in a child process)')
@@ -659,7 +566,7 @@ def main(argv: list[str]) -> int:
659
  return 0
660
  report = Report()
661
  for r in recipes:
662
- build(r, formats, args.out, args.cache, args.calib_dir, args.calib_samples,
663
  args.verify_coreml, report)
664
  print('\nDone.' + (f' Failed: {report.failed}.' if report.failed else '')
665
  + (f' Skipped: {report.skipped}.' if report.skipped else ''))
 
8
  objectDetection/yolo26 yolo26{n,s,m,l,x} @640, yolo26{n,s,m,l} @320 and @256
9
  objectDetection/yolov9 yolov9{t,s,m,c} @320 and @640
10
  segmentation/yolo26-seg yolo26{n,s,m}-seg @640
 
11
 
12
  Every hosted file is one output of ONE recipe in `RECIPES` below, and the recipe
13
  holds exactly the settings that file records about itself: the Ultralytics
 
39
  int8 convert_lib.quantize_openvino_int8: NNCF post-training quantisation
40
  of the ONNX, calibrated on the first N images (sorted by file name)
41
  of --calib-dir (default $CAMSTACK_CALIB_DIR or ./calibration-images)
 
42
 
43
  INT8 calibration: the hosted INT8 IRs record subset_size 128 (YOLO26) and 300
44
  (YOLOv9), drawn from COCO; an IR does not record WHICH images. The documented
 
60
  from __future__ import annotations
61
 
62
  import argparse
 
63
  import json
64
  import os
65
  import shutil
 
83
  # --- Recipe model ------------------------------------------------------------
84
 
85
 
 
 
 
 
 
 
 
 
 
86
  @dataclass(frozen=True)
87
  class OnnxExport:
88
  """Ultralytics export(format="onnx") arguments, as the hosted ONNX records them."""
 
127
  imgsz: int
128
  toolchain: Toolchain
129
  # The PyTorch checkpoint: an Ultralytics asset id (`yolo26n` -> yolo26n.pt,
130
+ # auto-downloaded by Ultralytics).
131
+ checkpoint: str
132
+ onnx: Optional[OnnxExport]
133
  coreml: Optional[CoremlExport]
134
  openvino: tuple[OpenvinoOutput, ...] = ()
135
  calib_samples: int = 0
 
 
136
  note: str = ''
137
 
138
  def outputs(self) -> list[str]:
139
  """Mirror paths this recipe produces (an .mlpackage is a directory)."""
140
  out: list[str] = []
141
+ if self.onnx is not None:
142
  out.append(f'{self.folder}/onnx/{self.name}.onnx')
143
  if self.coreml is not None:
144
  out.append(f'{self.folder}/coreml/{self.name}.mlpackage/')
145
  for ov in self.openvino:
146
  stem = f'{self.folder}/openvino/{self.name}{ov.suffix}'
147
  out.extend([f'{stem}.xml', f'{stem}.bin'])
 
 
148
  return out
149
 
150
 
 
155
  TC_2604 = Toolchain('8.4.24', '2.10.0', '9.0', '2026.2.1')
156
  TC_2607_REDUCED = Toolchain('8.4.92', 'onnx 2.13.0, coreml 2.5.1', '8.3.0', '2026.2.1')
157
  TC_2607_YOLOV9 = Toolchain('8.4.98', '2.13.0', '9.0', '2026.2.1')
 
158
 
159
  FP16_IR = OpenvinoOutput('', 'fp16')
160
 
 
209
  )
210
 
211
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
212
  RECIPES: tuple[Recipe, ...] = (
213
  *(_yolo26_full(t) for t in 'nsmlx'),
214
  *(_yolo26_reduced(t, r) for t in 'nsml' for r in (320, 256)),
215
  *(_yolov9(t, r) for t in ('t', 's', 'm', 'c') for r in (320, 640)),
216
  *(_yolo26_seg(t) for t in 'nsm'),
 
217
  )
218
 
219
  FAMILIES = {
220
  'yolo26': 'objectDetection/yolo26',
221
  'yolov9': 'objectDetection/yolov9',
222
  'yolo26-seg': 'segmentation/yolo26-seg',
 
223
  }
224
+ ALL_FORMATS = ('onnx', 'coreml', 'openvino')
225
 
226
  # --- Helpers ----------------------------------------------------------------
227
 
 
232
  return sum(f.stat().st_size for f in path.rglob('*') if f.is_file()) / 1_048_576
233
 
234
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
235
  def warn_toolchain(recipe: Recipe) -> None:
236
  try:
237
  import ultralytics
 
252
  return dest
253
 
254
 
255
+ def checkpoint_path(recipe: Recipe) -> str:
 
 
256
  return f'{recipe.checkpoint}.pt' # Ultralytics downloads its own assets
257
 
258
 
 
334
  # --- Format steps -------------------------------------------------------------
335
 
336
 
337
+ def build_onnx(recipe: Recipe, out: Path) -> Path:
338
  dest = out / recipe.folder / 'onnx' / f'{recipe.name}.onnx'
 
 
 
339
  assert recipe.onnx is not None
340
  print(f' → ONNX (imgsz={recipe.imgsz}, dynamic={recipe.onnx.dynamic}, opset={recipe.onnx.opset})')
341
  src = ultralytics_export(
342
+ checkpoint_path(recipe), format='onnx', imgsz=recipe.imgsz,
343
  dynamic=recipe.onnx.dynamic, simplify=True, opset=recipe.onnx.opset,
344
  nms=False, batch=1, half=False,
345
  )
346
  return place(src, dest)
347
 
348
 
349
+ def build_coreml(recipe: Recipe, out: Path, verify: bool) -> Path:
350
  assert recipe.coreml is not None
351
  c = recipe.coreml
352
  print(f' → CoreML (imgsz={recipe.imgsz}, dynamic={c.dynamic}, batch={c.batch}, half={c.half})')
353
  src = ultralytics_export(
354
+ checkpoint_path(recipe), format='coreml', imgsz=recipe.imgsz,
355
  dynamic=c.dynamic, batch=c.batch, half=c.half, nms=False,
356
  )
357
  dest = place(src, out / recipe.folder / 'coreml' / f'{recipe.name}.mlpackage')
 
382
  return skipped
383
 
384
 
 
 
 
 
 
 
 
 
 
 
385
  def verify_coreml_batch(mlpackage: Path, imgsz: int) -> None:
386
  """Predict with N=1 then N=4 on a flexible-batch package, in a throwaway child.
387
 
 
416
  return None
417
 
418
 
419
+ def build(recipe: Recipe, formats: set[str], out: Path, calib_dir: Path,
420
  calib_samples: Optional[int], verify_coreml: bool, report: Report) -> None:
421
  print('\n' + '=' * 70 + f'\n{recipe.name} ({recipe.folder}, {recipe.imgsz}×{recipe.imgsz})\n' + '=' * 70)
422
  if recipe.note:
423
  print(f' {recipe.note}')
424
  warn_toolchain(recipe)
425
  onnx_path: Optional[Path] = None
426
+ if formats & {'onnx', 'openvino'} and recipe.onnx:
427
+ result = run_step(report, f'{recipe.name} onnx', lambda: build_onnx(recipe, out))
428
  onnx_path = result if isinstance(result, Path) else None
429
  if 'coreml' in formats and recipe.coreml is not None:
430
  if sys.platform != 'darwin':
431
  print(' ⊘ CoreML needs macOS')
432
  report.skipped.append(f'{recipe.name} coreml')
433
  else:
434
+ run_step(report, f'{recipe.name} coreml', lambda: build_coreml(recipe, out, verify_coreml))
435
  if 'openvino' in formats and recipe.openvino and onnx_path is not None:
436
  samples = calib_samples or recipe.calib_samples or 300
437
  skipped = run_step(report, f'{recipe.name} openvino',
438
  lambda: build_openvino(recipe, onnx_path, out, calib_dir, samples))
439
  report.skipped.extend(skipped if isinstance(skipped, list) else [])
 
 
440
 
441
 
442
  def adhoc_recipe(args: argparse.Namespace) -> Recipe:
 
495
  def list_recipes() -> None:
496
  for r in RECIPES:
497
  ov = ','.join(f'{o.precision}{"→" + o.suffix if o.suffix else ""}' for o in r.openvino)
498
+ onnx = f'{"dynamic" if r.onnx and r.onnx.dynamic else "static"} opset{r.onnx.opset if r.onnx else ""}'
 
 
499
  cm = (f'{"flex≤" + str(r.coreml.batch) if r.coreml.dynamic else "static"}'
500
  f'{" fp16" if r.coreml.half else ""}') if r.coreml else '-'
501
  int8 = f' int8 N={r.calib_samples}' if any(o.precision == 'int8' for o in r.openvino) else ''
502
  print(f'{r.name:30s} {r.folder:28s} {r.imgsz:4d} onnx[{onnx}] coreml[{cm}] '
503
+ f'openvino[{ov}]{int8} '
504
+ f'ultralytics {r.toolchain.ultralytics} from {r.checkpoint}.pt')
505
 
506
 
507
  def parse_args(argv: list[str]) -> argparse.Namespace:
 
515
  sel.add_argument('--check-hosted', action='store_true',
516
  help='compare the recipes with the live mirror and exit (non-zero on a gap)')
517
  sel.add_argument('--dry-run', action='store_true', help='print the files that would be built')
518
+ p.add_argument('--formats', default=','.join(ALL_FORMATS), help='subset of onnx,coreml,openvino')
519
  p.add_argument('--out', type=Path, default=Path('exported-models'))
 
 
520
  p.add_argument('--calib-dir', type=Path, default=DEFAULT_CALIB_DIR)
521
  p.add_argument('--verify-coreml', action='store_true',
522
  help='predict N=1 and N=4 on each flexible-batch CoreML package (in a child process)')
 
566
  return 0
567
  report = Report()
568
  for r in recipes:
569
+ build(r, formats, args.out, args.calib_dir, args.calib_samples,
570
  args.verify_coreml, report)
571
  print('\nDone.' + (f' Failed: {report.failed}.' if report.failed else '')
572
  + (f' Skipped: {report.skipped}.' if report.skipped else ''))