YOLO Vision 2026 :

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.

Résumé rapide
  • 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 format xyxy, 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êteObjectifSortie de détectionPost-traitement
One-to-One (par défaut)Inférence de bout en bout(N, 300, 6)Seuil de confiance uniquement
One-to-ManySortie 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âcheSortie de bout en boutDonné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.

Aucun changement de code requis avec l'API Ultralytics
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 / YOLO11YOLO26 (bout en bout)
Sortie de détection(N, nc + 4, 8400)(N, 300, 6)
Format de boîtexywh (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)
DispositionCoordonnées de boîte + scores de classe par ancrage[x1, y1, x2, y2, conf, class_id]
NMS requisOuiNon
Post-traitementNMS + filtre de confianceFiltre 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 NMS

Passage à 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 :

Utilisation de la tête one-to-many pour une sortie traditionnelle basée sur NMS
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.

Que se passe-t-il lorsque le mode bout en bout n'est pas pris en charge

Lorsque tu exportes vers l'un de ces formats, Ultralytics bascule automatiquement vers la tête un-à-plusieurs et enregistre un avertissement. 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, 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.

La quantification et la version du runtime peuvent désactiver le bout en bout

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étriqueBout en bout (par défaut)Un à plusieurs + NMS (end2end=False)
mAPval COCO0,6-0,8 en moinsRéférence
Post-traitementFiltre de confiance uniquementPipeline NMS complet
Complexité du déploiementMinimaleNé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 (ou yolo26n-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 de xywh vers xyxy
  • 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=8 sur JetPack 6, et LiteRT avec quantize=8 ou quantize="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=False avec nms=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=True sur un modèle de bout en bout lors de l'exportation, il sera automatiquement forcé à nms=False avec 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=False combiné avec nms=True est 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 scenes

    La 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âcheForme de la sortieDescription
    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
  • Tu peux vérifier à partir de l'API Python d'Ultralytics ou à partir des métadonnées du modèle ONNX exporté :

    Vérifier si un modèle est end-to-end
    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 enabled

    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.end2end indique 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é avec end2end=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.

  • 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=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 ; les formes de sortie yolo26n.pt, yolo26n-seg.pt, yolo26n-pose.pt et yolo26n-obb.pt sont répertoriées sous Comment fonctionne la détection de bout en bout.

Commentaires