赞
踩
作者AlexeyAB大神! YOLOv4 拥有43.5%mAP+65FPS ,达到了精度速度最优平衡,
作者团队:Alexey Bochkovskiy&中国台湾中央研究院
论文链接:
https://arxiv.org/pdf/2004.10934.pdf
代码链接:
GitHub - AlexeyAB/darknet: YOLOv4 / Scaled-YOLOv4 / YOLO - Neural Networks for Object Detection (Windows and Linux version of Darknet )
————————————————
在讲YOLOv4之前,先介绍一下两个包:Bag of Freebies(免费包)和Bag-of-Specials(特赠包)
Bag of Freebies:指的是那些不增加模型复杂度,也不增加推理的计算量的训练方法技巧,来提高模型的准确度
Bag-of-Specials:指的是那些增加少许模型复杂度或计算量的训练技巧,但可以显著提高模型的准确度
YOLOv4主要的贡献:
①构建了一个简单且高效的目标检测模型,该算法降低了训练门槛,这使得普通人员都可以使用 1080Ti 或 2080 Ti GPU 来训练一个超快,准确的(super fast and accurate)目标检测器。
②验证了最先进的 Bag-of-Freebies 和 Bag-of-Specials 方法在训练期间的影响
BoF指的是
1)数据增强:图像几何变换(随机缩放,裁剪,旋转),Cutmix,Mosaic等
2)网络正则化:Dropout,Dropblock等
3) 损失函数的设计:边界框回归的损失函数的改进 CIOU
BoS指的是
1)增大模型感受野:SPP、ASPP等
2)引入注意力机制:SE、SAM
3)特征集成:PAN,BiFPN
4)激活函数改进:Swish、Mish
5)后处理方法改进:soft NMS、DIoU NMS
③修改了最先进的方法,并且使其更为有效,适合单GPU训练。包括 CBN,PAN, SAM等,从而使得 YOLO-v4 能够在一块 GPU 上就可以训练起来。
输入端的创新点:训练时对输入端的改进,主要包括Mosaic数据增强、cmBN、SAT自对抗训练
BackBone主干网络:各种方法技巧结合起来,包括:CSPDarknet53、Mish激活函数、Dropblock
Neck:目标检测网络在BackBone和最后的输出层之间往往会插入一些层,比如Yolov4中的SPP模块、FPN+PAN结构
Prediction:输出层的锚框机制和Yolov3相同,主要改进的是训练时的回归框位置损失函数CIOU_Loss,以及预测框筛选的nms变为DIOU_nms
Yolov4对训练时的输入端进行改进,使得训练时在单张GPU上跑的结果也蛮好的。比如数据增强Mosaic、cmBN、SAT自对抗训练。
Yolov4中使用的Mosaic是参考2019年底提出的CutMix数据增强的方式,但CutMix只使用了两张图片进行拼接,而Mosaic数据增强则采用了4张图片,随机缩放、随机裁剪、随机排布的方式进行拼接。
为什么要进行Mosaic数据增强呢?
在平时项目训练时,小目标的AP一般比中目标和大目标低很多。而Coco数据集中也包含大量的小目标,但比较麻烦的是小目标的分布并不均匀。Coco数据集中小目标占比达到41.4%,数量比中目标和大目标都要多。但在所有的训练集图片中,只有52.3% 的图片有小目标,而中目标和大目标的分布相对来说更加均匀一些。
针对这种状况,Yolov4的作者采用了Mosaic数据增强的方式。
主要有2个优点:
1.丰富数据集:随机使用4张图片,随机缩放,再随机分布进行拼接,大大丰富了检测数据集,特别是随机缩放增加了很多小目标,让网络的鲁棒性更好。
2.batch不需要很大:Mosaic增强训练时,可以直接计算4张图片的数据,使得Mini-batch大小并不需要很大,一个GPU就可以达到比较好的效果。
SAT全称:Self-adversarial-training。可以自己增加或者让网络增加噪音点来增加训练难度
CSPDarknet53-它是在YOLOv3主干网络Darknet53的基础上,借鉴了2019年发表的CSPNet算法的经验,所形成的一种Backbone结构,其中包含了5个CSP模块。每个CSP模型的实现细节如3.2.1所述。CSP模块可以先将基础层的特征映射划分为两部分,然后通过跨阶段层次结构将它们合并起来,这样不仅减少了计算量,而且可以保证模型的准确率。它的优点包括:(1)增强CNN网络的学习能力,轻量化模型的同时保持模型的精度;(2)降低整个模型的计算瓶颈;(3)降低算法的内存成本。有关CSP模块的更多细节请看该论文。
Mish激活函数-该激活函数是在2019年提出的,该函数是在Leaky_relu算法的基础上改进而来的,具体的比较请看下图。当x>0时,Leaky_relu与Mish激活函数基本相同;当x<0时,Mish函数基本为0,而Leaky_relu函数为λ x \lambda xλx。YOLOv4的Backbone中均使用了Mish激活函数,而后面的Neck网络中则使用了leaky_relu激活函数。总而言之,Mish函数更加平滑一些,可以进一步提升模型的精度。更多的细节请看该论文。
Yolov4中使用的Dropblock,其实和常见网络中的Dropout功能类似,也是缓解过拟合的一种正则化方式。
Dropblock在2018年提出,论文地址:https://arxiv.org/pdf/1810.12890.pdf
传统的Dropout很简单,一句话就可以说的清:随机删除减少神经元的数量,使网络变得更简单。
dropout主要作用在全连接层,而dropblock可以作用在任何卷积层之上
而Dropblock和Dropout相似,比如下图:
中间Dropout的方式会随机的删减丢弃一些信息,但Dropblock的研究者认为,卷积层对于这种随机丢弃并不敏感,因为卷积层通常是三层连用:卷积+激活+池化层,池化层本身就是对相邻单元起作用。而且即使随机丢弃,卷积层仍然可以从相邻的激活单元学习到相同的信息。
因此,在全连接层上效果很好的Dropout在卷积层上效果并不好。
所以右图Dropblock的研究者则干脆整个局部区域进行删减丢弃。
这种方式其实是借鉴2017年的cutout数据增强的方式,cutout是将输入图像的部分区域清零,而Dropblock则是将Cutout应用到每一个特征图。而且并不是用固定的归零比率,而是在训练时以一个小的比率开始,随着训练过程线性的增加这个比率。
在特征图上一块一块的进行归0操作,去促使网络去学习更加鲁棒的特征
为了保证Dropblock后的特征图与原先特征图大小一致,需要和dropout一样,进行rescale操作
Dropblock的研究者与Cutout进行对比验证时,发现有几个特点:
优点一:Dropblock的效果优于Cutout
优点二:Cutout只能作用于输入层,而Dropblock则是将Cutout应用到网络中的每一个特征图上
优点三:Dropblock可以定制各种组合,在训练的不同阶段可以修改删减的概率,从空间层面和时间层面,和Cutout相比都有更精细的改进。
Yolov4中直接采用了更优的Dropblock,对网络的正则化过程进行了全面的升级改进。
神经网络最大的缺点就是太自信(过拟合),毕竟每个东西都是由原子组成,多多少少有一些相似,所以不要让模型太过绝对,拿下面图片距举例,虽然我们预测的是猫,但是让狗的概率不至于为0,留一丝喘息的余地,日后好相见,当然大概率还是猫。
使用之前(左)和使用之后的区别(右),明显右边的聚类更好一些。
CIOU_loss-目标检测任务的损失函数一般由分类损失函数和回归损失函数两部分构成,回归损失函数的发展过程主要包括:最原始的Smooth L1 Loss函数、2016年提出的IoU Loss、2019年提出的GIoU Loss、2020年提出的DIoU Loss和最新的CIoU Loss函数。
IoU Loss-所谓的IoU Loss,即预测框与GT框之间的交集/预测框与GT框之间的并集。这种损失会存在一些问题,具体的问题如下图所示,(1)如状态1所示,当预测框和GT框不相交时,即IOU=0,此时无法反映两个框之间的距离,此时该 损失函数不可导,即IOU_Loss无法优化两个框不相交的情况。(2)如状态2与状态3所示,当两个预测框大小相同时,那么这两个IOU也相同,IOU_Loss无法区分两者相交这种情况。
GIOU_Loss-为了解决以上的问题,GIOU损失应运而生。GIOU_Loss中增加了相交尺度的衡量方式,缓解了单纯IOU_Loss时存在的一些问题。
GIOU引入了最小封闭形状C(C是把A和B包含在内的最小矩形),在不重叠的情况下能让预测框尽可能的朝着真实框前进。
我们再看这个公式的最后一部分,意思是C减去A和B的并集再除以C,当然分子的值越小越好,最好为0。
L
G
I
o
U
=
1
−
I
o
U
+
∣
C
−
B
∪
B
g
t
∣
∣
C
∣
L_{GIoU} = 1-IoU + \frac{|C-B \cup B^{gt}|}{|C|}
LGIoU=1−IoU+∣C∣∣C−B∪Bgt∣
但是GIOU Loss也有一定的缺陷,就是当遇到预测框完全在真实框里面的时GIOU就和IOU一样了,不能确定哪个框更好了。
L
D
I
o
U
=
1
−
I
o
U
+
ρ
2
(
b
,
b
g
t
)
c
2
L_{DIoU} = 1-IoU + \frac{\rho^2(b,b^{gt})}{c^2}
LDIoU=1−IoU+c2ρ2(b,bgt)
b: 预测框
b{gt}: 真实框
ρ
\rho
ρ :欧式距离
公式最后一部分的分子表示真实框和预测框中心点的欧式距离,图中d。
分母是能覆盖预测框与真实框的最小BOX的对角线长度,图中c
两个框越重合的时候,d值越小,当两个框重合时,d值为0。
DIOU直接优化距离,网络收敛速度更快,并且解决了GIOU的问题。也是用的比较多的方法。下面两张图片是为了好理解:
如下图所示,当真实框包裹预测框时,此时预测框的中心点的位置都是一样的,因此按照DIOU_Loss的计算公式,三者的值都是相同的。为了解决这个问题,CIOU_Loss应运而生。
L
C
I
o
U
=
1
−
I
o
U
+
ρ
2
(
b
,
b
g
t
)
c
2
+
α
ν
L_{CIoU} = 1-IoU + \frac{\rho^2(b,b^{gt})}{c^2}+\alpha\nu
LCIoU=1−IoU+c2ρ2(b,bgt)+αν
ν
=
4
π
2
(
arctan
ω
g
t
h
g
t
−
arctan
ω
h
)
2
\nu=\frac{4}{\pi^2}(\arctan\frac{\omega^{gt}}{h^{gt}}-\arctan\frac{\omega}{h})^2
ν=π24(arctanhgtωgt−arctanhω)2
α
=
ν
(
1
−
I
o
U
)
+
ν
\alpha=\frac{\nu}{(1-IoU)+\nu}
α=(1−IoU)+νν
一个好的损失函数要考虑3方面因素:重叠面积,中心点距离,长宽比
在DIOU的时候已经把重叠面积和中心点距离考虑进去了,现在还差一个长宽比
ν
\nu
ν。当真实框长宽比
ω
g
t
h
g
t
\frac{\omega^{gt}}{h^{gt}}
hgtωgt与预测框长宽比
ω
h
\frac{\omega}{h}
hω一直时最后一项为0,其中
α
\alpha
α可以看做权重参数。
总而言之,IOU_Loss主要考虑了检测框和GT框之间的重叠面积;GIOU_Loss在IOU的基础上,解决边界框不重合时出现的问题;DIOU_Loss在IOU和GIOU的基础上,同时考虑了边界框中心点距离信息;CIOU_Loss在DIOU的基础上,又考虑了边界框宽高比的尺度信息。
1.遍历图片中所有识别出目标的类,对每个类的所有框进行单独分析
2.再将所有的狗的预测框按分数从大到小排序,如下图;
3.下一步,设狗类概率最大的框为target,依次比较它和其他非0框进行(IOU-DIOU)计算,如果计算结果大于设定的DIoU阈值(这里是ε=0.5),就将该框的狗的概率置为0,如下target和第二个框的(IOU-DIOU)明显大于阈值0.5,所以舍去第二个框,把这个框的狗类概率设为0,如下图;
4.继续扫描到第三个框,它与最大概率框的(IOU-DIOU)小于0.5,需要保留,继续扫描后面的框,直到所有框都与最大概率框比较完毕为止。此时保留了不少框。
5.接下来,以次大概率的框bb15(因为一开始排序过,它在顺序上也一定是保留框中最靠近上一轮的基础框的)为基础,将它后面的其它框于之比较,如下图:
如果bb15框(次大概率的框)和bb7框的(IOU-DIOU)大于0.5,则可以剔除第4个框:把这个框的狗类概率设置为0
6. 假设在经历了所有的扫描之后,对Dog类别只留下了两个框,如下:
因为对计算机来说,图片可能出现两只Dog,保留概率不为0的框是安全的。不过代码后续设置了一定的阈值(比如0.3)来删除掉概率太低的框,这里的蓝色框在最后并没有保留,因为它在最后会因为阈值不够而被剔除。
7.上面描述了对Dog种类进行的框选择。接下来,我们还要对其它79种类别分别进行上面的操作
8. 最后进行纵向跨类的比较(为什么?因为上面就算保留了最大概率的Dog框,但该框可能在Cat的类别也为概率最大且比Dog的概率更大,那么我们最终要判断该框为Cat而不是Dog)。判定流程和法则如下:
最后保留的预测框就是最终呈现的预测框
首先要说一下FPN,也就是下图,自顶向下的模式,也就是将高层特征传下来,是不是还少了从低层特征传上去的路径呢?把箭头方向变一下就行了?如果conv1-5一共有一百层,岂不是又要重新走一遍?浪费时间!!!来我们看看PAN是怎么解决这件事情的
PAN,也就是下图,引入了自底向上的路径,使得底层信息更容易传到顶部。并且还是一个捷径,红色的需要走个100层(Resnet)),才能得到P2-P5,绿色的直接用P2-P5就行了。
PAN的另一点小改变,在特征融合的时候并不是简单的加法(下图a),而是concat操作(下图b)。可以理解为加法是合体成一个人,concat是两个人合作,所以毕竟双拳难敌四脚嘛!!!
V3中为了更好满足不同输入大小,训练的时候要改变输入数据的大小。SPP其实就是用最大池化来满足最终输入特征一致即可
首先看看CBL模块是怎么工作的:
CBL由3个卷积层组成($1*1*512, 3*3*1024$和$1*1*512$)
1x1和3x3代表卷积的大小,512和1024代表卷积核的大小,比如传到CBL模块的特征图为608x608x250,那么一个卷积核就是把传
过来的250个特征全部卷积一遍按相应位置相加合成一个特征图,依次做512遍,注意这里的512个卷积层的初始参数是不同的。
可以看这篇文章加深理解:神经网络必备基础知识:卷积、池化、全连接(通道数问题、kernel与filter的概念)
中间池化层的操作原理(
19
∗
19
∗
512
19*19*512
19∗19∗512举例,分别代表长宽和特征图的个数):
池化层有 1×1 ,5×5 padding=5 // 2,9×9 padding=9 // 2,13×13 padding=13 // 2的最大池化的方式
其中padding前半部分代表卷积的大小,后半部分代表填充的像素。步长都默认为1。
中间池化层并不会改变特征图的个数,但是池化的大小会改变特征图的长和宽,为了保证长宽一致,我们需要加padding。
假设输入图片为 H x W 卷积核大小为FxF,步长stride=S,padding设置为P(填充的像素数)
公式:输出图像的大小=(H - F +2P)/S +1
因此padding是计算出来的,并不是随意选择的。
a:V3版本中正常的ResNet
b:ResNet中引入了CSP,其实CSP可以和各种网络结合。
今天主要说CSPResNet,我们把Base layer看做特征图,当数据来的时候把它的特征图的channel维度一分为2,一部分正常走ResNet,再把另一部分直接concat到这个block中就是这么简单。
当然这在损失不是很多的情况下加快了训练速度,符合yolo的思想。
采用的主干网络为 CSPDarknet53,CSPDarknet53是在Yolov3主干网络Darknet53的基础上,借鉴2019年CSPNet的经验,产生的Backbone结构,其中包含了1个CBM和5个CSP模块
骨干部分图如下:
①CBM:
Yolov4网络结构中的最小组件,由Conv+Bn+Mish激活函数三者组成。
② CSP模块:
借鉴了CSPNet网络结构,由CBM组件和X个Res unint模块Concate组成。
第一个CSP模块:由CBM组件和1个Res unint模块Concate组成。
将CBM组件处理后的特征图
608
∗
608
∗
32
608*608*32
608∗608∗32的F_conv2传入第一个CSP1模块进行处理(其中只有1个残差单元)
第二个CSP模块:由CBM组件和2个Res unint模块Concate组成。
将第一个csp模块处理后的
304
∗
304
∗
64
304*304*64
304∗304∗64特征图,传入到第二个CSP模块处理
同理经过下采样后变成了
152
∗
152
∗
128
152*152*128
152∗152∗128的特征图,然后分别经过两个
1
∗
1
∗
64
1*1*64
1∗1∗64的s=1的卷积后得到两个分支,其中一个分支的特征块进入残差模块进行处理后,再与另一个分支进行拼接,最后第二个csp模块的最后输出是
152
∗
152
∗
128
152*152*128
152∗152∗128(残差模块中的卷积层:
1
∗
1
∗
64
1*1*64
1∗1∗64和
3
∗
3
∗
64
3*3*64
3∗3∗64)
第三个CSP模块:由8个Res unint模块和CBM组件Concate组成。
将第二个csp模块处理后的
152
∗
152
∗
128
152*152*128
152∗152∗128的特征图,传入到第三个个CSP模块处理
同理也是经过同样的操作,最后第三个csp模块的最后输出是 76 ∗ 76 ∗ 256 76*76*256 76∗76∗256 (残差模块中的卷积层: 1 ∗ 1 ∗ 128 1*1*128 1∗1∗128和 3 ∗ 3 ∗ 128 3*3*128 3∗3∗128),这个模块后又分为两个分支,一个分支继续进行csp模块处理,另一个分支直接进入到neck处理
第四个CSP模块:由8个Res unint模块和CBM组件Concate组成。
将第三个csp模块的一个分支
76
∗
76
∗
256
76*76*256
76∗76∗256的特征图,传入到第四个CSP模块处理
同理也是经过同样的操作,最后第四个csp模块的最后输出是
38
∗
38
∗
512
38*38*512
38∗38∗512 (残差模块中的卷积层:
1
∗
1
∗
256
1*1*256
1∗1∗256和
3
∗
3
∗
256
3*3*256
3∗3∗256),这个模块后又分为两个分支,一个分支继续进行csp模块处理,另一个分支直接进入到neck处理
第五个CSP模块:由4个Res unint模块和CBM组件Concate组成。
将第四个csp模块的一个分支
38
∗
38
∗
512
38*38*512
38∗38∗512的特征图,传入到第五个CSP模块处理
同理也是经过同样的操作,最后第五个csp模块的最后输出是
19
∗
19
∗
1024
19*19*1024
19∗19∗1024 (残差模块中的卷积层:
1
∗
1
∗
512
1*1*512
1∗1∗512和
3
∗
3
∗
512
3*3*512
3∗3∗512),这个模块输出结果直接进入到neck处理
特征增强模块,主要由CBL组件,SPP模块和FPN+PAN的方式组成
① CBL组件:
由Conv+Bn+Leaky_relu激活函数三者组成
将第五个csp4模块的输出结果
19
∗
19
∗
1024
19*19*1024
19∗19∗1024的特征图,传入到CBL组件中处理
spp前后三个CBL组件是对称的,它们的卷积分别是
1
∗
1
∗
512
,
3
∗
3
∗
1024
1*1*512, 3*3*1024
1∗1∗512,3∗3∗1024和
1
∗
1
∗
512
1*1*512
1∗1∗512,步长都是1。
②SPP模块:
采用1×1,5×5,9×9,13×13的最大池化的方式,进行多尺度融合
spp模块采用的1×1 ,5×5 padding=5 // 2,9×9 padding=9 // 2,13×13 padding=13 // 2的最大池化的方式,进行多尺度融合,从前面三个CBL组件输出的结果:
19
∗
19
∗
512
19*19*512
19∗19∗512的特征图,将之送入spp模块中,最后的结果为
19
∗
19
∗
2048
19*19*2048
19∗19∗2048,再经过三个CBL组件的卷积后得到
19
∗
19
∗
512
19*19*512
19∗19∗512的特征图 。
③ FPN+PAN的结构:
PAN是借鉴图像分割领域PANet的创新点
这样结合操作,FPN层自顶向下传达强语义特征,而PAN则自底向上传达强定位特征,两两联手,从不同的主干层对不同的检测层进行参数聚合,加速了不同尺度特征的融合,进一步提高特征提取的能力。
根据CBAM改进出来的SAM。不光NLP,语音识别领域在搞attention,CV中也一样。
有channel维度和spatial维度两方面
channel维度:在我们输入一张图片之后,会得到若干特征图,这些特征图的重要性不一,因此我们给他一个权重,也就是让网络更“专注”于一些重要的东西。
spatial维度:每一个特征图上都有我们想要的前景,前景的位置就是我们需要着重注意的地方。
CBAM行是行,但是引入了挺多计算量,不太符合yolo的思想。SAM其实是在CBAM的基础上只保留了位置(spatial)维度。
a图是原始的SAM,yolo v4在这上面的基础上做了一些升级。我们看a图中做完pooling之后还做了卷积,不如一步到位直卷积,省了许多参数。
YoloHead利用获得到的特征进行预测,是一个解码的过程
在特征利用部分,YoloV4提取多尺度特征进行目标检测,一共提取三个特征层,分别位于中间层,中下层,底层,三个特征层的shape分别为(19,19,255),(38,38,255),(76,76,255) 在Yolov3的设计中,每个特征图的每个格子中,都配置3个不同的先验框,所以最后三个特征图,这里暂且reshape为19 × 19 × 3 × 85、38 × 38 × 3 × 85、76 × 76 × 3 × 85,这样更容易理解,在代码中也是reshape成这样之后更容易操作。 三张特征图就是整个Yolo输出的检测结果,检测框位置(4维)、检测置信度(1维)、类别(80维)都在其中,加起来正好是85维。特征图最后的维度85,代表的就是这些信息,而特征图其他维度N × N × 3,N × N代表了检测框的参考位置信息,3是3个不同尺度的先验框。
①先验框(anchor box)
YOLO3采用了K-means聚类得到先验框的尺寸,YOLO4延续了这种方法,为每种下采样尺度设定3种先验框,总共聚类出9种尺寸的先验框。在COCO数据集中(原始图片全部resize为608 × 608),九个框分别是 [[12, 16], [19, 36], [40, 28], [36, 75], [76, 55], [72, 146], [142, 110], [192, 243], [459, 401]],顺序为w × h。 将前三个先验框分配给
76
∗
76
∗
255
76*76*255
76∗76∗255的特征图,中间三个框分配给
38
∗
38
∗
255
38*38*255
38∗38∗255的特征图,最后三个框分配给
19
∗
19
∗
255
19*19*255
19∗19∗255的特征图。
②解码检测框
有了先验框与输出特征图后,就可以解码检测框 x,y,w,h。 例如:(19,19,3,85),分别对应着19*19个网格,每个网格3种anchors,85=(x,y,w,h,confident),此时box的x,y是相对于网格的偏移量,所以还需要经过一些列的处理,处理方式见下图:
注意:σ(tx),σ(ty)是基于bbox框中心点左上角格点坐标的偏移量
③置信度解码
物体的检测置信度,置信度在输出85维中占固定一位,由sigmoid函数解码即可,解码之后数值区间在[0,1]中。
④类别解码
COCO数据集有80个类别,所以类别数在85维输出中占了80维,每一维独立代表一个类别的置信度。使用sigmoid激活函数替代了Yolov2中的softmax,取消了类别之间的互斥,可以使网络更加灵活。
⑤筛选预测框
三个特征图一共可以解码出 19 × 19 × 3 + 38 × 38× 3 + 76 × 76 × 3 = 22743个box以及相应的类别、置信度。 首先,设置一个置信度阈值,筛选掉低于阈值的box,再经过DIOU_NMS(非极大值抑制)后,就可以输出整个网络的预测结果了。
参考链接:yolov4的全面详解
参考链接:YOLOv4算法详解
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。