#YOLO #目标检测 #模型部署 #边缘计算 #端到端推理

⚠️ 痛点直击:NMS 的 O(N²) 时间复杂度在边缘设备上是性能杀手。8400 个候选框的两两比较,CPU 上轻松吃掉 10-30ms。

阅读时间:约 10 分钟


两代模型,两种哲学

在深入张量格式之前,我们需要先理解一个根本性的设计分歧——YOLOv8 信奉"宁可多生成,后面再筛",而 YOLO26 选择"训练时就解决,推理时直接用"

💡 比喻时间

想象你在快餐店点餐。YOLOv8 是那种把菜单上所有菜都端上来、让你自己挑的餐厅——上菜快,但挑菜(NMS)费时间。YOLO26 则是一位经验丰富的主厨,直接把你最想吃的几道菜精准端出来,不多不少。

YOLOv8 由 Ultralytics 于 2023 年初发布,采用 Anchor-Free 设计和解耦头(Decoupled Head)。它在三个尺度特征图上生成密集预测,通过分布焦点损失(DFL)优化边界框回归,最终需要 NMS 清理冗余检测。

YOLO26 则是 2026 年初的产物,核心卖点是端到端无 NMS 推理。通过双头训练架构(一对多头加速收敛 + 一对一头保证推理唯一性)、移除 DFL 模块、以及 STAL/ProgLoss 等训练策略,它在模型内部就完成了"去重"工作。

架构特性 YOLOv8 YOLO26
推理模式 传统模式 + 外部 NMS 端到端,无需 NMS
边界框回归 DFL 分布焦点损失 直接回归浮点坐标
输出策略 密集预测,固定 8400 框 动态筛选 + 固定上限
目标设备 偏通用,GPU 友好 专为边缘 / CPU 优化

输出张量:到底长什么样?

这是全文最核心的部分。两个模型的输出张量在形状、语义、可用性三个维度上截然不同。

一眼看懂

YOLOv8 YOLO26
形状 (B, 84, 8400) (B, 300, 6)
含义 84 = 4坐标(xywh) + 80类别概率 8400 个候选框,需外部 NMS 筛选 6 = 4坐标(xyxy) + 1置信度 + 1类别ID 最多 300 个检测结果,已排序去重

YOLOv8:84 × 8400 意味着什么?

先看维度 84:前 4 个值是边界框的中心坐标和宽高 (cx, cy, w, h),全部是归一化值;后 80 个值是 COCO 数据集 80 个类别的概率分数,经过 softmax 归一化。你需要自己找到最大概率对应的类别,还要把 cx/cy/w/h 解码成像素坐标。

再看维度 8400:这些候选框来自三层特征图——P3(80×80,负责小目标)、P4(40×40,中等目标)、P5(20×20,大目标),每个网格点生成一个预测。绝大多数框是垃圾,重叠严重,必须靠 NMS 清理。

ℹ️ 注意转置陷阱:YOLOv8 输出形状是 (B, 84, 8400) 而不是 (B, 8400, 84),解析时需要先做转置操作,这是很多新手踩过的坑。

YOLO26:6 × 300 的极简哲学

YOLO26 的输出,每个检测结果只有 6 个数:x1, y1, x2, y2, confidence, class_id。坐标是左上角和右下角(xyxy 格式),直接缩放到原图尺寸就能画框;置信度是模型内部融合好的分数,无需额外计算;类别 ID 是整数索引,拿来就用。

300 个检测框已经按置信度降序排列,前面的框就是模型最有把握的检测结果。你只需要设一个置信度阈值(比如 0.25),把低于阈值的框丢掉,完事。

💡 比喻时间

再用一个比喻:YOLOv8 给你的是一整箱未分拣的快递(8400 个包裹),你得自己找、拆、扔;YOLO26 给你的是快递柜里按重要性排好的 300 个格子,打开前几个就是你要的东西。


全方位对比:一张表说清楚

维度 YOLOv8 YOLO26
输出形状 (B, 84, 8400) (B, 300, 6)
坐标格式 中心点+宽高 (xywh) 对角点 (x1y1x2y2)
置信度 需手动计算 直接输出
类别信息 80 维概率向量 1 维类别 ID
NMS 必须 不需要
后处理步骤 4 步:解码→NMS→过滤→排序 1 步:阈值过滤
后处理复杂度 O(N²) O(N)
CPU 后处理延迟 10-30ms <0.3ms
跨框架兼容性 依赖各框架 NMS 实现 天然兼容大多数框架

代码说话:输出解析实战

光看表格不够直观,我们用一段可运行的代码来对比两个模型的完整后处理流程。你可以直接复制到本地跑一下,感受差距有多大。

import numpy as np
import time
​
# ═══════════════════════════════════════════════════
# 模拟数据:假设输入图像尺寸 640×640,COCO 80 类
# ═══════════════════════════════════════════════════
np.random.seed(42)
IMG_SIZE = 640
​
# YOLOv8 输出: (1, 84, 8400)
v8_output = np.random.rand(1, 84, 8400).astype(np.float32)
​
# YOLO26 输出: (1, 300, 6) — 坐标已归一化
v26_output = np.random.rand(1, 300, 6).astype(np.float32)
v26_output[..., 4] = np.random.rand(300)           # 置信度 0~1
v26_output[..., 5] = np.random.randint(0, 80, 300)  # 类别ID
​
​
# ═══════════════════════════════════════════════════
# YOLOv8 后处理(完整 4 步流程)
# ═══════════════════════════════════════════════════
def nms(boxes, scores, iou_thresh=0.45):
    """简易 NMS 实现"""
    x1 = boxes[:, 0] - boxes[:, 2] / 2
    y1 = boxes[:, 1] - boxes[:, 3] / 2
    x2 = boxes[:, 0] + boxes[:, 2] / 2
    y2 = boxes[:, 1] + boxes[:, 3] / 2
    areas = (x2 - x1) * (y2 - y1)
    order = scores.argsort()[::-1]
    keep = []
    while order.size > 0:
        i = order[0]
        keep.append(i)
        xx1 = np.maximum(x1[i], x1[order[1:]])
        yy1 = np.maximum(y1[i], y1[order[1:]])
        xx2 = np.minimum(x2[i], x2[order[1:]])
        yy2 = np.minimum(y2[i], y2[order[1:]])
        inter = np.maximum(0, xx2 - xx1) * np.maximum(0, yy2 - yy1)
        iou = inter / (areas[i] + areas[order[1:]] - inter + 1e-6)
        inds = np.where(iou <= iou_thresh)[0]
        order = order[inds + 1]
    return keep
​
​
def postprocess_v8(output, conf_thresh=0.25, iou_thresh=0.45):
    """YOLOv8: 转置 → 解码 → 过滤 → NMS"""
    preds = output[0].T                 # 步骤1: 转置 (84,8400) → (8400,84)
    boxes = preds[:, :4] * IMG_SIZE     # 步骤2: xywh 坐标解码
    class_probs = preds[:, 4:]          # 80 个类别概率
    scores = class_probs.max(axis=1)    # 取最大概率作为置信度
    class_ids = class_probs.argmax(axis=1)
​
    mask = scores > conf_thresh          # 步骤3: 置信度过滤
    boxes, scores, class_ids = boxes[mask], scores[mask], class_ids[mask]
​
    keep = nms(boxes, scores, iou_thresh)  # 步骤4: NMS 去重
    return boxes[keep], scores[keep], class_ids[keep]
​
​
# ═══════════════════════════════════════════════════
# YOLO26 后处理(仅 1 步:阈值过滤)
# ═══════════════════════════════════════════════════
def postprocess_v26(output, conf_thresh=0.25):
    """YOLO26: 过滤低置信度框,完事"""
    dets = output[0]                     # (300, 6)
    mask = dets[:, 4] > conf_thresh      # 仅需一步阈值过滤
    dets = dets[mask]
    boxes = dets[:, :4] * IMG_SIZE       # xyxy 坐标缩放
    scores = dets[:, 4]                  # 置信度直接可用
    class_ids = dets[:, 5].astype(int)   # 类别 ID 直接可用
    return boxes, scores, class_ids
​
​
# ═══════════════════════════════════════════════════
# 性能对比
# ═══════════════════════════════════════════════════
N = 100
​
t0 = time.perf_counter()
for _ in range(N):
    postprocess_v8(v8_output)
v8_ms = (time.perf_counter() - t0) / N * 1000
​
t0 = time.perf_counter()
for _ in range(N):
    postprocess_v26(v26_output)
v26_ms = (time.perf_counter() - t0) / N * 1000
​
print(f"YOLOv8 后处理: {v8_ms:.2f}ms")
print(f"YOLO26 后处理: {v26_ms:.2f}ms")
print(f"加速比: {v8_ms/v26_ms:.1f}x")

跑一下你会发现,哪怕用纯 NumPy 模拟,YOLO26 的后处理也比 YOLOv8 快一个数量级以上。在真实的边缘设备上,这个差距会更加明显。


部署视角:NMS 是隐藏的"地雷"

很多人在选模型时只看 mAP 和 FPS,但真正到部署环节才发现——NMS 的跨框架兼容性是最大的坑

ONNX Runtime、TensorRT、OpenVINO、CoreML、TFLite……每个推理框架对 NMS 算子的支持方式都不一样。有的原生支持,有的需要你用 C++ 手撸一个,有的干脆不支持。YOLOv8 在每个框架上都要处理这个兼容性问题,而 YOLO26 由于输出已经是最终结果,天然绕过了这颗地雷。

推理框架 YOLOv8 YOLO26
ONNX Runtime 需转置 + 外接 NMS 直接可用
TensorRT 需手写 NMS Plugin 端到端模式
OpenVINO 需处理 NMS 兼容 天然兼容
CoreML / TFLite 需适配 NMS 算子 端到端输出
NCNN / RKNN 不支持端到端 支持端到端

实战建议:如果你的项目需要在 3 个以上推理框架上部署同一个模型,YOLO26 的统一输出格式能帮你省下大量适配代码。


选型指南:你到底该选哪个?

没有绝对的好坏,只有适不适合。

选 YOLOv8 如果你……

  • 需要极致 mAP 精度

  • GPU 资源充足,对延迟不敏感

  • 需要自定义 NMS 策略

  • 已有成熟的 v8 部署 pipeline

选 YOLO26 如果你……

  • 部署在边缘设备(Nano / 树莓派)

  • 实时性是硬指标(<30ms)

  • CPU 资源受限

  • 需要快速上线、简化运维


写在最后

核心差异速记

  • 形状(B, 84, 8400) vs (B, 300, 6) — 从"大而全"到"小而精"

  • 坐标:xywh(需解码)vs xyxy(直接可用)

  • NMS:必须外部执行 vs 模型内部已完成

  • 延迟:后处理 10-30ms vs <0.3ms — 差距 100 倍

  • 部署:每个框架单独适配 vs 天然跨平台兼容

YOLO26 的输出张量设计代表了目标检测领域的一个重要趋势——把复杂性从推理阶段前移到训练阶段。通过双头训练、改进损失函数等手段,让模型在训练时就学会输出干净、唯一、排序好的检测结果,从而在推理时实现真正的端到端。

当然,工程世界没有银弹。如果你的场景需要极致精度、需要灵活控制 NMS 策略、或者已经有成熟的 YOLOv8 pipeline 在生产环境稳定运行,也没必要为了追新而迁移。

但如果你正在启动一个新的边缘部署项目,YOLO26 值得作为首选方案认真评估。


如果这篇文章对你有帮助,点个赞让更多人看到 👍

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐