Ultralytics YOLO27 : Inscris-toi sur la liste d’attente.
Get Started
Ultralytics YOLO en production·Optimiser·Leçon 3/9
Leçonintermédiaire

Optimiser avec TensorRT

Crée un moteur TensorRT FP16, décide si INT8 vaut son coût en précision et soumets le moteur à un contrôle avant le déploiement.

Sur un GPU NVIDIA, un moteur TensorRT FP16 est généralement le gain de vitesse le plus facile à obtenir : environ 1,5× plus rapide dans le benchmark Ultralytics sur A100, sans changement de mAP. INT8 va plus loin, mais l’INT8 après entraînement a coûté de 4 à 6 points de mAP à YOLO26s à YOLO26m sur COCO. Cette leçon t’apprend à savoir quelle étape tu entreprends et à la mesurer avant tes utilisateurs.

Résultat

Crée un moteur TensorRT FP16, décide à l’aide d’un critère écrit si INT8 en vaut la peine, puis accepte ou rejette chaque moteur selon le mAP et la latence p95.

Parcours accéléré
Si tu connais déjà les bases, voici la version courte.
  1. FP16 d’abord : yolo export model=best.pt format=engine quantize=16, sur le GPU qui l’exécutera.

  2. INT8 seulement si FP16 ne respecte pas le budget : ajoute quantize=8 data=your.yaml avec plus de 500 images représentatives de la production.

  3. Soumets chaque moteur à un contrôle : mAP50-95 à moins de 0,5 point (FP16) ou dans les limites de ton budget INT8, et latence p95 inférieure au budget.

  4. INT8 trop destructeur pour la précision ? L’entraînement conscient de la quantification (train quantize=8) en récupère la majeure partie.

Pratique

Nécessite un GPU NVIDIA

Le code de cette leçon nécessite un GPU NVIDIA avec TensorRT installé. Chaque argument présenté est répertorié pour format=engine dans la documentation du mode d'export.

FP16 est la première étape la plus sûre#

Les GPU NVIDIA à partir de Volta disposent de cœurs tenseurs FP16, et les modèles de détection ont rarement besoin de FP32 à l’inférence. Commence ici :

from ultralytics import YOLO

model = YOLO("yolo26n.pt")  # or runs/detect/pills_v1/weights/best.pt
model.export(format="engine", quantize=16, workspace=4)  # Moteur FP16, espace de travail du constructeur jusqu'à 4 Gio

workspace limite la mémoire GPU que TensorRT peut utiliser pendant la création ; laisse ce paramètre vide pour laisser TensorRT décider. La page d’intégration TensorRT publie ce résultat sur A100 (YOLOv8n, 640 px) :

PrécisionPrédiction, lot de 8 (ms)mAP50-95 sur COCO val
FP320.520.37
FP160.340.37
INT80.280.33

Le modèle est plus ancien que YOLO26, mais la tendance du compromis reste valable : FP16 était environ 1,5× plus rapide sans coût ; INT8 a apporté un gain supplémentaire de 1,2× pour un coût de 4 points. Si FP16 respecte ton budget, déploie-le.

Tu n’as pas de GPU NVIDIA local ? L’onglet Export de la plateforme Ultralytics crée le moteur sur le GPU cloud de ton choix, avec les mêmes options de taille d’image, précision, lot, mode dynamique, NMS et espace de travail :

Onglet Export de modèle de la plateforme Ultralytics présentant TorchScript, ONNX, OpenVINO, TensorRT et CoreML, avec un moteur TensorRT déjà exporté sur un RTX 5090, en imgsz 640 et FP16

Choisis la famille de GPU sur laquelle tu vas déployer : le moteur de la capture d’écran a été créé sur un RTX 5090 et ne fonctionnera que sur cette famille.

INT8 nécessite des données d’étalonnage#

La quantification INT8 mappe les activations de chaque couche sur 256 niveaux. Pour déterminer ces plages, l’exporteur fait passer des images d’étalonnage dans le modèle et enregistre les activations observées ; ces images doivent donc ressembler aux données de production :

from ultralytics import YOLO

model = YOLO("yolo26n.pt")
model.export(
    format="engine",
    quantize=8,
    data="coco128.yaml",  # les images d’étalonnage proviennent de la partition val de ce jeu de données ; utiliser my_dataset/data.yaml
    fraction=1.0,  # part ou nombre de ces images à utiliser
    batch=8,  # des lots d’étalonnage plus importants donnent des plages plus stables
    dynamic=True,  # avec batch=8, le moteur accepte des lots de 1 à 8
    workspace=4,
)

Le coût d’INT8 dépend du modèle. La documentation du mode Export a mesuré les moteurs TensorRT YOLO26 sur COCO val (mAP50-95) :

ModèleMoteur FP32INT8, étalonné (PTQ)INT8 après entraînement conscient de la quantification (QAT)
YOLO26n0.40320.39340.3935
YOLO26s0.47940.44120.4711
YOLO26m0.52690.46960.5137

L’étalonnage seul coûte 1 point à YOLO26n et de 4 à 6 points aux modèles plus grands. Le QAT affine le modèle avec quantize=8 dans train afin que ses poids tolèrent INT8 ; le point de contrôle contient ses propres plages, son export INT8 ne nécessite pas de données d’étalonnage et son score est à 1 ou 2 points de celui de FP32. Voici comment prendre ta décision :

Soumets le moteur à un contrôle avant le déploiement#

Chaque moteur doit réussir les mêmes contrôles sur le GPU de déploiement :

VérificationContrôle
mAP50-95 sur ton jeu de validationÀ moins de 0,5 point de FP32 pour FP16 ; dans les limites de ton budget écrit pour INT8
AP par classeAucune classe ne perd plus d’environ 1 point (les petites classes varient le plus)
Latence p95Sous le budget avec la taille de lot utilisée en production
Seuil opérationnelconf recalculé à partir de la propre courbe F1 du moteur
DéterminismeLa même image donne exactement les mêmes boîtes deux fois de suite
yolo val model=yolo26n.engine data=coco8.yaml  # or my_dataset/data.yaml
yolo benchmark model=yolo26n.pt data=coco8.yaml imgsz=640 format=engine quantize=16

D’où vient le gain de vitesse#

Fusion des couches TensorRT : les couches de convolution, de biais et ReLU séparées du réseau non optimisé deviennent des couches CBR fusionnées dans le réseau optimisé par TensorRT

TensorRT fusionne chaque convolution, biais et ReLU dans un seul noyau (les blocs « CBR » à droite) et supprime les étapes de concaténation, ce qui réduit considérablement le nombre de noyaux lancés par le GPU et la quantité de données transférées. Dans YOLO26, cela accélère les chaînes conv-BN-activation présentes dans tout le réseau, le bloc d’attention (PSA) du backbone et les nombreuses petites opérations de la tête de détection. Si un moteur reste lent, profile-le avec trtexec ou NVIDIA Nsight : une seule couche prend souvent 30 % ou plus du temps.

Pièges#

Calibrer avec les mauvaises données

Symptôme : INT8 perd 1 point sur COCO et 6 sur tes caméras. Solution : calibre avec une partie mise de côté de ton jeu de validation ; NVIDIA recommande au moins 500 images représentatives. Le calibrage varie également selon les appareils : effectue-le donc sur le GPU cible du déploiement.

Conserver le seuil de confiance FP32

Symptôme : le rappel baisse après le passage à INT8 avec la même valeur conf. Solution : INT8 peut modifier les valeurs de confiance ; choisis à nouveau conf à partir de la propre courbe F1 du moteur INT8.

Moteur créé sur le mauvais GPU

Symptôme : le moteur ne peut pas être désérialisé ou s'exécute plus lentement que prévu sur la machine de déploiement. Solution : crée-le sur la famille de GPU de déploiement avec des versions compatibles de TensorRT et de l'environnement d'exécution CUDA, puis livre .onnx pour que les appareils puissent recompiler. Si le calibrage échoue pendant la compilation, augmente workspace ou diminue imgsz ou batch.

Sur Jetson, DeepStream exécute les moteurs obtenus dans un pipeline vidéo accéléré matériellement ; dans un centre de données, Triton Inference Server les met à disposition.

Essayer

Sur un GPU NVIDIA (local ou dans l’onglet Export de la plateforme), crée un moteur FP16 pour ton modèle. Exécute yolo val sur le moteur et sur .pt avec le fichier YAML de ton jeu de données, évalue le moteur sur le GPU de déploiement et rédige un rapport de contrôle d’une page : mAP50-95 pour les deux, écart, latence p95 par rapport à ton budget et décision (déployer FP16, essayer INT8 ou changer la taille du modèle).

Terminé lorsque
Tu as terminé la leçon lorsque tous les éléments suivants sont réunis.
  • Un moteur FP16 existe et a été créé sur la famille de GPU sur laquelle il sera exécuté.

  • Ton rapport de contrôle présente côte à côte le mAP50-95 du moteur et de PyTorch, ainsi que leur latence p95.

  • Ta décision découle du tableau de contrôle et précise ce que tu essaierais ensuite en cas d’échec.

Afficher la solution
from ultralytics import YOLO

if __name__ == "__main__":  # validation starts worker processes on Windows
    data = "coco8.yaml"  # or my_dataset/data.yaml
    model = YOLO("yolo26n.pt")
    engine = model.export(format="engine", quantize=16, workspace=4)

    base = model.val(data=data, plots=False).box.map
    fp16 = YOLO(engine).val(data=data, plots=False).box.map
    print(f"PyTorch {base:.4f}  FP16 engine {fp16:.4f}  gap {abs(base - fp16) * 100:.2f} points")

    # Only if FP16 misses the latency budget:
    # model.export(format="engine", quantize=8, data=data, batch=8, dynamic=True, workspace=4)

Un rapport satisfaisant indique : écart inférieur à 0,5 point, p95 sous le budget, décision déployer FP16. Si le p95 dépasse le budget, exporte en INT8 avec ton propre fichier YAML d’étalonnage, relance les deux mêmes lignes et ne déploie INT8 que si l’écart reste dans les limites du budget défini au préalable ; sinon, essaie le QAT ou un modèle plus petit.

Et ensuite ?

Pas sur NVIDIA ? Ensuite : OpenVINO, l’équivalent d’Intel pour les CPU, et pourquoi tu dois tout de même mesurer les performances sur la cible.