了解 Ultralytics YOLO26 中的端到端检测#
YOLO26 detection-style models — 包括检测、分割、姿态估计和 OBB — 默认采用 NMS-free:它们直接从模型输出最终检测结果,无需 Non-Maximum Suppression (NMS) 后处理步骤。像 YOLOv8 和 YOLO11 这样的早期模型会产生数千个重叠的预测结果,必须通过单独的 NMS 步骤进行过滤,这会增加延迟、使导出图变得复杂,并且在不同的硬件平台上表现可能不一致。
这被称为端到端 object detection,并且默认启用。其结果是更简单的部署流程和更低的延迟 — 在 CPU ONNX 推理(Intel Xeon CPU @ 2.00 GHz)上,YOLO26n 的运行速度比 YOLO11n 快高达 43%。
本指南将带你了解有哪些变化,你是否需要更新代码,哪些导出格式支持端到端推理,以及如何从旧的 YOLO 模型平滑迁移。
有关此架构转变背后动机的更深入探讨,请参阅 Ultralytics 关于为什么 YOLO26 移除 NMS 的博客文章。
- 正在使用 Ultralytics API 或 CLI? 无需更改——只需将你的模型名称更换为
yolo26n.pt。 - 是否在使用自定义推理代码(ONNX Runtime、TensorRT 等)? 更新你的后处理——检测输出现在是
(N, 300, 6)在xyxy格式中,无需 NMS。其他任务会附加额外的数据(早期描述或按钮相关生成的指标、关键点或角度)。 - 正在导出? 大多数格式原生保留端到端输出;少数格式会回退到传统输出,且量化可能会禁用该功能 — 请参阅导出格式兼容性。
端到端检测的工作原理#
YOLO26 在训练期间使用双头架构。两个头共享相同的骨干网络和颈部网络,但以不同的方式产生输出:
| 检测头 | 用途 | 检测输出 | 后处理 |
|---|---|---|---|
| 一对一 (默认) | 端到端推理 | (N, 300, 6) | 仅置信度阈值 |
| 一对多 | 传统 YOLO 输出 | (N, nc + 4, 8400) | 需要 NMS |
上述形状适用于检测,其中 N 是批大小,nc 是类别数(例如 COCO 的 80),而 8400 个锚点计数是 imgsz=640 处的值。其他任务将一对一输出扩展为每次检测包含额外数据:
| 任务 | 端到端输出 | 额外数据 |
|---|---|---|
| Detection | (N, 300, 6) | — |
| 实例分割 | (N, 300, 6 + nm) + 原型 (N, nm, H, W) | nm 掩码系数(默认 32) |
| Pose | (N, 300, 57) | 17 个关键点 × 3 (x, y, 可见性) |
| OBB | (N, 300, 7) | 旋转角度 |
在训练期间,两个头同时运行——多对一(one-to-many)头提供更丰富的学习信号,而一一对应头则学习产生干净、不重叠的预测。在推理和导出期间,默认只有一一对应头处于活跃状态,每张图像以 [x1, y1, x2, y2, confidence, class_id] 格式产生多达 300 个检测结果。
当你调用 model.fuse() 时,它会折叠 Conv + BatchNorm 层以加快推理速度,并且在端到端模型上,还会移除多对一头——从而减小模型大小和 FLOPs。有关双头架构的更多详细信息,请参阅 YOLO26 模型页面。
我需要更改代码吗?#
使用 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")使用自定义推理代码#
是的,输出格式不同。 如果你为 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 会向每个检测附加特定于任务的数据——请参阅输出形状表。
对于端到端模型,后处理变得简单得多——例如,在使用 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 NMS切换到一对多头#
如果你需要传统的 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)导出格式兼容性#
大多数导出格式开箱即生地支持端到端推理,包括 ONNX、TensorRT、CoreML、OpenVINO、LiteRT 和 MNN。
以下格式不支持端到端,并且会自动回退到多对一头:NCNN、RKNN、PaddlePaddle、ExecuTorch、IMX、Edge TPU 和 Qualcomm QNN。
对于 Hailo,导出器是从加载的检测头而不是从参数中选择输出路径,因此如果传入 end2end 将被拒绝:默认的 YOLO26 检测模型保留其无 NMS 的一对一输出,而检测头已经是 end2end=False 的检查点则使用 HailoRT NMS 编译传统路径。
准确度与速度权衡#
端到端检测在对准确率影响极小的情况下,提供了显著的部署优势:
| 指标 | 端到端(默认) | 多对一 + NMS (end2end=False) |
|---|---|---|
| COCO mAPval | 降低 0.6-0.8 | 基准 |
| 后处理 | 仅置信度过滤器 | 完整的 NMS 流水线 |
| 部署复杂度 | 最小 | 需要实现 NMS |
在五个检测尺度上,一对一检测头在 COCO 上会损失 0.6-0.8 的 mAP — YOLO26n 为 40.9 到 40.1,YOLO26x 为 57.5 到 56.9 — 以完全舍弃 NMS 过程为代价。如果最高准确度是你的首选,请使用 end2end=False 回退到多对一头。
有关所有模型大小(n、s、m、l、x)的详细基准测试,请参阅 YOLO26 性能指标。
从 YOLOv8 或 YOLO11 迁移#
如果你正在将现有项目升级到 YOLO26:
- Ultralytics API / CLI 用户: 无需更改——只需将模型名称更新为
yolo26n.pt(或yolo26n-seg.pt、yolo26n-pose.pt、yolo26n-obb.pt) - 自定义后处理代码: 更新以处理新的输出形状——用于检测的
(N, 300, 6),加上用于分割、姿态和 OBB 的特定于任务的数据。同时请注意框格式从xywh到xyxy的更改 - 导出管道: 检查你的目标格式的格式兼容性部分
- TensorRT 8.5.0 以下版本: 端到端在所有精度下均被禁用 — 请将 TensorRT 升级到 8.5.0 或更高版本以保留它
- 量化导出: JetPack 6 上带有
quantize=8的 TensorRT 10.3.0,以及带有quantize=8或quantize="w8a16"的 LiteRT,会自动禁用端到端 — 请以更高的精度导出以保留它 - FP16 导出: 如果你需要 FP16 中的所有输出,请使用
end2end=False进行导出——请参阅为什么 output0 保持为 FP32 - iOS / CoreML: 完全支持端到端。如果你需要 Xcode 预览支持,请将
end2end=False与nms=True一起使用 - 边缘设备 (NCNN, RKNN): 这些格式会自动回退到一对多,因此请在你的设备端流水线中包含 NMS
结论#
端到端检测是 YOLO26 中的默认设置,如果你使用 Ultralytics Python API 或 CLI,则不需要更改代码。只有自定义后处理管道需要更新以读取新的 (N, 300, 6) 输出并放弃 NMS 步骤——除了回退到多对一输出的导出格式(如 NCNN 和 RKNN),它们仍然需要在设备上进行 NMS。有关所有模型大小的详细速度和准确率基准测试,请参阅 YOLO26 模型页面;有关导出选项和格式的完整集合,请参阅导出模式文档。
常见问题解答#
max_det参数(默认值:300)设置每张图像返回的最大检测数。你可以在推理或导出时对其进行调整:model.predict("image.jpg", max_det=100) # fewer detections model.export(format="onnx", max_det=500) # more detections for dense scenes该值作为检测头的 top-k 嵌入到导出的计算图中,因此
max_det=500将输出张量放宽到最多(1, 500, 6),受锚点数量限制。是的,这就是检测预期的端到端输出格式:批大小为 1,最多 300 个检测结果,每个结果包含 6 个值
[x1, y1, x2, y2, confidence, class_id]。只需按置信度阈值过滤 — 无需 NMS。对于其他任务,输出形状会有所不同:
任务 输出形状 描述 检测 (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 个旋转角度 你可以从 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这两个检查回答了不同的问题:ONNX 元数据记录了被导出的检测头,而
predictor.model.end2end报告后端输出已经过后处理且不需要外部 NMS。对于使用end2end=False, nms=True导出的模型,它们的结果会不一致,该模型使用多对一头,但将 NMS 嵌入到了计算图中,并且还输出(1, 300, 6)— 因此单独依靠标志或输出形状都无法识别检测头。有关其他任务形状,请参阅输出形状常见问题解答。是的。YOLO26 检测样式的任务变体——检测、实例分割、姿态估计和有向目标检测 (OBB)——默认支持端到端推理。
end2end=False回退也可以在这些任务中使用。每个任务都用任务特定数据扩展了基础检测输出;
yolo26n.pt、yolo26n-seg.pt、yolo26n-pose.pt和yolo26n-obb.pt的输出形状在端到端检测工作原理下列出。