理解 Ultralytics YOLO26 中的端到端检测

介绍

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) 由于不受支持的算子限制(例如 torch.topk),会自动回退到传统输出。

端到端检测的工作原理

YOLO26 在 训练 期间使用了双头架构。两个头共享相同的骨干网络 (backbone) 和颈部 (neck),但以不同的方式产生输出:

头 (Head)目的检测输出后处理
一对一 (One-to-One) (默认)端到端推理(N, 300, 6)仅置信度阈值过滤
一对多 (One-to-Many)传统 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 模型页面

我需要更改我的代码吗?

使用 Ultralytics Python API 或 CLI

无需更改。 如果你使用标准的 Ultralytics Python APICLI,一切都会自动运行——预测验证导出 都能直接处理端到端模型。

使用 Ultralytics API 无需更改代码
from ultralytics import YOLO

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

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

使用自定义推理代码

是的,输出格式不同。 如果你为 YOLOv8YOLO11 编写了自定义后处理逻辑(例如,在使用 ONNX RuntimeTensorRT 进行推理时),你需要对其进行更新以处理新的输出形状:

YOLOv8 / YOLO11YOLO26 (端到端)
检测输出(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!

切换到一对多头

如果你需要传统的 YOLO 输出格式(例如,为了复用现有的基于 NMS 的后处理代码),你可以通过设置 end2end=False 随时切换到一对多头:

使用一对多头进行传统的基于 NMS 的输出
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)

导出格式兼容性

大多数 导出格式 都原生支持端到端推理,包括 ONNXTensorRTCoreMLOpenVINOTFLiteTF.jsMNN

以下格式 不支持 端到端,并会自动回退到一对多头:NCNNRKNNPaddlePaddleExecuTorchIMXEdge TPU

当不支持端到端时会发生什么

当你导出到这些格式时,Ultralytics 会自动切换到一对多头并记录一条警告——无需手动干预。这意味着对于这些格式,你需要在推理流水线中包含 NMS,就像 YOLOv8YOLO11 一样。

TensorRT + INT8

TensorRT 支持端到端,但在 TensorRT ≤10.3.0 版本上使用 int8=True 导出时,它会被 自动禁用

精度与速度的权衡

端到端检测提供了显著的部署优势,且对 精度 的影响极小:

指标端到端 (默认)一对多 + NMS (end2end=False)
CPU 推理速度高达 43% 的提速基准
mAP 影响~0.5 mAP 降低与 YOLO11 持平或更高
后处理仅置信度过滤完整 NMS 流水线
部署复杂度极小需要实现 NMS

对于大多数实际应用,~0.5 mAP 的差异是可以忽略不计的,特别是在考虑到速度和简洁性收益时。如果最高精度是你的首要任务,你可以随时使用 end2end=False 回退到一对多头。

请参阅 YOLO26 性能指标 以获取所有模型尺寸 (n, s, m, l, x) 的详细基准测试。

从 YOLOv8 或 YOLO11 迁移

如果你要将现有项目升级到 YOLO26,这里有一份快速检查清单以确保平滑过渡:

  • Ultralytics API / CLI 用户: 无需更改,只需将模型名称更新为 yolo26n.pt(或 yolo26n-seg.pt, yolo26n-pose.pt, yolo26n-obb.pt
  • 自定义后处理代码: 更新以处理新的输出形状——检测为 (N, 300, 6),外加 分割姿态估计OBB 的任务特定数据。还要注意框格式从 xywhxyxy 的变化
  • 导出流水线: 检查上述 格式兼容性 部分以获取你的目标格式信息
  • 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

常见问题 (FAQ)

我能同时使用 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 中使用检测模型的预览功能。

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 值重新训练。

我导出的 ONNX 模型输出 (1, 300, 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

或者,检查输出形状——端到端检测模型的输出为 (1, 300, 6),而传统模型的输出为 (1, nc + 4, 8400)。关于其他任务的形状,请参阅 输出形状常见问题解答

分割、姿态和 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)
OBByolo26n-obb.pt(N, 300, 7)

评论