Yolov4项目概述
Yolov4论文:Optimal Speed and Accuracy of Object Detection Yolov4是在2020年CVPR从作者的名字可以知道上面发表的Yolov4并不是原Yolo系列作者。
性能对比
单独将YOLOv4和YOLOv3相比之下,它的提升还是很大的,首先是AP上升大约有10个点,速度有12%YOLOv作者在这篇论文中做了很多实验。
- Backbone:CSPDarknet53
- Neck:SPP,PAN
- Head:YOLOv3
- Eliminte grid sensitivity
- Mosaic data augumentation
- IoU threshold(match positive samples)
- Optimizered Anchors
网络Backbone-CSPDarknet53
Yolov3的backbone是Darknet53
,Yolov4的backboe是CSPDarknet53
.在Darknet引入53CSP
结构。CSP
结构是在CSPnet
论文提出。
CSP结构
该结构有何作用呢?
- 增强CNN的学习能力
- 移除计算瓶颈
- 减少使用显存
也就是说,使用CSP
结构不仅能加快网络的推理速度,还能减少显存的使用,还能提高网络的学习能力。
- 首先,它将输入特征层分为两部分:
Part1
和Part2
,针对Part2
这个分支将通过一系列DenseNet
block,然后通过一个transition,和我们一起输出Part1
上输出Concat拼接融合,然后通过Transition模块。
源码中对Part
和Part2
输入特征层按通道方向征层。但是yolov4这篇论文Part1,Part不是这样分割的
。 根据源码进行简单的绘制,如上图所示:
- 在CSPnet下采样将在之前进行(对应s2)下采样后的输出依次通过左右两个分支
1x1
卷积层。请注意,两个分支的输出特征层只有输入特征层的一半(128
变为64
) - 然后在右边part2分支将连接一系列
ResBlock
,然后接上1x1
卷积层,对应CSPnet
中的transition
- 接下来,输出它part输出1中concat拼接。接下来再通过一个
1x1
卷积层,对应CSPnet
最后一个结构transition.
CSPDarknet 53网络结构
- 这里的
ConvBnMish
等于Conv Bn Mish
,这里的ResBlock
通过结构主分支1x1
卷积层,连接一个3x3
卷积层,然后与我们输入其输出Add
加,得到我们的ResBlock
的输出。 DownSample1
,假设我们的输入图片是一个416x416x3
彩色图片,首先通过卷积核3x3
,步距为1,通道数为32
卷积层。然后通过一个卷积核3x3
,步距为2
,通道数为64
卷积层,然后左右分支1x1
卷积层。然后在右分支上连接一个resBlock
,然后通过一个1x1
卷积融合,左右分支结果通过concat
拼接。然后通过一个1x1
的卷积层。DownSample1
中的CSP模块与上述模块略有不同,主要区别在左右分支1x1
卷积核,在CSP通过这两个卷积层,我们将减半通道的数量DownSample1
这里没有减半。- 从
DownSample1
之后,比如DownSample2
就像我们以前一样CSP
模块的结构是一样的了。首先通过卷积核为3x3
,步距为2
,通道数为128
卷积层part1,part2上接上1x1
卷积,通道数为64
. 然后在part2上接了2个ResBlock
,然后通过1x1
卷积层,然后在Concat
拼接,然后通过1x1
的卷积层。 - 接下来的
DownSample3
,DownSample4
,DownSample5
都是一样的csp
结构,区别就是每一个csp
结构的resblock
堆叠次数不同。还有不同数量的通道,但它们的结构基本相似。
SPP 模块
SPP(Spatial Pyramid Pooling), 输入的特征层依次通过kernel大小为5x5
,9x9
,13x13
需要注意的是,这里的步距为1。通过相应的方式padding之后,他们输出的特征层大小和输入特征层的高度、宽度和channel都一样。然后将这三个模块的输出与原输入共四个分支的输出进行输出Concat这就是我们的SPP结构。
通过SPP能在一定程度上解决多尺度问题
PAN
PAN(Path Aggregation Network)
-
网络通过Backbone通过
FPN
特色金字塔,在FPN
将高层语义信息融入模块中的低层。b
模块恰到好处FPN
相反,像高层一样整合底层语义信息FPN与模块b合作PANet
-
在原始的
PANet
,特征与特征层的融合采用相加
的策略,yolov4采用的是concate
在通道维度拼接的策略。
Yolov4完整的网络结构
- cspdarknet上面已经提到了53部分,这个模块通过简图表示,分别标记
DownSample1~ DownSample5
- 在
DownSample5
在输出中,一个接一个ConvSet1
,ConvSet1
如图所示,如图所示。 - 通过
Convset
之后会有一个SPP
结构,然后通过ConvSet2
,通过三个卷积层对应Convset2
之后我们得到了一个13x13x512
特征图对应于输入图像416x416x3
为例的。 - 在
ConvSet2
输出的基础上再接一个1x1
卷积层,正在通过UpSample1
将特征图翻倍,由13x13x256
变为26x26x256,接着对backbone中 DownSample4
的输出通过1x1
的卷积的输出,与UpSample1
的输出通过concate
卷积进行拼接,拼接之后在通过Convset3
得到26x26x256
的特征图 - 接下来对
ConvSet3
的输出通过一个1x1
的卷积层,通过UpSample2
再将特征图将特征图高宽在翻倍,有26x26
变为52x52
。然后将backbone中DownSample3
的输出通过1x1
的卷积层调整通道,然后与UpSample2
的输出通过Concat
拼接得到输出后,在通过ConvSet4
就可以得到52x52x128
的特征图,在这个特征图之上通过一个3x3
的卷积层以及1x1
的卷积层就能得到针对当前预测特征图的输出。注意最后一个卷积层没有BN
和激活函数。它的输出通道 c h a n n e l = ( 4 + 1 + n c l s ) ∗ 3 channel=(4+1+n_cls)*3 channel=(4+1+ncls)∗3,4是每个anchor需要预测4个目标回归参数,1表示置信度,这里x3是因为我们针对每个预测特征层都有3个anchor模板。 - 接下来对
52x52x128
的特征图,通过kenerl为3,步距为2的卷积的输出与Convset3
输出的26x26x256
的特征图进行concat
拼接。然后通过Convset5
最后接一个3x3
的卷积层和1x1
的卷积层就可以得到针对26x26x256
这个预测特征图的输出。 - 接下来对
ConvSet5
的输出,在通过一个kenerl大小为3x3
,步距为2
的特征层得到13x13x512
的特征图,与另一个13x13x512
的特征图进行拼接。在通过一个ConvSet6
,在通过3x3
的卷积层和1x1
的卷积层,得到第三个预测特征图的预测输出了。
优化策略
1.Eliminate grid sensitivity
- 网络针对每个预测特征层,都是通过1个
1x1
卷积层进行预测的,也就是说1x1
卷积层每滑动到一个grid cell
中,都会预测当前grid cell
对应的3 anchor的一系列输出值,包括边界框回归参数、每个类别score分数。每个anchor
的回归参数有 t x , t y , t w , t h t_x,t_y,t_w,t_h tx,ty,tw,th。 - b x = σ ( t x ) + c x b_x=\sigma(t_x)+c_x bx=σ(tx)+cx, b y = σ ( t y ) + c y b_y=\sigma(t_y)+c_y by=σ(ty)+cy ,其中 b x , b y b_x,b_y bx,by 我们预测边界框中心点坐标, c x , c y c_x,c_y cx,cy当前
grid cell
左上角的坐标。预测边界框的宽 b w = p w e t w b_w=p_we^{t_w} bw=pwetw,预测边界框高度 b h = p h e t h b_h=p_he^{t_h} bh=pheth,其中 p w , p h p_w,p_h pw,ph为anchor
的宽和高。 - 关于预测边界框中心点 c x , c y c_x,c_y cx,cy,通过 σ ( t x ) \sigma(t_x) σ(tx)、 σ ( t y ) \sigma(t_y) σ(ty)被限制在当前
grid_cell
内部的,这样会出现问题,比如我们的GTbox它的中心点如果落在当前grid cell
边界上的时候,比如刚好落在左上角点,那么此时 σ ( t x ) \sigma(t_x) σ(tx)、 σ ( t y ) \sigma(t_y) σ(ty)都应该为0。但是我们的sigmoid激活函数可以发现,只有当x
趋近于负无穷才会为0,但是对于这么极端的数值,一般网络是无法达到的。 - 为了解决这个问题,作者引入了缩放因子
scale
,在原来 b x = σ ( t x ) + c x b_x=\sigma(t_x)+c_x bx=σ(tx)+cx, b y = σ ( t y ) + c y b_y=\sigma(t_y)+c_y by=σ(ty)+cy的基础上作了改进: b x = ( σ ( t x ) . s c a l e x y − s c a l e x y − 1 2 ) + c x b_x=(\sigma(t_x).scale_{xy}-\frac{scale_{xy}-1}{2})+c_x bx=(σ(tx).scalexy−2scalexy−1)+cx b y = ( σ ( t y ) . s c a l e x y − s c a l e x y − 1 2 ) + c y b_y=(\sigma(t_y).scale_{xy}-\frac{scale_{xy}-1}{2})+c_y by=(σ(ty).scalexy−2scalexy−1)+cy 目前github中主流的实现方法,包括yolov5中,是将scale
设为2
的, 将scale=2
带入,就有下面两个公式: b x = ( 2 σ ( t x ) − 0.5 ) + c x b_x=(2\sigma(t_x)-0.5)+c_x bx=(2σ(tx)−0.5)+cx b y = ( 2 σ ( t y ) − 0.5 ) + c y b_y=(2\sigma(t_y)-0.5)+c_y by=(2σ(ty)−0.5)+cy - 我这里画出了 σ ( x ) \sigma(x) σ(x)和 2 σ ( t x ) − 0.5 2\sigma(t_x)-0.5 2σ(tx)−0.5的曲线 蓝色的是原始sigma函数,值域是在[0,1]之间, 2 σ ( t x ) − 0.5 2\sigma(t_x)-0.5 2σ(tx)−0.5对应的是橙色的曲线,很明显在相同的
x
范围内,通过scale
之后能够取到y
的范围更广一些。换句话说通过scale
之后,y
对x
变得更加敏感了。值域有(0,1)
,变为(-0.5,1.5)
之间了。通过变换之后我们的预测值很容易到达grid_cell的边界0,1位置了。
2.Mosaic data augumentation
就是将四张不同的图片按照一定的规则给拼接在一起,拼接好之后就能得到一张新的图片,这样做可以扩充训练的样本多样性
3.IoU threshold
IoU threshold
是为了匹配正样本所使用的IoU阈值,在yolov3 spp
中它是如何匹配正样本的呢?首先针对每个GT会和每个anchor
模板进行match
,在yolov3中针对预测特征层会采用3种不同的模板,分别是AT1
,AT2
,AT3
. 通过GT
与anchor
模板左上角对齐来计算IoU