本教程转载于:https://blog.paperspace.com/how-to-implement-a-yolo-object-detector-in-pytorch/, 在原教程上加入了自己的理解,我的理解将用 这样的格式写出

这是一个关于从头开始构建 YOLO v3检测器的教程,详细介绍了如何从配置文件创建网络体系结构、加载权重和设计输入/输出管道。

什么是YOLO?

YOLO 代表你只看一次( You Only Look Once)。它是一种物体探测器,利用深度卷积神经网络学到的特征来探测物体。在我们开始写代码之前,我们必须了解 YOLO 是如何工作的。

一个完整的卷积神经网络

YOLO 仅使用卷积层,使其成为一个完全卷积网络(FCN)。它有75个卷积层,带有跳过连接和上采样层。没有使用任何形式的pooling,使用stride为2的卷积层对特性映射进行下采样。这有助于防止由于池化而导致的低级特性的丢失。

作为一个 FCN,YOLO 可以允许输入任意大小的图片。然而,在实践中,由于各种各样的问题,我们可能希望坚持一个固定的输入大小。

这些问题中最大的一个是,如果我们想批量处理图像(批量处理图像可以通过 GPU 并行处理,从而提高速度) ,我们需要所有固定高度和宽度的图像。这需要将多个图像连接到一个batch处理。

网络通过给卷积操作指定较大的stride来实现下采样。例如,如果网络的步幅是32,那么一个416 x 416的输入图像将产生一个13 x 13的输出。

解释输出

通常情况下( 所有对象检测器都是这样的) ,卷积层学习的特征会被传递到一个分类器/回归器,从而进行接下来的预测(预测box的坐标,类标签等)。

在 YOLO,预测是通过使用1 x 1的卷积层来完成的。

现在,首先要注意的是我们的输出是一个feature map。由于我们已经使用了1 x 1的卷积核,所以预测图的大小正好是之前特征图的大小。在 YOLO v3(及其之后的版本)中,每个网格可以预测一个固定数量的边界框。

我们的feature map有(b x (5 + c))个属性。B表示每个单元所能预测的box的数量(anchor box的数量)。根据论文,anchor box中的每一个box都可能专门用于检测特定类型的物体。每个box都有 5 + c 个属性,这些属性描述了每个box的中心坐标、维度、对象得分和类别置信度。YOLOv3将会为每个格点预测3个检测框。

这一段如果之前完全没有接触过YOLO系列的文章话,可能会比较懵。YOLO系统的一个核心思想就是将图像划分为NxN的网格。针对每个格点算法先指定几个anchor,选出最合适的anchor后对它的形状进行微调

让我们考虑下面的一个例子,其中输入的图像是416 x 416,网络的stride是32。如前所述,feature map的尺寸将会变为13 x 13。接着我们将输入图像分成13 × 13个单元。

yolo-5

在图像中,黄色的框是ground truth box(标注框),其中标注框的中心点所在的网格被标记为了红色。该网格预测出来的box将会被作为预测候补

现在,红色单元格是网格中第7行的第7个单元格。现在,我们将feature map中第7行的第7个单元(特征映射中的对应单元)分配为负责检测狗狗的单元格。

现在,这个红色的网格可以预测三个边界框。但是哪一个会作为狗狗的预测框呢?为了理解这一点,我们必须首先理解锚(anchor)的概念。

注意,我们在这里讨论的单元格是预测的feature map上的一个单元格。我们将输入的图像划分为一个网格,以确定预测feature map上的哪个单元的是负责预测

Anchor Boxes

预测bounding box的宽度和高度可能是有意义的,但在实践中,这会导致在训练过程中不稳定的梯度。相反,大多数现代目标检测器都会预测对数空间变换说人话就是,我们先选几个默认的框。这些默认的框叫做anchor,然后我们预测anchor和真实box之间的偏移量(上移一点、下移一点....)

YOLOV3中每个单元格会预测三个检测框。

回到我们之前的问题,负责检测狗狗的边界框将是一个与真实标签具有最大重合度的anchor box。

做出预测

下面的公式描述了如何转换网络输出以获得预测的边界框。

bx=σ(tx)+cxby=σ(ty)+cybw=pwetwbh=pheth\begin{gathered} b_{x}=\sigma\left(t_{x}\right)+c_{x} \\ b_{y}=\sigma\left(t_{y}\right)+c_{y} \\ b_{w}=p_{w} e^{t_{w}} \\ b_{h}=p_{h} e^{t_{h}} \end{gathered} \\

bxb_xbyb_ybwb_wbhb_h 是我们预测的 x,y 中心坐标,宽度和高度。txt_xtyt_ytwt_w,这就是网络的输出。cxc_xcyc_y 是坐标网格的左上角坐标。pwp_wphp_h的锚的尺寸。

中心坐标

请注意,我们正在通过一个sigmoid函数来得到我们的中心坐标的预测值。这将强制输出的值在0到1之间。为什么会这样呢?

通常,YOLO 不会预测边界框的中心的绝对坐标,它预测的偏移量是(这两句话不知道怎么翻译了…): image-20210818173515545

例如,现在我们要预测一个狗狗。如果中心的预测值是(0.4,0.7) ,那么这意味着中心的坐标为(6.4,6.7) 。(因为红色网格的左上方坐标是(6,6))。

但是,如果预测的 x,y 坐标大于1,比如说(1.2,0.7) ,会发生什么呢。这意味着中心位于(7.2,6.7)。请注意,中心现在位于红细胞的右边,或者第7行的第8个细胞。这打破了 YOLO 背后的理论,因为如果我们假设红色盒子负责预测狗,狗的中心肯定位于红色细胞,而不是旁边的那个。

因此,为了补救这个问题,输出通过一个Sigmoid函数,它将输出压缩在0到1的范围内,这样预测值就可以有效地保持在预测的网格中心。

Bounding Box的尺寸

边界框尺寸的预测尺寸是通过将anchor乘以一个对数转换空间来得到的。

img

产生的预测,bwb_wbhb_h,是根据图像的高度和宽度进行了归一化之后的结果。(训练标签也是这样的)。因此,如果包含狗的盒子的预测 bx 和 by 为(0.3,0.8) ,那么13x13特征映射的实际宽度和高度为(13x0.3,13x0.8)。

Objectness Score

对象得分表示对象包含在边界框中的概率。对于红色和相邻的网格,它应该接近1,而对于拐角处的网格,它应该接近0。

对象性得分也通过一个Sigmoid函数,因为它可以被理解为一个概率。

Class Confidences

类别信任度表示被检测对象属于特定类别(狗、猫、香蕉、汽车等)的概率。在 v3版本之前,YOLO 习惯于对class scores进行softmax处理。

然而,这种设计在 v3中被取消了,作者们选择了使用 sigmoid。原因在于,Softmaxing 类分数假定这些类是相互排斥的。简单地说,如果一个对象属于一个类,那么它就保证不能属于另一个类。如果我们的检测器是基于COCO数据集,这样是正确的。

然而,当我们有像 Women 和 Person 这样的类别时,这种假设可能就不成立了。这就是作者避免使用 Softmax 激活函数的原因。

Softmax函数是在分类网络中经常出现一种处理方式,YOLOv3这样的处理方式也可以给我们一些启示

不同尺度的预测

YOLOv3可以在3个不同的尺度(scale)上进行预测。所述检测层用于对三种不同大小的特征图进行检测,分别具有32、16、8步。这意味着,在输入416 x 416的情况下,我们可以在13 x 13,26 x 26和52 x 52三个规模的特征图上进行检测。

网络对输入图像进行下采样直到第一个检测层,在第一个检测层中使用stride为32的卷积层的feature map进行检测。此外,网络层还会被上采样到2倍大小,并与具有相同大小feature map的先前层进行连接。另一个检测发生在stride为16的层。重复同样的上采样过程,并在stride为8的层进行最终检测。

在每个scale,每个单元格都会预测3个边界盒使用3个锚,使总数锚使用9。(不同scale的锚是不同的)

img

在作者的报告说,这有助于 YOLOv3更好地检测小对象,这是早期版本 YOLO 经常抱怨的问题。上采样可以帮助网络学习细粒度的特征,这些特征将有助于检测小物体。

输出处理

对于大小为416 x 416的图像,YOLO 将预测((52 x 52) + (26 x 26) + 13 x 13) x3 = 10647个box。然而,在我们的图像中,只有一个物体,一只狗。我们如何将侦测到的数量从10647减少到1?

基于目标置信度的阈值分割

首先,我们根据Ojectness score 过滤一些框。通常,得分低于阈值的框将被过滤掉。

NMS极大值抑制

NMS 的目的是解决同一图像的多重检测问题。例如,红色网格单元格的所有3个边框都可能检测到一个框,或者相邻的单元格可能检测到同一个对象。

img


YOLO 只能检测训练数据集中出现过的类别对象。我们将使用官方的权重文件。通过对 COCO 数据集进行网络训练,从而可以检测出80种目标类别。

这就是第一部分。这篇文章充分解释了 YOLO 算法,使你能够实现检测器。然而,如果你想深入了解 YOLO 的工作原理,它是如何被训练的,以及与其他探测器相比它的表现如何,你可以阅读原始的论文。

在下一部分中,我们将实现组装检测器所需的各种layer。