目录
1,概述
2,yolov4网络结构上的变化
2.1,BackBone骨干网络(CSPDarknet53)
2.2,增加感受野的SPP结构
2.3 ,特征整合(neck的区别)
3,其它的trick
3.1 常用技巧总结
3.2 YOLO v4使用的新技巧
3.2.1 CmBN
3.2.2 数据增强
3.2.3 SAM(空间注意力机制)改进
3.2.4 激活函数的改变
3.2.5 label smooth
3.2.6 DropBlock
3.2.7 CIOU LOSS and DIOU
据介绍,YOLOv4 在 MS COCO 数据集上获得了 43.5% 的 AP 值 (65.7% AP50),在 Tesla V100 上实现了 ∼65 FPS 的实时速度。
该研究的主要贡献如下:
1. 建立了一个高效强大的目标检测模型。它使得每个人都可以使用 1080Ti 或 2080Ti 的 GPU 来训练一个快速准确的目标检测器。
2. 验证了当前最优 Bag-of-Freebies 和 Bag-of-Specials 目标检测方法在检测器训练过程中的影响。
3. 修改了 SOTA 方法,使之更加高效,更适合单 GPU 训练。这些方法包括 CBN、PAN、SAM 等。
YOLOv4模型由以下部分组成:
yolov3的结构如如下:
从两个网络结构可以看出,yolov4的Head部分,和yolov3一样,其他部分都做了改进,同时还有一些新的算法引入,v4实际上就是保留Darknet作为backbone,然后通过大量的实验研究了众多普适性算法对网络性能的影响,然后找到了它们最优的组合。下面分开看每个部分。
v4保留Darknet作为backbone,但是单元结构上和v3是有一些区别的,具体的区别可以看下面的对比图:
同时v4还引入SPP结构,增加感受野。SPP结构在v4中的应用,如下图所示:
在一般的CNN结构中,在卷积层后面通常连接着全连接。而全连接层的特征数是固定的,所以在网络输入的时候,会固定输入的大小(fixed-size)。但在现实中,我们的输入的图像尺寸总是不能满足输入时要求的大小。然而通常的手法就是裁剪(crop)和拉伸(warp)。
这样做总是不好的:图像的纵横比(ratio aspect) 和 输入图像的尺寸是被改变的。这样就会扭曲原始的图像。而何凯明在这里提出了一个SPP(Spatial Pyramid Pooling空间金字塔池)层能很好的解决这样的问题, 但SPP通常连接在最后一层卷基层。
CNN一般结构和SPP结构
1)SPP原理
空间金字塔池化,使得任意大小的特征图都能够转换成固定大小的特征向量,这就是空间金字塔池化的意义(多尺度特征提取出固定大小的特征向量),送入全连接层。整体框架大致为:输入图像,卷积层提取特征,空间金字塔池化提取固定大小特征,全连接层。
SPP原理
2)实例说明
空间金字塔池化如何提取特征,得到固定大小的特征向量:
我们假设一个很简单两层网络:输入一张任意大小的图片,假设其大小为(w,h),输出21个神经元。也就是我们输入一张任意大小的特征图的时候,我们希望提取出21个特征。空间金字塔特征提取的过程如下:
如上图所示,当我们输入一张图片的时候,我们利用不同大小的刻度,对一张图片进行了划分。上面示意图中,利用了三种不同大小的刻度(4*4,2*2,1*1),对一张输入的图片进行了划分,最后总共可以得到16+4+1=21个块,我们即将从这21个块中,每个块提取出一个特征,这样刚好就是我们要提取的21维特征向量。
第一张图片,我们把一张完整的图片,分成了16个块,也就是每个块的大小就是(w/4,h/4);
第二张图片,划分了4个块,每个块的大小就是(w/2,h/2);
第三张图片,把一整张图片作为了一个块,也就是块的大小为(w,h)。
空间金字塔最大池化的过程,其实就是从这21个图片块中,分别计算每个块的最大值,从而得到一个输出神经元。最后把一张任意大小的图片转换成了一个固定大小的21维特征(当然你可以设计其它维数的输出,增加金字塔的层数,或者改变划分网格的大小)。上面的三种不同刻度的划分,每一种刻度我们称之为:金字塔的一层,每一个图片块大小我们称之为:windows size了。如果你希望,金字塔的某一层输出n*n个特征,那么你就要用windows size大小为:(w/n,h/n)进行池化了。
3)通用公式
我们先假定固定输入图像的尺寸s=224, 而此网络卷积层最后输出256层feature-maps, 且每个feature-map大小为13×13(a=13),全连接层总共256×(9+4+1)个神经元, 即输全连接层输入大小为256×(9+4+1)。即我们需要在每个feature-map的到一个数目为(f=9+4+1)的特征。
由于pooling窗口(w×w)很明显如果我们用一个pooling窗口怎么也很难得到f=9+4+1,再加上如果输入图像尺度变化的话,是根本不可能。
这里用了3个pooling窗口(w×w), 而对应的pooling stride 为t, 经多这3个窗口pooling池化得到3个n×n,n=3,2,1的结果。饼画好了,怎么得到我们的窗口大小ww和stride tt呢?
n=2,n=1n=2,n=1以此类推,将3个pooling后的结果合并,很容易发现和我们的期望一致。
4)SPP的优点和作用
SPP 显著特点
1) 不管输入尺寸是怎样,SPP 可以产生固定大小的输出
2) 使用多个窗口(pooling window)
3) SPP 可以使用同一图像不同尺寸(scale)作为输入, 得到同样长度的池化特征。
其它特点
1) 由于对输入图像的不同纵横比和不同尺寸,SPP同样可以处理,所以提高了图像的尺度不变(scale-invariance)和降低了过拟合(over-fitting)
2) 实验表明训练图像尺寸的多样性比单一尺寸的训练图像更容易使得网络收敛(convergence)
3) SPP 对于特定的CNN网络设计和结构是独立的。(也就是说,只要把SPP放在最后一层卷积层后面,对网络的结构是没有影响的, 它只是替换了原来的pooling层)
4) 不仅可以用于图像分类而且可以用来目标检测
从上面的描述,我们应该懂了作者的意思。作者是整体先对整张图片进行卷积然后,在把其中的目标窗口拿出来Pooling,得到的结果用作全连接层的输入。
特点:只需要计算一次卷积层,训练速度快。
YOLO v3中采用类似FPN,YOLO v4采用的是PANet结构整合特征。如下图所示:
下面就详细介绍一下,什么是 PANet结构,如图所示:
FPN 高维度向低维度传递语义信息(大目标更明确)
PAN 低维度向高维度再传递一次语义信息(小目标也更明确)
YOLO v4文中将前人的工作主要分为Bag of freebies和Bag of specials,前者是指不会显著影响模型测试速度和模型复杂度的技巧,主要就是数据增强操作,对应的Bag of specials就是会稍微增加模型复杂度和速度的技巧,但是如果不大幅增加复杂度且精度有明显提升,那也是不错的技巧。下图对这些技巧做了总结:
bag-of-freebies:不会对测试过程的时间造成影响的方法。这里主要包括数据增强,dropout等正则化方法,对数据不平衡问题进行处理的方法(focal loss等),最后就是bbox回归问题进行处理的方法(改变mse loss 为IOU loss等)。
bag-of-specials:在网络中插入模块使得网络的测试过程的时间轻微增加的方法。这里主要包括上面讲到的各种用于提取并组合特征的Neck,在网络中加入attention module(注意力模块),以及一些类似NMS(非最大值抑制)的后处理方法。
YOLO v4使用以下新功能:WRC(加权残差连接),CSP(跨阶段部分连接), CmBN(交叉小批量标准化),SAT(自对抗训练),Mish激活,马赛克数据增强,DropBlock正则化和CloU丢失,并结合其中一些特性来实现最新结果:在MSCOCO数据集以Tesla V10以65FPS的实时速度获得43.5%AP(AP50为65.7%),其功能的结合,可以参考下图:
表示CBN的修改版本,如下图所示,定义为跨微批量标准化(CmBN)。这仅收集单个批中的小批之间的统计信息。
知识回顾:
*什么是BN
Batch Normalization “批归一化”:Batch是批量的数据,即每次优化点的样本数目,通常BN层用在卷积层后面,用于重新调整数据分布;
将数据分为若干组,按组进行数据的更新参数,一组中的数据共同决定了本次梯度的方向,从而减少了下降的随机性;
具体的步骤为:
假设Batch Normalization的大小是m
其操作可以分成2步,
使用下面一个例子说明BN的操作过程:
BN就是仅仅利用当前迭代时刻信息进行norm,而CBN在计算当前时刻统计量时候会考虑前k个时刻统计量,从而实现扩大batch size操作。同时作者指出CBN操作不会引入比较大的内存开销,训练速度不会影响很多,但是训练时候会慢一些,比GN还慢。
CmBN的做法和前面两个都不一样,其把大batch内部的4个mini batch当做一个整体,对外隔离。CBN在第t时刻,也会考虑前3个时刻的统计量进行汇合,而CmBN操作不会,不再滑动cross,其仅仅在mini batch内部进行汇合操作,保持BN一个batch更新一次可训练参数。具体流程是:假设当前是第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专门设计的,属于实践性改进。
对这三种归一化的方法,解释比较详细的博文,可以查看下面的连接:
【YOLO v4】Normalization: BN、CBN、CmBN_满船清梦压星河HK的博客-CSDN博客_cmbn和bn
深度学习中的BN_CBN_CmBN_Hobart-CSDN博客_cmbn和bn
庖丁解牛yolo_v4之CmBN_Bruce_0712的博客-CSDN博客
Mosaic法
是一种将4张训练图片混合成一张的新数据增强方法,这样可以丰富图像的上下文信息。如下图所示:
这种做法的好处是允许检测上下文之外的目标,增强模型的鲁棒性。此外,在每一层从4个不同的图像批处理标准化计算激活统计,这大大减少了对大mini-batch处理size的需求。
AdversarialTraining自对抗训练
自对抗训练也是一种新的数据增强方法,该技术分前后两个阶段进行。
自对抗训练也是一种新的数据增强方法,可以一定程度上抵抗对抗攻击。其包括两个阶段,每个阶段进行一次前向传播和一次反向传播。
第一阶段,CNN通过反向传播改变图片信息,而不是改变网络权值。通过这种方式,CNN可以进行对抗性攻击,改变原始图像,造成图像上没有目标的假象;
第二阶段,对修改后的图像进行正常的目标检测。
将SAM从空间上的attention修改为点上的attention,并将PAN的short-cut连接改为拼接
什么是注意力机制,可以在下面博文链接中查看:
https://blog.csdn.net/YOULANSHENGMENG/article/details/121356154
YOLO,是一种 one-shot 的目标检测技术,由Joseph Redmon和Ali Farhadi在2016年引入,目前已经有4个版本的技术。在这里,我们会来看看YOLOv4,特别是它的优化器,使用的两个bags的优化函数:在训练期间使用的“Bag of Freebies (BoF)”和在推理期间使用的“Bag of Specials (BoS)”。
Bag of Specials包含了用于YOLOv4架构的主干和检测器的低计算成本模块。这些是:
在这里,我们可以看到Mish激活函数同时存在于主干和检测器中。那么,是什么让它“special”呢?让我们进一步了解这个激活函数。
Mish是光滑的非单调激活函数,可定义为:
f(x) = x・tanh(ς(x))
其中, ς(x) = ln(1+e^x),是一个softmax激活函数和。
Mish的性能详细说明如下:
无上界有有界:无上界是任何激活函数都需要的特性,因为它避免了导致训练速度急剧下降的梯度饱和。因此,加快训练过程。无下界属性有助于实现强正则化效果(适当的拟合模型)。(Mish的这个性质类似于ReLU和Swish的性质,其范围是[≈0.31,∞))。
非单调函数:这种性质有助于保持小的负值,从而稳定网络梯度流。大多数常用的激活函数,如ReLU [f(x) = max(0, x)], Leaky ReLU [f(x) = max(0, x), 1],由于其差分为0,不能保持负值,因此大多数神经元没有得到更新。
无穷阶连续性和光滑性:Mish是光滑函数,具有较好的泛化能力和结果的有效优化能力,可以提高结果的质量。在图中,可以看到ReLU和Mish之间的一个随机初始化的神经网络在宏观平滑度上的剧烈变化。然而,在Swish和Mish的情况下,宏观上或多或少还是相似的。
计算量较大,但是效果更好:与ReLU相比,它的计算比较贵,但在深度神经网络中显示了比ReLU更好的结果。
自门控:此属性受到Swish函数的启发,其中标量输入被提供给gate。它优于像ReLU这样的点式激活函数,后者只接受单个标量输入,而不需要更改网络参数。
Python实现
使用PyTorch可以在python中实现Mish函数,如下所示:
import torch
import torch.nn as nn
import torch.nn.functional as Fclass Mish(nn.Module):
def __init__(self):
super().__init__()
def forward(self, x):
return x*(torch.tanh(F.softplus(x)))
在诸如CIFAR-10, CIFAR-100, CalTech-256, ASL等具有挑战性的数据集的70多个不同的问题标准中,Mish函数的表现超过了广泛使用的激活函数,如ReLU和Swish。下图显示了Mish、Swish和ReLU在不同模型的CIFAR-10数据集上的性能,从图中可以很容易地推断,Mish比Swish函数的性能大约高0.494%,ReLU比Swish函数的性能高1.671%,因此是三者中最准确的:
在YOLOv4中,使用了Mish函数+ CSPDarknet53的组合,尽管代价有点高,但它极大地提高了检测的准确性,因此使Mish成为**“Specials”**之一。
label smoothing是一种正则化的方式,全称为Label Smoothing Regularization(LSR),即标签平滑正则化。
在传统的分类任务计算损失的过程中,是将真实的标签做成one-hot的形式,然后使用交叉熵来计算损失。而label smoothing是将真实的one hot标签做一个标签平滑处理,使得标签变成又概率值的soft label.其中,在真实label处的概率值最大,其他位置的概率值是个非常小的数。
1)什么是标签的one-hot形式
one-hot编码:是将类别变量转换为机器学习算法中容易处理的一种形式!
看个例子便于理解:
index | fruit |
1 | apple |
2 | banana |
3 | strawberry |
4 | watermelon |
如上表所示;如果我们预测的标签是:fruit 列的四个水果,直接看的话,我们人类是很容易区分它们之间的关系;但是对于计算机很难直接区分!但是如果用 index:1,2,3,4 来做 label 的话,就会出现比较关系,因为每个label之间的距离是不同的。这样计算机就可以用数字当作 fruit 的 label。例如你做一个风控模型,预测的是四个风险类别[低,中,高,紧急],其实你也可以用1,2,3,4来做label,因为确实存在一个比较。但这本质上就成了回归问题。
对于分类问题,传统的one-hot编码的标签向量为:
2) label smoothing
one-hot硬编码形式的标签会导致过拟合,而label smoothing是一种正则化策略,通常用于分类问题,通过soft one-hot 标签来引入噪声,减小了真实样本标签的类别在计算损失函数时的权重,从而改善泛化能力差的问题。
而label smoothing结合了均匀分布,用更新的标签向量来替换传统的one-hot编码的标签向量:
其中K为多分类的类别总个数,是一个较小的超参数(一般取0.1),即
这样,标签平滑后的分布就相当于往真实分布中加入了噪声,避免模型对于正确标签过于自信,使得预测正负样本的输出值差别不那么大,从而避免过拟合,提高模型的泛化能力。
转自博文:
庖丁解牛yolo_v4之DropBlock_Bruce_0712的博客-CSDN博客
1)什么是DropBlock操作:
(a)原始输入图像
(b)绿色部分表示激活的特征单元,b图表示了随机dropout激活单元,但是这样dropout后,网络还会从drouout掉的激活单元附近学习到同样的信息
(c)绿色部分表示激活的特征单元,c图表示本文的DropBlock,通过dropout掉一部分相邻的整片的区域(比如头和脚),网络就会去注重学习狗的别的部位的特征,来实现正确分类,从而表现出更好的泛化。
2)DropBlock 模块的参数设置
DropBlock 模块主要有2个参数,block_size,γ。
block_size:表示dropout的方块的大小(长,宽),当block_size=1,DropBlock 退化为传统的dropout,正常可以取3,5,7
γ:表示drop过程中的概率,也就是伯努利函数的概率
首先,保证DropBlock drop的元素个数和传统dropout drop的元素个数相等。(传统的dropout drop的元素个数为drop概率乘以一共的元素个数,即(1-keep_prob)*(feat_size*feat_size)
DropBlock drop的元素个数也是drop概率乘以一共的元素个数)
需要先设置一个drop的有效区域,为了保证drop的block不会超出原始图像,如下图(a)中绿色的区域,也就是原始的图减去block,即(feat_size-block_size+1)。
然后设置随机drop的中间点的概率(概率γ为伯努利函数的概率),如上图(a)中红色的×,实际需要的是要drop掉X周围的block_size大小的区域,也就是一个X对应一个block_size大小的区域(假设不相互重叠)。
所以,DropBlock 的概率即γ*(block_size*block_size),有效的区域面积为(feat_size-block_size+1)*(feat_size-block_size+1),最终得到drop掉的元素数目为γ*(block_size*block_size)*(feat_size-block_size+1)*(feat_size-block_size+1)
最后,dropout==DropBlock ,即让(1-keep_prob)*(feat_size*feat_size)=γ*(block_size*block_size)*(feat_size-block_size+1)*(feat_size-block_size+1)
这样就会得到上面最终的伯努利概率γ。
3)整体流程:
(1)输入特征层A,block_size,γ,模式(训练,测试)
(2,3,4)如果是测试,直接返回特征层A
(5)根据输入的概率γ,使用伯努利函数对生成的随机数mask矩阵进行drop,最终该步骤得到的mask只有0,1值。如上图中(a)。
伯努利概率分布为0-1分布,或者两点分布,公式如下
(6)对上一步得到的mask进行max pooling操作(stride=1,kernel_size=block_size),得到最终需要使用的mask。如上图中(b)。
(7)输入矩阵和Mask矩阵相乘,得到输出矩阵
(8)将上一步的输出矩阵进行归一化操作,保证做DropBlock 之前和做DropBlock 之后,该层都具体相同的均值,方差。
讲解的比较好的博文可以看该博文:
GIoU DIoU CIoU loss 损失函数_不佛的博客-CSDN博客_ciou loss
在深度学习中,损失函数扮演着很重要的角色。通过最小化损失函数,使得模型达到收敛状态,减少模型预测值的误差。因此,不同的损失函数,对模型的影响是重大的。下面总结一下常用的损失函数:
图像分类:交叉熵
目标检测:Focal loss、L1/L2损失函数、IOU Loss、GIOU、DIOU、CIOU
IOU Loss:考虑检测框和目标框重叠面积。
GIOU Loss:在IOU的基础上,解决边界框不重合时的问题。
DIOU Loss:在IOU的基础上,考虑边界框中心距离的信息。
CIOU Loss:在DIOU的基础上,考虑边界框宽高比的尺度信息。
图像识别:Triplet Loss、Center Loss、Sphereface、Cosface、Arcface
1)IOU Loss
该IOU Loss是旷视在2016年提出的《UnitBox: An Advanced Object Detection Network》。该论文的主要观点之一是:
使用基于欧式距离的L-n损失函数,其前提是假设4个坐标变量都是独立的,但实际上,这些坐标变量是具有一定的关联性。考虑检测框和目标框重叠面积
评价指标使用了IOU,而回归坐标框又使用4个坐标变量,这两者是不等价的。具有相同的欧式距离的框,其IOU值却不是唯一的。所以,提出了IOU loss,直接使用IOU作为损失函数:
同时,也会有人使用的是:
最简单的,直接将1-IoU定义为损失,基本没有办法学习,主要原因是:当预测框和目标框不相交时,IoU始终为0,损失函数不可导,无法优化。
另外这种损失定义方式无法区分IoU的各种情况,同样的IoU值,重叠形状可以有许多种,它们在效果上是有差异的,因此我们在损失中应该表现这种差异,如此才能获得合适的优化力度。接下来对IoU损失的改进过程,都是为了更合理地衡量预测框和目标框的差异。
2)GIOU
该GIOU Loss损失函数是斯坦福于2019年提出的《Generalized Intersection over Union: A Metric and A Loss for Bounding Box Regression》。在上面的IOU Loss中
1,无法对两个不重叠的框进行优化,
2,无法反映出两个框到底距离有多远。
为了解决这个问题,作者提了GIOU。
其中,C表示两个框的最小外接矩阵面积。即先求出两个框的IOU,然后求出外接矩阵C的面积,减去A与B的面积。最终得到GIOU的值。
GIoU损失不仅关注重叠区域,还关注非重合区域,解决了无重叠框之间差距无法评估的问题。当预测框和目标框完全重叠:GIoU=IoU=1;当预测框和目标框无重叠,GIoU随着距离增大而减小,趋近于-1。
3)DIoU loss
GIoU有一个问题,一旦预测框和目标框出现包含关系,或者宽和高对齐的情况,差集为0,GIoU就退化成了IoU,无法评估相对位置,收敛缓慢。
4)CIoU loss
最后还有没考虑到的差异,就是形状了,也就是宽高比。
总结:
目标检测任务的损失函数一般由Classificition Loss(分类损失函数)和Bounding Box Regeression Loss(回归损失函数)两部分构成。
回归损失函数近些年的发展过程是:
Smooth L1 Loss → IoU Loss(2016)→ GIoU Loss(2019)→ DIoU Loss(2020)→ CIoU Loss(2020)
IOU_Loss:主要考虑检测框和目标框重叠面积。
GIOU_Loss:在IOU的基础上,解决边界框不重合时的问题。
DIOU_Loss:在IOU和GIOU的基础上,考虑边界框中心点距离的信息。
CIOU_Loss:在DIOU的基础上,考虑边界框宽高比的尺度信息。
DIoU_NMS:
当两个不同物体挨得很近时,由于IOU值比较大,往往经过NMS处理后,只剩下一个检测框,这样导致漏检的错误情况发生。
DIOU-NMS不仅仅考虑IOU,还考虑两个框中心点之间的距离。如果两个框之间IOU比较大,但是两个框的距离比较大时,可能会认为这是两个物体的框而不会被过滤掉。