Link to this section理解 Ultralytics YOLO26 中的端到端检测#
Link to this section简介#
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 采用了不同的方法。它直接从模型输出最终的检测结果,无需外部过滤。这就是所谓的端到端 目标检测,并且在所有 YOLO26 模型中默认启用。其结果是部署流程更简单、延迟更低,且在 CPU 上的推理速度提升高达 43%。
本指南将带你了解有哪些变化,你是否需要更新代码,哪些导出格式支持端到端推理,以及如何从旧的 YOLO 模型顺利迁移。
欲深入了解此次架构转变背后的动机,请参阅 Ultralytics 博客文章:为什么 YOLO26 移除了 NMS 以及它如何改变部署方式。
- 正在使用 Ultralytics API 或 CLI? 无需任何更改 —— 只需将你的模型名称更改为
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). - 需要导出? 大多数格式原生支持端到端输出。但是,少数格式(NCNN、RKNN、PaddlePaddle、ExecuTorch、IMX、Edge TPU 和 QNN)由于不支持的操作符约束(例如
torch.topk),会自动回退到传统输出。Hailo HEF 工作流是从 ONNX 使用 Hailo 特定的脚本进行编译的,因此请务必验证你模型的检测头和 NMS 配置。
Link to this section端到端检测的工作原理#
YOLO26 在 训练 期间使用了双头架构。两个头共享相同的主干网络和颈部,但产生输出的方式不同:
| 头 | 用途 | 检测输出 | 后处理 |
|---|---|---|---|
| 一对一 (默认) | 端到端推理 | (N, 300, 6) | 仅置信度阈值 |
| 一对多 | 传统 YOLO 输出 | (N, nc + 4, 8400) | 需要 NMS |
上述形状适用于 检测 任务。其他任务在上述一对一输出的基础上为每个检测结果扩展了额外数据:
| 任务 | 端到端输出 | 额外数据 |
|---|---|---|
| 检测 | (N, 300, 6) | — |
| 实例分割 | (N, 300, 6 + nm) + 原型 (N, nm, H, W) | nm 掩码系数(默认 32) |
| 姿态估计 | (N, 300, 57) | 17 个关键点 × 3 (x, y, 可见性) |
| OBB | (N, 300, 7) | 旋转角度 |
在训练期间,两个头同时运行 —— 一对多头提供更丰富的学习信号,而一对一头学习产生整洁、无重叠的预测结果。在 推理 和 导出 期间,默认只有一对一头处于激活状态,每张图像最多产生 300 个检测结果,格式为 [x1, y1, x2, y2, confidence, class_id]。
当你调用 model.fuse() 时,它会将 Conv + BatchNorm 层融合以实现更快的推理,并且在端到端模型上,它还会移除一对多头 —— 从而减小模型大小和 FLOPs。关于双头架构的更多详细信息,请参阅 YOLO26 模型页面。
Link to this section我需要更改代码吗?#
Link to this section使用 Ultralytics Python API 或 CLI#
无需任何更改。 如果你使用标准的 Ultralytics Python API 或 CLI,一切都会自动运行 —— 预测、验证 和 导出 都开箱即用地处理端到端模型。
from ultralytics import YOLO
# Load a YOLO26 model
model = YOLO("yolo26n.pt")
# Predict — no NMS step, no code changes
results = model.predict("image.jpg")Link to this section使用自定义推理代码#
是的,输出格式不同。 如果你为 YOLOv8 或 YOLO11 编写了自定义后处理逻辑(例如,在使用 ONNX Runtime 或 TensorRT 运行推理时),你需要对其进行更新以处理新的输出形状:
| YOLOv8 / YOLO11 | YOLO26 (端到端) | |
|---|---|---|
| 检测输出 | (N, nc + 4, 8400) | (N, 300, 6) |
| 边界框格式 | xywh (中心 x, 中心 y, 宽, 高) | xyxy (左上 x, 左上 y, 右下 x, 右下 y) |
| 布局 | 每个锚点的框坐标 + 类分数 | [x1, y1, x2, y2, conf, class_id] |
| 需要 NMS | 是 | 否 |
| 后处理 | NMS + 置信度过滤 | 仅置信度过滤 |
对于 分割、姿态估计 和 OBB 任务,YOLO26 会将任务特定的数据附加到每个检测结果中 —— 请参阅上方的 输出形状表格。
其中 N 是 批次大小,nc 是类别数量(例如 COCO 数据集为 80)。
使用端到端模型,后处理变得简单得多 —— 例如,在使用 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!Link to this section切换到一对多头#
如果你需要传统的 YOLO 输出格式(例如,为了复用现有的基于 NMS 的后处理代码),你可以通过设置 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)Link to this section导出格式兼容性#
大多数 导出格式 开箱即用地支持端到端推理,包括 ONNX、 TensorRT、 CoreML、 OpenVINO、 TFLite、 TF.js 和 MNN。
以下格式不支持端到端,会自动回退到一对多头:NCNN、RKNN、PaddlePaddle、ExecuTorch、IMX、Edge TPU 和 Qualcomm QNN。
对于 Hailo HEF,编译步骤发生在 ONNX 导出之后的 model.export(format=...) 之外。请使用与你确切检测模型匹配的 Hailo DFC 日志、.alls 模型脚本和 NMS JSON;如果你的 Hailo 工具链不支持端到端的 YOLO26 图,请使用 end2end=False 导出 ONNX 模型并编译传统的检测头。
TensorRT 支持端到端,但在 TensorRT ≤10.3.0 版本上使用 int8=True 导出时,此功能会自动禁用。
Link to this section精度与速度的权衡#
端到端检测在部署上带来了显著的好处,且对 精度 的影响极小:
| 指标 | 端到端 (默认) | 一对多 + NMS (end2end=False) |
|---|---|---|
| CPU 推理速度 | 提升高达 43% | 基准 |
| mAP 影响 | 降低约 0.5 mAP | 匹配或超过 YOLO11 |
| 后处理 | 仅置信度过滤 | 完整的 NMS 流程 |
| 部署复杂度 | 极简 | 需要实现 NMS |
对于大多数实际应用场景,~0.5 的 mAP 差异是可以忽略不计的,特别是考虑到速度和简洁性的提升时。如果最大化精度是你的首要任务,你始终可以使用 end2end=False 回退到一对多头。
请参阅 YOLO26 性能指标 以获取所有模型尺寸 (n, s, m, l, x) 的详细基准测试。
Link to this section从 YOLOv8 或 YOLO11 迁移#
如果你正在将现有项目升级到 YOLO26,这里有一份快速检查清单以确保顺利过渡:
- Ultralytics API / CLI 用户: 无需更改 —— 只需将模型名称更新为
yolo26n.pt(或yolo26n-seg.pt、yolo26n-pose.pt、yolo26n-obb.pt) - 自定义后处理代码: 更新代码以处理新的输出形状 —— 检测任务为
(N, 300, 6),以及针对 分割、姿态估计 和 OBB 的任务特定数据。同时请注意边界框格式已从xywh更改为xyxy - 导出流程: 请检查上方 格式兼容性 部分以查看你的目标格式
- TensorRT + INT8: 请确认你的 TensorRT 版本高于 10.3.0 以获得端到端支持
- FP16 导出: 如果你需要所有输出均为 FP16,请使用
end2end=False进行导出 —— 参见 为什么 output0 在使用 half=True 和 end2end=True 导出时仍为 FP32 - iOS / CoreML: 完全支持端到端。如果你需要 Xcode 预览支持,请将
end2end=False与nms=True配合使用 - 边缘设备 (NCNN, RKNN): 这些格式会自动回退到“一对多”模式,因此请在你的设备端流水线中包含 NMS
Link to this section常见问题 (FAQ)#
Link to this section我可以同时使用 end2end=True 和 nms=True 吗?#
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.
不过,将 end2end=False 与 nms=True 结合使用是一种有效的配置 —— 它会将传统的 NMS 写入导出后的计算图中。这对 CoreML 导出很有用,因为它让你能直接在 Xcode 中使用检测模型的预览功能。
Link to this section在端到端模型中,max_det 参数控制什么?#
max_det 参数(默认值:300)设定了“一对一”头部每张图片可输出的最大检测数量。你可以在推理或导出时进行调整:
model.predict("image.jpg", max_det=100) # fewer detections, slightly faster
model.export(format="onnx", max_det=500) # more detections for dense scenes请注意,默认的 YOLO26 检查点是使用 max_det=300 训练的。虽然你可以增大该数值,但“一对一”头部在训练期间被优化为生成最多 300 个清晰的检测结果,因此超出该限制的检测质量可能会降低。如果你需要每张图片超过 300 个检测结果,请考虑使用更大的 max_det 值进行重训练。
Link to this section我导出的 ONNX 模型输出为 (1, 300, 6) —— 这是正确的吗?#
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.
对于其他任务,输出形状会有所不同:
| 任务 | 输出形状 | 描述 |
|---|---|---|
| 检测 | (1, 300, 6) | [x1, y1, x2, y2, conf, class_id] |
| 分割 | (1, 300, 38) + (1, 32, 160, 160) | 6 个框数值 + 32 个掩码系数,外加一个原型掩码张量 |
| 姿态 | (1, 300, 57) | 6 个框数值 + 17 个关键点 × 3 (x, y, 可见度) |
| OBB | (1, 300, 7) | 6 个框数值 + 1 个旋转角度 |
Link to this section如何检查我的导出模型是否为端到端模型?#
你可以使用 Ultralytics Python API 或直接查看导出的 ONNX 模型元数据来进行检查:
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或者,检查输出形状 —— 端到端检测模型输出 (1, 300, 6),而传统模型输出 (1, nc + 4, 8400)。关于其他任务的形状,请参见 输出形状常见问题解答。
Link to this section实例分割、姿态估计和 OBB 任务支持端到端吗?#
支持。YOLO26 检测风格的任务变体 —— 检测、实例分割、姿态估计 和 旋转目标检测 (OBB) —— 默认支持端到端推理。end2end=False 回退选项在这些任务中同样可用。
每个任务都在基础检测输出之上扩展了特定任务的数据:
| 任务 | 模型 | 端到端输出 |
|---|---|---|
| 检测 | yolo26n.pt | (N, 300, 6) |
| 实例分割 | yolo26n-seg.pt | (N, 300, 38) + 原型 (N, 32, 160, 160) |
| 姿态 | yolo26n-pose.pt | (N, 300, 57) |
| OBB | yolo26n-obb.pt | (N, 300, 7) |