Link to this sectionComprendre la détection de bout en bout dans Ultralytics YOLO26#
Link to this sectionIntroduction#
Si tu passes à YOLO26 depuis un modèle antérieur comme YOLOv8 ou YOLO11, l'un des changements les plus importants que tu remarqueras est la suppression du Non-Maximum Suppression (NMS). Les modèles YOLO traditionnels produisent des milliers de prédictions qui se chevauchent, nécessitant une étape de post-traitement NMS distincte pour filtrer et obtenir les détections finales. Cela ajoute de la latence, complique les graphiques d'exportation et peut se comporter de manière incohérente sur différentes plateformes matérielles.
YOLO26 adopte une approche différente. Il génère directement les détections finales depuis le modèle — aucun filtrage externe n'est requis. C'est ce qu'on appelle la détection d'objets de bout en bout, et elle est activée par défaut dans tous les modèles YOLO26. Le résultat est un pipeline de déploiement plus simple, une latence plus faible et jusqu'à 43 % d'inférence plus rapide sur les CPU.
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 un aperçu approfondi de la motivation derrière ce changement architectural, consulte l'article de blog d'Ultralytics sur les raisons pour lesquelles YOLO26 supprime le NMS et comment cela modifie le déploiement.
- Tu utilises l'API ou la CLI d'Ultralytics ? Aucun changement n'est nécessaire — remplace simplement le nom de ton modèle par
yolo26n.pt. - Tu utilises un 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, aucun NMS n'est requis. Les autres tâches ajoutent des données supplémentaires (coefficients de masque, points clés ou angle). - Exportation ? La plupart des formats prennent en charge nativement la sortie de bout en bout. Cependant, quelques formats (NCNN, RKNN, PaddlePaddle, ExecuTorch, IMX, Edge TPU et QNN) reviennent automatiquement à la sortie traditionnelle en raison de contraintes d'opérateurs non pris en charge (par exemple,
torch.topk). Les flux de travail Hailo HEF compilent depuis ONNX avec des scripts spécifiques à Hailo, vérifie donc la tête de détection et la configuration NMS pour ton modèle.
Link to this sectionComment 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. D'autres tâches étendent la sortie one-to-one 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'instance | (N, 300, 6 + nm) + proto (N, nm, H, W) | Coefficients de masque nm (32 par défaut) |
| 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 fonctionnent simultanément — la tête one-to-many fournit un signal d'apprentissage plus riche, tandis que la tête one-to-one apprend à produire des prédictions propres et sans chevauchement. Pendant l'inférence et l'exportation, seule la tête one-to-one 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(), il fusionne les couches Conv + BatchNorm pour une inférence plus rapide et, sur les modèles de bout en bout, supprime également la tête one-to-many — réduisant 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.
Link to this sectionDois-je modifier mon code ?#
Link to this sectionUtilisation de l'API Python ou de la CLI Ultralytics#
Aucun changement nécessaire. Si tu utilises l'API Python Ultralytics standard ou la CLI, tout fonctionne automatiquement — la prédiction, la validation et l'exportation gèrent nativement les modèles de bout en bout.
from ultralytics import YOLO
# Load a YOLO26 model
model = YOLO("yolo26n.pt")
# Predict — no NMS step, no code changes
results = model.predict("image.jpg")Link to this sectionUtilisation 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 (x centre, y centre, largeur, hauteur) | xyxy (x haut-gauche, y haut-gauche, x bas-droite, y bas-droite) |
| 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, pose et OBB, YOLO26 ajoute des données spécifiques à la tâche à chaque détection — voir le tableau des formes de sortie ci-dessus.
Où N est la taille du batch et nc est le nombre de classes (par exemple, 80 pour COCO).
Avec les modèles de bout en bout, le post-traitement devient beaucoup plus simple — par exemple, lors de l'utilisation de 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] > conf_threshold] # confidence filter — that's it!Link to this sectionPassage à la tête One-to-Many#
Si tu as besoin du format de sortie YOLO traditionnel (par exemple, pour réutiliser un code de post-traitement basé sur le NMS existant), tu peux passer à la tête one-to-many à tout moment 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)Link to this sectionCompatibilité des formats d'exportation#
La plupart des formats d'exportation prennent en charge l'inférence de bout en bout nativement, notamment ONNX, TensorRT, CoreML, OpenVINO, TFLite, TF.js et MNN.
Les formats suivants ne prennent pas en charge le mode bout en bout et reviennent automatiquement à la tête one-to-many : NCNN, RKNN, PaddlePaddle, ExecuTorch, IMX, Edge TPU et Qualcomm QNN.
Lorsque tu exportes vers l'un de ces formats, Ultralytics passe automatiquement à la tête one-to-many et enregistre un avertissement — aucune intervention manuelle n'est nécessaire. Cela signifie que tu auras besoin du NMS dans ton pipeline d'inférence pour ces formats, tout comme avec YOLOv8 ou YOLO11.
Pour Hailo HEF, l'étape de compilation a lieu en dehors de model.export(format=...) après une exportation ONNX. Utilise les logs DFC de Hailo, le script de modèle .alls et le JSON NMS qui correspondent exactement à ton modèle de détection ; si un graphique YOLO26 de bout en bout n'est pas pris en charge par ta chaîne d'outils Hailo, exporte le modèle ONNX avec end2end=False et compile la tête de détection traditionnelle.
TensorRT prend en charge le mode bout en bout, mais il est désactivé automatiquement lors de l'exportation avec int8=True sur TensorRT 10.3.0 avec JetPack 6.
Link to this sectionCompromis entre précision et vitesse#
La détection de bout en bout offre des avantages de déploiement significatifs avec un impact minimal sur la précision :
| Métrique | Bout en bout (par défaut) | One-to-Many + NMS (end2end=False) |
|---|---|---|
| Vitesse d'inférence CPU | Jusqu'à 43 % plus rapide | Référence |
| Impact sur le mAP | ~0,5 mAP de moins | Égale ou dépasse YOLO11 |
| Post-traitement | Filtre de confiance uniquement | Pipeline NMS complet |
| Complexité du déploiement | Minimale | Nécessite l'implémentation du NMS |
Pour la plupart des applications réelles, la différence de ~0,5 mAP est négligeable, surtout si l'on considère les gains de vitesse et de simplicité. Si la précision maximale est ta priorité absolue, tu peux toujours revenir à la tête one-to-many en utilisant 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).
Link to this sectionMigration depuis YOLOv8 ou YOLO11#
Si tu mets à niveau un projet existant vers YOLO26, voici une liste de contrôle rapide pour assurer une transition en douceur :
- Utilisateurs de l'API / CLI 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, plus les données spécifiques à la tâche pour la segmentation, la pose et l'OBB. Note également le changement de format de boîte dexywhversxyxy - Pipelines d'exportation : Vérifie la section compatibilité des formats ci-dessus pour ton format cible
- TensorRT + INT8 : Sur JetPack 6, TensorRT 10.3.0 désactive automatiquement le mode bout en bout avec
int8=True— utilise une version différente de TensorRT pour conserver le mode bout en bout - Exportations FP16 : Si tu as besoin de toutes les sorties en FP16, exporte avec
end2end=False— vois pourquoi output0 reste en FP32 - iOS / CoreML : Le mode bout en bout est entièrement pris en charge. Si tu as besoin de la prise en charge de l'aperçu Xcode, 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
Link to this sectionFAQ#
Link to this sectionPuis-je utiliser end2end=True et nms=True ensemble ?#
Non. Ces options sont mutuellement exclusives. Si tu définis nms=True sur un modèle de bout en bout pendant l'exportation, il sera automatiquement forcé sur nms=False avec un avertissement. La tête de bout en bout gère déjà le filtrage des doublons en interne, le NMS externe est donc inutile.
Cependant, end2end=False combiné avec nms=True est une configuration valide — cela intègre le NMS traditionnel dans le graphique d'exportation. Cela peut être utile pour les exportations CoreML car cela te permet d'utiliser directement la fonction Aperçu dans Xcode avec le modèle de détection.
Link to this sectionQue contrôle le paramètre max_det dans les modèles de bout en bout (end-to-end) ?#
Le paramètre max_det (par défaut : 300) définit le nombre maximal de détections que la tête one-to-one peut générer 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, slightly faster
model.export(format="onnx", max_det=500) # more detections for dense scenesNote que les points de contrôle (checkpoints) YOLO26 par défaut ont été entraînés avec max_det=300. Bien que tu puisses augmenter cette valeur, la tête one-to-one a été optimisée durant l'entraînement pour produire jusqu'à 300 détections propres. Par conséquent, les détections au-delà de cette limite pourraient être de moindre qualité. Si tu as besoin de plus de 300 détections par image, envisage un réentraînement avec une valeur max_det plus élevée.
Link to this sectionMon modèle ONNX exporté produit (1, 300, 6) — est-ce correct ?#
Oui, c'est le format de sortie end-to-end attendu pour la détection : une batch size de 1, jusqu'à 300 détections, chacune avec 6 valeurs [x1, y1, x2, y2, confidence, class_id]. Filtre simplement par seuil de confiance et le tour est joué — 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 |
Link to this sectionComment vérifier si mon modèle exporté est de type end-to-end ?#
Tu peux vérifier en utilisant l'API Python d'Ultralytics ou en inspectant directement les métadonnées du modèle ONNX exporté :
from ultralytics import YOLO
model = YOLO("yolo26n.onnx")
model.predict(verbose=False) # run predict to setup predictor first
print(model.predictor.model.end2end) # True if end-to-end is enabledAlternativement, vérifie la forme de la sortie — les modèles de détection end-to-end produisent (1, 300, 6), tandis que les modèles traditionnels produisent (1, nc + 4, 8400). Pour les formes d'autres tâches, consulte la FAQ sur les formes de sortie.
Link to this sectionLe mode end-to-end est-il pris en charge pour les tâches de segmentation d'instance, de pose et d'OBB ?#
Oui. Les variantes de tâches de style détection de YOLO26 — détection, segmentation d'instance, estimation de pose et détection d'objets orientés (OBB) — prennent en charge l'inférence end-to-end par défaut. Le recours à end2end=False est é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 :
| Tâche | Modèle | Sortie de bout en bout |
|---|---|---|
| Détection | yolo26n.pt | (N, 300, 6) |
| Segmentation d'instance | yolo26n-seg.pt | (N, 300, 38) + proto (N, 32, 160, 160) |
| Pose | yolo26n-pose.pt | (N, 300, 57) |
| OBB | yolo26n-obb.pt | (N, 300, 7) |