Skip to content

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

inx-model-zoo

Vision models converted for the inxware embedded runtime (eRT), together with the originals they were converted from, so any conversion here can be repeated rather than trusted.

Licensing: these are AGPL-3.0 derivatives. Every model here descends from Ultralytics YOLOv8 weights. Read NOTICE before shipping any of them in a product — the AGPL's network clause reaches software served over a network, not only software distributed as a binary.

Model files are held in Git LFS (see .gitattributes). yolov8m-pose.onnx is 101 MB, over GitHub's 100 MB per-file hard limit, so LFS is required here rather than merely tidy. Clone with git lfs install already done, or the working tree fills with pointer files.

Using one in eRT

The ml_image_inference block needs its Model Type parameter to match the model — there is no auto-detect, and a mismatch fails the load rather than falling back:

Model kind Model Type Notes
YOLOv8 object detection 1006
YOLOv8 pose estimation 1008
YOLOv5 object detection 1003

0 is not a "don't care" — it fails with EHS_ML_MODEL_TYPE_ERR (12).

File naming

Converted files are named <model>-<quantisation>.tfl. The suffix is the whole point of the file, so it is worth knowing which is which:

Suffix Quantisation Weights Activations Input / output Use it?
-dyn dynamic range int8 float32 float32 yes - the default
-int8 full integer int8 int8 uint8 no for YOLOv8, see below
-fp16 half precision float16 float16 float32 not currently produced
(none) none float32 float32 float32 reference / accuracy check

-dyn is the one you want. Dynamic range quantises only the weights, so the file is ~4x smaller and loads faster, while every activation stays float32 and nothing numerically dangerous happens to the detection head.

-int8 quantises the activations too, which is what unlocks AVX-VNNI and makes it fast in principle - and what destroys a YOLOv8 head in practice, for the reason set out under Why there is no full-int8 pose model that works below. It is published only as a labelled specimen of that failure.

Files predating this convention (yolo8n, yolo8md, yolo8mu8, yolo8m8, yolov8m32) carry ad-hoc names. The Inventory table below records what each one measurably is, which is more reliable than what its name suggests.

Where the originals come from

All PyTorch weights are Ultralytics' own published assets, release v8.4.0:

File Upstream URL
yolov8n.pt https://github.com/ultralytics/assets/releases/download/v8.4.0/yolov8n.pt
yolov8m.pt https://github.com/ultralytics/assets/releases/download/v8.4.0/yolov8m.pt
yolov8s-pose.pt https://github.com/ultralytics/assets/releases/download/v8.4.0/yolov8s-pose.pt
yolov8m-pose.pt https://github.com/ultralytics/assets/releases/download/v8.4.0/yolov8m-pose.pt

The .onnx files beside them are exports of those weights, not separate downloads. Every .tfl derives from the .pt in the same directory.

Which of these run on which engine

On Windows, use the .onnx files. The .tfl files will not load there.

The Windows eRT runtimes (win_x86_64_{qt,gtk_gst,lvgl}_mv) use OpenCV DNN as their inference engine, and as of 2026-09-14 that engine accepts ONNX only — it refuses .tflite/.tfl outright with EHS_ML_MODEL_TYPE_ERR (12). That is not a policy choice about this zoo; OpenCV's TFLite importer failed every model tried and segfaulted on two of them, so the format is rejected before it can reach the importer. See ert-components/docs/ml-hal.md § .tflite through OpenCV DNN for the model-by-model evidence.

Verified directly against the mingw OpenCV 5.0 DLLs the Windows runtimes ship (cross-compiled probe, run under wine), testing both gates the engine applies — the graph must parse, and the model must declare a static input shape:

Model ONNX parses Input shape declared Verdict on Windows
yolov8n.onnx yes 640x640x3 loads
yolov8m.onnx yes 640x640x3 loads
yolov8s-pose.onnx yes 640x640x3 loads
yolov8m-pose.onnx yes 640x640x3 loads

The static-shape column is not a formality: OpenCV DNN cannot report a model's input geometry, and eRT needs it both to hand frames to the model and to scale detection boxes, so a dynamic-shape export is refused with EHS_ML_MODEL_TENSOR_DIM_ERR (8) rather than run against a guessed size. These four are static because they were exported without dynamic=True — keep it that way when re-exporting.

Note the pose models load on the OpenCV DNN engine, but Model Type 1008 (YOLOv8 pose post-processing) is currently implemented for Hailo only, so a pose model is not yet end-to-end usable on Windows. Object detection (1006) is.

On Linux and Android the TFLite engine is the default and the .tfl files are the right choice; nothing above changes that.

Each directory has its own README recording that model's exact conversion command, tensor shapes and SHA-256 checksums, so any file here can be regenerated or verified rather than trusted.

Inventory

Each directory has its own README with that model's exact conversion command, tensor shapes and checksums: yolov8s-pose, yolov8m-pose, yolov8n, yolov8m, hailo.

layout is the one that silently costs you a day: eRT requires NHWC. An Ultralytics web UI export produces NCHW, which eRT cannot consume.

Pose estimation — output [1, 56, 8400] = 4 box + 1 class + 17 joints x 3

File MB In Layout Out Status
yolov8s-pose/tflite/yolov8s-pose-dyn.tfl 11.5 FLOAT32 NHWC FLOAT32 recommended
yolov8m-pose/tflite/yolov8m-pose-dyn.tfl 25.7 FLOAT32 NHWC FLOAT32 recommended, more accurate
yolov8s-pose/tflite/yolov8s-pose-int8.tfl 11.5 UINT8 NHWC UINT8 broken — do not use, see below
hailo/yolov8s_pose.hef 10.6 Hailo-8; raw heads

Object detection — output [1, 84, 8400] = 4 box + 80 classes

File MB In Layout Out Status
yolov8n/tflite/yolo8n.tfl 3.2 FLOAT32 NHWC FLOAT32 good
yolov8m/tflite/yolo8md.tfl 25.1 FLOAT32 NHWC FLOAT32 good
yolov8m/tflite/yolo8mu8.tfl 25.2 UINT8 NHWC FLOAT32 uint8 input, float output
yolov8m/tflite/yolo8m8.tfl 25.3 FLOAT32 NCHW FLOAT32 eRT cannot load this
yolov8m/tflite/yolov8m32.tfl 99.0 FLOAT32 NCHW FLOAT32 eRT cannot load this
hailo/yolov8n.hef 4.9 Hailo-8; NMS compiled in

The two NCHW files are kept because they are what a web-UI export looks like, and recognising one is most of diagnosing it — not because they are usable.

The .hef files were found in an ert-components working tree rather than produced here. Their architecture is Hailo Model Zoo's, but neither matches any published Hailo build by checksum (v2.11.0-v2.14.0 were compared), so the compiler version and operator are unknown — see hailo/README.md for the evidence and what it does and does not establish.

Why there is no full-int8 pose model that works

Full int8 quantisation is measurably faster, and it destroys this model. The YOLOv8 head is one concatenated tensor carrying values on two incompatible scales — box and keypoint coordinates spanning 0-640, and class scores and keypoint visibilities spanning 0-1 — and TFLite gives an activation tensor a single per-tensor scale. Measured on yolov8s-pose-int8.tfl:

output scale = 2.789376, zero point = 14

A confidence of 0.90 therefore encodes to code 14, which is the zero point: every score and every joint visibility quantises to zero. The full 0-1 probability range spans 0.36 of one code out of 255.

This is not a calibration problem and more calibration images do not help — it is the arithmetic of one scale over two ranges. Dynamic-range quantisation (int8 weights, float32 activations and IO) is the correct trade and is what the -dyn files are. Per-channel quantisation applies to weights, not activations, so it does not rescue this either.

Measured throughput

640x640, TFLite + XNNPACK, i7-12700H (6 P-cores + 8 E-cores, 20 threads, AVX2 + AVX-VNNI), 10 iterations after 3 warm-up:

Model 1 thread 4 threads 8 threads 20 threads
yolov8s-pose dyn 10.4 fps 25.5 fps 26.0 fps 1.1 fps
yolov8m-pose dyn 4.3 fps 10.8 fps 11.2 fps 0.8 fps

Do not set Thread Number to the core count. At 20 threads this CPU is 24x slower than at 8: the P-core/E-core split plus hyperthreading makes oversubscription catastrophic rather than merely unhelpful. 4 threads reaches 98% of the best result, which is why eRT's auto mode caps there (EHS_ML_TFLITE_AUTO_THREADS_MAX).

Regenerating any of this

Conversion scripts, and the reasoning behind each converter setting, are in ert-components/scripts/ai-utils/model-conversion/:

python3 -m venv venv && source venv/bin/activate
pip install -r requirements.txt
pip install ultralytics          # AGPL-3.0, tool only - see NOTICE

# .pt -> SavedModel. Do this LOCALLY: it is NHWC, which eRT needs.
yolo export model=yolov8s-pose.pt format=saved_model imgsz=640

# SavedModel -> .tfl, int8 weights with a float32 boundary
python3 export_tflite_int8.py yolov8s-pose_saved_model \
        -o yolov8s-pose-dyn.tfl --quant dynamic

# verify before it goes near a device (no dependencies)
python3 tfl_inspect.py yolov8s-pose-dyn.tfl --camera 640x640x3

tfl_inspect.py is a zero-dependency FlatBuffer reader — it is the quickest way to catch an NCHW export or an unexpected tensor dtype before a device does.

About

Vision models converted for the inxware embedded runtime (eRT), with the originals they were converted from. AGPL-3.0 derivatives of Ultralytics YOLOv8 - see NOTICE.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors