Grundlegendes zur End-to-End-Erkennung in Ultralytics YOLO26

Einführung

If you're upgrading to YOLO26 from an earlier model like YOLOv8 or YOLO11, one of the biggest changes you'll notice is the removal of Non-Maximum Suppression (NMS). Traditional YOLO models produce thousands of overlapping predictions that need a separate NMS post-processing step to filter down to final detections. This adds latency, complicates export graphs, and can behave inconsistently across different hardware platforms.

YOLO26 verfolgt einen anderen Ansatz. Es gibt die endgültigen Erkennungen direkt vom Modell aus – keine externe Filterung erforderlich. Dies wird als End-to-End Objekterkennung bezeichnet und ist in allen YOLO26-Modellen standardmäßig aktiviert. Das Ergebnis ist eine einfachere Bereitstellungspipeline, eine geringere Latenz und bis zu 43% schnellere Inferenz auf CPUs.

Dieser Leitfaden führt dich durch die Änderungen, ob du deinen Code aktualisieren musst, welche Exportformate End-to-End-Inferenz unterstützen und wie du reibungslos von älteren YOLO-Modellen migrierst.

Für einen tieferen Einblick in die Motivation hinter diesem architektonischen Wandel siehe den Ultralytics Blog-Beitrag darüber, warum YOLO26 NMS entfernt und wie sich das auf die Bereitstellung auswirkt.

Kurze Zusammenfassung
  • Verwendest du die Ultralytics API oder CLI? Es sind keine Änderungen erforderlich – ändere einfach deinen Modellnamen zu yolo26n.pt.
  • Verwendest du eigenen Inferenz-Code (ONNX Runtime, TensorRT, etc.)? Aktualisiere deine Nachverarbeitung – der Erkennungsausgang ist jetzt (N, 300, 6) im xyxy-Format, NMS ist nicht erforderlich. Andere Aufgaben hängen zusätzliche Daten an (Maskenkoeffizienten, Keypoints oder Winkel).
  • Exportieren? Die meisten Formate unterstützen die End-to-End-Ausgabe nativ. Einige Formate (NCNN, RKNN, PaddlePaddle, ExecuTorch, IMX und Edge TPU) greifen jedoch aufgrund nicht unterstützter Operator-Beschränkungen (z. B. torch.topk) automatisch auf die traditionelle Ausgabe zurück.

Wie End-to-End-Erkennung funktioniert

YOLO26 verwendet während des Trainings eine Dual-Head-Architektur. Beide Köpfe teilen sich das gleiche Backbone und den gleichen Neck, erzeugen aber Ausgaben auf unterschiedliche Weise:

HeadZweckErkennungsausgabeNachverarbeitung
One-to-One (Standard)End-to-End-Inferenz(N, 300, 6)Nur Konfidenz-Schwellenwert
One-to-ManyTraditionelle YOLO-Ausgabe(N, nc + 4, 8400)Erfordert NMS

Die obigen Formen gelten für die Erkennung. Andere Aufgaben erweitern die One-to-One-Ausgabe mit zusätzlichen Daten pro Erkennung:

AufgabeEnd-to-End-AusgabeZusätzliche Daten
Detection(N, 300, 6)
Segmentierung(N, 300, 6 + nm) + proto (N, nm, H, W)nm Maskenkoeffizienten (Standard 32)
Pose(N, 300, 57)17 Keypoints × 3 (x, y, Sichtbarkeit)
OBB(N, 300, 7)Rotationswinkel

During training, both heads run simultaneously — the one-to-many head provides a richer learning signal, while the one-to-one head learns to produce clean, non-overlapping predictions. During inference and export, only the one-to-one head is active by default, producing up to 300 detections per image in the format [x1, y1, x2, y2, confidence, class_id].

Wenn du model.fuse() aufrufst, werden Conv + BatchNorm-Schichten für eine schnellere Inferenz zusammengefügt und bei End-to-End-Modellen wird auch der One-to-Many-Kopf entfernt – was Modellgröße und FLOPs reduziert. Weitere Details zur Dual-Head-Architektur findest du auf der YOLO26-Modellseite.

Muss ich meinen Code ändern?

Verwendung der Ultralytics Python API oder CLI

Keine Änderungen erforderlich. Wenn du die standardmäßige Ultralytics Python API oder CLI verwendest, funktioniert alles automatisch – Vorhersage, Validierung und Export verarbeiten End-to-End-Modelle von Haus aus.

Keine Codeänderungen mit der Ultralytics API erforderlich
from ultralytics import YOLO

# Load a YOLO26 model
model = YOLO("yolo26n.pt")

# Predict — no NMS step, no code changes
results = model.predict("image.jpg")

Verwendung von benutzerdefiniertem Inferenz-Code

Ja, das Ausgabeformat ist anders. Wenn du eine benutzerdefinierte Nachverarbeitungslogik für YOLOv8 oder YOLO11 geschrieben hast (zum Beispiel bei der Inferenz mit ONNX Runtime oder TensorRT), musst du diese aktualisieren, um die neue Ausgabeform zu verarbeiten:

YOLOv8 / YOLO11YOLO26 (End-to-End)
Erkennungsausgabe(N, nc + 4, 8400)(N, 300, 6)
Box-Formatxywh (Zentrum x, Zentrum y, Breite, Höhe)xyxy (oben-links x, oben-links y, unten-rechts x, unten-rechts y)
LayoutBox-Koordinaten + Klassen-Scores pro Anchor[x1, y1, x2, y2, conf, class_id]
NMS erforderlichJaNein
NachverarbeitungNMS + Konfidenz-FilterNur Konfidenz-Filter

Für Segmentierung, Pose und OBB-Aufgaben fügt YOLO26 aufgabenspezifische Daten zu jeder Erkennung hinzu – siehe die Tabelle der Ausgabeformen oben.

Wobei N die Batchgröße ist und nc die Anzahl der Klassen (z. B. 80 für COCO).

Bei End-to-End-Modellen wird die Nachverarbeitung viel einfacher – zum Beispiel bei der Verwendung von 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!

Wechsel zum One-to-Many-Kopf

Wenn du das traditionelle YOLO-Ausgabeformat benötigst (zum Beispiel, um bestehenden NMS-basierten Nachverarbeitungscode wiederzuverwenden), kannst du jederzeit zum One-to-Many-Kopf wechseln, indem du end2end=False setzt:

Verwendung des One-to-Many-Kopfes für traditionelle NMS-basierte Ausgabe
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)

Kompatibilität der Exportformate

Die meisten Exportformate unterstützen End-to-End-Inferenz von Haus aus, einschließlich ONNX, TensorRT, CoreML, OpenVINO, TFLite, TF.js und MNN.

Die folgenden Formate unterstützen kein End-to-End und greifen automatisch auf den One-to-Many-Kopf zurück: NCNN, RKNN, PaddlePaddle, ExecuTorch, IMX und Edge TPU.

Was passiert, wenn End-to-End nicht unterstützt wird

Wenn du in eines dieser Formate exportierst, wechselt Ultralytics automatisch zum One-to-Many-Kopf und protokolliert eine Warnung – kein manueller Eingriff erforderlich. Das bedeutet, dass du NMS in deiner Inferenz-Pipeline für diese Formate benötigst, genau wie bei YOLOv8 oder YOLO11.

TensorRT + INT8

TensorRT unterstützt End-to-End, aber es wird automatisch deaktiviert, wenn du mit int8=True auf TensorRT ≤10.3.0 exportierst.

Kompromisse bei Genauigkeit und Geschwindigkeit

End-to-End-Erkennung bietet erhebliche Vorteile bei der Bereitstellung mit minimalen Auswirkungen auf die Genauigkeit:

MetrikEnd-to-End (Standard)One-to-Many + NMS (end2end=False)
CPU-InferenzgeschwindigkeitBis zu 43% schnellerBasislinie
mAP-Auswirkung~0,5 mAP niedrigerEntspricht oder übertrifft YOLO11
NachverarbeitungNur Konfidenz-FilterVollständige NMS-Pipeline
BereitstellungskomplexitätMinimalErfordert NMS-Implementierung

Für die meisten realen Anwendungen ist der Unterschied von ~0,5 mAP vernachlässigbar, insbesondere wenn man die Geschwindigkeits- und Einfachheitsvorteile betrachtet. Wenn maximale Genauigkeit deine höchste Priorität ist, kannst du jederzeit auf den One-to-Many-Kopf zurückgreifen, indem du end2end=False verwendest.

Siehe die YOLO26-Leistungsmetriken für detaillierte Benchmarks über alle Modellgrößen (n, s, m, l, x).

Migration von YOLOv8 oder YOLO11

Wenn du ein bestehendes Projekt auf YOLO26 aktualisierst, findest du hier eine kurze Checkliste für einen reibungslosen Übergang:

  • Benutzer der Ultralytics API / CLI: Keine Änderungen erforderlich – aktualisiere einfach den Modellnamen auf yolo26n.pt (oder yolo26n-seg.pt, yolo26n-pose.pt, yolo26n-obb.pt)
  • Benutzerdefinierter Nachverarbeitungscode: Aktualisiere auf die neuen Ausgabeformen – (N, 300, 6) für die Erkennung, plus aufgabenspezifische Daten für Segmentierung, Pose und OBB. Beachte auch die Änderung des Box-Formats von xywh auf xyxy
  • Export-Pipelines: Überprüfe den Abschnitt Formatkompatibilität oben für dein Zielformat
  • TensorRT + INT8: Überprüfe, ob deine TensorRT-Version >10.3.0 für End-to-End-Unterstützung ist
  • FP16-Exporte: Wenn du alle Ausgaben in FP16 benötigst, exportiere mit end2end=False – siehe warum output0 FP32 bleibt beim Exportieren mit half=True und end2end=True
  • iOS / CoreML: End-to-End wird vollständig unterstützt. Wenn du Xcode Preview-Unterstützung benötigst, verwende end2end=False mit nms=True
  • Edge-Geräte (NCNN, RKNN): Diese Formate greifen automatisch auf One-to-Many zurück, also füge NMS in deine On-Device-Pipeline ein

FAQ

Kann ich end2end=True und nms=True zusammen verwenden?

No. These options are mutually exclusive. If you set nms=True on an end-to-end model during export, it will be automatically forced to nms=False with a warning. The end-to-end head already handles duplicate filtering internally, so external NMS is unnecessary.

Allerdings ist end2end=False in Kombination mit nms=True eine gültige Konfiguration – es integriert traditionelles NMS in den Export-Graphen. Dies kann nützlich für CoreML-Exporte sein, da du die Vorschaufunktion in Xcode direkt mit dem Erkennungsmodell verwenden kannst.

Was steuert der max_det-Parameter bei End-to-End-Modellen?

Der max_det-Parameter (Standard: 300) legt die maximale Anzahl an Erkennungen fest, die der One-to-One-Kopf pro Bild ausgeben kann. Du kannst ihn zum Zeitpunkt der Inferenz oder des Exports anpassen:

model.predict("image.jpg", max_det=100)  # fewer detections, slightly faster
model.export(format="onnx", max_det=500)  # more detections for dense scenes

Beachte, dass die standardmäßigen YOLO26-Checkpoints mit max_det=300 trainiert wurden. Obwohl du diesen Wert erhöhen kannst, wurde der One-to-One-Kopf während des Trainings darauf optimiert, bis zu 300 saubere Erkennungen zu erzeugen, daher könnten Erkennungen über diesem Limit von geringerer Qualität sein. Wenn du mehr als 300 Erkennungen pro Bild benötigst, erwäge ein erneutes Training mit einem höheren max_det-Wert.

Mein exportiertes ONNX-Modell gibt (1, 300, 6) aus – ist das korrekt?

Yes, that's the expected end-to-end output format for detection: batch size of 1, up to 300 detections, each with 6 values [x1, y1, x2, y2, confidence, class_id]. Simply filter by confidence threshold and you're done — no NMS needed.

Für andere Aufgaben unterscheidet sich die Ausgabeform:

AufgabeAusgabeformBeschreibung
Detektion(1, 300, 6)[x1, y1, x2, y2, conf, class_id]
Segmentierung(1, 300, 38) + (1, 32, 160, 160)6 Box-Werte + 32 Masken-Koeffizienten, plus ein Prototyp-Masken-Tensor
Pose(1, 300, 57)6 Box-Werte + 17 Keypoints × 3 (x, y, Sichtbarkeit)
OBB(1, 300, 7)6 Box-Werte + 1 Rotationswinkel

Wie überprüfe ich, ob mein exportiertes Modell End-to-End ist?

Du kannst dies entweder über die Ultralytics Python API oder durch direkte Inspektion der Metadaten des exportierten ONNX-Modells prüfen:

Prüfen, ob ein Modell End-to-End ist
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

Alternativ kannst du die Ausgabe-Form prüfen – End-to-End-Detektionsmodelle geben (1, 300, 6) aus, während traditionelle Modelle (1, nc + 4, 8400) ausgeben. Für andere Aufgaben-Formen siehe das FAQ zu Ausgabe-Formen.

Wird End-to-End für Segmentierung, Pose und OBB-Aufgaben unterstützt?

Ja. Alle YOLO26-Aufgabenvarianten – Detektion, Segmentierung, Pose-Schätzung und orientierte Objektdetektion (OBB) – unterstützen standardmäßig End-to-End-Inferenz. Der end2end=False-Fallback ist ebenfalls für alle Aufgaben verfügbar.

Jede Aufgabe erweitert die Basis-Detektionsausgabe um aufgabenspezifische Daten:

AufgabeModellEnd-to-End-Ausgabe
Detektionyolo26n.pt(N, 300, 6)
Segmentierungyolo26n-seg.pt(N, 300, 38) + Proto (N, 32, 160, 160)
Poseyolo26n-pose.pt(N, 300, 57)
OBByolo26n-obb.pt(N, 300, 7)

Kommentare