İçeriğe geç

Teknik Yazılar

Gömülü Sistemler··7 dk okuma

TensorRT ile Model Hızlandırma: FP16 Engine ve Jetson Optimizasyonu

Aynı model, aynı kart, iki kat hız. TensorRT'nin ne yaptığını ve .engine dosyasının neden bavula konup taşınamayacağını anlatıyoruz.

Uçuş öncesi son testte kameradan gelen kare ile ekrandaki kutu arasında gözle görülür bir gecikme varsa, sorun genelde modelin doğruluğunda değil çalıştırma biçimindedir. Bizim durumumuzda YOLO11m, Jetson Orin NX 16GB üzerinde 640 piksel tam-kare çıkarımda 15-20 FPS bandında çalışıyor. Bu, 20 m irtifadan hedef tespiti için yeterli; ama aynı hat üzerinde SIYI A8 mini’den gelen 1080p RTSP akışının çözülmesi, FastMosaic’in kare biriktirmesi ve pymavlink telemetrisi de var. GPU’yu boşa harcadığımız her milisaniye başka bir yerden kesiliyor.

PyTorch ile eğitilmiş bir .pt dosyası aslında bir tarif: her katman ayrı ayrı, Python yorumlayıcısının gözetiminde, genel amaçlı çekirdeklerle çalışıyor. Masaüstü RTX kartında bunun bedeli fark edilmiyor. 10-25 W güç zarfındaki bir modülde ise doğrudan FPS olarak geri dönüyor.

Bu yazıda modeli değiştirmeden hız kazanmanın en doğrudan yolunu, yani NVIDIA TensorRT ile derlenmiş .engine dosyalarını anlatıyoruz. Özellikle de bu konuda en sık kırılan kurala: engine dosyası taşınabilir bir model formatı değildir.

TensorRT tam olarak ne yapıyor

TensorRT bir çıkarım (inference) derleyicisi. Eğitilmiş bir ağ grafiğini alıp hedef GPU için özelleştirilmiş bir çalıştırma planı üretiyor. NVIDIA’nın saydığı temel teknikler şunlar:

  • Katman ve tensör kaynaştırma (layer/tensor fusion): Conv + BatchNorm + aktivasyon gibi ardışık işlemler tek bir GPU çekirdeğinde birleştiriliyor. Her birleşme, bir çekirdek başlatma maliyeti ve bir bellek gidiş-dönüşü daha az demek.
  • Hassasiyet kalibrasyonu (precision calibration): Ağırlıkların ve ara sonuçların FP16 veya INT8 gibi daha dar sayı biçimlerinde tutulması. Tensor Core’lar bu biçimlerde belirgin biçimde daha hızlı.
  • Çekirdek otomatik ayarı (kernel auto-tuning): Her katman için, o karttaki gerçek ölçümlere bakarak aday CUDA çekirdekleri arasından en hızlısı seçiliyor.
  • Dinamik tensör belleği: Ara tensörler için bellek, ömürleri çakışmayan katmanlar arasında yeniden kullanılıyor.

Üçüncü madde, yazının ilerleyen kısmındaki kritik kuralın kaynağı. TensorRT tahmin yürütmüyor, hedef GPU üzerinde ölçüm yapıp karar veriyor.

FP32, FP16, INT8: hız ile doğruluğun takası

Ultralytics’in Jetson kılavuzundaki Orin NX 16GB ölçümleri bu takası net gösteriyor. Aşağıdaki tablo, dokümantasyonun referans modeli olan YOLO26n için, 640 piksel girdiyle alınmış değerler — bizim YOLO11m’imiz değil, ama formatlar arası oranlar aynı mantıkla okunur (2026 itibarıyla):

Format Çıkarım (ms) mAP50-95 Ne zaman tercih edilir
PyTorch (.pt) 13.90 0.4799 Geliştirme, hata ayıklama, hızlı deneme
TorchScript 11.60 0.4787 Python bağımlılığını azaltmak isteyip TensorRT kuramadığınızda
ONNX 14.18 0.4763 Taşınabilirlik gerektiğinde; Jetson’da hız için değil
TensorRT FP32 7.01 0.4770 Doğrulukta sıfır risk isteyen doğrulama koşuları
TensorRT FP16 4.13 0.4789 Uçuş yapılandırması — varsayılan tercihimiz
TensorRT INT8 3.49 0.4489 Kare bütçesi gerçekten sıkışıksa ve doğruluk kaybı ölçüldüyse

Okunması gereken üç oran var. TensorRT FP32 bile PyTorch’a göre yaklaşık 2 kat hızlı — yani daha ilk adımda, hiçbir hassasiyet düşürmeden kazanç geliyor. FP16’ya geçmek bunun üzerine yaklaşık 1,7 kat daha ekliyor ve bu tabloda mAP’ye ölçülebilir bir zarar vermiyor. INT8 ise FP16 üzerine sadece ~1,2 kat kazandırırken mAP50-95’i 0,479’dan 0,449’a düşürüyor; yaklaşık 3 puanlık bir kayıp.

Bizim tercihimiz FP16. Küçük hedefleri 20 m’den yakalamaya çalışan bir tespit hattında 3 puanlık mAP kaybı, 0,6 ms uğruna verilecek bir taviz değil.

.pt → ONNX → .engine akışı

Ultralytics dışa aktarımı ONNX’i ara grafik olarak kullanıyor; opset argümanı da bu ara adımı ilgilendiriyor. Tek komutla halledilebiliyor:

# Jetson'ın ÜZERİNDE çalıştırılır
yolo export model=best.pt format=engine imgsz=640 quantize=16 batch=1 workspace=4

Python tarafında aynısı:

from ultralytics import YOLO

model = YOLO("best.pt")
model.export(format="engine", imgsz=640, quantize=16, batch=1)

# Çıkarım tarafı hiç değişmiyor
trt = YOLO("best.engine")
results = trt("frame.jpg", conf=0.25)

Önemli bir API değişikliği: eski half=True ve int8=True bayrakları artık quantize=16 ve quantize=8 biçimine taşındı. Eskileri hâlâ kabul ediliyor ama kullanımdan kaldırma uyarısı veriyor (2026 itibarıyla). Sık kullanılan argümanlar:

Argüman Varsayılan İşlevi
quantize None Hassasiyet: 32, 16 veya 8
imgsz 640 Engine’e gömülen giriş boyutu
batch 1 İzin verilen azami yığın boyutu
dynamic False Değişken giriş boyutu profili
workspace None Derleme sırasında GiB cinsinden azami çalışma alanı
data None INT8 kalibrasyonu için veri seti yapılandırması
fraction 1.0 Kalibrasyonda kullanılacak veri seti oranı

Kritik kural: engine dosyası hedef cihazda derlenmeli

Ultralytics dokümantasyonu bunu açıkça yazıyor: TensorRT engine’i derlediği GPU üzerinde profilleyip ayarlıyor, dolayısıyla .engine taşınabilir bir model formatı sayılmamalı. NVIDIA tarafındaki gerekçe daha da nettir — serileştirilmiş plan dosyası varsayılan olarak üç şeye kilitlidir:

  1. Derlendiği TensorRT sürümüne. Plan içine kaydedilir ve yüklemede kontrol edilir.
  2. GPU’nun hesaplama yeteneğine (compute capability). Major ve minor sürüm plana yazılır, yükleme anında karta karşı doğrulanır.
  3. Platforma. İşletim sistemi ve CPU mimarisi de sabittir; x86 masaüstünde derlenen bir plan ARM tabanlı Jetson’da açılmaz.

NVIDIA bu kısıtları gevşetmek için bayraklar sunuyor: VERSION_COMPATIBLE, kAMPERE_PLUS (Ampere ve sonrası tüm mimariler) ve kSAME_COMPUTE_CAPABILITY. Hepsi cihaza özel engine’e kıyasla performans kaybettirebiliyor. Pratik sonuç değişmiyor: derlemeyi uçacak karta yaptırın, .engine dosyasını sürüm kontrolüne koymayın, CI’da üretip sahaya taşımaya çalışmayın.

Sabit mi dinamik mi giriş boyutu

Varsayılan olarak engine sabit girişle derlenir: imgsz ve batch plana gömülür. dynamic=True ile değişken boyut profili açılabilir; INT8 dışa aktarımında bu zaten varsayılan olarak etkinleşiyor.

Seçenek Ne zaman Bedeli
Sabit (dynamic=False) Tek ve değişmeyen çıkarım boyutu Farklı boyut denemek için yeniden derleme
Dinamik (dynamic=True) Tam kare + kırpma/tiling gibi karışık boyutlar Optimizasyon profili dışındaki boyutlarda daha düşük hız

batch argümanının azami değeri belirttiğini unutmayın: daha küçük yığınlar kabul edilir, daha büyükleri hata verir.

imgsz çıkarım hattıyla eşleşmeli

Burası bizim de ders çıkardığımız yer. Modeli imgsz=1280 ile eğitiyoruz ama uçuşta tam kareyi 640’ta işliyoruz. Engine’i eğitim değerine bakarak 1280’de derlerseniz, çıkarım hattı 640 gönderdiğinde ya boyut uyuşmazlığı hatası alırsınız ya da sessizce yeniden ölçekleme yapılır ve ölçtüğünüz hız gerçek hız olmaz.

Kural basit: engine’in imgsz değeri, uçuşta gerçekten beslediğiniz tensörün boyutu olmalı. Eğitim çözünürlüğü ile karıştırmayın. Farklı çözünürlükte tiling de yapıyorsanız ya her boyut için ayrı engine derleyin ya da dynamic=True kullanıp profil aralığını bilinçli seçin.

INT8’e geçecekseniz kalibrasyon verisi

INT8, eğitim sonrası nicemlemeyle (post-training quantization) çalışır ve aktivasyon aralıklarını öğrenmek için gerçek veriye ihtiyaç duyar. NVIDIA en az 500 temsili kalibrasyon görüntüsü öneriyor. Ultralytics tarafında bu, data argümanıyla veri seti yapılandırmasını göstererek yapılıyor; fraction ile alt küme seçilebiliyor.

yolo export model=best.pt format=engine imgsz=640 quantize=8 \
     data=suas_aerial.yaml fraction=0.5 batch=1

“Temsili” kelimesi burada belirleyici. Kalibrasyon setiniz web’den toplanmış yakın çekim fotoğraflardan oluşuyorsa, 20 m’den çekilmiş küçük hedeflerin aktivasyon aralıkları hiç görülmez ve saha performansı doğrulama metriğinizden kötü çıkar. Kalibrasyon bir .cache dosyası üretir; veri seti veya yığın boyutu belirgin biçimde değiştiğinde bu dosyayı silin, yoksa eski aralıklar yeniden kullanılır.

Sık düşülen tuzaklar

  • Masaüstünde derleyip Jetson’a kopyalamak. En yaygın hata. Sonuç ya yükleme hatası ya da mimari uyuşmazlığı; ikisi de uçuş sabahı istemeyeceğiniz sürprizler.
  • JetPack yükselttikten sonra engine’i yeniden derlememek. JetPack, TensorRT ve CUDA sürümünü birlikte getirir; eski plan yeni çalışma zamanında açılmayabilir.
  • Eğitim imgsz’si ile dışa aktarım imgsz’sini karıştırmak. Ölçtüğünüz FPS’in hangi çözünürlüğe ait olduğunu bilmeden optimizasyon yapmış olursunuz.
  • Ölçümü güç modu ayarlamadan almak. sudo nvpmodel -m 0 ve sudo jetson_clocks çalıştırılmadan alınan sayılar, kartın gerçek tavanını göstermez. jtop ile sıcaklık ve saat frekansını izlemek de faydalı.
  • DLA’yı otomatik hız kazancı sanmak. Orin NX 16GB’de 614 MHz’de çalışan 2 DLA çekirdeği var, ama DLA öncelikli olarak verim ve enerji verimliliği hedefliyor; GPU’ya kıyasla gecikmeyi düşürmek zorunda değil. Ayrıca TensorRT 11.0’da DLA desteklenmiyor, DLA dışa aktarımı TensorRT 10.x gerektiriyor (2026 itibarıyla).
  • INT8’e doğrulama koşusu yapmadan geçmek. Nicemlenmiş engine’i mutlaka kendi doğrulama setinizde tekrar ölçün. Bizim aerial-only doğrulama setimizdeki mAP50 0.950 değeri FP32 modele ait; INT8 sonrası aynı sayıyı varsaymak yanlış olur.

Pratik özet

  1. Engine’i her zaman uçacak Jetson’ın üzerinde derleyin. .engine dosyasını depoya koymayın, derleme adımını kurulum betiğine koyun.
  2. Varsayılanınız FP16 (quantize=16) olsun. Referans ölçümlerde PyTorch’a göre ~3 kat hız, ölçülebilir doğruluk kaybı olmadan geliyor.
  3. Dışa aktarımdaki imgsz ve batch değerlerini çıkarım hattınızın gerçekten gönderdiği tensörle birebir eşleyin; eğitim çözünürlüğünü değil.
  4. INT8’i ancak kare bütçeniz gerçekten sıkışıksa değerlendirin, en az 500 temsili görüntüyle kalibre edin ve doğrulama setinde mAP kaybını ölçerek karar verin.
  5. Her hız ölçümünü nvpmodel -m 0 + jetson_clocks sonrası, kart ısındıktan sonra alın. JetPack veya Ultralytics sürümü değiştiğinde engine’i yeniden derleyip ölçümü tekrarlayın.
  • tensorrt
  • jetson
  • yolo11
  • fp16
  • kenar-bilisim

Zor bir mühendislik probleminiz mi var?

Yapılabilir mi, ne kadar sürer, nasıl kurulur: konuşarak başlayalım.

Projenizi Konuşalım