Exporter pour le déploiement
Exporte best.pt vers ONNX, OpenVINO, TensorRT, CoreML, LiteRT ou QNN, puis vérifie que l'export correspond au modèle PyTorch avant de le déployer.
Ton best.pt nécessite Python et PyTorch pour fonctionner ; les téléphones, les navigateurs, les Jetson et les serveurs de production ne les ont généralement pas. Le mode Export convertit le modèle en un fichier autonome utilisable par ces environnements d'exécution, en un seul appel. Le piège : le fait qu'un export se charge ne garantit pas qu'il soit correct, et une comparaison mal faite peut faire paraître défectueux un export correct ou masquer un export défectueux.
Dans cette leçon, tu vas exporter le modèle de pilules vers ONNX, l'exécuter avec la même API YOLO, vérifier qu'il correspond à PyTorch pour les boîtes et le mAP de validation avec des paramètres identiques, puis choisir le format adapté à ta cible : ONNX, OpenVINO, TensorRT, CoreML, LiteRT ou QNN.
Pratique
Exemple pratique : exporter vers ONNX#

yolo export model=runs/detect/pills_v1/weights/best.pt format=onnxPyTorch: starting from 'runs/detect/pills_v1/weights/best.pt' with input shape (1, 3, 320, 320) BCHW and output shape(s) (1, 5, 2100) (5.2 MB)
ONNX: export success ✅ 0.9s, saved as 'runs/detect/pills_v1/weights/best.onnx' (9.3 MB)
Predict: yolo predict task=detect model=runs/detect/pills_v1/weights/best.onnx imgsz=320
Validate: yolo val task=detect model=runs/detect/pills_v1/weights/best.onnx imgsz=320 data=my_dataset/data.yamlLigne par ligne :
input shape (1, 3, 320, 320): une image, 3 canaux couleur, un carré fixe de 320×320 — leimgszutilisé pour l'entraînement, intégré au fichier.output shape(s) (1, 5, 2100): 4 valeurs de boîte plus 1 score de classe pour 2 100 boîtes candidates ; NMS est exécuté en dehors du graphe par défaut.9.3 MB: le fichier ONNX stocke des poids FP32 ; il est donc plus volumineux que le.pten FP16.Predict:/Validate:: des commandes prêtes à l'emploi pour le fichier exporté, avec leimgszapproprié.
Quelques arguments couvrent la plupart des besoins ; le guide d'intégration ONNX répertorie les autres.
| Argument | Par défaut | Utilise-le pour |
|---|---|---|
imgsz | Taille d'entraînement | Exporter avec une autre taille d'entrée fixe, par exemple imgsz=640 |
dynamic | False | Accepter des tailles d'entrée variables au lieu d'une seule forme fixe |
quantize | Aucun (FP32) | 16 pour les poids FP16 (yolo26n.onnx passe de 9.5 MB à 4.8 MB) ; 8 pour INT8 lorsque le format le prend en charge |
nms | Aucun | nms=True intègre NMS au graphe, de sorte que l'environnement d'exécution renvoie les boîtes finales |
Exemple pratique : vérifier que l'export correspond au modèle#
La classe YOLO charge aussi les fichiers exportés ; le code de prédiction présenté précédemment fonctionne donc sans modification. Compare les deux fichiers sur la même image de validation :
from ultralytics import YOLO
image = "my_dataset/images/val/Frame_144.jpg"
pt = YOLO("runs/detect/pills_v1/weights/best.pt")(image, rect=False, verbose=False)[0] # square input, like ONNX
onnx = YOLO("runs/detect/pills_v1/weights/best.onnx")(image, verbose=False)[0]
print(f"pt: {len(pt.boxes)} pills, mean conf {pt.boxes.conf.mean():.3f}")
print(f"onnx: {len(onnx.boxes)} pills, mean conf {onnx.boxes.conf.mean():.3f}")
print(f"max box difference: {(pt.boxes.xyxy - onnx.boxes.xyxy).abs().max():.4f} px")pt: 25 pills, mean conf 0.870
onnx: 25 pills, mean conf 0.870
max box difference: 0.0002 pxMême nombre, même confiance, boîtes identiques à une fraction de pixel près. Passons maintenant à la vérification plus rigoureuse : la validation sur l'ensemble du découpage :
from ultralytics import YOLO
pt = YOLO("runs/detect/pills_v1/weights/best.pt").val(data="my_dataset/data.yaml", rect=False, verbose=False)
onnx = YOLO("runs/detect/pills_v1/weights/best.onnx").val(data="my_dataset/data.yaml", verbose=False)
print(f".pt mAP50-95 {pt.box.map:.4f}")
print(f".onnx mAP50-95 {onnx.box.map:.4f}").pt mAP50-95 0.6570
.onnx mAP50-95 0.6570Identiques. (La validation rectangulaire par défaut du fichier .pt a obtenu 0.659 : le léger écart vient du remplissage de l'entrée, et non de l'export.)
Une fois la correspondance vérifiée, mesure le temps avec yolo benchmark sur l'appareil cible afin de connaître sa vitesse réelle avant le déploiement.
Choisir un format pour ta cible#

| Objectif | Format | Remarques |
|---|---|---|
| Format portable par défaut : serveurs et ordinateurs de bureau sous Linux, Windows et Mac | onnx | ONNX Runtime sur CPU ou GPU ; l'export le plus rapide à vérifier |
| GPU NVIDIA et Jetson | engine (TensorRT) | Le plus rapide sur NVIDIA ; exporte sur l’appareil. Voir Optimiser avec TensorRT |
| Processeurs Intel et iGPU | openvino | Gains de vitesse réels sur CPU grâce aux noyaux Intel. Voir OpenVINO sur CPU |
| Applications pour iPhone, iPad et Mac | coreml | Natif ; utilise l’Apple Neural Engine |
| Android et autres appareils mobiles ou embarqués | litert | INT8 recommandé pour les appareils mobiles |
| NPU Snapdragon | qnn | Accélération Hexagon HTP ; poids INT8 avec activations 16 bits par défaut ; choisis l’architecture HTP avec name |
| Navigateur Web | onnx avec ONNX Runtime Web | Les modèles plus petits sont viables : n et s |
from ultralytics import YOLO
model = YOLO("runs/detect/pills_v1/weights/best.pt")
model.export(format="onnx") # multiplateforme : ONNX Runtime
model.export(format="openvino") # CPU / iGPU Intel
model.export(format="engine", quantize=16) # NVIDIA TensorRT, FP16 (exécution sur le GPU cible)
model.export(format="coreml") # Apple iOS / macOS
model.export(format="litert", quantize=8, data="my_dataset/data.yaml") # Android / périphérie, INT8
model.export(format="qnn", name="73", data="my_dataset/data.yaml") # NPU Qualcomm Snapdragon (HTP v73) ; calibre avec tes propres donnéesChaque export écrit les fichiers à côté des poids : best.onnx, best_openvino_model/, best.engine, et ainsi de suite. Commence par ONNX, même si tu optes finalement pour un autre format : c’est le plus rapide à vérifier et il sert d’entrée à plusieurs autres chaînes d’outils. Le guide des options de déploiement compare tous les formats, et Choisir une cible de déploiement t’aide à prendre ta décision.
La quantification des modèles échange de la précision contre une réduction de taille et un gain de vitesse. FP16 (quantize=16) divise la taille du fichier par deux avec une précision presque inchangée. INT8 (quantize=8) réduit encore la taille et accélère davantage, mais nécessite des images de calibration — des images représentatives que l’export traite pour déterminer les plages de valeurs ; Ultralytics en recommande au moins 300. Valide toujours un modèle INT8 avant sa mise en production : la perte peut être négligeable ou importante selon le modèle et le jeu de calibration.
Éviter ces erreurs#
Symptôme : le modèle .pt détecte 35 pilules dans Frame_144.jpg, tandis que le fichier ONNX en détecte 25, et l'exportation semble défectueuse. Cause : l'inférence PyTorch complète chaque image jusqu'au plus petit rectangle dont les dimensions sont alignées sur le stride (192×320 pour ces images 16:9), tandis qu'un modèle ONNX statique utilise toujours une image carrée de 320×320. Des entrées différentes entraînent des détections de confiance faible différentes. Solution : passe rect=False au modèle .pt pour la comparaison, comme dans parity.py.
Symptôme : tu passes imgsz=640 à best.onnx, mais le journal indique toujours 320x320. Cause : un export statique a une seule taille d'entrée, définie au moment de l'exportation. Solution : exporte à la taille prévue pour l'exécution (imgsz=640) ou exporte avec dynamic=True.
Un .engine créé sur un A100 ne fonctionnera pas sur un Jetson Orin et risque de ne pas fonctionner après une mise à niveau de TensorRT. Exporte sur l'appareil cible, avec la version de TensorRT qui sera utilisée. ONNX est portable ; les moteurs ne le sont pas.
Si tu omets data lors d'un export INT8, Ultralytics affiche un avertissement, puis effectue l'étalonnage sur l'échantillon COCO8 par défaut — huit images qui ne ressemblent en rien à tes pilules. Passe ton propre échantillon : model.export(format="litert", quantize=8, data="my_dataset/data.yaml").
Tu as déployé#
Tu disposes maintenant d’un best.pt entraîné, de résultats de validation comparés à une référence, d’un fichier exporté pour ton environnement d’exécution et de la preuve que l’export correspond à l’original. C’est le cycle complet — données, entraînement, validation, export, déploiement — que les équipes en production exécutent régulièrement. Ultralytics YOLO en production part de ton export vérifié et couvre les environnements d’exécution optimisés, les pipelines de suivi, le traitement de plusieurs flux et la surveillance.
Afficher la solution
from ultralytics import YOLO
# Train
model = YOLO("yolo26n.pt")
model.train(data="my_dataset/data.yaml", epochs=10, imgsz=320, name="pills_e2e")
# Validate
metrics = model.val()
print(f"mAP50-95 = {metrics.box.map:.3f}") # 0.659
# Export
model.export(format="onnx")parity.py: pt 25 pills, onnx 25 pills, max box difference 0.0002 px
without rect: pt 35 pills (192x320 input) vs onnx 25 (320x320): input mismatch, not an export bug
val_export.py: .pt 0.6570, .onnx 0.6570
Target: Intel laptop CPU -> openvino, for faster CPU inference than ONNX Runtime