2、YOLO模型基础:YOLO系列(v3/v4/v5/v8等)的输出张量结构、锚框与网格概念
在DeepStream中集成YOLO模型,首先需要理解YOLO系列模型输出的本质——它不是一个简单的分类得分向量,而是一个编码了目标位置、尺寸、类别与置信度的多维张量。这个张量的结构直接决定了DeepStream中Parser(解析器)的编写方式、NMS(非极大值抑制)的触发逻辑以及标签映射的索引规则。本章将系统梳理YOLOv3至YOLOv8的输出张量演变、锚框机制与网格划分原理,为后续在DeepStream中实现自定义解析打下坚实的理论基础。
2.1 核心原理:从网格到张量的编码逻辑
YOLO系列模型的核心思想是将目标检测视为一个回归问题。模型将输入图像划分为S×S的网格(grid cell),每个网格负责预测中心点落在该网格内的目标。这种设计使得检测速度极快,因为只需要一次前向传播即可输出所有目标的位置和类别。
在YOLOv3及后续版本中,每个网格单元预测B个边界框(bounding box),每个边界框包含5个基本参数加上C个类别概率。这5个参数分别是:中心点坐标偏移(tx, ty)、宽高缩放因子(tw, th)以及目标置信度(objectness)。最终输出的张量形状为:
输出张量维度: [B, (5 + C), S, S]
- B: 每个网格的锚框数量(通常为3)
- C: 检测类别数(如COCO为80)
- S: 特征图尺寸(如13、26、52)
以YOLOv3在416×416输入下为例,模型会产生三个尺度的输出:13×13(下采样32倍)、26×26(下采样16倍)、52×52(下采样8倍)。每个尺度对应不同大小的目标:13×13负责大目标,26×26负责中目标,52×52负责小目标。每个网格的3个锚框(anchor box)是预先通过K-means聚类数据集得到的先验框,用于加速模型收敛。
2.2 锚框机制与网格坐标解码
锚框(Anchor Box)是YOLO系列中最重要的先验知识之一。在YOLOv3/v4/v5中,每个网格单元预设3个不同宽高比的锚框,模型学习的是如何调整这些锚框来匹配真实目标。锚框的选择直接影响小目标检测的召回率。
| 模型版本 | 锚框策略 | 输出通道数 | 解码方式 |
|---|---|---|---|
| YOLOv3 | 9个锚框,按尺度分配3个 | 3×(5+C) | sigmoid(tx)+grid_x, sigmoid(ty)+grid_y |
| YOLOv4 | 9个锚框,沿用v3策略 | 3×(5+C) | 同v3,但使用CIoU损失 |
| YOLOv5 | 自动学习锚框,每尺度3个 | 3×(5+C) | 同v3,但缩放因子使用exp() |
| YOLOv8 | 无锚框(anchor-free) | 4+C | 直接回归中心点与宽高 |
以YOLOv5为例,解码公式如下:
bx = 2 * sigmoid(tx) - 0.5 + grid_x
by = 2 * sigmoid(ty) - 0.5 + grid_y
bw = (2 * sigmoid(tw))^2 * anchor_w
bh = (2 * sigmoid(th))^2 * anchor_h
其中grid_x和grid_y是网格的整数索引,anchor_w和anchor_h是锚框的宽高。这种解码方式使得中心点坐标被限制在网格内,而宽高则通过平方操作保证非负。在DeepStream中,Parser需要读取原始张量,执行上述解码,然后输出归一化的边界框坐标(通常为0~1之间的相对坐标)。
2.3 YOLOv8的结构变化:无锚框设计
YOLOv8是Ultralytics在2023年发布的重要更新,其最大的变化是彻底移除了锚框机制,转向anchor-free检测头。这意味着输出张量的通道数从3×(5+C)减少为(4+C),每个网格单元只预测一个目标(或背景),不再有多个锚框的冗余。
YOLOv8的输出张量形状为:
[1, 4+C, S, S] 或 [1, 84, 8400](经过reshape后)
- 4: 边界框的x1, y1, x2, y2(或cx, cy, w, h)
- C: 类别数(COCO为80)
- 8400: 三个尺度特征图展平后的总数(80×80 + 40×40 + 20×20)
这种设计带来了两个直接影响:第一,模型参数量减少,推理速度更快;第二,Parser的编写逻辑简化,不再需要遍历多个锚框,只需对每个网格位置直接读取坐标和类别概率。但需要注意的是,YOLOv8的输出坐标是相对于输入图像尺寸的像素值(在640×640输入下),而非归一化坐标,DeepStream中需要除以输入尺寸进行归一化。
2.4 案例拆解:COCO数据集下的张量解析对比
假设我们使用COCO数据集(80类),输入尺寸为640×640,对比YOLOv5s和YOLOv8s的输出张量:
| 属性 | YOLOv5s | YOLOv8s |
|---|---|---|
| 输出尺度数 | 3(80×80, 40×40, 20×20) | 3(80×80, 40×40, 20×20) |
| 每尺度通道数 | 3×(5+80)=255 | 4+80=84 |
| 总预测数 | 3×8400=25200 | 8400 |
| 坐标格式 | cx,cy,w,h(需解码) | x1,y1,x2,y2(直接使用) |
| 置信度 | 有独立objectness | 无,类别得分即置信度 |
在DeepStream中,YOLOv5的Parser需要执行以下步骤:
- 遍历每个尺度、每个网格、每个锚框,共25200次预测。
- 对每个预测执行sigmoid解码,得到边界框坐标和置信度。
- 将置信度与类别得分相乘,得到最终得分。
- 按得分阈值过滤,再执行NMS。
而YOLOv8的Parser只需:
- 将[1,84,8400]转置为[8400,84]。
- 直接读取每行的x1,y1,x2,y2和80个类别得分。
- 取最大类别得分作为置信度,过滤后执行NMS。
从计算量上看,YOLOv8的解析效率提升约3倍,这对于实时视频分析场景(如DeepStream)尤为重要。
2.5 常见误区与工程复盘
误区一:混淆锚框与网格的概念。网格是图像划分的固定单元,锚框是预设的边界框形状。网格数量由特征图尺寸决定,锚框数量是超参数。在DeepStream中,如果错误地将锚框数量当作网格数量,会导致张量维度解析错误。
误区二:忽略letterbox预处理的影响。YOLO系列通常使用letterbox保持宽高比,将图像填充至正方形。这意味着模型输出的坐标是相对于填充后图像的,在DeepStream中需要将坐标映射回原始图像尺寸,否则检测框会偏移。
误区三:YOLOv8的坐标未归一化。YOLOv8输出的x1,y1,x2,y2是像素值(0~640),而DeepStream的NMS插件通常期望0~1的归一化坐标。必须在Parser中除以输入尺寸(如640)进行归一化。
复盘总结:理解YOLO的输出张量结构是DeepStream集成的第一步。对于YOLOv3/v4/v5,核心是掌握锚框解码公式;对于YOLOv8,核心是适应无锚框的简化输出。在实际项目中,建议先使用Python脚本离线验证解析逻辑的正确性,再移植到DeepStream的C++ Parser中,这样可以大幅减少调试时间。同时,注意不同版本YOLO的坐标约定(中心点vs左上角)、归一化方式(0~1 vs 像素值)以及置信度计算方式,这些细节决定了检测结果的准确性。