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 réseaux fonctionnent simultanément : le réseau « un-à-plusieurs » fournit un signal d'apprentissage plus riche, tandis que le réseau « un-à-un » apprend à produire des prédictions nettes et sans chevauchement. Pendant inférence et export, uniquement 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 regroupe les couches Conv et BatchNorm pour accélérer l'inférence et, sur les modèles de bout en bout, supprime également la tête « un-à-plusieurs », ce qui réduit la taille du modèle et le nombre de FLOP. Pour plus de détails sur l'architecture à double tête, consultez le Page du modèle YOLO26.
Dois-je modifier mon code ?
Utilisation dePython ou de l'interface CLI Ultralytics
Aucune modification n'est nécessaire. Si vous utilisez Python standard Ultralytics ou CLI, tout fonctionne automatiquement : la prédiction, la validation et l'exportation gèrent toutes les étapes de bout en bout dès l'installation.
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 d'une inférence avec ONNX ou TensorRT), vous devrez le mettre à jour pour qu'il prenne en charge 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 la boîte | xywh (x du centre, y du centre, largeur, hauteur) | xyxy (x en haut à gauche, y en haut à gauche, x en bas à droite, y en bas à droite) |
| Mise en page | Coordonnées des boîtes + notes de classe par point d'ancrage | [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 rapidité
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 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 tient compte des gains en termes de rapidité et de simplicité. Si la précision maximale est votre priorité absolue, vous pouvez toujours vous rabattre sur 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 l'encadré, qui passe dexywhàxyxy - Pipelines d'exportation : consultez la section sur la compatibilité des formats ci-dessus pour connaître le format de destination
- TensorRT INT8 : assurez-vous que votre TensorRT est supérieure à 10.3.0 pour bénéficier d'une prise en charge complète
- 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 périphériques (NCNN, RKNN) : ces formats basculent automatiquement vers un mode « un-à-plusieurs » ; veillez donc à inclure NMS votre pipeline côté appareil
FAQ
Puis-je utiliser « end2end=True » et « nms=True » simultanément ?
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 contraint de 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, le modèle « one-to-one » a été optimisé pendant l'entraînement pour produire jusqu'à 300 détections fiables ; par conséquent, les détections au-delà de cette limite risquent d'être de moindre qualité. Si vous avez besoin de plus de 300 détections par image, envisagez de réentraîner le modèle avec une valeur plus élevée 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 en fonction du seuil de confiance, et le tour est joué — pas NMS .
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, ainsi qu'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 case + 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érifier 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
Vous pouvez également vérifier la structure des données 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 types 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 enrichit les résultats 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) |