一、数据增强
- mosaic
- 仿射变换与透视变换
- Mixup
mosaic代码位置仿射变换 与 透视变换代码片段位置
二、网络结构
1. 网络不同尺寸
nsmlx
与网络深宽度
yolov5 官方提供了5个目标检测的网络版本:yolov5n
、yolov5s
、yolov5m
、yolov5l
、yolov5x
,早年是刚好对应的五个yaml文件:
后来改为了一个yaml文件,通过scales
参数控制尺寸:
scales: # model compound scaling constants, i.e. 'model=yolov5n.yaml' will call yolov5.yaml with scale 'n'# [depth, width, max_channels]n: [0.33, 0.25, 1024]s: [0.33, 0.50, 1024]m: [0.67, 0.75, 1024]l: [1.00, 1.00, 1024]x: [1.33, 1.25, 1024]
- 各版本的网络结构都是类似的,backbone和head参数都一样,不同的只是
depth_multiple
和width_multiple
这两个参数depth_multiple
控制网络深度:有些模块需要重复 n 次,此时,我们就会用到depth_multiple * n
来控制该模块重复的次数,达到控制网路深度的作用width_multiple
控制网络宽度:用于控制某些模块输出的特征图channel
数,比如 卷积层的输出channel
数,达到控制网络宽度的效果。
yolov5n
是yolov5
系列中深度最小,特征图channel
数最少的网络。其他的都是在此基础上不断加深(depth
),不断加宽(width
)。
nsmlx
从左往右网络的尺寸变大,参数量变大。
举例说明l和s尺寸
# YOLOv5 v6.0 backbone
backbone:# [from, number, module, args]- [-1, 1, Conv, [64, 6, 2, 2]] # 0-P1/2- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4- [-1, 3, C3, [128]]- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8- [-1, 6, C3, [256]]- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16- [-1, 9, C3, [512]]- [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32- [-1, 3, C3, [1024]]- [-1, 1, SPPF, [1024, 5]] # 9
depth
控制网络深度:
比如说,yolov5l型号的backbone中,number
表示该模块的重复次数,四个C3
块分别重复3, 6, 9, 3
次。
如果是yolov5s型号,那么需要都乘depth = 0.33
,重复次数变为1, 2, 3, 1
。原本就是1或者乘完小于1的就不用乘重复1次。
width
控制网络宽度:
比如,yolov5l型号的backbone中,args
表示参数列表,第一个值是模块输出的channel数,前两Conv层分别为64, 128
。
如果是yolov5s型号,需要都乘width=0.5
,变为32, 64
。
官方更多改造版
还有其他版本的配置文件,可查看https://github.com/ultralytics/yolov5/tree/master/models/hub
常规版本名称后加了6的,是能更好支持更大尺寸图像(常规只能处理640x640)1280x1280。
2. yaml参数解读
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license# Ultralytics YOLOv5 object detection model with P3/8 - P5/32 outputs
# Model docs: https://docs.ultralytics.com/models/yolov5
# Task docs: https://docs.ultralytics.com/tasks/detect# Parameters
nc: 80 # number of classes
scales: # model compound scaling constants, i.e. 'model=yolov5n.yaml' will call yolov5.yaml with scale 'n'# [depth, width, max_channels]n: [0.33, 0.25, 1024]s: [0.33, 0.50, 1024]m: [0.67, 0.75, 1024]l: [1.00, 1.00, 1024]x: [1.33, 1.25, 1024]# YOLOv5 v6.0 backbone
backbone:# [from, number, module, args]- [-1, 1, Conv, [64, 6, 2, 2]] # 0-P1/2- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4- [-1, 3, C3, [128]]- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8- [-1, 6, C3, [256]]- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16- [-1, 9, C3, [512]]- [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32- [-1, 3, C3, [1024]]- [-1, 1, SPPF, [1024, 5]] # 9# YOLOv5 v6.0 head
head:- [-1, 1, Conv, [512, 1, 1]]- [-1, 1, nn.Upsample, [None, 2, "nearest"]]- [[-1, 6], 1, Concat, [1]] # cat backbone P4- [-1, 3, C3, [512, False]] # 13- [-1, 1, Conv, [256, 1, 1]]- [-1, 1, nn.Upsample, [None, 2, "nearest"]]- [[-1, 4], 1, Concat, [1]] # cat backbone P3- [-1, 3, C3, [256, False]] # 17 (P3/8-small)- [-1, 1, Conv, [256, 3, 2]]- [[-1, 14], 1, Concat, [1]] # cat head P4- [-1, 3, C3, [512, False]] # 20 (P4/16-medium)- [-1, 1, Conv, [512, 3, 2]]- [[-1, 10], 1, Concat, [1]] # cat head P5- [-1, 3, C3, [1024, False]] # 23 (P5/32-large)- [[17, 20, 23], 1, Detect, [nc]] # Detect(P3, P4, P5)
每一行有4个参数[from, number, module, args]
from
:模块输入来源,- 一般为-1,表示上一层输出是本层输入。
- 其他数字指层的索引(从0开始)
- 对于
Concat
模块,from参数是一个list列表,因为有两个输入,比如[-1, 4]
number
:这个模块或者模块内的某一部分,重复堆叠多少次。比如[-1, 3, C3, [128]]
说明C3块中的残差块要堆叠3次。module
:模块名称。args
:为一个list,记录该模块的参数,一般第一个值表示输出的channel数,具体看下面图片
3. 各个模块
Conv
padding
不写时,默认输出尺寸不变,自动计算padding大小。
C3
一个CSP模块。C3的名称含义是,除了要重复的残差块以外,有3个卷积层。( a CSP bottleneck includes 3 conv layers)
args
的第二个参数为True或者不写时,表示残差块都有残差连接。
例子中,输入尺寸为 160x160x64 , c1=64 ,c2=64, n=1
SPPF
args
的第二个参数表示max_pooling
层的Kernel size
例子中,输入尺寸为 20x20x512 , c1=512 ,c2=512, k=5
Concat
args
就一个元素,记录在第几个维度上拼接。1表示第二个维度也就是channel维度。(batch, channel, w, h)
nn.Upsample
args
的三个值对应nn.Upsample
的参数,输出尺寸、缩放比例、插值方法。
直接调用 nn.Upsample
,传入对应参数
import torch.nn as nnupsample = nn.Upsample(size=None, scale_factor=2, mode='nearest')
size
:指定输出的尺寸 。size
和scale_factor
只能二选一填写,输出尺寸和缩放比例都指定时会报错。scale_factor
:指定尺寸放大的比例因子。mode
:指定上采样的模式。可选的模式包括:'nearest'
:最近邻插值,使用最近邻像素的值来进行插值。'linear'
:线性插值,使用线性插值方法。'bilinear'
:双线性插值,对每个输出像素使用二维线性插值方法。'bicubic'
:双三次插值,使用双三次插值方法。'trilinear'
:三线性插值,对每个输出像素使用三维线性插值方法。
Detect
网络输出层
每个输出对应3个anchor。
后来版本就用Anchor-free,所以不指定anchors参数了[[17, 20, 23], 1, Detect, [nc]]
3. yolov5l完整网络结构图
Axure图片资料
4. 网络搭建代码详解
三、损失函数
YOLOv5 是基于 anchor 的目标检测算法,即 anchor - base。每个网格(grid cell)都会预先设定几个不同尺寸和比例的 anchor 框。这些 anchor 框是根据训练数据集里目标的尺寸统计信息得到的, 例如常见的目标宽度、高度的分布等。在检测过程中,模型会以这些 anchor 框为基础,预测目标的位置、尺寸以及类别等信息。比如,模型会预测相对于 anchor 框的偏移量(包括中心点的偏移、宽高的缩放比例),从而得到最终的预测边界框(bounding box)
在训练过程中,需要确定哪些 anchor 是正样本(负责预测目标),哪些是负样本(不负责预测目标),具体规则下面介绍。
1. 网络预测结果
网络预测出的结果为一个list,三个元素对应于三个尺度的feature map。比如feature map 1张量尺寸为(2,3,80,80,85)
,对应不同维度在特征图、锚框、预测参数(坐标、置信度、类别 )上的含义。
张量维度 (2, 3, 80, 80, 85)
的拆解说明
2
:batch_size
(批次大小,即一次处理的图像数量 )3
:对应该尺度下的3
个anchors
(锚框数量 )80
:feature map
的宽(特征图宽度维度 )80
:feature map
的高(特征图高度维度 )85
:由以下部分组成(85 = 2 + 2 + 1 + 80
):2
:(tx, ty)
,预测的bbox
的中心点坐标偏移量2
:(tw, th)
,预测的bbox
的宽高因子1
:包含预测对象的置信度(不关心是什么类别,只判断是否有 )80
:COCO数据集的80
个类别的置信度(每个类别对应的预测置信度 )
如何通过网络预测结果的 tx,ty,tw,tht_x, t_y, t_w, t_htx,ty,tw,th,进一步计算得到feature map 尺度下的预测框bbox的中心点坐标和宽高的:
predicted bbox 的中心点坐标计算
回故yolov3的坐标计算方式:
- 模型输出的 tx,tyt_x, t_ytx,ty 是无约束的数值,通过 Sigmoid 函数 σ(t)=11+e−t\sigma(t) = \frac{1}{1 + e^{-t}}σ(t)=1+e−t1
可将其压缩到(0, 1)
,表示 预测中心点在网格内的相对偏移比例(0 对应网格左上角,1 对应右下角)。
v3方法是直接网格基准 + 归一化偏移得到 bbox 中心点在特征图上的绝对位置。但计算得到的中心点预测存在的问题:
因为 预测值 tx、tyt_x、t_ytx、ty 无法取到正负无穷,那么预测中心点坐标 bx,byb_x, b_ybx,by 无法取到 0 或 1,即 中心点无法落在 grid cell 的四个边缘上。
yolov5对其做了改进:
取值范围 (图中黄色绿区域):
cx−0.5<x<cx+1.5cy−0.5<y<cy+1.5c_x - 0.5 < x < c_x + 1.5 \\ c_y - 0.5 < y < c_y + 1.5 cx−0.5<x<cx+1.5cy−0.5<y<cy+1.5
中心点的范围上下界正好是grid cell四个角相邻的grid cell的中心点。所以本grid cell 取不到边缘,会由相邻周围grid cell来负责预测。
yolov5进行改进:偏移范围扩展(2⋅σ(t)−0.52 \cdot \sigma(t) - 0.52⋅σ(t)−0.5)
给偏移量 σ(t)\sigma(t)σ(t) 乘以 2 并减 0.5 后,偏移范围变为 [-0.5, 1.5]
。这让预测的中心点可以“超出当前网格”,覆盖当前grid cell的边缘以及相邻网格区域(比如目标中心靠近网格边缘时,可能属于当前网格预测,但实际坐标在相邻网格范围内),提升对边界目标的预测能力。
predicted bbox 的宽高计算
回归yolov3的bbox宽高计算:
github上有人提出了高度和宽度预测存在的问题 ,yolov3和yolov4都有这个问题:
当 twt_wtw 和 tht_hth 较大时,etwe^{t_w}etw和 ethe^{t_h}eth 可能会指数爆炸,导致预测框bbox的宽度和高度不受限,进一步导致梯度不受控,损失值为NaN,最终会导致训练失败。
yolov5也对这点做了改进,使得bbox宽高范围限值在了4倍的anchor尺寸以内:
2. 正样本匹配
正样本匹配的目的,对于图像中的每一个 bbox
,找出:
- 它由输出特征图中的哪些
grid cell
来负责预测 - 它由哪些尺寸的
anchor
来负责预测
基于这些负责预测的 grid cells
中负责预测的 anchors
,得到的预测 bbox
就是正样本,否则就是负样本
也可以简单理解为
- 负责预测
gt box
的anchor
就是正样本, - 不负责预测的
anchor
就是负样本
正样本匹配举例说明
下面我们举例说明:
我们想要从网络输出的 3个 feature map
中分别找出预测某 gt box
的正样本,下面我们以 feature map 1
举例 (从 feature map 1
中找正样本)
yaml文件中预设的anchors:
- 第一个用于检测小尺度物体的3个anchors,对应80x80的feature map 1,
P3/8
。 - 第二行是用于检测中等尺度物体的3个anchors,对应40x40的feature map 2,
P4/16
。 - 第三行是用于检测大物体的,对应20x20的feature map 3,
P5/32
。
yaml文件中预设的anchors的尺寸,相对于640x640的原图大小。第一行的三个大小的anchors映射到feature map 1的尺寸缩减8倍,如图所示。
fearture map1中的每个像素映射会原图都是一个grid cell,每个grid cell都会基于三个尺寸的anchors预测出三个bbox。所以,feature map 1
一共会预测出 80 x 80 x 3 = 19200
个 anchors。
如何从19200
个anchors筛选出正样本。
(1)假设 gt bbox
的中心点落在如上图所示的 grid cell
中的左下方区域,根据规则(具体选grid cell的规则后面介绍)我们就让3个grid cell一起来预测该gt box。
- 该grid cell
- 它左边的grid cell
- 它下边的grid cell
(2)将 gt box 的宽度和高度 分别和 3个 anchor 的宽度和高度做对比,选出适合的 anchors 用于预测 gt box (具体选择anchors的规则之后介绍)。
这里假设 anchor 1 和 anchor 2 用于负责预测 gt box,对应正样本。不负责预测的anchor 3对应负样本。
所以,一共 80 x 80 x 3 = 19200
个 anchors 中,仅仅对于这feature map 1的一个 gt box 来说,有6个正样本(3个grid_cell x 2个anchors),其他的都是负样本。
选择负责预测的grid cell的规则
规则为:如果ground truth中心点落在 grid cell 左上区域,那么本身和左还有上3个grid cell共同负责预测。
为什么是这三个grid cell,因为 gt box中心点所在的 grid cell 以及它的左侧、上侧、左上侧的 4个 grid cell 的预测中心点位置都可能落在 该 grid cell 的左上角,其他的不行。
这里对gt box中心点所在的 grid cell 周围一圈的grid cell 分析。图中粉色 grid cell 对应的预测中心点的取值范围为黄色区域
有四个grid cell的范围覆盖到了gt box的中心点,但官方实现时,仅使用 该 grid cell 左侧 和上侧的 grid cell 来一起进行预测,不使用 左上角的grid cell,可能是因为 左上角的 grid cell 预测中心点落在 该区域的概率太小,所以不进行考虑。
上面我们是以 gt bbox 的中心点落在 grid cell 左上角为例 来进行分析的,以下是 gt bbox 的中心点落在 grid cell 左上角、右上角,左下角、右下角的,中心点的所有情况。图片来源:https://docs.ultralytics.com/yolov5/tutorials/architecture_description/#44-build-targets
选择负责预测的anchor的规则
选择规则为:将 gt box 和 3个 anchors 比对宽度和高度, 如果满足我们指定的条件,那么这个尺寸的 anchors 就负责预测这个 gt box。
指定的条件为:
max(wgtwat,watwgt,hgthat,hathgt)<4\max\left( \frac{w_{\text{gt}}}{w_{\text{at}}},\ \frac{w_{\text{at}}}{w_{\text{gt}}},\ \frac{h_{\text{gt}}}{h_{\text{at}}},\ \frac{h_{\text{at}}}{h_{\text{gt}}} \right) < 4 max(watwgt, wgtwat, hathgt, hgthat)<4
翻译与代码:
j = torch.max(r, 1 / r).max(2)[0] < self.hyp["anchor_t"]
等价转换后:
14<wgtwat,watwgt,hgthat,hathgt<4\frac{1}{4} < \frac{w_{\text{gt}}}{w_{\text{at}}},\ \frac{w_{\text{at}}}{w_{\text{gt}}},\ \frac{h_{\text{gt}}}{h_{\text{at}}},\ \frac{h_{\text{at}}}{h_{\text{gt}}} < 4 41<watwgt, wgtwat, hathgt, hgthat<4
即两个框的宽高比误差分别不大于4倍。如图:
举例参考:https://docs.ultralytics.com/yolov5/tutorials/architecture_description/#44-build-targets
因为每个尺寸的特征图都设计的三个尺寸的anchors,anchors长宽都放大4倍后分别和gt box对比,如果超出就为负样本。比如图汇总的anchor 1,而对于anchor 2 和 3是符合条件的。
注 : 同一个 gt bbox 可以由多个不同尺寸的 anchor 来进行预测
正样本匹配代码讲解
代码在官方build_targets
函数中,代码解释图