原文为英文,进行了翻译和部分修改,原文地址
代码地址:github仓库、ACgit仓库
相关内容:
YOLOv3论文翻译
YOLOv3原理及流程简述
从头实现YOLOv3:第2部分
从头实现YOLOv3:第3部分
从头实现YOLOv3:第4部分
从头实现YOLOv3:第5部分
本文是关于从头开始构建YOLO v3 detector
的教程,详细介绍了如何从配置文件创建网络体系结构、加载权重和设计输入/输出管道。
目标检测是一个从深度学习的最新发展中受益匪浅的领域。近年来,人们开发了许多目标检测算法,其中包括YOLO
、SSD
、Mask RCNN
和RetinaNet
。
在过去的几个月里,我一直在一个研究实验室致力于改进目标检测。从这次经历中获得的最大收获之一是认识到学习目标检测的最佳方法是自己从头开始实现算法。这正是本教程中要做的。
我们将使用PyTorch
实现一个基于yolov3
的目标检测器,yolov3
是目前速度最快的目标检测算法之一。
本教程分为5个部分:
-
第1部分(本部分):了解
YOLO
的工作原理 -
第2部分:创建网络结构的层
-
第3部分:实现网络的前向传递
-
第4部分:目标得分阈值化和非最大值抑制
-
第5部分:设计输入和输出管道
第1部分:了解YOLO
的工作原理
前置知识
-
你应该了解卷积神经网络是如何工作的。这还包括
Residual Blocks
,skip connections
, 和Upsampling
的知识。 -
什么是目标检测、
bounding box
回归、IoU
和非最大值抑制。 -
基本
PyTorch
用法。
YOLO
是什么
YOLO
代表"You Only Look Once"。它是一种目标检测器,利用深度卷积神经网络学习的特征来检测物体。在开始编写代码之前,必须了解YOLO
是如何工作的。
全卷积神经网络
YOLO
只使用卷积层,使其成为完全卷积网络(FCN
)。它有75个卷积层,带有skip connections
和上采样层。不使用任何形式的pooling
,并使用带有步长2的卷积层对特征映射进行下采样。这有助于防止经常由pooling
导致的失去底层特征信息的现象。
作为FCN
,YOLO
对输入图像的大小是不变的。然而,在实践中可能希望保持恒定的输入大小,因为在实现算法时,只会显示它们的heads
。
如果想成批处理图像(成批图像可以由GPU
并行处理,从而提高速度),我们需要所有固定高度和宽度的图像。这是将多个图像连接成一个大批量(将多个PyTorch
张量连接成一个)所需要的。
网络通过步长对图像进行下采样。例如,如果网络的步长为32,则大小为416 x 416
的输入图像将产生大小为13 x 13
的输出。通常,网络中任何层的步长等于该层输出与输入图像的比值。
解读输出
通常,(与所有目标检测器的情况一样)由卷积层学习的特征被传递到分类器/回归器上,该分类器/回归器进行检测预测(边界框的坐标、类标签等)。
在YOLO
中,预测是通过使用1 x 1
卷积的卷积层来完成的。
现在,首先要注意的是输出是一个特征图。因为使用了1 x 1
卷积,所以输出预测图的大小等于它之前输入的特征图的大小。在YOLO v3
(及其子代)中,解释此预测图的方式是,每个单元格都可以预测固定数量的边界框。
虽然在技术上正确的术语来描述特征图中的一个单元格是一个神经元,但将其称为单元格使其在我们的文章中更直观。
在深度方面,在特征图中有(B x (5 + C))
个条目。 B
表示每个单元格可以预测的边界框数量。根据论文,这 B
个边界框中的每一个都可能专门用于检测某种目标。每个边界框都有 5 + C
个属性,描述了每个边界框的中心坐标、尺寸、objectness score 和 C 类置信度。 YOLO v3
中每个单元格预测 3 个边界框。
在深度方面,在特征图中有(B x (5 + C))
个条目。 B
表示每个单元格可以预测的边界框数量。根据论文,这 B
个边界框中的每一个都可能专门用于检测某种目标。每个边界框都有 5 + C
个属性,描述了每个边界框的中心坐标、尺寸、objectness score 和 C 类置信度。 YOLO v3
中每个单元格预测 3 个边界框。
如果目标的中心落在某个单元格的感受野中,则希望特征图的该单元格通过其中一个边界框来检测目标(感受野是输入图像对单元格可见的区域)。
这与 YOLO
的训练方式有关,其中只有一个边界框负责检测任何给定的目标。首先,必须确定这个边界框属于哪个单元格。
为此,将输入图像划分为维度等于最终特征图维度的网格。
看看下面的示例,其中输入图像为 416 x 416
,网络的步长为 32。如前所述,特征图的维度为 13 x 13
。然后将输入图像划分为 13 x 13
的单元格。
然后,选择包含目标ground truth box
中心的单元格(在输入图像上)作为负责预测目标的单元格。在图像中,它是标记为红色的单元格,其中包含ground truth box
(标记为黄色)的中心。
现在,红色单元格是网格第 7 行中的第 7 个单元格,将特征图第 7 行的第 7 个单元格(特征图上的对应单元格)指定为负责检测狗的单元格。
现在,这个单元格可以预测三个边界框。哪一个将被分配给狗的真实标签?为了理解这一点,必须全面了解anchor
的概念。
请注意,在这里谈论的单元格是预测特征图上的单元格。将输入图像划分为网格只是为了确定预测特征图的哪个单元格负责预测
Anchor Boxes
预测边界框的宽度和高度可能是有意义的,但在实践中,这会导致训练期间的梯度不稳定。大多数现代目标检测器预测对预测进行对数变换,或者只是简单地偏移到称为anchor
的预定义默认边界框,anchor
是预先指定好的边界框,拥有固定的尺寸和数量,通常每个单元格都有相同数量的若干个anchor
。
然后,将这些变换应用于anchor boxes
以获得预测。 YOLO v3
有三个anchor
,所以每个单元格预测三个边界框。
回到之前的问题,负责检测狗的边界框是若干anchor
中与ground truth box
的 IoU
最高的anchor
所生成的边界框。
也就是说,输出的特征图被划分为13 x 13
的网格,总共有13 x 13
个单元格,目标的ground truth box
中心所在的cell
(单元格)负责预测该目标;每个单元格有3个anchor
,找出其中与ground truth box
的IOU
最高的anchor
,该anchor
生成的边界框负责检测该目标。
预测
以下公式描述了如何转换网络输出特征图以获得预测边界框。
bx、by、bw、bh是预测边界框的 x、y 中心坐标、宽度和高度。 tx, ty, tw, th 是网络输出的特征图中的特征。 cx 和 cy 是网格的左上角坐标。 pw 和 ph 是anchor
尺寸。
中心坐标
请注意,下面通过 sigmoid
函数进行中心坐标预测,这会强制输出值介于 0 和 1 之间。
通常,YOLO
不会预测边界框中心的绝对坐标。它预测的是偏移量:
- 相对于检测目标的单元格的左上角 。
- 由特征图中的单元格的尺寸归一化,即 1。
例如,考虑狗图像的情况。如果中心的预测是 (0.4, 0.7),那么这意味着中心位于 13 x 13
特征图上的 (6.4, 6.7)。 (因为红色单元格的左上角坐标是 (6,6))。
但是如果预测的 x,y 坐标大于 1,例如 (1.2, 0.7),这意味着中心位于 (7.2, 6.7),即中心现在位于红色单元格右侧的单元格中,或第 7 行中的第 8 个单元格。这打破了 YOLO
背后的理论,因为如果假设红框负责预测狗,那么狗的中心必须位于红框中,而不是旁边的那个。
因此,为了解决这个问题,输出通过一个 sigmoid
函数,该函数将输出压缩在 0 到 1 的范围内,有效地保持在负责预测的单元格的中心。
边界框的尺寸
通过对输出进行对数变换然后乘以anchor
的尺寸来预测边界框的尺寸(宽高)。
由此产生的预测 bw 和 bh 通过图像的高度和宽度进行归一化。 (训练标签是这样选择的)。所以,如果包含狗的边界框的预测 bx 和 by 是 (0.3, 0.8),那么 13 x 13
特征图上的实际宽度和高度是 (13 x 0.3, 13 x 0.8)。
Objectness Score
Objectness Score
表示目标在边界框内的概率。对于红色和相邻单元格,它应该接近 1,而对于角落的网格,它几乎是 0。
objectness score
也通过 sigmoid
传递,因为它被解释为概率(在 0 到 1 之间)。
类别置信度
类别置信度表示检测到的目标属于特定类别(狗、猫、香蕉、汽车等)的概率。在 v3
之前,YOLO
对类分数进行 softmax
。
然而,这个设计在 v3
中被放弃了,作者选择使用 sigmoid
。原因是 Softmax
类分数假设这些类是互斥的。简单来说,如果一个目标属于一个类,那么它就不可能属于另一个类。对于COCO
数据库而言,情况确实如此。
然而,当我们有像 Women
和 Person
这样的类时,这个假设可能不成立。这就是作者不使用 Softmax
的原因。
跨尺度预测
YOLO v3
在 3 个不同的尺度上进行预测。检测层用于对三种不同大小的特征图进行检测,步长分别为 32、16、8。这意味着,对于 416 x 416
的输入,在 13 x 13
、26 x 26
和 52 x 52
的尺度上进行检测(对应于大、中、小三种大小图像)。
网络对输入图像进行下采样,直到第一个检测层,其中使用步长为 32 的层的特征图进行检测。接着,网络层被上采样 2 倍,并与具有相同特征图尺寸的前一层的特征图连接。然后在步长 16 的层进行另一个检测。重复相同的上采样过程,并在步长 8 的层进行最终检测。
在每个尺度上,每个单元格使用3个anchor
预测3个bounding box
,使得使用的anchor
总数为9个(不同尺度的anchor
不同)。
各层网络的步长均为1或2,首先将网络最初的输入图像
416 x 416
经过若干次卷积层下采样为52 x 52
、26 x 26
、13 x 13
,然后对13 x 13
特征图进行目标检测;接着该13 x 13
特征图通过上采样层变为26 x 26
,同时与之前层的26 x 26
特征图连接,再进行检测;52 x 52
的检测同样如此。可以利用Netron加载神经网络的配置文件查看传播过程。
作者认为,这有助于 YOLO v3
更好地检测小物体,这是早期 YOLO
版本的常见不足。上采样可以帮助网络学习细粒度特征,这些特征有助于检测小物体。
输出处理
对于大小为 416 x 416
的图像,YOLO
预测 (52 x 52 + 26 x 26 + 13 x 13) x 3 = 10647 个边界框。然而,就我们的图像而言,只有一个目标,一只狗。如何将边界框从 10647 减少到 1?
利用类别置信度的阈值处理
首先,根据它们的 objectness score
过滤边界框,objectness score
低于阈值的边界框会被去掉。
非极大值抑制
NMS
旨在解决同一图像多次检测的问题。例如,红色网格单元格的所有3个边界框可能检测到一个框,或者相邻单元格可能检测到同一个目标。
小结
YOLO
只能检测用于训练网络的数据集中存在的类的目标。我们将在检测器中使用官方权重文件。这些权重是通过在 COCO
数据集上训练网络获得的,因此可以检测 80 个目标类别。
这就是第一部分。这部分充分解释了 YOLO
算法,但是如果想深入了解 YOLO
的工作原理、训练方式以及与其他检测器相比的性能,可以阅读原始论文或是论文翻译。
在下一部分中,将创建把检测器组合在一起所需的各个层。