论文原文地址:
YOLOv3
摘要
我们针对YOLO提供了一些改进。我们在设计上做出了一些改变让它效果更好。我们也训练了这个相当好的网络。它比之前的网络大一点但是准确率更高。不用担心,它的速度依然很快。在320*320的图片上,YOLOv3可以达到单张图片检测速度22ms、28.2的mAP,和SSD准确率一样但速度是它的3倍。在使用以前的IOU mAP标准上,YOLOv3表现非常好。在一个Titan X上检测速度为51ms,精度为57.9
A
P
50
AP_{50}
A
P
5
0
,而RetinaNet检测速度为198ms,精度为57.5
A
P
50
AP_{50}
A
P
5
0
,精度相当但速度却是它的3.8倍。和往常一样,所有的代码都在:
https://pjreddie.com/yolo/
.
YOLOv3的工作
边界框预测。
YOLOv3中对边界框的预测遵循了YOLO9000中的方法。依旧使用维度聚类来生成anchors。对于每个bbx,网络预测4个值,即
t
x
t_x
t
x
、
t
y
t_y
t
y
、
t
w
t_w
t
w
和
t
h
t_h
t
h
,最终的预测映射关系为:
b
x
=
σ
(
t
x
)
+
c
x
b
y
=
σ
(
t
y
)
+
c
y
b
w
=
p
w
e
t
w
b
h
=
p
h
e
t
h
b_x = \sigma(t_x)+c_x \\ b_y = \sigma(t_y)+c_y \\ b_w = p_we^{t_w } \\ b_h = p_he^{t_h}
b
x
=
σ
(
t
x
)
+
c
x
b
y
=
σ
(
t
y
)
+
c
y
b
w
=
p
w
e
t
w
b
h
=
p
h
e
t
h
其中,
c
x
c_x
c
x
和
c
y
c_y
c
y
为当前cell相对于图片左上角的偏移量,
p
w
p_w
p
w
和
p
h
p_h
p
h
是anchor的宽高。下图给了更直观的解释(和YOLOv2中的图相同)
在训练过程中,采用最简单的误差平方和损失。另外,采用Logistic回归来预测每个bbx的目标得分。当一个先验bbx和某个ground truth的重合度比其他的bbx都高,那结果应该为1;那些重合度大于指定阈值但不是最好的先验bbx将被忽略。
类别预测。
某些数据集可能存在多类别标签,如在Open Image Dataset中,存在许多重叠的标签(Woman和Person等)。对于这样的多类别标签,Softmax函数不再使用。因此,在YOLOv3中采用logistic分类器代替。损失函数采用交叉信息损失。
跨尺度预测。
YOLOv3在3个不同大小的特征图进行预测。每一个尺度上都预测bbx位置信息(4个值)、包含目标的概率(1个值)和类别概率(C个值,C为类别数)。设anchor数量为A(每个位置预测A个bbx),所以,对于一个大小为N*N的特征图,最终预测得到的张量shape为N*N*[A*(4+1+C)]。另外,为了提高预测的准确性,YOLOv3中还利用上采样来融合不同深度的特征图信息,最终的特征图相对于原始图片的下采样倍数分别为32倍、16倍和8倍。
特征提取网络。
作者提出了一种新的网络结构用于特征提取,该网络包含53个卷积层,因此叫Darknet-53。按照文中的话来说,这个网络是YOLOv2中的Darknet-19和残差网络的结合体。具体体现在:(1)采用多个3*3和1*1的卷积层相连的形式;(2)引入残差网络中的shortcut连接。具体的结构如下:
在Keras实现的YOLOv3中,对应的Darknet-53代码如下:
def DarknetConv2D(*args, **kwargs):
"""Wrapper to set Darknet parameters for Convolution2D."""
darknet_conv_kwargs = {'kernel_regularizer': l2(5e-4)} # 对卷积层使用L2正则化
darknet_conv_kwargs['padding'] = 'valid' if kwargs.get('strides')==(2,2) else 'same'
darknet_conv_kwargs.update(kwargs)
return Conv2D(*args, **darknet_conv_kwargs)
def DarknetConv2D_BN_Leaky(*args, **kwargs):
"""Darknet Convolution2D followed by BatchNormalization and LeakyReLU."""
no_bias_kwargs = {'use_bias': False} # 不使用偏置项
no_bias_kwargs.update(kwargs)
return compose(
DarknetConv2D(*args, **no_bias_kwargs),
BatchNormalization(),
LeakyReLU(alpha=0.1))
def resblock_body(x, num_filters, num_blocks):
'''A series of resblocks starting with a downsampling Convolution2D'''
# Darknet uses left and top padding instead of 'same' mode
x = ZeroPadding2D(((1,0),(1,0)))(x)
x = DarknetConv2D_BN_Leaky(num_filters, (3,3), strides=(2,2))(x)
for i in range(num_blocks):
y = compose(
DarknetConv2D_BN_Leaky(num_filters//2, (1,1)),
DarknetConv2D_BN_Leaky(num_filters, (3,3)))(x)
x = Add()([x,y])
return x
def darknet_body(x):
'''Darknent body having 52 Convolution2D layers'''
# 对应论文中的Darknet-53
x = DarknetConv2D_BN_Leaky(32, (3,3))(x)
x = resblock_body(x, 64, 1)
x = resblock_body(x, 128, 2)
x = resblock_body(x, 256, 8)
x = resblock_body(x, 512, 8)
x = resblock_body(x, 1024, 4)
return x
从代码中可以看到更多的细节:(1)大部分卷积层后都接有BN层和LeakyReLU层,可以把这种结构看成一个基本的卷积单元;(2)每个残差块中包含3个卷积单元,对应的卷积核分别是3*3、1*1、3*3,且卷积核1*1的卷积层的维度是3*3的一半,shortcut连接从第一个卷积层后引入到第三个卷积层后。(3)在每个残差块的1*1卷积层卷积步长为2,输出的特征图大小变为输入的一半,从而实现了下采样的过程(因此网络中不再需要最大池化进行下采样)
作者在文中也给出了Darknet-53和其他几种典型结构的对比:
可以发现,Darknet-53在准确率上可以和152层的残差网络相媲美,而在速度上达到78FPS,满足实时性的需求。
实验结果
作者文章最后把YOLOv3和其他的一些目标检测网络在准确率和检测速度上进行了对比,先看准确率:
对比结果可以发现:(1)相对于前一个版本YOLOv2,v3有着明显的提升;(2)相比于准确率最高的RetinaNet,v3仍有一些差距,但在老式的评价方法
A
P
50
AP_{50}
A
P
5
0
上,差距比较小;(3)相比于SSD系列,v3在精度上实力相当;(4)对比于Faster R-CNN系列算法,v3在精度上略弱,但差距不大。
再来看一下速度上的对比:
可以明显地看出,YOLOv3系列的检测速度是其他算法的好几倍,当然,前提是依然保持着非常不错的mAP。从数据上也可以发现,貌似只有YOLOv3系列能达到时时检测的要求。