Hep yanlış giden üç adımda dönüşüm pipeline'ı
Araştırmada eğitilmiş PyTorch modelinden edge donanımda çalışan INT8 binary'ye gitmek dokümanlarda basit görünür. Pratikte her adımın kendi başarısızlık modu var.Adım 1 — PyTorch → ONNX
ONNX export vanilla CNN'ler için çoğunlukla çözülmüş bir problem. Yanlış gittiği yer:- Dinamik şekiller. Modeliniz dinamik giriş boyutları kullanıyorsa, açık dynamic_axes ile export etmelisiniz.
- Özel op'lar. Upstream'lenmemiş torchvision'dan herhangi bir şey (DeformableConv, belirli NMS varyantları) özel sembolik fonksiyon gerektirir.
- Control flow. Tensor değerlerine bağlı if ifadeleri Loop / If node'larına dönüşür; tüm backend'ler desteklemez.
- Opset sürümü. Birçok hedef runtime en son opset'ten 1-2 sürüm geride. Runtime'ınızın desteklediği en düşük opset'e export edin.
ONNX export'unu hareket etmeden önce 10-100 görüntüde PyTorch modeline karşı her zaman doğrularız. Çıktılar 1e-5 içinde eşleşmeli.
Adım 2 — ONNX → optimize edilmiş graph
ONNX Runtime, TensorRT, OpenVINO, Hailo DFC hepsi graph düzeyi optimizasyon yapar. Çoğunlukla şeffaf. Isırdığı yer:- Operatör destek boşlukları. TensorRT kapsamı mükemmel; Hailo daha seçici.
- Layout transform'ları. NCHW vs NHWC önemli. Bazı runtime'lar yanlış varsayılan seçer ve %30 perf cezası yersiniz.
- Dinamik batch boyutları. Çoğu üretim deploy batch=1; engine'i batch=1 için spesifik inşa edin.
Adım 3 — INT8'e quantization
Doğruluk regresyonunun yaşadığı yer burası. İki tat:Post-training quantization (PTQ). Temsili veri setinde aktivasyon dağılımlarını kalibre et, tensor başına scale/zero-point seç, tamamlandı. Hızlı (dakika). Yaygın mimarilerde sıkça %0.5-2 doğruluk kaybeder.
Quantization-aware training (QAT). Eğitim graph'ına fake-quantization op'ları enjekte et, birkaç epoch fine-tune et. Yavaş (saat, bazen gün). PTQ doğruluk regresyonunun çoğunu kurtarır.
PTQ ne zaman yeterli vs QAT ne zaman gerekli:
- ResNet tarzı backbone'lar, büyük modeller, iyi dağıtılmış aktivasyonlar → PTQ iyi.
- Mobil tarzı mimariler (MobileNet, EfficientNet), zaten sıkıştırılmış modeller → QAT sıkça gerekli.
- Attention'lı, özel normalizasyonlu veya cosine-similarity skorlamalı her şey → neredeyse her zaman QAT.
- Sabit doğruluk SLA'lı üretim hedefi → her halükarda QAT çalıştır.
Kalibrasyon veri seti seçimi — yetersiz değer verilen adım
Kalibrasyon seti quantizer'ın gördüğü aktivasyon aralıklarını belirler. Kullanın:- En az 256 görüntü, ideal 1024.
- Üretimden yakalanmış, orijinal eğitim setinden değil.
- Gerçekten beklediğiniz aydınlatma, ürünler ve günün saati varyasyonunu kapsayan.
- Augmentation yok. Modelin eğitildiği için değil, göreceği için quantize edin.
Kötü bir kalibrasyon seti FP32'nin %1'i içinde INT8 ile %5 regresyonlu INT8 arasındaki farktır. Bunu yeterince yanlış yöne gittiğini gördük, artık kalibrasyon seti inşasını kendi incelemesiyle ayrı bir mühendislik görevi olarak ele alıyoruz.
Doğrulama, uçtan uca
Final binary kalibrasyon setinde değil, ayrılmış bir test setinde doğrulanmalı. Karşılaştırın:- FP32 PyTorch doğruluğu (baseline).
- ONNX FP32 doğruluğu (PyTorch ile eşleşmeli).
- ONNX INT8 doğruluğu (hedef: FP32'nin %1'i içinde).
- Cihazdaki INT8 doğruluğu (ONNX INT8 ile eşleşmeli).
Herhangi bir adım gürültü zemininden fazla ayrışırsa bug var. Göndermeyin.
Dönüşüm yığınınız nedir? ONNX-Runtime + DirectML kullanan veya vendor toolchain'lerine sıkı sıkıya bağlı kalan var mı?
The conversion pipeline, in three steps that always go wrong
Going from a research-trained PyTorch model to an INT8 binary running on edge hardware looks simple in the docs. In practice, every step has its own failure modes.Step 1 — PyTorch → ONNX
ONNX export is mostly a solved problem for vanilla CNNs. Where it goes wrong:- Dynamic shapes. If your model uses dynamic input dimensions, you have to export with explicit dynamic_axes.
- Custom ops. Anything from torchvision that hasn't been upstreamed (DeformableConv, certain NMS variants) needs a custom symbolic function.
- Control flow. If-statements that depend on tensor values become Loop / If nodes that not all backends support.
- Opset version. Many target runtimes lag the latest opset by 1-2 versions. Export targeting the lowest opset your runtime supports.
We always validate the ONNX export against the PyTorch model on 10-100 images before moving on. Outputs should match to within 1e-5.
Step 2 — ONNX → optimized graph
ONNX Runtime, TensorRT, OpenVINO, Hailo DFC all do graph-level optimization. Mostly transparent. Where it bites:- Operator support gaps. TensorRT's coverage is excellent; Hailo's is more selective.
- Layout transforms. NCHW vs NHWC matters. Some runtimes pick the wrong default and you eat a 30 % perf penalty.
- Dynamic batch sizes. Most production deployments are batch=1; build the engine for batch=1 specifically.
Step 3 — quantization to INT8
This is where the accuracy regression lives. Two flavors:Post-training quantization (PTQ). Calibrate the activation distributions on a representative dataset, choose scale/zero-point per tensor, done. Fast (minutes). Often loses 0.5-2 % accuracy on common architectures.
Quantization-aware training (QAT). Inject fake-quantization ops into the training graph, fine-tune for a few epochs. Slow (hours, sometimes days). Recovers most of the PTQ accuracy regression.
When PTQ is enough vs when QAT is needed:
- ResNet-style backbones, large models, well-distributed activations → PTQ is fine.
- Mobile-style architectures (MobileNet, EfficientNet), already-compressed models → QAT often needed.
- Anything with attention, custom normalization, or cosine-similarity scoring → QAT, almost always.
- Production target with fixed accuracy SLA → run QAT regardless.
Calibration dataset selection
The calibration set determines the activation ranges the quantizer sees. Use:- At least 256 images, ideally 1024.
- Captured from production, not from the original training set.
- Covering the variation in lighting, products, and time-of-day you actually expect.
- No augmentation. Quantize for what the model will see, not what it was trained on.
A bad calibration set is the difference between INT8 within 1 % of FP32 and INT8 with 5 % regression.
Validation, end-to-end
The final binary should be validated on a held-out test set, not on the calibration set. Compare:- FP32 PyTorch accuracy (baseline).
- ONNX FP32 accuracy (should match PyTorch).
- ONNX INT8 accuracy (target: within 1 % of FP32).
- On-device INT8 accuracy (should match ONNX INT8).
If any step diverges by more than the noise floor, you have a bug. Don't ship.
What's your conversion stack?