Comprendre la détection de bout en bout dans Ultralytics
Introduction
Si vous passez à YOLO26 depuis un modèle antérieur tel que YOLOv8 ou YOLO11, l'un des changements les plus notables que vous remarquerez est la suppression de la suppression non maximale (NMS). YOLO traditionnels produisent des milliers de prédictions qui se chevauchent et nécessitent une étape NMS distincte pour filtrer les détections finales. Cela ajoute de la latence, complique les graphiques d'exportation et peut entraîner un comportement incohérent selon les différentes plateformes matérielles.
YOLO26 adopte une approche différente. Il génère les détections finales directement à partir du modèle, sans nécessiter de filtrage externe. Cette technique, appelée « détection d'objets de bout en bout », est activée par défaut dans tous les modèles YOLO26. Il en résulte un processus de déploiement simplifié, une latence réduite et une inférence jusqu'à 43 % plus rapide sur les processeurs.
Ce guide vous explique en détail les changements apportés, si vous devez mettre à jour votre code, quels formats d'exportation prennent en charge l'inférence de bout en bout, et comment migrer en douceur depuis YOLO anciens YOLO .
Pour mieux comprendre les raisons qui ont motivé ce changement architectural, consultez l'articleUltralytics expliquant pourquoi YOLO26 supprime NMS.
Résumé rapide
- Utilisez-vous Ultralytics ou CLI Ultralytics ? Aucune modification n'est nécessaire — il suffit de remplacer le nom de votre modèle par
yolo26n.pt. - Utilisez-vous du code d'inférence personnalisé (ONNX , TensorRT, etc.) ? Mettez à jour votre post-traitement — les résultats de la détection sont désormais
(N, 300, 6)dansxyxyformat, aucun NMS . D'autres tâches ajoutent des données supplémentaires (coefficients de masquage, points clés ou angle). - Vous exportez ? La plupart des formats prennent en charge nativement la sortie de bout en bout. Cependant, certains formats (NCNN, RKNN, PaddlePaddle, ExecuTorch, IMX et Edge TPU) basculent automatiquement vers la sortie traditionnelle en raison de contraintes d'opérateurs non prises en charge (par exemple,
torch.topk).
Comment fonctionne la détection de bout en bout
YOLO26 utilise une architecture à deux têtes pendant l'entraînement. Les deux têtes partagent le même réseau de base et le même « cou », mais génèrent des résultats de manière différente :
| Tête | Objectif | Sortie de détection | Post-traitement |
|---|---|---|---|
| Un-à-un (par défaut) | Inférence de bout en bout | (N, 300, 6) | Seuil de confiance uniquement |
| Un-à-plusieurs | YOLO classique | (N, nc + 4, 8400) | Nécessite un système de gestion du réseau ( NMS) |
Les formes ci-dessus servent à la détection. D'autres tâches complètent cette sortie « un-à-un » en fournissant des données supplémentaires pour chaque détection :
| Tâche | Résultat de bout en bout | Données supplémentaires |
|---|---|---|
| Détection | (N, 300, 6) | — |
| Segmentation | (N, 300, 6 + nm) + proto (N, nm, H, W) | nm coefficients de masquage (valeur 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 fonctionnent simultanément — la tête un-vers-plusieurs fournit un signal d'apprentissage plus riche, tandis que la tête un-vers-un apprend à produire des prédictions claires et non superposées. Pendant inférence et export, seul le tête-à-tête est activée par défaut, générant jusqu'à 300 détections par image au format [x1, y1, x2, y2, confidence, class_id].
Lorsque vous appelez model.fuse(), il plie les couches Conv + BatchNorm pour une inférence plus rapide et, sur les modèles de bout en bout, supprime également la tête un-à-plusieurs — réduisant la taille du modèle et les FLOPs. Pour plus de détails sur l'architecture à double tête, voir le Page du modèle YOLO26.
Dois-je modifier mon code ?
Utilisation dePython ou de l'interface CLI Ultralytics
Aucune modification nécessaire. Si vous utilisez l'API python Ultralytics standard ou la CLI, tout fonctionne automatiquement — la prédiction, la validation et l'exportation gèrent toutes les modèles de bout en bout prêts à l'emploi.
L'Ultralytics ne nécessite aucune modification du code
from ultralytics import YOLO
# Load a YOLO26 model
model = YOLO("yolo26n.pt")
# Predict — no NMS step, no code changes
results = model.predict("image.jpg")
yolo predict model=yolo26n.pt source=image.jpg
Utilisation d'un code d'inférence personnalisé
Oui, le format de sortie est différent. Si vous avez écrit une logique de post-traitement personnalisée pour YOLOv8 ou YOLO11 (par exemple, lors de l'exécution de l'inférence avec ONNX Runtime ou TensorRT), vous devrez la mettre à jour pour gérer la nouvelle forme de sortie :
| YOLOv8 YOLO11 | YOLO26 (de 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 (x en haut à gauche, y en haut à gauche, x en bas à droite, y en bas à droite) |
| Mise en page | Coordonnées de boîte + scores de classe par ancre | [x1, y1, x2, y2, conf, class_id] |
| NMS | 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 tâche à chaque détection — voir le tableau des formats de sortie ci-dessus.
Où N est le taille de lot et nc correspond au 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, lorsqu'on utilise ONNX :
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!
Passage à la tête « un-à-plusieurs »
Si vous avez besoin du format YOLO traditionnel (par exemple, pour réutiliser du code de post-traitement existant NMS), vous pouvez à tout moment passer à la tête « one-to-many » en définissant end2end=False:
Utilisation de la tête « un-à-plusieurs » pour la sortie traditionnelle 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)
yolo predict model=yolo26n.pt source=image.jpg end2end=False
yolo val model=yolo26n.pt data=coco.yaml end2end=False
yolo export model=yolo26n.pt 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 dès leur installation, notamment ONNX, TensorRT, CoreML, OpenVINO, TFLite, TF.js et MNN.
Les formats suivants ne prennent pas en charge la configuration « de bout en bout » et basculent automatiquement vers la configuration « un-à-plusieurs » : NCNN, RKNN, PaddlePaddle, ExecuTorch, IMX et Edge TPU.
Que se passe-t-il lorsque le chiffrement de bout en bout n'est pas pris en charge ?
Lorsque vous exportez vers l'un de ces formats, Ultralytics bascule Ultralytics vers l'en-sortie et génère un avertissement — aucune intervention manuelle n'est nécessaire. Cela signifie que vous aurez besoin de NMS votre pipeline d'inférence pour ces formats, tout comme avec YOLOv8 ou YOLO11.
TensorRT INT8
TensorRT prend en charge le traitement de bout en bout, mais c'est désactivé automatiquement lors de l'exportation avec int8=True sur TensorRT .3.0.
Compromis entre précision et vitesse
La détection de bout en bout offre des avantages considérables en matière de déploiement, tout en ayant un impact minimal sur la précision:
| Métrique | De bout en bout (par défaut) | Un-à-plusieurs + NMSend2end=False) |
|---|---|---|
| Vitesse d'inférence CPU | Jusqu'à 43 % plus rapide | Référence |
| mAP | d'environ 0,5 mAP | Égale ou dépasse YOLO11 |
| Post-traitement | Filtre de confiance uniquement | NMS complet |
| Complexité du déploiement | Minimal | Nécessite NMS ) |
Pour la plupart des applications concrètes, la valeur d'environ 0,5 mAP la différence est négligeable, surtout si l'on considère les gains de vitesse et de simplicité. Si la précision maximale est votre priorité absolue, vous pouvez toujours revenir à la tête un-à-plusieurs en utilisant end2end=False.
Consultez les indicateurs de performance de YOLO26 pour obtenir des résultats de tests comparatifs détaillés pour toutes les tailles de modèles (n, s, m, l, x).
Migration depuis YOLOv8 YOLO11
Si vous mettez à niveau un projet existant vers YOLO26, voici une liste de contrôle rapide pour garantir une transition en douceur :
- CLI de Ultralytics / de l'interface CLI Ultralytics : Aucune modification n'est nécessaire — il suffit de mettre à jour le nom du modèle pour
yolo26n.pt(ouyolo26n-seg.pt,yolo26n-pose.pt,yolo26n-obb.pt) - Code de post-traitement personnalisé : Mise à jour permettant de prendre en charge les nouveaux formats de sortie —
(N, 300, 6)pour la détection, ainsi que des données spécifiques à la tâche pour segmentation, pose, et OBB. Notez également le changement de format de boîte dexywhàxyxy - Pipelines d'exportation : Consultez la section compatibilité des formats ci-dessus pour votre format cible
- TensorRT + INT8 : Vérifiez que votre version de TensorRT est >10.3.0 pour un support de bout en bout
- Exportations FP16 : Si vous souhaitez que toutes les sorties soient au format FP16, exportez avec
end2end=False— voir Pourquoi la sortie 0 reste en FP32 ? - iOS CoreML: La prise en charge de bout en bout est entièrement assurée. Si vous avez besoin de la prise en charge de Xcode Preview, utilisez
end2end=Falseavecnms=True - Appareils en périphérie (NCNN, RKNN) : Ces formats basculent automatiquement vers le mode un-à-plusieurs, il faut donc inclure le NMS dans votre pipeline sur l'appareil.
FAQ
Puis-je utiliser end2end=True et nms=True ensemble ?
Non. Ces options s'excluent mutuellement. Si vous définissez nms=True selon un modèle de bout en bout pendant export, il sera automatiquement forcé à nms=False avec une mise en garde. Le contrôleur de bout en bout gère déjà en interne le filtrage des doublons ; NMS externe NMS donc pas nécessaire.
Cependant, end2end=False associé à nms=True est une configuration valide — elle intègre NMS traditionnel NMS le graphe d'exportation. Cela peut être utile pour CoreML les exportations, car cela vous permet d'utiliser directement la fonction « Aperçu » de Xcode avec le modèle de détection.
Quel est le rôle du paramètre max_det dans les modèles de bout en bout ?
L'argument max_det Le paramètre (valeur par défaut : 300) définit le nombre maximal de détections que le module de reconnaissance « un-à-un » peut générer par image. Vous pouvez le modifier 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 scenes
Notez que les checkpoints par défaut de YOLO26 ont été entraînés avec max_det=300. Bien que vous puissiez augmenter cette valeur, la tête un-à-un a été optimisée pendant l'entraînement pour produire jusqu'à 300 détections nettes, de sorte que les détections au-delà de cette limite peuvent être de qualité inférieure. Si vous avez besoin de plus de 300 détections par image, envisagez de réentraîner avec un plus grand max_det valeur.
Mon ONNX exporté renvoie (1, 300, 6) — est-ce correct ?
Oui, c'est bien le format de sortie de bout en bout attendu pour la détection : taille de lot de 1 à 300 détections, chacune comportant 6 valeurs [x1, y1, x2, y2, confidence, class_id]. Il suffit de filtrer par seuil de confiance et le tour est joué — pas de NMS nécessaire.
Pour les autres tâches, la structure des résultats diffère :
| Tâche | Forme de sortie | Description |
|---|---|---|
| Détection | (1, 300, 6) | [x1, y1, x2, y2, conf, class_id] |
| Segmentation | (1, 300, 38) + (1, 32, 160, 160) | 6 valeurs de boîte + 32 coefficients de masque, plus un tensor 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 |
Comment puis-je vérifier si mon modèle exporté est de bout en bout ?
Vous pouvez vérifier cela soit à l'aide dePython Ultralytics , soit en examinant directement les métadonnées ONNX exporté :
Vérifiez si un modèle est de bout en bout
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
import onnxruntime as ort
session = ort.InferenceSession("yolo26n.onnx")
metadata = session.get_modelmeta().custom_metadata_map
print(metadata.get("end2end")) # 'True' if end-to-end is enabled
Alternativement, vérifiez la forme de sortie — les modèles de détection de bout en bout produisent (1, 300, 6), tandis que les modèles traditionnels produisent (1, nc + 4, 8400). Pour d'autres formes de tâches, consultez le FAQ sur les formes de sortie.
La prise en charge de bout en bout est-elle disponible pour les tâches de segmentation, de pose et d'OBB ?
Oui. Toutes les variantes de tâches de YOLO26 — détection, segmentation, estimation de pose, et la détection d'objets orientés (OBB) — prennent en charge l'inférence de bout en bout par défaut. Le end2end=False La solution de secours est également disponible pour toutes les 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 | Résultat de bout en bout |
|---|---|---|
| Détection | yolo26n.pt | (N, 300, 6) |
| Segmentation | 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) |