ronghuaiyang · 6月29日

一阶段的物体检测器,从直觉到细节的方方面面(一)

作者:MATTHIJS HOLLEMANS

编译:ronghuaiyang

首发:AI公园公众号

导读

这篇文章非常详细的讲解了一阶段物体检测器的诸多细节和方方面面,并以yolo和ssd为例,非常细致的比较了两者细节上的异同点,由于文章太长,所以分多次给大家连载,今天是第一部分,主要内容是物体检测中的网格和锚框。

目标检测是一种计算机视觉技术,用于发现图像中感兴趣的物体:

10261593416010_.pic.jpg

这个任务比分类更进一步,分类只会告诉你什么是图像的“主体”,而物体检测可以找到多个物体,对物体分类,并定位物体在图像的什么地方。

物体检测模型预测的是包围框,每个物体一个,以及每个物体的分类概率。

通常情况下,物体检测会预测出非常多的包围框。每个框还有一个置信度得分,表示模型认为该框真正包含物体的可能性。作为一个后处理步骤,我们过滤掉得分低于某个阈值的框(也称为非最大抑制)。

物体检测比分类更复杂。你会遇到的问题之一就是训练图像中可以有从零到几十个物体,模型可能输出多个预测,那么该如何为损失函数找出哪些预测应该和哪个真实的边界框进行比较呢?

由于我在移动设备上工作,我最感兴趣的是单阶段物体检测器。

像 Faster R-CNN 这样的高端模型首先生成所谓的建议区域(图像中可能包含物体的区域),然后对这些区域分别进行预测。这样工作得很好,但也相当慢,因为它需要多次运行模型的检测和分类部分。

另一方面,单阶段检测器只需要通过神经网络一次就可以预测所有的边界框。这更快,也更适合移动设备。单阶段检测器最常见的例子是 YOLO、SSD、SqueezeDet 和 DetectNet。

不幸的是,这些模型的研究论文遗漏了许多重要的技术细节,而且也没有关于训练这些模型的深入的博客文章。因此,为了弄清这些细节,我花了大量时间试图理解这些文章,挖掘其他人的源代码,并从头开始训练我自己的物体检测器。

在这篇(很长的)博客文章中,我将尝试解释这些单阶段检测器是如何工作的,以及如何对它们进行训练和评估。

为什么物体检测非常有技巧性

分类器以一个图像作为输入,并产生一个单一的输出,即类的概率分布。但这只是给你一个关于图像整体的总结,当图像有多个感兴趣的对象时,它就不那么有效了。

在下面的图像中,分类器可能会识别出图像包含一定数量的"猫"和一定数量的“狗”,但这是它所能做到的最好程度。

image.png

另一方面,物体检测模型会通过预测每个物体的边界框来告诉你各个物体的位置:

image.png

由于它现在可以专注于对边界框内的物体进行分类,而忽略外部的所有内容,因此该模型能够为单个物体提供更可靠的预测。

如果你的数据集附带了边框标注(所谓的**ground-truth box **),那么向模型添加本地化输出就很容易了。只要简单地预测额外的 4 个数字,边界框的每个角一个。

image.png

现在模型有两个输出了:

  1. 分类结果的一般概率分布
  2. 边界框回归值。

模型的损失函数简单地将边界框的回归损失与分类的交叉熵损失相加,通常为均方误差(MSE):

outputs = model.forward_pass(image)
class_pred = outputs[0]
bbox_pred = outputs[1]
class_loss = cross_entropy_loss(class_pred, class_true)
bbox_loss = mse_loss(bbox_pred, bbox_true)
loss = class_loss + bbox_loss
optimize(loss)

现在你可以像往常一样使用 SGD 来优化模型,这是一个综合损失,它实际上工作得很好。下面是一个预测的例子:

10271593416197_.pic.jpg

模型已经正确地找到了这个物体(dog)的类别以及它在图像中的位置。红色方框是 ground truth,而青色方框是预测。这不是一个完美的匹配,但非常接近。

:这里给出的 52.14%的分数是分类的分数(82.16% dog)和关于边界框是否真的包含物体的置信度(63.47%)分数的组合。

为了评估预测框与 ground truth 的匹配程度,我们可以计算两个边界框之间的IOU

IOU 是 0 到 1 之间的一个数字,越大越好。理想情况下,预测框和 ground truth 的 IOU 为 100%,但在实践中,任何超过 50%的 IOU 通常都被认为是正确的预测。对于上面的例子,IOU 是 74.9%,你可以看到预测框匹配的很好。

使用回归输出来预测单个边界框会得到很好的结果。然而,就像当图像中有不止一个感兴趣的对象时,就不能很好地工作了,所以这个简单的定位方案就失败了:

10281593416257_.pic.jpg

这个模型只能预测一个边界框,所以它必须选择其中一个物体,但是这个边界框最终出现在了中间的某个地方。实际上,这里发生的事情非常有意义:模型知道有两个物体,但它只有一个边界框可以放弃,所以它妥协并将预测框放在两匹马之间。框的大小也是在两匹马大小的中间。

注意:你可能期望模型现在会在两个物体周围绘制方框,但这并没有发生,因为它没有经过这样的训练。数据集中的 ground-truth 标注总是围绕单个物体绘制,而不是围绕一组物体。

你可能会想,“这听起来很容易解决,让我们通过提供模型额外的回归输出来添加更多的边界框检测器。“毕竟,如果这个模型能够预测_N_个边界框,那么它应该能够找到_N_个物体,对吧?听起来像个计划,但行不通。

即使一个模型有多个这样的检测器,我们仍然得到的边界框都在图像的中间:

10291593416289_.pic.jpg

为什么会这样?问题是,模型不知道应该将哪个边界框分配给哪个物体,为了安全起见,它将它们都放在中间的某个地方。

模型无法决定,“我可以在左边的马周围放置包围框 1,在右边的马周围放置包围框 2。“相反,每个检测器仍然试图预测所有的物体,而不是其中的一个。即使模型有_N_个检测器,它们也不能作为一个团队一起工作。具有多个边界框检测器的模型仍然与只预测一个边界框的模型完全相同。

我们需要的是使边界框检测器专门化的方法,这样每个检测器将尝试预测一个单一的物体,不同的检测器将发现不同的对象。

在一个没有专门化的模型中,每个检测器应该能够处理图像中任何可能位置上的每一种可能的物体。这个要求实在是太过分了……模型现在想要学习预测总是在图像中心的框,因为在整个训练集中,实际上这样最小化了它所犯错误的数量。

从 SGD 的角度来看,这样做的平均结果非常好,但在实践中也不是一个真正有用的结果……所以我们需要更明智地对待如何训练模型。

YOLO、SSD 和 DetectNet 等单阶段检测器都通过将每个边界框检测器分配到图像中的特定位置来解决这个问题。通过这种方式,检测器学会专门研究特定位置的物体。为了得到更好的结果,我们还可以让检测器专门研究物体的形状和大小。

进入网格的世界

使用固定的探测器网格是单阶段检测器的主要思想,也是它们与基于建议区域检测器(如 R-CNN)的区别所在。

让我们考虑这种模型的最简单的架构。它存在于作为特征提取器的基本网络中。像大多数特征提取器一样,它通常是在 ImageNet 上训练的。

在 YOLO 的情况下,特征提取器以 416×416 像素的图像作为输入。SSD 通常使用 300×300 的图像。这些比用于分类的图像要大(通常是 224×224),因为我们不想丢失小细节。

image.png

主干网络可以是任意的,比如 Inception、ResNet 或 YOLO 的 DarkNet,但在移动设备上,使用小型、快速的架构是有意义的,比如 SqueezeNet 或 MobileNet。

在我自己的实验中,我使用了一个经过 224×224 图像训练的 MobileNet V1 特征提取器。我将其放大到 448×448,然后在 ILSVRC 2012 的 130 万张图像数据集上对这个网络进行了 7 个 epochs 的微调,使用了随机 crop 和颜色抖动等基本数据增强。在这些较大的图像上重新训练特征提取器,可以使模型在用于物体检测的 416×416 输入上工作得更好。

在特征提取器的顶部是几个额外的卷积层。它们经过了 finetune,以学习如何预测边界框和这些边界框内物体的类概率。这是模型的物体检测部分。

有许多用于训练物体检测器的公共数据集。在这篇文章中,我们将使用 Pascal VOC)数据集,它有 20 个类。因此,神经网络的第一部分在 ImageNet 上训练,第二部分在 VOC 上训练。

当你查看 YOLO 或 SSD 的实际架构时,你会发现它们比这个简单的示例网络稍微复杂一些,并带有跳过连接等,但是我们稍后会讨论这个问题。目前,上面的模型就足够了,实际上可以用来构建一个快速且相当精确的物体检测器。

最后一层的输出是一个 feature map(上图中的绿色部分)。在我们的例子模型中,这是一个有 125 个通道的 13×13 的特征图。

注意:这里的数字 13 来自于输入大小为 416 像素,并且这里使用的特定基础网络有 5 个池化层(或具有 stride 2 的卷积层),它们一起将输入缩小了 32 倍,416 / 32 = 13。如果你想要一个更细的网格,例如 19×19,那么输入图像应该是 19×32 = 608 像素宽和高(或者你可以使用一个步幅更小的网络)。

我们把这个特征图解释为一个 13×13 的网格。这个数字是奇数,所以中间有一个单个的 cell。网格中的每个单元都有 5 个独立的物体检测器,每个检测器都预测一个边界框。

image.png

这里的关键是检测器的位置是固定的:它只能检测位于该单元格附近的物体(实际上,该物体的中心必须位于网格单元格内)。这使我们避免了上一节中的问题,其中检测器有太多的自由。有了这个网格,图像左侧的探测器永远无法预测位于右侧的物体。

每个目标探测器产生 25 个数字:

  • 20 个包含类概率的数字
  • 4 个边界框坐标(中心 x,中心 y,宽度,高度)
  • 1 个置信度得分

因为每个 cell 有 5 个检测器,5×25 = 125,所以我们有 125 个输出通道。

与常规分类器一样,用于类概率的 20 个数字也应用了 softmax。我们可以通过观察最高的数字来找到获胜的类别。(虽然也经常把它当作多标签分类,在这种情况下,20 个类是独立的,我们使用 sigmoid 而不是 softmax。)

置信度得分是 0 到 1 之间的一个数字(或 100%),它描述了模型认为这个预测边界框包含真实物体的可能性。它也被称为“是否有物体”分数。注意,这个分数只说明了这是否是一个物体,而没有说明这是什么类型的物体——这是类概率的作用。

该模型总是预测相同数量的边界框:13×13 个 cell 乘以 5 个检测器,得到 845 个预测。显然,这些预测中的绝大多数都是不好的 ——毕竟,大多数图像最多只包含少量的物体,不超过 800 个。置信度得分告诉我们哪些预测框可以忽略。

通常,我们最终会得到十几个模型认为不错的预测。其中一些会重叠 —— 这是因为相近的 cell 可能会对同一个物体做出预测,有时单个细 cell 会做出多个预测(尽管在训练中不鼓励这样做)。

image.png

在物体检测中,具有多个大致重叠的预测是很常见的。标准的后处理技术是应用非最大抑制 (NMS)来删除这些重复项。简而言之,NMS 保留了具有最高置信度的预测,并删除了与这些预测重叠超过某个阈值(比如 60%)的任何其他框。

通常我们只会保留 10 个左右最好的预测,而放弃其他的。理想情况下,我们希望图像中的每个物体只有一个边界框。

好了,这描述了使用网格进行物体检测的基本 pipeline。但是“为什么”这样是有用的呢?

约束是个好东西

我已经提到,将每个边界框检测器分配到图像中的一个固定位置是使单阶段物体检测器可以工作的诀窍。我们使用 13×13 的网格作为空间约束,使模型更容易学习如何预测物体。

对于机器学习来说,使用这种(架构)约束是一种有用的技术。实际上,卷积本身也是一种约束:卷积层实际上只是全连接(FC)层的一个更受约束的版本。(这就是为什么你可以使用 FC 层来实现卷积,反之亦然——它们本质上是一样的。)

如果我们只使用普通的 FC 层,机器学习模型学习图像就会困难得多。卷积层上的约束 —— 它一次只查看几个像素,并且连接的权值相同 —— 帮助模型从图像中提取知识。我们使用这些约束来移除自由度,并引导模型学习我们希望它学习的内容。

同样,网格迫使模型学习专门用于特定位置的物体检测器。左上角单元格中的检测器将仅预测位于左上角单元格附近的物体,而不会预测距离较远的物体。(对模型进行了训练,使给定网格单元中的检测器只负责检测中心落在网格单元内的物体。)

该模型的原始版本没有这样的约束,因此它的回归层从未得到仅在特定位置查看的提示。

锚框

网格是一个有用的约束,它限制了检测器在图像中找到目标的位置。我们还可以添加另一个约束来帮助模型做出更好的预测,那就是对物体形状的约束。

我们的示例模型有 13×13 个网格单元,每个单元有 5 个检测器,所以总共有 845 个检测器。但是为什么每个网格单元有 5 个探测器而不是一个呢?嗯,就像检测器很难预测可以放在任何地方的物体一样,探测器也很难预测任何形状或大小的物体。

我们使用网格来专门化我们的检测器,使其只查看特定的空间位置,通过在每个网格单元中使用几个不同的检测器,我们还可以使每个物体检测器专门化于特定的物体形状。

我们将探测器在 5 个特定的形状上训练:

10301593416396_.pic.jpg

红色框是训练集中最典型的五个物体形状,青色框分别是训练集中最小和最大的物体。注意,这些边界框显示在模型的 416×416 像素的输入分辨率中。(图中还显示了浅灰色的网格,因此你可以看到这五个形状与网格单元之间的关系。每个网格单元在输入图像中覆盖 32×32 像素。)

这五种形状称为“锚”或“锚框”。锚不过是一个宽度和高度的列表:

anchors = [1.19, 1.99,     # width, height for anchor 1
           2.79, 4.60,     # width, height for anchor 2
           4.54, 8.93,     # etc.
           8.06, 5.29,
           10.33, 10.65]

锚点描述数据集中最常见(平均)的 5 个物体形状。我所说的“形状”实际上是指它们的宽度和高度,因为我们总是在处理基本的矩形。

有 5 个锚并不是意外。在网格单元中,每个检测器都有一个锚点。就像网格对检测器施加位置约束一样,锚点迫使单元内的检测器专门处理特定的物体形状。

cell 中的第一个检测器负责检测与第一个锚点大小相似的物体,第二个检测器负责检测与第二个锚点大小相似的物体,依此类推。因为每个 cell 有 5 个检测器,我们也有 5 个锚。

因此,检测器 1 将拾取小的物体,检测器 2 将拾取稍大的物体,检测器 3 将拾取长而平的物体,检测器 4 将拾取高而薄的物体,检测器 5 将拾取大的物体。

:上述代码段中锚的宽度和高度是在网格的 13×13 坐标系中表示的,所以第一个锚点的网格宽度略大于 1 个,网格高度接近 2 个。最后一个锚点以超过 10×10 的网格覆盖几乎整个网格。这就是 YOLO 储存锚的方式。然而,SSD 有几个不同大小的网格,因此使用归一化坐标(0 到 1 之间)作为锚,因此它们独立于网格的大小。两种方法都可以。

重要的是要知道这些锚是预先选定的。它们是不变的,在训练中不会改变。

因为锚的宽度和高度是预先选定的,YOLO 论文也称它们为“维度先验”。(Darknet,YOLO 的官方源代码,称它们为“偏差”,我想这是正确的 —— 检测器倾向于预测某种形状的物体 —— 但重载这个术语会让人感到困惑。)

YOLO 通过在所有训练图像的所有框上运行k-means 聚类来选择锚点(使用_k = 5_来找到最常见的五个物体形状)。因此,YOLO 的锚点是“特定于你正在训练(和测试)的数据集”。

k-means 算法找到了一种将所有数据点划分为簇的方法。这里的数据点是数据集中所有 ground-truth 边界框的宽度和高度。如果我们在 Pascal VOC 数据集中的框上运行 k-means,我们会发现以下 5 个簇:

10311593416440_.pic.jpg

这些簇表示此数据集中不同物体形状的五个“平均值”。你可以看到,k-means 发现有必要将非常小的物体分组在蓝色簇中,将稍大的物体分组在红色簇中,将非常大的对物体分组在绿色簇中。它决定把中等大小的物体分成两组:一组边界框宽比高大(黄色),另一组高比宽达(紫色)。

但是 5 个锚是最佳选择吗?我们可以在不同数量的簇上多次运行 k-means,并计算它们最接近的 ground-truth 框和锚框之间的平均 IOU。不出所料,使用更多的聚类中心(更大的_k_值)会得到更高的平均 IOU,但这也意味着我们需要在每个网格单元中使用更多的检测器,这会使模型运行得更慢。对于 YOLOv2,他们选择了 5 个锚点作为召回率和模型复杂度之间的平衡。

10321593416475_.pic.jpg

SSD 不使用 k-means 来寻找锚点。相反,它使用一个数学公式来计算锚的大小。因此,SSD 的锚与数据集是“独立的”(顺便说一下,SSD 的论文称它们为“默认框”)。你可能会认为特定于数据集的锚会提供更好的预测,但我不确定这是否真的重要(YOLO 的作者似乎认为有关系)。

另一个小的区别是:YOLO 的锚点只有宽度和高度,而 SSD 的锚点还有 x、y 的位置。YOLO 简单地假设锚的位置总是在网格单元的中心。(对于 SSD,这也是默认的做法。)

由于有了锚,检测器不必非常努力地工作就可以做出非常好的预测,因为所有都是 0 的预测输出的就是锚框,锚框相当接近真实的物体(平均而言)。这让训练变得容易多了!如果没有锚点,每个检测器将不得不从头开始了解不同的边界框形状是什么样子……这是一个更加困难的任务。

:当我在本文中谈到 YOLO 时,我通常指的是 YOLO v2 或 v3。如果你在阅读 2015 年至 2016 年的论文或博客文章时,发现他们提到了 YOLO,他们经常说的是 YOLOv1,这是非常不同的。版本 1 的网格更小(7×7,每个单元只有 2 个检测器),使用全连接层而不是卷积层来预测网格,并且不使用锚点。那个版本的 YOLO 已经过时了。v2 和 v3 之间的差异要小得多。到了 v3,YOLO 在很多方面都与 SSD 非常相似。

(未完待续,明天见)

—END—

英文原文:https://machinethink.net/blog...

推荐阅读


关注图像处理,自然语言处理,机器学习等人工智能领域,请点击关注AI公园专栏
欢迎关注微信公众号
AI公园 公众号二维码.jfif
4 阅读 197
推荐阅读
0 条评论
关注数
119
内容数
76
关注图像处理,NLP,机器学习等人工智能领域
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
Arm中国学堂公众号
关注Arm中国学堂
实时获取免费 Arm 教学资源信息
Arm中国招聘公众号
关注Arm中国招聘
实时获取 Arm 中国职位信息