Understanding End-to-End Detection in Ultralytics YOLO26#
YOLO26 detection-style models — detection, segmentation, pose, and OBB — are NMS-free by default: they output final detections directly from the model, with no Non-Maximum Suppression (NMS) post-processing step. Earlier models like YOLOv8 and YOLO11 produce thousands of overlapping predictions that a separate NMS step has to filter down, which adds latency, complicates export graphs, and can behave inconsistently across hardware platforms.
This is known as end-to-end object detection, and it is enabled by default. The result is a simpler deployment pipeline and lower latency — YOLO26n runs up to 43% faster than YOLO11n on CPU ONNX inference (Intel Xeon CPU @ 2.00 GHz).
This guide walks you through what changed, whether you need to update your code, which export formats support end-to-end inference, and how to migrate smoothly from older YOLO models.
For a deeper look at the motivation behind this architectural shift, see the Ultralytics blog post on why YOLO26 removes NMS.
- Using the Ultralytics API or CLI? No changes needed — just swap your model name to
yolo26n.pt. - Using custom inference code (ONNX Runtime, TensorRT, etc.)? Update your post-processing — detection output is now
(N, 300, 6)inxyxyformat, no NMS required. Other tasks append extra data (mask coefficients, keypoints, or angle). - Exporting? Most formats keep end-to-end output natively; a few fall back to traditional output, and quantization can disable it — see Export Format Compatibility.
How End-to-End Detection Works#
YOLO26 uses a dual-head architecture during training. Both heads share the same backbone and neck, but produce outputs in different ways:
| Head | Purpose | Detection Output | Post-Processing |
|---|---|---|---|
| One-to-One (default) | End-to-end inference | (N, 300, 6) | Confidence threshold only |
| One-to-Many | Traditional YOLO output | (N, nc + 4, 8400) | Requires NMS |
The shapes above are for detection, where N is the batch size, nc is the number of classes (e.g., 80 for COCO), and the 8400 anchor count is the value at imgsz=640. Other tasks extend the one-to-one output with additional data per detection:
| Task | End-to-End Output | Extra Data |
|---|---|---|
| Detection | (N, 300, 6) | — |
| Instance Segmentation | (N, 300, 6 + nm) + proto (N, nm, H, W) | nm mask coefficients (default 32) |
| Pose | (N, 300, 57) | 17 keypoints × 3 (x, y, visibility) |
| OBB | (N, 300, 7) | Rotation angle |
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].
When you call model.fuse(), it folds Conv + BatchNorm layers for faster inference and, on end-to-end models, also removes the one-to-many head — reducing model size and FLOPs. For more details on the dual-head architecture, see the YOLO26 model page.
Do I Need to Change My Code?#
Using the Ultralytics Python API or CLI#
No changes needed. If you use the standard Ultralytics Python API or CLI, everything works automatically — prediction, validation, and export all handle end-to-end models out of the box.
from ultralytics import YOLO
# Load a YOLO26 model
model = YOLO("yolo26n.pt")
# Predict — no NMS step, no code changes
results = model.predict("image.jpg")Using Custom Inference Code#
Yes, the output format is different. If you wrote custom post-processing logic for YOLOv8 or YOLO11 (for example, when running inference with ONNX Runtime or TensorRT), you'll need to update it to handle the new output shape:
| YOLOv8 / YOLO11 | YOLO26 (end-to-end) | |
|---|---|---|
| Detection output | (N, nc + 4, 8400) | (N, 300, 6) |
| Box format | xywh (center x, center y, width, height) | xyxy (top-left x, top-left y, bottom-right x, bottom-right y) |
| Layout | Box coords + class scores per anchor | [x1, y1, x2, y2, conf, class_id] |
| NMS required | Yes | No |
| Post-processing | NMS + confidence filter | Confidence filter only |
For segmentation, pose, and OBB tasks, YOLO26 appends task-specific data to each detection — see the output shapes table.
With end-to-end models, post-processing becomes much simpler — for example, when using 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 NMSSwitching to the One-to-Many Head#
If you need the traditional YOLO output format (for example, to reuse existing NMS-based post-processing code), you can switch to the one-to-many head when it is available by setting 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)Export Format Compatibility#
Most export formats support end-to-end inference out of the box, including ONNX, TensorRT, CoreML, OpenVINO, LiteRT, and MNN.
The following formats do not support end-to-end and automatically fall back to the one-to-many head: NCNN, RKNN, PaddlePaddle, ExecuTorch, IMX, Edge TPU, and Qualcomm QNN.
For Hailo, the exporter picks the output path from the loaded head rather than from an argument, so end2end is rejected if passed: a default YOLO26 detection model keeps its NMS-free one-to-one outputs, while a checkpoint whose head is already end2end=False compiles the traditional path with HailoRT NMS.
Accuracy and Speed Trade-offs#
End-to-end detection provides significant deployment benefits with minimal impact on accuracy:
| Metric | End-to-End (default) | One-to-Many + NMS (end2end=False) |
|---|---|---|
| COCO mAPval | 0.6-0.8 lower | Baseline |
| Post-Processing | Confidence filter only | Full NMS pipeline |
| Deployment Complexity | Minimal | Requires NMS implementation |
Across the five detection scales the one-to-one head costs 0.6-0.8 mAP on COCO — 40.9 to 40.1 for YOLO26n and 57.5 to 56.9 for YOLO26x — in exchange for dropping the NMS pass entirely. If maximum accuracy is your priority, fall back to the one-to-many head with end2end=False.
See the YOLO26 performance metrics for detailed benchmarks across all model sizes (n, s, m, l, x).
Migrating from YOLOv8 or YOLO11#
If you're upgrading an existing project to YOLO26:
- Ultralytics API / CLI users: No changes needed — just update the model name to
yolo26n.pt(oryolo26n-seg.pt,yolo26n-pose.pt,yolo26n-obb.pt) - Custom post-processing code: Update to handle the new output shapes —
(N, 300, 6)for detection, plus task-specific data for segmentation, pose, and OBB. Also note the box format change fromxywhtoxyxy - Export pipelines: Check the format compatibility section for your target format
- TensorRT below 8.5.0: end-to-end is disabled at every precision — upgrade TensorRT to 8.5.0 or later to keep it
- Quantized exports: TensorRT 10.3.0 with
quantize=8on JetPack 6, and LiteRT withquantize=8orquantize="w8a16", auto-disable end-to-end — export at a higher precision to keep it - FP16 exports: If you need all outputs in FP16, export with
end2end=False— see why output0 stays FP32 - iOS / CoreML: End-to-end is fully supported. If you need Xcode Preview support, use
end2end=Falsewithnms=True - Edge devices (NCNN, RKNN): These formats auto-fallback to one-to-many, so include NMS in your on-device pipeline
Conclusion#
End-to-end detection is the default in YOLO26 and needs no code changes if you use the Ultralytics Python API or CLI. Only custom post-processing pipelines need updating to read the new (N, 300, 6) output and drop the NMS step — except for export formats that fall back to one-to-many output (such as NCNN and RKNN), which still require NMS on-device. For detailed speed and accuracy benchmarks across all model sizes, see the YOLO26 model page, and for the full set of export options and formats, see the Export mode documentation.
FAQ#
No. These options are mutually exclusive. If you set
nms=Trueon an end-to-end model during export, it will be automatically forced tonms=Falsewith a warning. The end-to-end head already handles duplicate filtering internally, so external NMS is unnecessary.However,
end2end=Falsecombined withnms=Trueis a valid configuration — it bakes traditional NMS into the export graph. This can be useful for CoreML exports because it lets you use the Preview function in Xcode with the detection model directly.The
max_detparameter (default: 300) sets the maximum number of detections returned per image. You can adjust it at inference or export time:model.predict("image.jpg", max_det=100) # fewer detections model.export(format="onnx", max_det=500) # more detections for dense scenesThe value is baked into an exported graph as the head's top-k, so
max_det=500widens the output tensor to up to(1, 500, 6), capped by the anchor count.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 — no NMS needed.For other tasks, the output shape differs:
Task Output Shape Description Detection (1, 300, 6)[x1, y1, x2, y2, conf, class_id]Segmentation (1, 300, 38)+(1, 32, 160, 160)6 box values + 32 mask coefficients, plus a prototype mask tensor Pose (1, 300, 57)6 box values + 17 keypoints × 3 (x, y, visibility) OBB (1, 300, 7)6 box values + 1 rotation angle You can check from the Ultralytics Python API or from the exported ONNX model metadata:
Check if a model is end-to-endfrom 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 enabledThe two checks answer different questions: the ONNX metadata records the head that was exported, while
predictor.model.end2endreports that the backend output is already post-processed and needs no external NMS. They disagree for a model exported withend2end=False, nms=True, which uses the one-to-many head but bakes NMS into the graph and also outputs(1, 300, 6)— so neither the flag nor the output shape alone identifies the head. For other task shapes, see the output shapes FAQ.Yes. YOLO26 detection-style task variants — detection, instance segmentation, pose estimation, and oriented object detection (OBB) — support end-to-end inference by default. The
end2end=Falsefallback is available across these tasks as well.Each task extends the base detection output with task-specific data;
yolo26n.pt,yolo26n-seg.pt,yolo26n-pose.pt, andyolo26n-obb.ptoutput shapes are listed under How End-to-End Detection Works.