A hands-on demo:
- take a YOLO v26 segmentation model
- shrink it
- measure what breaks
- run it live on a phone
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Cloud / Desktop β
β GPU Β· 24 GB RAM Β· unlimited power β
ββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββ
β big, slow, polluter
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Embedded / Mobile / Browser β
β limited RAM Β· battery Β· no GPU β
ββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββ
β small, fast, frugal
βΌ
| Goal | Metric | Edge constraint |
|---|---|---|
| Smaller download | File size (MB) | network |
| Lower latency | Inference time (ms) | Real-time at 30 fps |
| Less memory | Peak RAM (MB) | 2β4 GB shared with OS |
| Less energy | Joules per frame? | Battery life |
β Measure file size (did it shrink?)
β Measure mAP50 / mAP50-95 (did accuracy drop?)
β Measure FPS on video (did it speed up?)
β Result check (are predictions still correct?)
The tradeoff triangle β pick two:
Accuracy
β²
β± β²
β± β² Quantization =
β± β² sacrifice accuracy
β± β²
βΌββββββββββΌ
Size ββββββββΊ Latency
Two recommended builds for any embedding project:
| Build | Format |
|---|---|
| Quality | FP16/FP32 |
| Fast | INT8 |
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Step 1 Export β
β Download the model β
ββββββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Step 2 Calibrate β
β Run FP32 model on 80 sample frames β diagnostic report β
ββββββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Step 3 Convert β
β Under the hood: .pt β ONNX β SavedModel β onnx2tf β .tflite β
ββββββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Step 5 Evaluate β
β Measure: mAP50, mAP50-95, precision, recall β
β Analyze confusion matrices β
ββββββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Step 6 Bench β
β For each example Γ each model variant: β
β Measure: FPS, avg inference time, avg confidence β
ββββββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Step 7 Summarize β
β sources, artifacts, evaluation, (FPS), β
β benchmarks, calibration, GPU info β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Detection (boxes) vs Segmentation (pixel masks):
Detection Segmentation
ββββββββββββββββββββββββββ ββββββββββββββββββββββββββ
β β β β
β ββββββββββββ β β ββββββββββ β
β β person β β β β person β β
β β 87% β β β β 87% β β
β ββββββββββββ β β ββββββββββ β
β β β β
ββββββββββββββββββββββββββ ββββββββββββββββββββββββββ
Faster, smaller model More visual, ~2Γ heavier
Segmentation models:
| Model | Params | PT size | ONNX FP32 | Best for |
|---|---|---|---|---|
| yolo26n-seg | 2.7 M | 6 MB | 11 MB | demonstrator |
| yolo26s-seg | 9.7 M | 20 MB | 39 MB | best int8 accuracy |
| yolo26m-seg | 21.2 M | 44 MB | 85 MB | production accuracy |
| yolo26l-seg | 47.0 M | 97 MB | 187 MB | large objects, high accuracy |
| yolo26x-seg | 99.1 M | 205 MB | 395 MB | highest accuracy, very heavy |
*.pt PyTorch weights
β
β Ultralytics model.export(format="tflite")
βΌ
*.onnx βββββββββββββββββββββ ONNX intermediate (FP32)
β
βββββ onnx2tf (float) βββββββββββββββββββββββββββββββββββββββββββ
β *_float32.tflite ~10 MB (full precision) β
β *_float16.tflite ~5 MB (half precision) β
β β
βββββ onnx2tf (int8=True, calibrated on coco128) ββββββββββββββββ€
β *_int8.tflite ~3 MB (dynamic-range) β
β *_full_integer_quant.tflite ~3 MB (full int8) β
β *_integer_quant.tflite ~3 MB (mixed int8 float32) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
| Technique | What it does |
|---|---|
| FP16 quantization | Halve weight precision (32β16 bits) |
| Dynamic-range INT8 | Quantize weights to int8, activations stay FP32 at runtime |
| Full-integer INT8 | Force everything to int8, no float fallback |
| Mixed quantization | Backbone INT8, detection head FP32 |
| Calibration | Representative dataset to compute activation ranges |
What we do NOT use (but could):
| Technique | Why not |
|---|---|
| QAT (Quantization-Aware Training) | Needs retraining; out of scope |
| Pruning / Clustering | More useful on larger models |
| Edge TPU / NNAPI delegates | Desktop demo, not mobile native |
| Split suppressions (WebGL) | WebGL-compatible ONNX export |
Note: Dynamic-range INT8 stores weights as int8 but dequantizes to FP32 at runtime.
Note: Full-integer INT8 forces everything to int8 : the detection head confidence scores are bad. Kept as a demo of what goes wrong when you blindly quantise without tree analysis.
Note: Full-integer INT8 is not supported for segmentation models due to Split operators in the graph (available for detect models).
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β BACKBONE (model.0 β model.22) β
β Feature extraction: Conv, BatchNorm, activations β
β Values span wide ranges β rounding to 256 int8 levels is fine. β
ββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββ
β
β βββββββββββββββ Quantizes well to INT8
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β DETECTION HEAD (model.23) β
β Boxes (cv2) + Classes (cv3) + NMS (TopK, Sigmoid, Gather) β
β Confidence scores live in a narrow range: 0.30 β 0.90 β
β β
β INT8 = 256 levels for [0,1] β step = 0.004 β
β conf 0.34 and conf 0.30 round to the SAME int8 value β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Detections fall below threshold, so objects vanish.
It depends on the platform:
- Web: WebGPU (best), WebGL (fallback), WASM (universal fallback)
- Mobile: NNAPI (Android), CoreML (iOS)
- Desktop: WebGPU (best), WebGL (fallback), WASM (universal fallback) with asynchronous execution
- Edge TPU: Coral USB Accelerator
*.pt PyTorch weights
β
β Ultralytics model.export(format="onnx")
β
βββββ Yolo onnx βββββββββββββββββββββββββββββββββββββββββββ
β fp32.onnx ~10 MB β
β opset 17, not end2end β
βββββ Onnx runtime ββββββββββββββββββββββββββββββ€
β quant.onnx ~3 MB β
β backbone uint8 type β
β detection head float32 type β
βββββββββββββββββββββββββββββββββββββββ
https://tigroo.github.io/embed-ai/pwa/
Note: The end2end YOLO export includes TopK / GatherElements / Mod in the detection head ... NOT supported by WebGL :(. So we export without end2end.
Note: NMS is done in JavaScript: ~1 ms overhead.
Note: Due to Split operators in the segmentation graph, full int8 quantisation is not possible for ONNX.
Backend negotiation (fastest β safest):
- WebGPU (newest, best perf when supported)
- WebGL (mature, broad support)
- WASM (universal fallback)
Various results:
- WebGPU to manually activate on browser Firefox: about:config β dom.webgpu.enabled : True
- WebGL works β 2-5Γ faster than WASM on most devices
- WASM on CPU with XNNPACK
pipenv install
pipenv run python main.py| Flag | Default | Description |
|---|---|---|
--output |
output |
Directory for all generated artifacts |
--model |
yolo26n-seg |
Model name (auto-downloaded if absent) |
--summary |
summary.json |
Summary JSON filename |
--pwa-only |
False | Skip TFLite export, only ONNX for PWA |
--calibration |
None | Path to calibration YAML (optional) |
Videos are auto-discovered from resources/*.mp4.
python serve_local.py