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即可。 - 正在使用自定义推理代码(如 ONNX Runtime、TensorRT 等)? 请更新你的后处理逻辑——检测输出现在是
(N, 300, 6)的xyxy格式,无需 NMS。其他任务会附加额外数据(掩码系数、关键点或角度)。 - 正在导出? 大多数格式原生支持端到端输出。但是,少数格式(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) + proto (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使用自定义推理代码#
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 (端到端) | |
|---|---|---|
| 检测输出 | (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 支持端到端,但在 JetPack 6 上使用 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: 在 JetPack 6 上,TensorRT 10.3.0 在使用
int8=True时会自动禁用端到端——使用不同的 TensorRT 版本以保留端到端 - FP16 导出: 如果你需要所有输出为 FP16,请使用
end2end=False导出——参见 为什么 output0 在使用 half=True 和 end2end=True 导出时保持 FP32 - iOS / CoreML: 完全支持端到端。如果你需要 Xcode 预览支持,请使用
end2end=False和nms=True - 边缘设备 (NCNN, RKNN): 这些格式会自动回退到一对多,因此请在你的设备端流水线中包含 NMS
Link to this section常见问题解答#
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)设置了单对单(one-to-one)检测头每张图像可以输出的最大检测数量。你可以在推理或导出时进行调整:
model.predict("image.jpg", max_det=100) # fewer detections, slightly faster
model.export(format="onnx", max_det=500) # more detections for dense scenes请注意,默认的 YOLO26 检查点(checkpoints)是在 max_det=300 的情况下训练的。虽然你可以增加这个值,但单对单检测头在训练过程中已经过优化,能够生成最多 300 个清晰的检测结果,因此超过该限制的检测质量可能会降低。如果你每张图像需要超过 300 个检测结果,请考虑使用更高的 max_det 值进行重新训练。
Link to this section我导出的 ONNX 模型输出为 (1, 300, 6) —— 这是正确的吗?#
是的,这是检测预期的端到端输出格式:batch size 为 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 个旋转角度 |
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) |