Comprendre la détection de bout en bout dans Ultralytics YOLO26#
Les modèles de style de détection YOLO26 — détection, segmentation, pose et OBB — sont sans NMS par défaut : ils fournissent les détections finales directement à partir du modèle, sans étape de post-traitement par Suppression Non Maximale (NMS). Les modèles précédents tels que YOLOv8 et YOLO11 produisent des milliers de prédictions superposées qu'une étape de NMS distincte doit filtrer, ce qui ajoute de la latence, complique les graphes d'exportation et peut se comporter de manière incohérente selon les plateformes matérielles.
C'est ce qu'on appelle la détection d'objets de bout en bout, et elle est activée par défaut. Le résultat est un pipeline de déploiement plus simple et une latence plus faible — YOLO26n s'exécute jusqu'à 43 % plus vite que YOLO11n sur une inférence ONNX sur CPU (Intel Xeon CPU @ 2.00 GHz).
Ce guide t'explique ce qui a changé, si tu dois mettre à jour ton code, quels formats d'exportation prennent en charge l'inférence de bout en bout, et comment migrer en douceur depuis les anciens modèles YOLO.
Pour en savoir plus sur la motivation derrière ce changement architectural, consulte l'article du blog Ultralytics expliquant pourquoi YOLO26 supprime la NMS.
- Tu utilises l'API ou la CLI d'Ultralytics ? Aucun changement nécessaire — remplace simplement le nom de ton modèle par
yolo26n.pt. - Tu utilises du code d'inférence personnalisé (ONNX Runtime, TensorRT, etc.) ? Mets à jour ton post-traitement : la sortie de détection est désormais
(N, 300, 6)au formatxyxy, sans besoin de NMS. Les autres tâches ajoutent des données supplémentaires (coefficients de masque, points clés ou angle). - Tu exportes ? La plupart des formats conservent nativement la sortie de bout en bout, quelques-uns reviennent à la sortie traditionnelle, et la quantification peut la désactiver — consulte Compatibilité des formats d'exportation.
Comment fonctionne la détection de bout en bout#
YOLO26 utilise une architecture à double tête pendant l'entraînement. Les deux têtes partagent le même backbone et le même neck, mais produisent des sorties de manières différentes :
| Tête | Objectif | Sortie de détection | Post-traitement |
|---|---|---|---|
| One-to-One (par défaut) | Inférence de bout en bout | (N, 300, 6) | Seuil de confiance uniquement |
| One-to-Many | Sortie YOLO traditionnelle | (N, nc + 4, 8400) | Nécessite le NMS |
Les formes ci-dessus concernent la détection, où N est la taille du lot, nc est le nombre de classes (par exemple, 80 pour COCO), et le compte d'ancres de 8400 est la valeur à imgsz=640. D'autres tâches étendent la sortie biunivoque avec des données supplémentaires par détection :
| Tâche | Sortie de bout en bout | Données supplémentaires |
|---|---|---|
| Détection | (N, 300, 6) | — |
| Segmentation d'instances | (N, 300, 6 + nm) + proto (N, nm, H, W) | coefficients de masque nm (par défaut 32) |
| Pose | (N, 300, 57) | 17 points clés × 3 (x, y, visibilité) |
| OBB | (N, 300, 7) | Angle de rotation |
Pendant l'entraînement, les deux têtes s'exécutent simultanément : la tête un à plusieurs fournit un signal d'apprentissage plus riche, tandis que la tête un à un apprend à produire des prédictions propres et sans chevauchement. Pendant l'inférence et l'exportation, seule la tête un à un est active par défaut, produisant jusqu'à 300 détections par image au format [x1, y1, x2, y2, confidence, class_id].
Lorsque tu appelles model.fuse(), les couches Conv + BatchNorm sont fusionnées pour une inférence plus rapide et, sur les modèles de bout en bout, la tête un à plusieurs est également supprimée, ce qui réduit la taille du modèle et les FLOPs. Pour plus de détails sur l'architecture à double tête, consulte la page du modèle YOLO26.
Dois-je modifier mon code ?#
Utilisation de l'API Python ou de la CLI Ultralytics#
Aucun changement nécessaire. Si tu utilises l'API Python Ultralytics ou la CLI standard, tout fonctionne automatiquement — la prédiction, la validation et l'exportation gèrent toutes les modèles de bout en bout dès leur sortie de la boîte.
from ultralytics import YOLO
# Load a YOLO26 model
model = YOLO("yolo26n.pt")
# Predict — no NMS step, no code changes
results = model.predict("image.jpg")Utilisation d'un code d'inférence personnalisé#
Oui, le format de sortie est différent. Si tu as écrit une logique de post-traitement personnalisée pour YOLOv8 ou YOLO11 (par exemple, lors de l'exécution d'une inférence avec ONNX Runtime ou TensorRT), tu devras la mettre à jour pour gérer la nouvelle forme de sortie :
| YOLOv8 / YOLO11 | YOLO26 (bout en bout) | |
|---|---|---|
| Sortie de détection | (N, nc + 4, 8400) | (N, 300, 6) |
| Format de boîte | xywh (centre x, centre y, largeur, hauteur) | xyxy (coin supérieur gauche x, coin supérieur gauche y, coin inférieur droit x, coin inférieur droit y) |
| Disposition | Coordonnées de boîte + scores de classe par ancrage | [x1, y1, x2, y2, conf, class_id] |
| NMS requis | Oui | Non |
| Post-traitement | NMS + filtre de confiance | Filtre de confiance uniquement |
Pour les tâches de segmentation, de pose et d'OBB, YOLO26 ajoute des données spécifiques à chaque détection — consulte le tableau des formes de sortie.
Avec les modèles de bout en bout, le post-traitement devient beaucoup plus simple — par exemple, lors de l'utilisation d'ONNX Runtime :
import onnxruntime as ort
# Load and run the exported end-to-end model
session = ort.InferenceSession("yolo26n.onnx")
output = session.run(None, {session.get_inputs()[0].name: input_tensor})
# End-to-end output: (batch, 300, 6) → [x1, y1, x2, y2, confidence, class_id]
detections = output[0][0] # first image in batch
detections = detections[detections[:, 4] > 0.25] # confidence filter, no NMSPassage à la tête One-to-Many#
Si tu as besoin du format de sortie YOLO traditionnel (par exemple, pour réutiliser du code de post-traitement basé sur la NMS existant), tu peux basculer vers la tête un à plusieurs lorsqu'elle est disponible en définissant end2end=False :
from ultralytics import YOLO
model = YOLO("yolo26n.pt")
# Prediction with NMS (traditional behavior)
results = model.predict("image.jpg", end2end=False)
# Validation with NMS
metrics = model.val(data="coco.yaml", end2end=False)
# Export without end-to-end
model.export(format="onnx", end2end=False)Compatibilité des formats d'exportation#
La plupart des formats d'exportation prennent en charge l'inférence de bout en bout par défaut, notamment ONNX, TensorRT, CoreML, OpenVINO, LiteRT et MNN.
Les formats suivants ne prennent pas en charge le mode de bout en bout et basculent automatiquement sur la tête un à plusieurs : NCNN, RKNN, PaddlePaddle, ExecuTorch, IMX, Edge TPU et Qualcomm QNN.
Pour Hailo, l'exportateur choisit le chemin de sortie à partir de la tête chargée plutôt qu'à partir d'un argument, donc end2end est rejeté s'il est passé : un modèle de détection YOLO26 par défaut conserve ses sorties un-à-un sans NMS, tandis qu'un point de contrôle dont la tête est déjà end2end=False compile le chemin traditionnel avec le NMS de HailoRT.
TensorRT et LiteRT prennent en charge le bout en bout, mais la branche est désactivée automatiquement sur TensorRT antérieur à 8.5.0, sur TensorRT 10.3.0 avec quantize=8 sur JetPack 6, et sur LiteRT avec quantize=8 ou quantize="w8a16". Chaque cas enregistre un avertissement et exporte la tête un-à-plusieurs.
Compromis entre précision et vitesse#
La détection de bout en bout offre des avantages de déploiement significatifs avec un impact minime sur la précision :
| Métrique | Bout en bout (par défaut) | Un à plusieurs + NMS (end2end=False) |
|---|---|---|
| mAPval COCO | 0,6-0,8 en moins | Référence |
| Post-traitement | Filtre de confiance uniquement | Pipeline NMS complet |
| Complexité du déploiement | Minimale | Nécessite l'implémentation du NMS |
À travers les cinq échelles de détection, la tête un-à-un coûte 0,6 à 0,8 de mAP sur COCO — de 40,9 à 40,1 pour YOLO26n et de 57,5 à 56,9 pour YOLO26x — en échange de la suppression totale de la passe NMS. Si la précision maximale est ta priorité, reviens à la tête un-à-plusieurs avec end2end=False.
Consulte les métriques de performance de YOLO26 pour des benchmarks détaillés sur toutes les tailles de modèles (n, s, m, l, x).
Migration depuis YOLOv8 ou YOLO11#
Si tu mets à niveau un projet existant vers YOLO26 :
- Utilisateurs de l'API / CLI d'Ultralytics : Aucun changement nécessaire — mets simplement à jour le nom du modèle par
yolo26n.pt(ouyolo26n-seg.pt,yolo26n-pose.pt,yolo26n-obb.pt) - Code de post-traitement personnalisé : Mets à jour pour gérer les nouvelles formes de sortie —
(N, 300, 6)pour la détection, ainsi que les données spécifiques aux tâches de segmentation, de pose et d'OBB. Note également le changement de format des boîtes dexywhversxyxy - Pipelines d'exportation : Vérifie la section compatibilité des formats pour ton format cible
- TensorRT inférieur à 8.5.0 : le bout en bout est désactivé à toutes les précisions — mets à niveau TensorRT vers la version 8.5.0 ou ultérieure pour le conserver
- Exportations quantifiées : TensorRT 10.3.0 avec
quantize=8sur JetPack 6, et LiteRT avecquantize=8ouquantize="w8a16", désactivent automatiquement le bout en bout — exporte à une précision supérieure pour le conserver - Exportations FP16 : Si tu as besoin de toutes les sorties en FP16, exporte avec
end2end=False— consulte pourquoi output0 reste en FP32 - iOS / CoreML : Le mode de bout en bout est entièrement pris en charge. Si tu as besoin de la prise en charge d'Xcode Preview, utilise
end2end=Falseavecnms=True - Périphériques Edge (NCNN, RKNN) : Ces formats reviennent automatiquement en mode one-to-many, alors inclut le NMS dans ton pipeline sur l'appareil
Conclusion#
La détection de bout en bout est activée par défaut dans YOLO26 et ne nécessite aucune modification de code si tu utilises l'API Python Ultralytics ou la CLI. Seuls les pipelines de post-traitement personnalisés doivent être mis à jour pour lire la nouvelle sortie (N, 300, 6) et supprimer l'étape de NMS — à l'exception des formats d'exportation qui reviennent à une sortie un à plusieurs (tels que NCNN et RKNN), qui nécessitent toujours la NMS sur l'appareil. Pour des benchmarks détaillés de vitesse et de précision sur toutes les tailles de modèles, consulte la page du modèle YOLO26, et pour l'ensemble des options et formats d'exportation, consulte la documentation du mode Export.
FAQ#
Non. Ces options s'excluent mutuellement. Si tu définis
nms=Truesur un modèle de bout en bout lors de l'exportation, il sera automatiquement forcé ànms=Falseavec un avertissement. La tête de bout en bout gère déjà le filtrage des doublons en interne, la NMS externe est donc inutile.Cependant,
end2end=Falsecombiné avecnms=Trueest une configuration valide — cela intègre la NMS traditionnelle dans le graphe d'exportation. Cela peut être utile pour les exportations CoreML car cela te permet d'utiliser directement la fonction Preview dans Xcode avec le modèle de détection.Le paramètre
max_det(par défaut : 300) définit le nombre maximal de détections renvoyées par image. Tu peux l'ajuster au moment de l'inférence ou de l'exportation :model.predict("image.jpg", max_det=100) # fewer detections model.export(format="onnx", max_det=500) # more detections for dense scenesLa valeur est intégrée dans un graphe exporté en tant que top-k de la tête, de sorte que
max_det=500élargit le tenseur de sortie jusqu'à(1, 500, 6), plafonné par le nombre d'ancres.Oui, c'est le format de sortie de bout en bout attendu pour la détection : taille du lot de 1, jusqu'à 300 détections, chacune avec 6 valeurs
[x1, y1, x2, y2, confidence, class_id]. Filtre simplement par seuil de confiance — aucun NMS n'est nécessaire.Pour d'autres tâches, la forme de la sortie diffère :
Tâche Forme de la sortie Description Détection (1, 300, 6)[x1, y1, x2, y2, conf, class_id]Segmentation d'instance (1, 300, 38)+(1, 32, 160, 160)6 valeurs de boîte + 32 coefficients de masque, plus un tenseur de masque prototype Pose (1, 300, 57)6 valeurs de boîte + 17 points clés × 3 (x, y, visibilité) OBB (1, 300, 7)6 valeurs de boîte + 1 angle de rotation Oui. Les variantes de tâches de type détection de YOLO26 — détection, segmentation d'instances, estimation de pose et détection d'objets orientés (OBB) — prennent en charge l'inférence de bout en bout par défaut. Le repli
end2end=Falseest également disponible pour ces tâches.Chaque tâche étend la sortie de détection de base avec des données spécifiques à la tâche ; les formes de sortie
yolo26n.pt,yolo26n-seg.pt,yolo26n-pose.ptetyolo26n-obb.ptsont répertoriées sous Comment fonctionne la détection de bout en bout.
Tu peux vérifier à partir de l'API Python d'Ultralytics ou à partir des métadonnées du modèle ONNX exporté :
Les deux vérifications répondent à des questions différentes : les métadonnées ONNX enregistrent la tête qui a été exportée, tandis que
predictor.model.end2endindique que la sortie du backend est déjà post-traitée et ne nécessite aucun NMS externe. Elles sont en désaccord pour un modèle exporté avecend2end=False, nms=True, qui utilise la tête un-à-plusieurs mais intègre le NMS dans le graphe et produit également(1, 300, 6)— de sorte que ni l'indicateur ni la forme de sortie seuls n'identifient la tête. Pour d'autres formes de tâches, consulte la FAQ sur les formes de sortie.