YOLOv5:YOLO目标检测模型的第五次迭代.

YOLOv5是一个面向实时工业应用而开源的目标检测算法,其优异性在于开源库的实用和鲁棒性。YOLOv5开源库的主要特点为:

YOLOv5P5P6 两个不同训练输入尺度的模型:P6 即为 1280x1280 输入的大模型;P5 是输入尺寸是 640x640的常规模型。本文主要介绍 P5 模型结构。

1. 数据增强模块

YOLOv5 目标检测算法中使用的数据增强比较多,包括:

其中 Mosaic 数据增强概率为 1,表示一定会触发;而对于 smallnano 两个版本的模型不使用 MixUp,其他的 l/m/x 系列模型则采用了 0.1 的概率触发 MixUp

其核心的 Mosaic + RandomAffine + MixUp 过程如下:

(1)Mosaic 马赛克

Mosaic 属于混合类数据增强,因为它在运行时候需要 4 张图片拼接,变相的相当于增加了训练的 batch size。其运行过程简要概况为:

  1. 随机生成拼接后 4 张图的交接中心点坐标,此时就相当于确定了 4 张拼接图片的交接点
  2. 随机选出另外 3 张图片的索引以及读取对应的标注
  3. 对每张图片采用保持宽高比的 resize 操作将其缩放到指定大小
  4. 按照上下左右规则,计算每张图片在待输出图片中应该放置的位置,因为图片可能出界故还需要计算裁剪坐标
  5. 利用裁剪坐标将缩放后的图片裁剪,然后贴到前面计算出的位置,其余位置全部补 114 像素值
  6. 对每张图片的标注也进行相应处理

由于拼接了 4 张图,所以输出图片面积会扩大 4 倍,从 640x640 变成 1280x1280,因此要想恢复为 640x640, 必须要再接一个 RandomAffine 随机仿射变换。

(2)RandomAffine 随机仿射变换

随机仿射变换有两个目的:

  1. 对图片进行随机几何仿射变换
  2. Mosaic 输出的扩大 4 倍的图片还原为 640x640 尺寸

随机仿射变换包括平移、旋转、缩放、错切等几何增强操作,同时由于 MosaicRandomAffine 属于比较强的增强操作,会引入较大噪声,因此需要对增强后的标注进行处理,过滤规则为:

(3)MixUp

MixUpMosaic 类似也属于混合图片类增强方法。随机选出另外一张图后将两图再随机混合。具体实现方法有多种,常见的做法是要么将 label 直接拼接起来,要么将 label 也采用 alpha 方法混合。

YOLOv5 实现的 MixUplabel 直接拼接,而图片通过分布采样混合。随机出来的另一张图也需要经过 Mosaic 马赛克 + RandomAffine 随机仿射变换 的增强后才能混合。

2. 网络结构

YOLOv5 网络结构是标准的 CSPDarknet + PAFPN + 非解耦 Head

YOLOv5 网络结构大小由 deepen_factorwiden_factor 两个参数决定。其中 deepen_factor 控制网络结构深度,即 CSPLayerDarknetBottleneck 模块堆叠的数量;widen_factor 控制网络结构宽度,即模块输出特征图的通道数。以 YOLOv5-l 为例,其 deepen_factor = widen_factor = 1.0

(1)backbone

CSPDarknet 整体结构和 ResNet 类似。P5 模型共 5 层结构,包含 1Stem Layer4Stage Layer

(2)Neck

YOLOv5 Neck采用PAFPN结构,Neck 模块输出的特征图和 Backbone 完全一致。即 P5 模型为 (B,256,80,80)(B,512,40,40)(B,1024,20,20)P6 模型为 (B,256,160,160)(B,512,80,80)(B,768,40,40)(B,1024,20,20)

(3)Head

YOLOv5 Head 结构和 YOLOv3 完全一样,为非解耦HeadHead 模块只包括 3 个不共享权重的卷积,用于将输入特征图进行变换。由于 YOLOv5 是非解耦输出,即分类和 bbox 检测等都是在同一个卷积的不同通道中完成。以 COCO 80 类为例:

3. 正负样本匹配策略

正负样本匹配策略的核心是确定预测特征图的所有位置中哪些位置应该是正样本,哪些是负样本,甚至有些是忽略样本。 匹配策略是目标检测算法的核心,一个好的匹配策略可以显著提升算法性能。

YOLOV5 的匹配策略简单总结为:采用了 anchorgt_bbox 的形状匹配度作为划分规则,同时引入跨邻域网格策略来增加正样本。 其主要包括如下两个核心步骤:

(1)Anchor设置

YOLOv5Anchor-based 的目标检测算法,其 Anchor size 的获取方式与 YOLOv3 类似,也是使用聚类获得,其不同之处在于聚类使用的标准不再是基于 IoU 的,而是使用形状上的宽高比作为聚类准则(即 shape-match)。

默认 Anchor size:

anchors = [[(10, 13), (16, 30), (33, 23)], [(30, 61), (62, 45), (59, 119)],
           [(116, 90), (156, 198), (373, 326)]]

(2)Bbox 编解码过程

Anchor-based 算法中,预测框通常会基于 Anchor 进行变换,然后预测变换量,这对应 GT Bbox 编码过程,而在预测后需要进行 Pred Bbox 解码,还原为真实尺度的 Bbox,这对应 Pred Bbox 解码过程。

YOLOv3 中,回归公式为:

\[\begin{aligned} b_x&=\sigma(t_x)+c_x \\ b_y&=\sigma(t_y)+c_y \\ b_w&=a_w\cdot e^{t_w} \\ b_h&=a_h\cdot e^{t_h} \\ \end{aligned}\]

而在 YOLOv5 中,回归公式为:

\[\begin{aligned} b_x&=(2\cdot\sigma(t_x)-0.5)+c_x \\ b_y&=(2\cdot\sigma(t_y)-0.5)+c_y \\ b_w&=a_w\cdot(2\cdot\sigma(t_w))^2 \\ b_h&=a_h\cdot(2\cdot\sigma(t_h))^2 \end{aligned}\]

改进之处主要有以下两点:

这个改进具有以下好处:

(3)匹配策略

YOLOv5的正样本匹配策略采用“比例”比较,即将 GT BboxWHAnchorWH 分别进行比例比较,要求最大比例$r^{max}$不超过给定阈值才算成功匹配。

\[\begin{aligned} r_w &= w_{gt} / w_{pt} \\ r_h & = h_{gt} / h_{pt} \\ r_w^{max}&=\max(r_w, 1/r_w) \\ r_h^{max}&=\max(r_h, 1/r_h) \\ r^{max}&=\max(r_w^{max}, r_h^{max}) \\ \end{aligned}\]

GT Bbox成功匹配之后,会将其相近的两个邻域位置也设置为正样本:

YOLOv5Assign 方式带来了以下改进:

4. 训练策略

(1)损失函数

YOLOv5 中总共包含 3Loss,分别为:

三个 loss 按照一定比例汇总:

\[Loss=\lambda_1L_{cls}+\lambda_2L_{obj}+\lambda_3L_{loc}\]

P3P4P5 层对应的 Objectness loss 按照不同权重进行相加,默认的设置是:

\[L_{obj}=4.0\cdot L_{obj}^{small}+1.0\cdot L_{obj}^{medium}+0.4\cdot L_{obj}^{large}\]

(2)优化策略

将优化参数分成 Conv/Bias/BN 三组,在 WarmUp 阶段,不同组采用不同的学习率以及 momentum 更新曲线。 同时在 WarmUp 阶段采用的是 iter-based 更新策略,而在非 WarmUp 阶段则变成 epoch-based 更新策略。

针对不同的 batch size 采用了不同的 weight decay 策略,具体来说为:

为了最大化不同 batch size 情况下的性能,设置总 batch size 小于 64 时候会自动开启梯度累加功能。

(3)推理过程

YOLOv5 输出特征图尺度为 80x8040x4020x20 的三个特征图,每个位置共 3anchor,因此输出特征图通道为 $3\times(5+80)=255$。 YOLOv5 是非解耦输出头,因此首先提前将其进行解耦,分成了类别预测分支、bbox 预测分支和 obj 预测分支。

YOLOv5的推理过程如下:

  1. 将三个不同尺度的类别预测分支、bbox 预测分支和 obj 预测分支进行拼接,并进行维度变换。为了后续方便处理,会将原先的通道维度置换到最后,类别预测分支、bbox 预测分支和 obj 预测分支的形状分别为 (b, 3x80x80+3x40x40+3x20x20, 80)=(b,25200,80),(b,25200,4),(b,25200,1)
  2. 分类预测分支和 obj 分支需要进行 sigmoid 计算,而 bbox 预测分支需要进行解码,还原为真实的原图解码后 xyxy 格式。
  3. 遍历 batch 中的每张图,然后用 score_thr 对类别预测分值进行阈值过滤,去掉低于 score_thr 的预测结果
  4. obj 预测分值和过滤后的类别预测分值相乘,然后依然采用 score_thr 进行阈值过滤,确保过滤后的检测框数目不会多于 nms_pre
  5. 基于前处理过程,将剩下的检测框还原到网络输出前的原图尺度,然后进行 nms 即可。最终输出的检测框不能多于 max_per_img

(4)batch shape 策略

为了加速验证集的推理过程,作者提出了 batch shape 策略,其核心原则是:确保在 batch 推理过程中同一个 batch 内的图片 pad 像素最少,不要求整个验证过程中所有 batch 的图片尺度一样。

其大概流程是:将整个测试或者验证数据的宽高比进行排序,然后依据 batch 设置将排序后的图片组成一个 batch, 同时计算这个 batch 内最佳的 batch shape,防止 pad 像素过多。最佳 batch shape 计算原则为在保持宽高比的情况下进行 pad,不追求正方形图片输出。

  image_shapes = []
  for data_info in data_list:
      image_shapes.append((data_info['width'], data_info['height']))

  image_shapes = np.array(image_shapes, dtype=np.float64)

  n = len(image_shapes)  # number of images
  batch_index = np.floor(np.arange(n) / self.batch_size).astype(
      np.int64)  # batch index
  number_of_batches = batch_index[-1] + 1  # number of batches

  aspect_ratio = image_shapes[:, 1] / image_shapes[:, 0]  # aspect ratio
  irect = aspect_ratio.argsort()

  data_list = [data_list[i] for i in irect]

  aspect_ratio = aspect_ratio[irect]
  # Set training image shapes
  shapes = [[1, 1]] * number_of_batches
  for i in range(number_of_batches):
      aspect_ratio_index = aspect_ratio[batch_index == i]
      min_index, max_index = aspect_ratio_index.min(
      ), aspect_ratio_index.max()
      if max_index < 1:
          shapes[i] = [max_index, 1]
      elif min_index > 1:
          shapes[i] = [1, 1 / min_index]

  batch_shapes = np.ceil(
      np.array(shapes) * self.img_size / self.size_divisor +
      self.pad).astype(np.int64) * self.size_divisor

  for i, data_info in enumerate(data_list):
      data_info['batch_shape'] = batch_shapes[batch_index[i]]