yolov4的全面详解

一. 前言 

作者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 上就可以训练起来。

二.yolov4的创新点

      输入端的创新点:训练时对输入端的改进,主要包括Mosaic数据增强、cmBN、SAT自对抗训练

     BackBone主干网络:各种方法技巧结合起来,包括:CSPDarknet53、Mish激活函数、Dropblock

      Neck:目标检测网络在BackBone和最后的输出层之间往往会插入一些层,比如Yolov4中的SPP模块、FPN+PAN结构

      Prediction:输出层的锚框机制和Yolov3相同,主要改进的是训练时的回归框位置损失函数CIOU_Loss,以及预测框筛选的nms变为DIOU_nms

  2.1输入端创新

        Yolov4对训练时的输入端进行改进,使得训练时在单张GPU上跑的结果也蛮好的。比如数据增强Mosaic、cmBN、SAT自对抗训练。

   2.1.1数据增强

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就可以达到比较好的效果。

  2.1.2 cmBN 

深度学习中的BN_CBN_CMBN

BN:

反向传播时经过该层的梯度是要乘以该层的参数的,即前向有:

 最后的\hat{} x_{i} 就是xi  归一化(BN)后的值,归一化后所有值满足均值为0方差为1

接着\hat{} x_{i}又进行了scale加上shift操作(y=scale*x+shift),每个神经元增加了两个参数scale和shift参数,这两个参数是通过训练学习到的,意思是通过scale和shift把这个值从标准正态分布左移或者右移一点并长胖一点或者变瘦一点,每个实例挪动的程度不一样,这样等价于非线性函数的值从正中心周围的线性区往非线性区移动。

在测试中使用BN:

在训练中使用BN是要计算均值\mu和方差\sigma^{_{2}}的,而这两个统计量是随着样本不同而变化的。如果在测试中依然遵循这样的方式,那么无疑同一个样本在不同的batch中预测会得到不一样的概率值,这显然是不对的。
在测试中,BN根据训练过程中计算的均值和方差,使用滑动平均去记录这些值。在测试的时候统一使用记录下来的滑动平均值,这一点可以从源码中看出来。所以在TensorFlow或者Pytorch中,BN的代码分别有is_training 和 self.training字段,就是为了区别使用行为的。

举个例子。(这里方差=标准差的平方)
在训练过程的第t次迭代中,我们得到了均值u和方差\sigma。那么u和\sigma将使用如下方式保存下来。

初始化\gamma=1,\beta=0,初始化\mu=[0,0] ,方差\sigma=[1,1]  ,他们的的个数是与特征图的channel深度相同的

CBN:

batch比较小时候,BN在batch维度统计不准确,导致准确率下降。在无法扩大batch训练的前提下,CBN通过收集最近几次迭代信息来更新当前迭代时刻的均值和方差,这样就变向实现了扩大batch目的。我们知道在当前迭代时刻,参数已经更新了N次,存储的前几个迭代的参数肯定无法直接和当前迭代次数进行合并计算,也就是由于网络权重的变化,不同迭代产生的网络激活无法相互比较。故需要找到一种解决办法。一种可行的方法就是利用当前和先前迭代的均值和方差。

然而t-\tau次轮的统计值\mu _{t-\tau }(\theta _{_{t-\tau }}) 和 \nu _{t-\tau }(\theta _{_{t-\tau }})对应的网络权重是\theta _{t-\tau },当前轮的网络权重是\theta _{t}。因此,直接利用多次迭代的统计值进行估计,会使估计的统计量不准确,导致性能的明显的下降。

对于某一层L,假设当前迭代时刻为t,则t-\tau时刻中的统计量\mu _{t-\tau }^{L}(\theta_{t-\tau })\nu _{t-\tau }^{L}(\theta _{t-\tau }),在第t时刻的参数\theta _{t},对于t-\tau时刻的统计值,可以在\theta _{t-\tau }处展开,\theta为权重参数

CMBN:

CmBN的做法和前面两个都不一样,其把大batch内部的4个mini batch当做一个整体,对外隔离,主要改变在于BN层的统计量计算方面,具体流程是:假设当前是第t次迭代时刻,也是mini-batch的起点,

(1) 在第t时刻开始进行梯度累加操作

(2) 在第t时刻开始进行BN统计量汇合操作,这个就是和CBN的区别,CBN在第t时刻,也会考虑前3个时刻的统计量进行汇合,而CmBN操作不会,其仅仅在mini batch内部进行汇合操作

(3) 就是正常的应用BN,对输入进行变换输出即可

(4) 在mini batch的最后一个时刻,进行参数更新和可学习参数更新

可以明显发现CmBN是CBN的简化版本,其唯一差别就是在计算第t时刻的BN统计量时候,CBN会考虑前一个mini batch内部的统计量,而CmBN版本,所有计算都是在mini batch内部。有人认为这种做法是为了减少内存消耗,提高训练速度,既然大家都是近似,差距应该不大,而且本身yolo训练时候,batch也不会特别小,不至于是1-2,所以CmBN的做法应该是为了yolov4专门设计的,属于实践性改进

Cmbn的过程:

 2.2 BackBone创新

Backbone:采用的主干网络为 CSPDarknet53,CSPDarknet53是在Yolov3主干网络Darknet53的基础上,借鉴2019年CSPNet的经验,产生的Backbone结构,其中包含了5个CSP模块

每个CSP模块前面的卷积核的大小都是3*3,stride=2,因此可以起到下采样的作用。

因为Backbone有5个CSP模块,输入图像是608*608,所以特征图变化的规律是:608->304->152->76->38->19   经过5次CSP模块后得到19*19大小的特征图。而且作者只在Backbone中采用了Mish激活函数,网络后面仍然采用Leaky_relu激活函数。           YOLOv3的主干网络采用的是darknet53,yolov4的Backbone:采用的主干网络为 CSPDarknet53

YOLOv4的作者是根据参考2019年的CSPNet的做法而改进的darknet53网络

CSPNet论文地址:https://arxiv.org/pdf/1911.11929.pdf

CSPNet全称是Cross Stage Paritial Network,主要从网络结构设计的角度解决推理中从计算量很大的问题。

CSPNet的作者认为推理计算过高的问题是由于网络优化中的梯度信息重复导致的。

这是因为类似于DenseNet的网络一样,更新权重的值反向传播,会造成重复计算梯度

因此采用CSP模块先将基础层的特征映射划分为两部分,然后通过跨阶段层次结构将它们合并,在减少了计算量的同时可以保证准确率。

Mish激活函数

Mish激活函数是2019年下半年提出的激活函数

论文地址:https://arxiv.org/abs/1908.08681

Leaky_relu激活函数的图形对比如下:

从图中可以看出该激活函数,在负值时并不是完全截断,而允许比较小的负梯度流入从而保证了信息的流动(因为梯度为负值时,作为relu激活函数,大多数神经元没有更新)

mish激活函数无边界,这让他避免了饱和(有下界,无上界)且每一点连续平滑且非单调性,从而使得梯度下降更好。

Dropblock

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,对网络的正则化过程进行了全面的升级改进。

 2.3 Neck创新

在目标检测领域,为了更好的提取融合特征,通常在Backbone输出层,会插入一些层,这个部分称为Neck。相当于目标检测网络的颈部,也是非常关键的。

Yolov4的Neck结构主要采用了SPP模块FPN+PAN的方式

作者在SPP模块中,使用k={1*1,5*5,9*9,13*13}的最大池化的方式,再将不同尺度的特征图进行Concat操作。spp模块是YOLOv4中在YOLOv3的基础上加了的模块,而PAN则也是YOLOv4的创新模块。

YOLOv3中的neck只有自顶向下的FPN,对特征图进行特征融合,而YOLOv4中则是FPN+PAN的方式对特征进一步的融合

下面是YOLOv3的neck中的FPN

如图所示,FPN是自顶向下的,将高层的特征信息通过上采样的方式进行传递融合,得到进行预测的特征图。

而YOLOv4中的neck如下:

 FPN+PAN借鉴的是18年CVPR的PANet,当时主要应用于图像分割领域,但Alexey将其拆分应用到Yolov4中,进一步提高特征提取的能力

 原本的PANet网络的PAN结构中,两个特征图结合是采用shortcut操作,而Yolov4中则采用concat(route)操作,特征图融合后的尺寸发生了变化

 2.4 检测头的loss创新

      损失函数=box位置损失+类别损失+置信度损失

YOLO V4用CIOU损失代替了YOLOv3的box位置损失,取代了预测框和真实框的中心点坐标以及宽高信息设定MSE(均方误差)损失函数或者BCE损失函数,其他部分损失没改变

三.yolov4流程详解

 3.1网络结构图

                                                       图1 网络结构

3.2 YOLOv4的方法

Yolo-v4:主要由三部分组成: Backbone,Neck和Head

3.2.1 Backbone

采用的主干网络为 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的F_conv2传入第一个CSP1模块进行处理(其中只有1个残差单元)

 第二个CSP模块:由CBM组件和2个Res unint模块Concate组成。

将第一个csp模块处理后的304*304*64特征图,传入到第二个CSP模块处理

        同理经过下采样后变成了152*152*128的特征图,然后分别经过两个1*1*64的s=1的卷积后得到两个分支,其中一个分支的特征块进入残差模块进行处理后,再与另一个分支进行拼接,最后第二个csp模块的最后输出是152*152*128   (残差模块中的卷积层:1*1*64和3*3*64)

 第三个CSP模块:由8个Res unint模块和CBM组件Concate组成。

        将第二个csp模块处理后的152*152*128的特征图,传入到第三个个CSP模块处理

同理也是经过同样的操作,最后第三个csp模块的最后输出是76*76*256   (残差模块中的卷积层:1*1*128和3*3*128),这个模块后又分为两个分支,一个分支继续进行csp模块处理,另一个分支直接进入到neck处理

第四个CSP模块:由8个Res unint模块和CBM组件Concate组成。

       将第三个csp模块的一个分支76*76*256的特征图,传入到第四个CSP模块处理

 同理也是经过同样的操作,最后第四个csp模块的最后输出是38*38*512   (残差模块中的卷积层:1*1*256和3*3*256),这个模块后又分为两个分支,一个分支继续进行csp模块处理,另一个分支直接进入到neck处理

第五个CSP模块:由4个Res unint模块和CBM组件Concate组成。

        将第四个csp模块的一个分支38*38*512的特征图,传入到第五个CSP模块处理

同理也是经过同样的操作,最后第五个csp模块的最后输出是19*19*1024  (残差模块中的卷积层:1*1*512和3*3*512),这个模块输出结果直接进入到neck处理

3.2.2 Neck:

特征增强模块,主要由CBL组件,SPP模块和FPN+PAN的方式组成

① CBL组件:

由Conv+Bn+Leaky_relu激活函数三者组成 

将第五个csp4模块的输出结果19*19*1024的特征图,传入到CBL组件中处理

spp前后三个CBL组件是对称的,它们的卷积分别是1*1*512,3*3*1024和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的特征图,将之送入spp模块中,最后的结果为19*19*2048,再经过三个CBL组件的卷积后得到19*19*512的特征图 

③ FPN+PAN的结构:

PAN是借鉴图像分割领域PANet的创新点

这样结合操作,FPN层自顶向下传达强语义特征,而PAN则自底向上传达强定位特征,两两联手,从不同的主干层对不同的检测层进行参数聚合,加速了不同尺度特征的融合,进一步提高特征提取的能力。

3.2.3 Head:

 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的特征图,中间三个框分配给38*38*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(非极大值抑制)后,就可以输出整个网络的预测结果了。

DIOU_NMS的处理步骤如下:  

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)。判定流程和法则如下:

最后保留的预测框就是最终呈现的预测框 



⑥Yolo-v4:损失函数 

 损失函数=box位置损失+类别损失+置信度损失

YOLO V4用CIOU损失代替了YOLOv3的box位置损失,取代了预测框和真实框的中心点坐标以及宽高信息设定MSE(均方误差)损失函数或者BCE损失函数,其他部分损失没改变

具体详解参考:目标检测中的IoU、GIoU、DIoU与CIoU_Runist blog-CSDN博客

              深入浅出Yolo系列之Yolov3&Yolov4&Yolov5&Yolox核心基础知识完整讲解 - 知乎

则:

位置损失

目标检测的一项重要任务就是确定目标的位置,即(x, y, h, w),所以损失值的计算中包含位置损失CIOU损失 (考虑了长和宽的比值)

置信度损失

置信度损失分为两个部分,有目标的置信度损失,无目标的置信度损失

置信度损失:采用二元交叉熵损失

有目标的置信度损失:

 无目标的置信度损失:

 所以综上19*19*255的特征图的损失Loss1

Yolov4 总Loss为三个特征图Loss之和:

 参考链接:YOLO V4 — 网络结构和损失函数解析(超级详细!) - 知乎

  1.  \lambda为权重常数,控制检测框Loss、有物体置信度Loss、没有物体的置信度Loss之间的比例,通常负例的个数是正例的几十倍以上,可以通过权重超参控制检测效果。
  2.  \mathbb{I}_{i,j}^{obj}若是正例则输出1,否则为0; \mathbb{I}_{i,j}^{noobj} 若是负例则输出1,否则为0;忽略样例都输出0。
  3. 置信度、类别标签由于是0,1二分类,所以使用交叉熵作为损失函数

最后:

与 SOTA 方法的比较:

参考链接:深入浅出Yolo系列之Yolov3&Yolov4&Yolov5&Yolox核心基础知识完整讲解 - 知乎

参考链接:YOLOv4 之CBN速读(Cross Iteration Batch Normalization) - 知乎

参考链接: 想读懂YOLOV4,你需要先了解下列技术(二) - 知乎

参考链接: 【论文解读】Yolo三部曲解读——Yolov3 - 知乎

参考链接:YOLO v3代码解读3 - 知乎

参考链接:深度学习论文翻译解析(二十):YOLOv4: Optimal Speed and Accuracy of Object Detection - 战争热诚 - 博客园

参考链接:BiFPN_申小隆的博客-CSDN博客_bifpn

  • 62
    点赞
  • 369
    收藏
    觉得还不错? 一键收藏
  • 11
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值