翻译原文:https://blog.paperspace.com/how-to-implement-a-yolo-object-detector-in-pytorch/
本篇文章是《如何使用PyTorch从零开始实现YOLO(v3)目标检测算法》的第一部分。这系列论文一共有五篇文章,五篇文章的主要内容在下文中有涉及。如果有问题欢迎和我交流~
目录
如何使用PyTorch从零开始实现YOLO(v3)目标检测算法?
如何使用PyTorch从零开始实现YOLO(v3)目标检测算法?
从零开始创建YOLO v3检测器的教程详细介绍了如何从配置文件中创建网络架构、加载权重和设计输入输出传输途径
目标检测这个领域,从最近深度学习的发展中受益良多。最近几年,已经有人研究出了关于目标检测的诸多算法,包括YOLO, SSD,Mask RCNN以及RetinaNet。
在过去的几个月中,我在实验室一直在研究提高目标检测的性能。从实验中得到的最重要的收获就是意识到了学习目标检测最好的方法就是你自己从零开始实现这个算法。这的确就这个教程中要涉及的事情。我们将会使用PyTorch来实现基于YOLO v3的目标检测算法,这个算法是目标检测中最快的算法之一。
这个教程分为五个部分:
- 第一部分:理解YOLO是如何工作的
- 第二部分:创建网络架构的层
- 第三部分:实现神经网络的前向传播
- 第四部分:目标得分阈值化和非极大值抑制回归
- 第五部分:设计输入输出的传输途径
前沿知识:
- 了解卷积神经网络是如何工作的。这应该包括残差网络、跳跃连接和上采样
- 了解什么是目标检测。边界框回归,IoU和非极大值回归
- 了解PyTorch的基本使用。你应该能够很容易创建简单的神经网
1 什么是YOLO
YOLO 表示You Only Look Once。它是一个目标检测器,它使用深度卷积神经网络学习到的特征去预测一个物体。在我们动手写代码之前,我们必须要理解YOLO是如何工作的。
2 全卷积神经网络
YOLO算法只使用卷积层,它确确实实是一个全卷积神经网络(FCN)。它有75个卷积层,跳跃连接和上采样层。没有使用任何形式的池化层,步长为2的卷积层用来对特征映射图进行下采样。这有助于减少经常由于池化所导致的低维度特征的损失。
作为一个全卷积层,YOLO输入图片的尺寸是固定的。但是,在实际应用过程中,各种各样的问题只有在应用这个算法的时候才会暴露出来,因此我们需要一个恒定的输入图片的尺寸。一个最大的问题就是,如果我们想要以批量的形式处理我们的图片的话(GPU可以以并行的形式处理批量的图片,会加快处理速度),我们需要所有的图片都有固定的宽和高。这需要把多个图片汇聚成一个大的批量(汇聚多个PyTorch张量变为一个张量)。
这个网络通过网络步长对图片进行下采样。举个例子,如果网络的步长是32,当输入图片的尺寸是416*416的时候,它的输出的特征图就是13*13了。一般来说,网络中一个层的步长等于这个层的输出较之输入缩小的比例(stride = input_size / output_size)。
3 输入层说明
一般来说,对于所有的目标检测器来说,卷积层学习到的特征会传递给分类器/回归器,然后它们能够做出预测(边界框的坐标值,类别标签等等)。在YOLO中,使用一个含有1*1卷积核的卷积层来进行预测(它将代替全连接层进行预测)。现在,第一个我们需要注意的事情就是,它的输出是一个特征图。既然我们使用了1*1的卷积核,预测之前和之后的特征图大小就会完全一致。在YOLO v3中,每一个栅格(grid)都会预测一个固定数量的边界框(每个栅格会预测三个边界框),特征映射图中每个栅格都有B*(5+C)参数,B代表的是每个单元可以预测几个边界框。根据论文所述,B个边界框中的每一个边界框都会专门检测一个确定的类别。每一个边界框都有(5+C)个属性,5是指用来描述边界框的中心点坐标(tx, ty),尺寸(tw, th),置信度得分(to)这五个参数,C是指每个边界框对于C个类别对象的的置信度。YOLO v3的单元预测3个边界框。(补充一句,因为有3个尺度的输出,每个尺度输出分配3类边界框,因此就会有3*3 = 9个类别的边界框)。我们希望特征映射图的每个单元使用一个边界框去预测一个目标物体,如果该目标物体的中心点落在这个单元的感受野中,我们就让这个单元去预测这个目标物体。
这和YOLO如何训练有关,我们需要一个边界框去负责检测任何给定的目标物体。首先,我们必须要确保这个边界框属于哪一个单元(这个目标物体的中心坐标落在了哪个栅格,这个栅格就负责预测这个目标物体的位置)。为了实现这个目标,我们将输入图片划分为和最终特征映射图相同尺寸的网格。我们来思考一下下面的例子,输入的图片尺寸是416*416,网络的步长是32,正如前面所指出,特征映射图的尺寸将会是13*13,然后我们将输入图片划分成13*13个单元
然后,包含物体的真实边界框的中心点的单元(在输入图像中)就被选为去负责预测这个目标物体。在图像中,就是那个被标记为红色的单元包含了真实边界框(标记为黄色)的中心点。现在,这个红色的单元就在输入网格中第七行。现在,我们就让特征映射图(和特征映射图的单元相一致)中第七列的第七个单元去负责检测这只小狗。现在,这个单元就可以去预测三个边界框。但是,哪一个边界框去负责预测这只小狗的真实标签值呢?为了搞清楚这个,我们必须要学习一下锚框的概念。注意我们现在在讨论的单元是指预测特征映射图的单元。我们将输入图片划分成一个栅格,就是为了决定让预测特征映射图上的哪个栅格负责预测目标物体。
4 锚框
直接预测边界框的宽和高是有可行的,但是在实际过程中,在训练过程中这样做会导致不稳定的梯度(YOLOv1就是输入一张图片,然后直接输出目标物体的中心坐标以及宽高,但是效果不好,才有了v2的改进)。相反,在大多数的模型目标物体检测器都是预测对数变换,或者使用简单的偏移量来根据默认的边界框进行学习,这称之为锚框(anchor box)
之后,这些变换都被用在锚框中去进行预测。YOLO v3有三个锚框,这是因为每个单元中有三个锚框去进行预测。回到我们刚才的问题,负责检测这只狗的边界框,它的锚框和标签边界框一定有着最高的IoU。(锚框的具体知识还请看这里)
5 做出预测
下面的公式描述了网络的输出时如何转变成预测边界框的。
我们预测的边界框的中心坐标和宽高。
是网络的输出。
是左上角栅格的坐标,
是锚框的宽和高。具体详情看这篇博客。
5.1 中心点坐标
注意的是,我们将我们的中心点坐标的预测输入到sigmoid函数中,这是为了强制让网络的输出值在0和1的范围之间,这样是为了让预测边界框的中心点一直落在需要作出预测的栅格中。通常来说,YOLO并没有直接预测边界框的中心点,它预测的是下面的偏差:
- 预测左上角用来预测目标物体的栅格的偏移量(上面两个公式)
- 在特征图中,使用单元的尺寸(宽和高)来进行归一化(下面两个公式)
举个例子,使用我们上面包含小狗的图片。如果预测的中心点坐标是(0.4,07),这就意味着在13*13的特征映射图中,它的中心位置是(7.4, 7.7)。如果预测的结果是(1.2, 0.7),这就一位置目标物体的坐标是 (7.2, 6.7)。这和YOLO的理论背道而驰,因为我们假设这个红色的边界框负责预测这只狗,这只狗的中心坐标应该落在红色的单元中,而不是落在其他单元中。因此,为了修正这个问题,网络的输出要经过sigmoid函数,它能够将输出挤压在0和1之间,有效的让目标物体的中心在保持在要预测的单元中。
5.2 边界框的尺寸
边界框的尺寸由输出的对数变化,然后乘以锚框的尺寸来预测:
结果的预测值是经过图片的宽和高归一化而来的,如果包含狗的边界框的宽和高的预测值是(0.3, 0.8),在13*13的特征映射图中,而目标物体实际中的宽和高就是(stride*0.3, stride*0.8),要乘以步长,这是因为特征图相比于真实图片缩小了stride倍,因此特征图中的物体比实际物体缩小了stride倍。
5.3 目标物体的得分
目标物体的得分表示的是边界框中包含目标物体的可能性。在红色单元中,它的值也应该是接近1的,而且在它相邻的单元中,几乎是0的。目标物体的得分也应该经过一个sigmoid函数,它表示的是一种可能性(我们希望越是能够包含物体的probability就越接近1,但是实际上并不是这样,因此focal loss对其进行了优化)。
5.4 种类的置信度
种类的置信度表示的是检测到的目标物体属于一个特定种类的可能性。在v3之前,YOLO使用的都是softmax函数来表示这种种类的置信度。但是,在v3中,这种使用softmax函数的方法已经被舍弃了,而且作者已经采用sigmoid函数来代替它。这是因为softmax种类的置信度假定类与类之间时相互排斥的。简单来说,如果一个目标物体属于一个类别,那么他就不能属于其他类别了。在coco数据集中,使用softmax函数是没有问题的。但是,当我们同时含有“人”和“女人”两种类型的时候,这种假设就站不住脚了。这也是作者已经避开使用softmax函数的原因。
6 跨尺度预测
YOLO v3跨越了三个尺度进行预测。检测层在三个不同尺寸的特征映射图上进行目标检测,这些尺寸的步长分别是32,16,8。这意味着,当输入的图片是416*416的时候,我们可以在13*13,26*26,52*52三个尺度上的特征映射图进行目标检测。这个网络对输入图片进行上采样,直到遇到第一个检测层,其中对步长为32的层的特征特征映射图进行检测。然后,对层向上采样2倍,并且将其和之前层拥有相同特征映射图的尺寸的特征映射层进行连接。另外一个目标检测在步长为16的网络层,执行相同的上采样步骤。最后一个目标检测发生在步长为8的层。对于每一个尺度的目标检测,每一个单元使用三个锚框预测三个边界框,总共有9个锚框。
作者认为这些帮助YOLO v3更好的检测小物体,这比YOLO之前的版本复杂的多了。上采样使得网络能够学习到更加颗粒的特征,这有助于检测到小的目标物体(经过了两次上采用,52*52的输出能够包含更多的细节信息,这对检测小物体更优帮助),这个多尺度预测是参考FPN网络,13*13的输出层用来预测较大的物体,26*26的输出层用来预测中等物体,52*52的输出层用来预测小物体。
7 处理输出
对于一幅尺寸为416*416的图片来说,YOLO算法预测了(52*52+26*26+13*13)*3 = 10647个边界框。但是在本案例中只有一个目标物体:小狗。我们如何把检测到的边界框的数量从10647减少到1呢?
7.1 给目标物体的置信度设置一个阈值
首先,我们基于他们的目标物体置信度进行过滤边界框。通常来说,置信度低于一定阈值的边界框将会被忽略。
7.2 非极大值抑制
非极大值抑制旨在解决同一张图片一个目标物体出现多个检测结果的问题。举例来说,红色单元的三个边界框可能会检测一个目标物体,或者相邻的单元可能会检测同一个物体,这就需要用到非极大值抑制了。
8 总结
YOLO算法只能够检测到已经在神经网络中训练过的、属于数据集中所提供的类别。我们会为检测器使用官方提供的权重参数文件。
(1) 从整体的网络架构上。YOLO v3变成了全卷积网络(FCN),只有卷积层、残差层和上采样层,没有池化层(保留更多低维度信息),没有全连接层,取而代之使用1*1的卷积层代替进行检测和分类。当使用批量方式对图片进行处理的时候,需要限制所有的输入图片都要有相同的尺寸。
(2)目标物体的框定。使用相对坐标的形式对目标物体进行框定,使用9个不同的anchor boxes作为参考,配合来间接表示预测边界框的位置,这样就能够保证我们可以更加准确的表示目标物体的位置。
(3)对小物体的识别上。为了能够更好的识别小物体,作者使用了多尺度预测,每个尺度下的特征映射图包含不同的图片特征,而且每个尺度使用3种不同的anchor boxes进行预测。
(4)边界框的处理上。生成的众多边界框,我们需要两步处理:设置置信度阈值和非极大值抑制。