# 深度学习目标检测：一个全面的回顾

原文链接：[Deep Learning for Object Detection: A Comprehensive Review](https://towardsdatascience.com/deep-learning-for-object-detection-a-comprehensive-review-73930816d8d9?from=hackcv&hmsr=hackcv.com)

![1](https://cdn-images-1.medium.com/max/1250/1*ftTEVgsx0jfvUSFB6X5mQg.jpeg)

随着自动驾驶汽车，智能视频监控，面部检测和不同人种统计等应用的兴起，快速准确的物体检测系统正在崛起。 这些系统不仅涉及识别和分类图像中的每个目标，而且通过在其周围绘制适当的边界框来定位每个目标。 这让目标检测比传统的计算机视觉前身——图像分类更加困难。

然而，幸运的是，最成功的目标检测方法目前是图像分类模型的扩展。 几个月前，Google为Tensorflow发布了一个[新的目标检测API](https://research.googleblog.com/2017/06/supercharge-your-computer-vision-models.html)。 在此版本中，提供了预构建体系结构和权重的[几个特定的模型](https://github.com/tensorflow/models/blob/master/object_detection/g3doc/detection_model_zoo.md)。

- 带有[Single Shot Multibox Detector](https://arxiv.org/abs/1512.02325) (SSD) 的 [MobileNets](http://research.googleblog.com/2017/06/mobilenets-open-source-models-for.html)
- 使用 [Inception V2](https://arxiv.org/abs/1512.00567) 结构的SSD
- 使用 [Resnet 101](https://arxiv.org/abs/1512.03385) 的[基于区域的完全卷积网络](https://arxiv.org/abs/1605.06409) (R-FCN) 
- 使用 Resnet 101 的[Faster RCNN](https://arxiv.org/abs/1506.01497) 
- 使用 [Inception Resnet v2](https://arxiv.org/abs/1602.07261) 结构的[Faster RCNN](https://arxiv.org/abs/1506.01497) 


在我[上一篇博客文章](https://medium.com/towards-data-science/an-intuitive-guide-to-deep-network-architectures-65fdc477db41)中，我介绍了上面列出的三种基本网络架构背后的直觉：MobileNets，Inception和ResNet。 这一次，我想对Tensorflow的目标检测模型做同样的事情：更快的R-CNN，R-FCN和SSD。 到本文结束时，我们希望能够理解深度学习如何应用于目标检测，以及这些目标检测模型如何相互激励和发散。

## Faster R-CNN

Faster R-CNN现在是基于深度学习的目标检测(object detection)的一个规范模型。 它帮助启发了许多检测和分割模型，包括我们今天要研究的其他两个模型。 不幸的是，如果我们不了解这两个模型的前身R-CNN和Fast R-CNN，我们就无法真正了解Faster R-CNN，所以让我们快速地了解它们的祖先。

### R-CNN

R-CNN是Faster R-CNN的祖父。 换句话说，R-CNN真正地揭开了序幕。

R-CNN（基于区域的卷积神经网络，**R**egion-based **C**onvolutional **N**eural **N**etwork）由3个简单步骤组成：

1. 使用称为选择性搜索的算法扫描输入图像以查找可能的目标，生成大约2000个**建议区域**(**region proposals**)
2. 在每个建议区域的基础上运行卷积神经网络（**CNN**）
3. 获取每个**CNN**的输出并将其输入a）SVM以对区域进行分类，以及b）线性回归器以缩小目标的边界框（如果存在这样目标的话）

这三个步骤如下图所示：

![2](https://cdn-images-1.medium.com/max/1000/1*D2sFqL329qKKx4Tvl31IhQ.png)

换句话说，我们首先提出区域，然后提取特征，然后根据它们的特征对这些区域进行分类。 实质上，我们已将目标检测转变为图像分类问题。 R-CNN非常直观，但速度很慢。

### Fast R-CNN

R-CNN的下一代是Fast R-CNN。 Fast R-CNN在很多方面与R-CNN相似，但通过两个主要增强功能提高了其检测速度：

1. 在提出区域**之前**对图像执行特征提取，因此仅在整个图像上运行一个CNN而不是在2000多个重叠区域运行2000个CNN
2. 用softmax层替换SVM，从而扩展神经网络以进行预测，而不是创建新模型

新模型看起来像这样：

![3](https://cdn-images-1.medium.com/max/1000/1*iWyUwIPO-5kA2ECAfaaPSg.png)

正如我们从图片中看到的那样，我们现在基于网络的最后一个特征图生成区域建议，而不是基于原始图像本身。 因此，我们可以为整个图像训练一个CNN。

此外，不是训练许多不同的SVM来对每个对象类进行分类，而是有一个softmax层直接输出分类概率。 现在我们只有一个神经网络用来训练，而不是一个神经网络和许多SVM。

Fast R-CNN在速度方面表现更好。 剩下的只有一大瓶颈：用于生成建议区域的选择性搜索算法。

### Faster R-CNN

在这一点上，我们回到了原来的目标：更快的R-CNN。更快的R-CNN的主要方法是使用快速神经网络取代比较慢的选择性搜索算法。更加具体的说，它使用了了**区域建议网络**（**region proposal network**，RPN）。

下面是RPN的工作原理：

- 在初始CNN的最后一层的时候，3x3滑窗在特征图上移动并将其映射到较低维度（例如256-d）
- 对于每个滑动窗口位置，它基于$k$个固定比率**锚箱**（**anchor boxes** ）生成多个可能的区域（默认边界框）
- 每个建议区域包括：a）该区域的“对象性”（“objectness”）得分和 b）该区域的边界框的4个坐标

换句话说，我们在最后一个特征图中查看每个位置，并考虑以它为中心的$k$个不同的框：一个高的，一个宽的，一个大的等。对于每个边框，不论我们是否认为它包含一个目标，都会进行输出并输出边框的坐标。这是一个滑动窗口位置的样子：

![4](https://cdn-images-1.medium.com/max/1600/1*7heX-no7cdqllky-GwGBfQ.png)

*2k*分数表示*k*个边界框在“目标”上的softmax概率。请注意，虽然RPN输出了边界框的坐标，但它不会对潜在对象进行分类：它唯一的任务仍然是提出目标区域。 如果锚箱的“对象性”得分高于某个阈值，则该框的坐标将作为建议区域。

一旦获得了建议区域，我们就直接将它们提供给本质上是Fast R-CNN的东西。 我们添加了一个全连接的池化层，最后是一个softmax分类层和边界框回归器。 从某种意义上说，**Faster R-CNN = RPN + Fast R-CNN**。

![5](https://cdn-images-1.medium.com/max/800/1*LHk_CCzzfP9mzw280kG70w.png)

总而言之，Faster R-CNN提高了速度和精度。值得注意的是，虽然这个模型在提高检测速度方面做了很多工作，但很少有模型能够以显著的优势超越Faster R-CNN。换句话说，Faster R-CNN可能不是用于目标检测的最简单或最快的方法，但它仍然是表现最好的方法之一。 例如，Tensorflow的Faster R-CNN使用了[最慢但最准确的Inception ResNet的模型]((https://github.com/tensorflow/models/blob/master/object_detection/g3doc/detection_model_zoo.md))。

在这部分的最后，Faster R-CNN可能看起来很复杂，但其核心设计与原始的R-CNN相同：**假设目标区域然后进行分类**。 这是目前许多目标检测模型的核心，包括下一个我们要介绍的。

### R-FCN

还记得Fast R-CNN如何通过在所有建议区域中共享单个CNN计算来提高原始检测速度吗？ 这种思想也是R-FCN背后的动力：*通过最大化共享计算来提高速度*。

R-FCN或基于区域的完全卷积网络在每个输出中共享100％的计算。[被完全卷积](https://leonardoaraujosantos.gitbooks.io/artificial-inteligence/content/image_segmentation.html)在模型设计中遇到了一个独特的问题。

一方面，当执行目标分类时，我们想要在模型中学习到*位置不变性*（location invariance）：无论猫在图像中出现在哪里，我们都希望将其归类为猫。 另一方面，当执行目标检测时，我们想要学习到*位置差异*（location variance）：如果猫在左上角，我们希望在左上角绘制一个框。 因此，如果我们试图在100％的网络上共享卷积计算，我们如何在位置不变性和位置差异之间进行折中？

R-FCN的解决方案：**位置敏感得分图**（**position-sensitive score maps**）。

每个位置敏感的得分图表示*一个目标类*的*一个相对位置*。 例如，只要检测到*右上角*的*猫*，就可以激活一个得分图。 在看到位于*左下角*的*汽车*，可能会激活另一个得分图。 你明白了吧。 本质上，这些得分图是**已被训练用来识别每个目标某些部分的卷积特征图。**

现在，R-FCN的工作原理如下：

1. 在输入图像上运行CNN（在本例中为ResNet）
2. 添加完全卷积层以生成上述“位置敏感得分图”的**得分库**。应该有k²（C + 1）得分图，其中k²表示划分目标的相对位置的数量（例如，3²是3x3格），C + 1表示类别的数量加上背景。
3. 运行完全卷积区域建议网络（fully convolutional region proposal network，RPN）以生成感兴趣的区域（RoI）
4. 对于每个Rol（感兴趣的区域），将其划分为与得分图相同的k²“箱子”（bins）或子区域
5. 对于每个bin，检查分数库以查看该bin是否与某个目标的相应位置匹配。 例如，如果我在“左上角”的bin上，我将获取与目标的“左上角”对应的得分图，并平均RoI区域中的值。 对每个类别重复此过程。
6. 只要每个k²箱具有每个类别的“目标匹配”值，就可以平均每个类别的值再获得一个分数。
7. 对RoI进行分类是用剩下的C + 1维向量进行softmax

总而言之，R-FCN看起来像这样，RPN生成了RoI：

![6](https://cdn-images-1.medium.com/max/800/1*cHEvY3E2HW65AF-mPeMwOg.png)

即使有解释和图像，你可能仍然对此模型的工作方式感到困惑。老实说，当你可以想象它在做什么时，R-FCN更容易理解。 下面是一个在实践中的R-FCN的例子：检测婴儿。

![7](https://cdn-images-1.medium.com/max/800/1*Q20DdanzQbvBjg4DLvJkGg.png)

简单地说，R-FCN考虑每个建议区域，将其划分为子区域，并在子区域上进行迭代，问：“这看起来像婴儿的左上角吗？”，“这看起来像婴儿的正上方吗？“，”这看起来像婴儿的右上角吗？“等等问题。它为所有可能的类别重复这个过程。 如果足够的子区域说“是的，我与婴儿的那部分相匹配！”，在所有类别的softmax之后，RoI被归类为婴儿。

通过这种设置，R-FCN能够通过提出不同的目标区域来同时解决*位置方差*，并通过让每个区域建议参考同一组得分图来确定*位置不变性*。无论猫出现在何处，这些得分图应该学会将猫分类为猫。最重要的是，它是完全卷积的，这意味着所有计算都在整个网络中共享。

结果是，R-FCN比Faster R-CNN快几倍，并且有了相当的精度。

### SSD

我们的最终模型是SSD，代表单次探测器（**S**ingle-**S**hot **D**etector）。与R-FCN一样，它比快速的R-CNN有了巨大的速度提升，但是是以完全不同的方式实现了这一点。

我们的前两个模型分两个步骤执行建议区域和区域分类。 首先，他们使用建议区域网络来生成感兴趣的区域; 接下来，他们使用全连接层或位置敏感的卷积层来对这些区域进行分类。 SSD在“单次拍摄”（single shot）中完成这两步，同时在处理图像时预测边界框和类别。

具体而言，给定输入图像和一组地面的实况标签，SSD执行以下操作：

1. 将图像传递给一系列卷积层，产生不同比例的几组特征图（例如10x10，然后是6x6，然后是3x3等等）
2. 对于*每个*特征图中的每个位置，使用3x3卷积层来评估一小组默认边界框。 这些默认边界框基本上等同于Faster R-CNN的锚箱。
3. 对于每个边界框，同时预测a）边界框偏移和b）类别概率
4. 在训练过程中，根据[IoU](https://en.wikipedia.org/wiki/Jaccard_index)将地面实况框与这些预测框进行匹配。 最佳预测框以及其它具有真实度> 0.5的IoU的边界框将被标记为“正面”。

SSD听起来很简单，但训练它有一个特别的问题。使用前两个模型，区域建议网络确保我们尝试分类的所有内容都具有成为“目标”的最小概率。但是，对于SSD，我们跳过了过滤步骤。我们在*几个不同的尺度*上，使用*多种不同的形状*，对*图像中的每个位置*进行分类和绘制边界框。这样导致的结果是，生成的边界框数量远远多于其他模型，并且几乎所有边界框都是负面的例子。

为了解决这种不平衡问题，SSD做了两件事。首先，它使用非最大抑制将高度重叠（[non-maximum suppression](https://docs.microsoft.com/en-us/cognitive-toolkit/Object-Detection-using-Fast-R-CNN#algorithm-details) ）的框组合到一个框中。换句话说，如果四个形状大小等相似的边界包含相同的目标，NMS将保存一个具有最高置信度并且丢弃其余部分。其次，该模型使用一种称为硬负挖掘（[hard negative mining](https://arxiv.org/pdf/1608.02236.pdf)）的技术来平衡训练期间的类别。在hard negative挖掘中，在每次训练迭代中仅使用具有最高训练损失（即假阳性）的负例子集。 SSD保持3：1的负例与正例的比例。

它的架构看起来像这样：

![8](https://cdn-images-1.medium.com/max/1250/1*p-lSawysBsiBzlcWZ9_UMw.png)

正如我上面提到的，最后有“额外的功能层”缩小了尺寸。 这些不同大小的特征映射有助于捕获不同大小的目标。 例如，这里是一个运行的SSD：

![9](https://cdn-images-1.medium.com/max/1000/1*JuhjYUWXgfxMMoa4SIKLkA.png)

在较小的特征图（例如4×4）中，每个单元覆盖图像的较大区域，使它们能够检测较大的目标。建议区域和分类同时进行：给定*p*个目标类别，每个边界框与（4+*p*）维向量相关联，每个向量输出4个边界偏移坐标和*p*类概率。 在最后一步中，softmax再次用于对目标进行分类。

最终，SSD与前两个模型没有太大区别。 它将跳过“建议区域”步骤，替换为同时考虑图像的每个位置中的每个单独的边界框及其分类。 由于SSD一次性完成所有工作，因此它是[三种模型中速度最快](https://github.com/tensorflow/models/blob/master/object_detection/g3doc/detection_model_zoo.md)的，而且表现相当可观。

### 结论

Faster R-CNN, R-FCN和SSD是目前最好且最广泛使用的三种目标检测模型。其他流行的模型往往与这三种模型非常相似，都依赖于深度CNN（比如：ResNet，Inception等）来进行最初的繁重工作，并且主要遵循相同的建议/分类流程。

此时，使用这些模型只需要了解Tensorflow的API。 Tensorflow有一个关于在这里使用这些[模型](https://github.com/tensorflow/models/blob/master/research/object_detection/object_detection_tutorial.ipynb)的入门教程。Give it a try, and happy hacking!