像玩乐高一样拆解Faster R-CNN:详解目标检测的实现过程

本文详细解释了 Faster R-CNN 的网络架构和工作流,一步步带领读者理解目标检测的工作原理,作者本人也提供了 Luminoth 实现,供大家参考。

  • Luminoth 实现:https://github.com/tryolabs/luminoth/tree/master/luminoth/models/fasterrcnn


  • 在阅读本文之前,若想了解 R-CNN 网络家族的发展,可以参看机器之心的文章:


    深度 | 用于图像分割的卷积神经网络:从R-CNN到Mark R-CNN


    去年,我们决定深入了解 Faster R-CNN,阅读原始论文以及其中引用到的其他论文,现在我们对其工作方式和实现方法有了清晰的理解。


    我们最终在 Luminoth 中实现了 Faster R-CNN,Luminoth 是基于 TensorFlow 的计算机视觉工具包,易于训练和监控,支持多种不同的模型。到目前为止,Luminoth 已经吸引了很大的关注,我们在 ODSC Europe 和 ODSC West 的论坛中也介绍过这个项目。

    (ODSC,Open Data Science Conference,专注于开源数据科学的会议)。


    基于开发 Luminoth 的工作和过去的报告,我们认为把所有实现 Faster RCNN 的细节和相关链接整合到一篇博客中是一个不错的点子,这对未来其他对此领域感兴趣的人会很有意义。


    背景


    Faster R-CNN 最早在 2015 年的 NIPS 发布。其在发布后经历了几次修改,这在之后博文中会有讨论。Faster-RCNN 是 RCNN 系列论文的第三次迭代,这一系列论文的一作和联合作者是 Ross Girshick。


    这一切始于 2014 年的一篇论文「Rich feature hierarchies for accurate object detection and semantic segmentation」(R-CNN),其使用了称为 Selective Search 的算法用来提取感兴趣候选区域,并用一个标准的卷积神经网络 (CNN) 去分类和调整这些区域。Fast R-CNN 从 R-CNN 演变优化而来,Fast R-CNN 发布于 2015 年上半年,其中一种称为感兴趣区域池化的技术,使得网络可以共享计算结果,从而让模型提速。这一系列算法最终被优化为 Faster R-CNN,这是第一个完全可微分的模型。


    框架


    Faster R-CNN 的框架由几个模块部件组成,所以其框架有些复杂。我们将从高层次的概述开始,之后会介绍不同组成部分的具体细节。


    从一张图片开始,我们将会得到:


  • 一个边框列表

  • 每个边框会被分配一个标签

  • 每对标签和边框所对应的概率


  • 完整的 Faster R-CNN 框架


    输入的图片以长×宽×高的张量形式表征,之后会被馈送入预训练好的卷积神经网络,在中间层得到特征图。使用该特征图作为特征提取器并用于下一流程。


    上述方法在迁移学习中经常使用,尤其在为小数据集训练分类器时,其通常取用了在另一个较大数据集训练好的权重。我们在下一章节会深入了解这个部分。接着,我们会使用到区域建议网络(Region Proposal Network,RPN)。使用 CNN 计算得到的特征,去寻找到预设好数量的可能包含目标的区域 (边框)。


    使用深度学习进行目标检测最大的困难可能是生成一个长度可变的边框列表。使用深度神经网络建模时,模型最后一部分通常是一个固定尺寸的张量输出(除了循环神经网络)。例如,在图片分类中,输出是 (N,) 形状的张量,N 是类别的数量,其中在第 i 个位置标量含有该图片属于类别 i 的概率。


    RPN 中长度可变列表的问题可以使用锚点解决:使用固定尺寸的参考边框在原始图片上一致地定位。不是直接探测目标在哪,而是把问题分两个方面建模,对每个锚点,我们考虑:


  • 这个锚点包含相关目标吗?

  • 如何调整锚点以更好的拟合到相关目标?


  • 可能会有点困扰,但是没关系,下面会深入了解。


    在取得一系列的相关目标和其在原始图片上的位置后,目标探测问题就可以相对直观地解决了。使用 CNN 提取到的特征和相关目标的边框,我们在相关目标的特征图上使用感兴趣区域池化 (RoI Pooling),并将与目标相关的特征信息存入一个新的张量。之后的流程与 R-CNN 模型一致,利用这些信息:


  • 对边框内的内容分类(或者舍弃它,并用「背景」标记边框内容)

  • 调整边框的坐标(使之更好地包含目标)


  • 显然,这样做会遗失掉部分信息,但这正是 Faster-RCNN 如何进行目标探测的基本思想。下一步,我们会仔细讨论框架、损失函数以及训练过程中各个组件的具体细节。


    基础网络


    之前提到过,Faster R-CNN 第一步要使用在图片分类任务 (例如,ImageNet) 上预训练好的卷积神经网络,使用该网络得到的中间层特征的输出。这对有深度学习背景的人来说很简单,但是理解如何使用和为什么这样做才是关键,同时,可视化中间层的特征输出也很重要。没有一致的意见表明哪个网络框架是最好的。原始的 Faster R-CNN 使用的是在 ImageNet 上预训练的 ZF 和 VGG,但之后出现了很多不同的网络,且不同网络的参数数量变化很大。例如,MobileNet,以速度优先的一个小型的高效框架,大约有 330 万个参数,而 ResNet-152(152 层),曾经的 ImageNet 图片分类竞赛优胜者,大约有 6000 万个参数。最新的网络结构如 DenseNet,可以在提高准确度的同时缩减参数数量。


    VGG


    在讨论网络结构孰优孰劣之前,让我们先以 VGG-16 为例来尝试理解 Faster-RCNN 是如何工作的。


    VGG 网络结构


    VGG,其名字来自于在 ImageNet ILSVRC 2014 竞赛中使用此网络的小组组名,首次发布于论文」Very Deep Convolutional Networks for Large-Scale Image Recognition」, 作者是 Karen Simonyan 和 Andrew Zisserman。以今天的标准来看这个网络谈不上深度,但是在发布之际 VGG16 比当时常用的网络要多一倍的层数,其推动了「深度 → 更强大性能 → 更好结果」的浪潮(只要训练是可行的)。


    当使用 VGG 进行分类任务时,其输入是 224×224×3 的张量 (表示一个 224×224 像素大小的 RGB 图片)。在分类任务中输入图片的尺寸是固定的,因为网络最后一部分的全连接层需要固定长度的输入。在接入全连接层前,通常要将最后一层卷积的输出展开成一维张量。


    因为要使用卷积网络中间层的输出,所以输入图片的尺寸不再有限制。至少,在这个模块中不再是问题,因为只有卷积层参与计算。让我们深入了解一下底层的细节,看看具体要使用哪一层卷积网络的输出。Faster R-CNN 论文中没有具体指定使用哪一层;但是在官方的实现中可以观察到,作者使用的是 conv5/conv5_1 这一层 (caffe 代码)。


    每一层卷积网络都在前一层的信息基础上提取更加抽象的特征。第一层通常学习到简单的边缘,第二层寻找目标边缘的模式,以激活后续卷积网络中更加复杂的形状。最终,我们得到一个在空间维度上比原始图片小很多,但表征更深的卷积特征图。特征图的长和宽会随着卷积层间的池化而缩小,深度会随着卷积层滤波器的数量而增加。

    从图片到卷积特征图