YOLO V5
网络结构:
与代码中yaml文件相互对应
C3与CSP文件类似
Backbone:
New CSP-Darknet53
Neck:
SPPF New CSP-PAN
Head:
YOLO v3 Head
网络结构【新】:
focus模块替换为普通卷积层
- 将focus模块替换为6*6的普通卷积层,两者功能相同,但后者效率更高
Focus模块:将输入特征层每2*2大小区域化成一个patch,每个patch中相同位置的相同颜色拼接在一起,就将原来的输入特征层的高宽都减半了,通道方向翻了4倍,再接上一个3*3的卷积层
将SPP换为SPPF
SPP:
将输入特征层并行的通过多个不同大小的Maxpool2d,再去融合输出
SPPF:
将输入串行的通过三个kernel=5的Maxpool2d,然后将输出与输入进行concat拼接
作用:将两个kernel=5的Maxpool2d拼接在一起等价于使用一个kernel=9的Maxpool2d,将三个Maxpool2d串行,等价于使用一个kernel=13的Maxpool2d。但是使用SPPF的结构效率更高,采用5*5相比于采用9*9的计算量更小,大大减小了参数。
实验
随机创建一个tensor分别进入SPP和SPPF,正向推理100次时间,对比输出结果:
import time
import torch
import torch.nn as nn
class SPP(nn.Module):
def __init__(self):
super().__init__()
self.maxpool1 = nn.MaxPool2d(5, 1, padding=2)
self.maxpool2 = nn.MaxPool2d(9, 1, padding=4)
self.maxpool3 = nn.MaxPool2d(13, 1, padding=6)
def forward(self, x):
o1 = self.maxpool1(x)
o2 = self.maxpool2(x)
o3 = self.maxpool3(x)
return torch.cat([x, o1, o2, o3], dim=1)
class SPPF(nn.Module):
def __init__(self):
super().__init__()
self.maxpool = nn.MaxPool2d(5, 1, padding=2)
def forward(self, x):
o1 = self.maxpool(x)
o2 = self.maxpool(o1)
o3 = self.maxpool(o2)
return torch.cat([x, o1, o2, o3], dim=1)
def main():
input_tensor = torch.rand(8, 32, 16, 16)
spp = SPP()
sppf = SPPF()
output1 = spp(input_tensor)
output2 = sppf(input_tensor)
print(torch.equal(output1, output2))
t_start = time.time()
for _ in range(100):
spp(input_tensor)
print(f"spp time: {time.time() - t_start}")
t_start = time.time()
for _ in range(100):
sppf(input_tensor)
print(f"sppf time: {time.time() - t_start}")
if __name__ == '__main__':
main()
使用SPPF比使用SPP快了2倍
C3:
C3包含三个卷积:两边各自经过卷积得到的feature进行concat得到bchw的大小,然后经过卷积,不改变维度的大小
一边只经过CBS,另一边经过CBS还要经过一个(可能含有多层的)BottleNeck
BottleNeck:
BottleNeck1:包含add操作,类似于短接;backbone中都使用BottleNeck1
BottleNeck2:只经过两个CBS;而在head中大部分都使用了BottleNeck2
数据增强:
-
Mosaic:
4张图片拼接为1张图片,扩充数据的多样性
-
Copy Paste:
将不同图像中的目标进行复制粘贴
注意:数据集中必须包含每个目标的实例分割标签
-
Random affine:
随机进行仿射变换:旋转、缩放、平移、错切
源码中采用缩放、平移
-
Mix up:
将两张图片按一定透明程度混合成一张新的图片,源码中启用概率较低
-
Albumentations:
为一个第三方包,使用滤波、直方图均衡化以及改变图片质量等,requirement.txt中被注释,默认不启用
-
Augment HSV:
随机调整Hue、Saturation、Value(色度,饱和度以及明度)
YOLO v3 SPP曾使用过
-
Random horizontal flip:
随机水平翻转、按一定比例翻转
训练策略:
-
Multi-scale training(0.5-1.5x)多尺度训练:
若输入为640*640,开启多尺度则实际输入为0.5*640-1.5*640之间随机取值(取值为32的整数倍,最大下采样采取的是32的整数倍)
-
AutoAnchor(For training custom data):
训练自己的数据集时可以使用,若目标的长宽比例和常见的长宽比例差距较大,启用后会自动根据数据集中的目标重新聚类生成新的anchor
-
Warmup and Cosine LR scheduler:
训练初期会将学习率从一个很小的值慢慢增长到所设置的初始学习率,以cosine的方式慢慢降低学习率
-
EMA(Exponential Moving Average):
给学习变量加上一个动量,更新参数时会更加平滑
-
Mixed precision(混合精度训练):
启用后可以减少对gpu显存的占用,理论上可以减半
-
Evolve hyper-parameters
损失函数:
平衡不同尺度损失:
针对三个预测特征层(P3, P4, P5)上的obj损失采用不同的权重。
针对预测小目标的预测特征层(P3)采用的权重是4.0
针对预测中等目标的预测特征层(P4)采用的权重是1.0
针对预测大目标的预测特征层(P5)采用的权重是0.4
作者说这是针对COCO数据集设置的超参数。
作用:一般小型目标更难预测,将小型目标的权重设置更大,有效解决正负样本不平衡的问题,增强训练的稳定性和收敛速度。
消除grid敏感度:
YOLOv2 YOLOv3采用的边界框回归的计算
将网络预测目标的中心点的偏移量限制在当前grid cell之内,若落在边界上,此时希望sigmoid过后为0,只能是x趋近于负无穷或者正无穷,为了解决这个问题,引入缩放因子
Yolov4:
Yolov5:
若采用之前的公式ex不受限制,容易出现指数爆炸,损失为nan,训练不稳定
匹配正样本:
YOLOv4与 YOLOv5也相似,主要的区别在于GT Box与Anchor Templates模板的匹配方式。在YOLOv4中是直接将每个GT Box与对应的Anchor Templates模板计算IoU,只要IoU大于设定的阈值就算匹配成功。
如果GT Box和对应的Anchor Template的 小于阈值anchor_t(在源码中默认设置为4.0),即GT Box和对应的Anchor Template的高、宽比例相差不算太大,则将GT Box分配给该Anchor Template模板。假设对某个GT Box而言,其实只要GT Box满足在某个Anchor Template宽和高的×0.25倍和×4.0倍之间就算匹配成功。
剩下的步骤和YOLOv4中一致:
将GT投影到对应预测特征层上,根据GT的中心点定位到对应Cell,注意图中有三个对
的Cell
因为网络预测中心点的偏移范围已经调整到了( − 0.5 , 1.5 ) (-0.5, 1.5)(−0.5,1.5),所以按理说只要Grid Cell左上角点距离GT中心点在( − 0.5 , 1.5 ) (−0.5,1.5)(−0.5,1.5)范围内它们对应的Anchor都能回归到GT的位置处。这样会让正样本的数量得到大量的扩充。
则这三个Cell对应的AT2和AT3都为正样本。
还需要注意的是,YOLOv5源码中扩展Cell时只会往上、下、左、右四个方向扩展,不会往左上、右上、左下、右下方向扩展。下面又给出了一些根据的位置扩展的一些Cell案例,其中%1表示取余并保留小数部分。