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这个分支将通过一系列DenseNetblock,然后通过一个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