# RCNN

时间回到 2012 年，卷积神经网络（CNN）在 ImageNet 比赛中的出色成绩让研究人员们意识到了其巨大的潜力，并尝试将其应用到计算机视觉的其他领域。 在随后的 2013 年，Ross Girshick 提出了基于卷积神经网络的目标检测算法 R-CNN 。 相较于基于手工特征和浅层模型的传统算法，R-CNN 在检测精度上有着跨越式的提升。

R-CNN 是 Region with CNN features 的缩写。 顾名思义，它是基于**区域**（region）的—— 即先在图像上找出一些可能包含物体的区域， 再基于这些图像区域预测其中是否包含物体、以及该物体的类别与精确的位置。

这种**基于区域**（region-based）的思想在后续的工作中不断改进，形成了 Fast RCNN，Faster RCNN，Mask RCNN 等一系列工作。 基于区域的方法也称为**两阶段方法**（two-staged methods）。

## 算法概览

![](/files/-MMQKC1MCC9vmAbSfRlZ)

R-CNN 目标检测算法的基本流程如上图所示，可以分为四个阶段：

1. 区域假设（region proposal）：基于经典视觉算法，在图像中寻找可能包含物体的区域；
2. 特征提取（feature extraction）：使用卷积网络计算该区域的图像特征；
3. 图像分类与边界框回归：基于图像特征预测该区域是否包含物体，物体的类别，以及对应的置信度；并基于回归模型，预测物体边界的精确位置；
4. 区域聚合：将所有区域集合在一起，去除低置信度以及重叠的区域，得到最终检测结果。

作为深度学习时代的早期算法，R-CNN 在系统设计上并不复杂。 但受限于当时人们对深度学习的实践经验，R-CNN 仍然使用了大量的经典算法，以提高系统的整体精度。 作为一本面向现代方法的教程，我们将重点介绍基于深度学习的模块，而将基于经典方法的工程实践收于附录。

### 区域假设（Region Proposal）

区域假设是一类经典视觉算法，它并不是 RCNN 的发明，而是许多经典检测系统都含有的模块。 区域假设可以从图像中找出**可能**包含物体的区域，称之为候选区域。 这种算法并不能达到目标检测所需的精度（precision）， 但与基于滑窗的密集采样相比，区域假设可以在保证召回率（recall）的前提下，将候选区域的数量减少一个数量级。

对于 PASCAL VOC 中常见的 500 x 375 的图像尺寸，如果以步长 10 像素，枚举所有 100 x 100 的区域，就可以产生 50x37 = 1850 个候选区域， 再枚举所有大小、长宽比，就会产生数量巨大的候选区域。 如果用机器学习模型对所有候选区域进行预测，计算量是不可接受的。

但根据经验我们知道，上述海量候选区域中大部分不包含物体或仅与物体有少量重叠。 区域假设就可以以很小的计算代价，提前排除掉这部分候选区域，仅保留那些可能包含物体的候选区域，供后续的模型进行预测。 因此也可以认为是一个初步筛选负样本（即不包含物体的候选区域）的过程。

区域假设的算法有很多，RCNN 采用的是 [selective search](/openmmlab-book/object-detection/intro-1/rcnn.md) 算法。 根据 RCNN 的论文描述，selective search 方法可以针对一张图片给出约 2000 个候选区域，在 PASCAL VOC 数据集上可以达到 98% 的召回率。

### 特征提取

卷积神经网络可以产生富含语义信息的图像特征，R-CNN 也利用了这个特性。 R-CNN 基于每个候选区域对图像进行裁剪，再送入卷积网络，计算出对应的图像特征。

由于候选区域的大小和长宽比并不固定，因此在送入卷积网络之前，还需要将这些图片区域拉伸至固定的尺寸。 尺寸的选取依赖所采用的神经网络模型，对于 ImageNet 预训练的模型而言，这个尺寸通常为 224 x 224 。

### 图像分类与边界框回归

接下来，R-CNN 设置了一个 K+1 类的分类器，这里 K 是数据集中有标记的物体类别的总数，而多出来的一类表示背景，即不包含任何物体。 这个分类器会基于每个区域的图像特征，预测该区域中是否包含物体，以及物体的类别。

R-CNN 还设置了一个回归模型，用于预测边界框的精确位置。 为了避免陷入技术细节，我们可以简单认为回归模型预测物体精确坐标与候选框坐标之间的偏移量。 实际的回归模型还包含一个编解码过程，我们在附录中详细介绍。

### 区域聚合

经过前述三个步骤，R-CNN 已经给出了所有可能包含物体的候选框。 这些候选框之间通常会有大量重叠。 这就需要一个额外的后处理步骤，将这些重叠的框去除。 这个步骤也不是 RCNN 的发明，而是目标检测中常用的一种方法一类后处理方法。 RCNN 采用的是非极大值抑制（non-maximum suppression，NMS）算法。

非极大值抑制的基本思路也非常简单： 如果两个预测框的重合度（通常以 IOU 表示）超过一定阈值，那么就将置信度较小的预测框删去。

非极大值抑制采用贪心算法处理所有的候选框： 初始化候选集合为全部候选框，结果集合为空集。 首先将全部候选框按置信度排序，选取其中置信度最高的候选框，并加入结果集合。 从候选集合中出去该候选框以及和与这个候选框重合度较高的候选框。 接下来在剩余的候选框中选取置信度最高的候选框，重复这个过程，直到候选集为空或结果集合数量达到设定的上限。

需要注意的是，在 RCNN 中， NMS 是每个类别独立进行的。

## R-CNN 的训练

在 RCNN 中，卷积网络、分类器、回归模型都是需要训练的模型。 由于这三个模块都可以用神经网络实现，因此是可以联合训练的。 但受限于早期的实践经验，在 RCNN 的原始论文中，这三个模块是分三个步骤分别进行训练的。

分步训练和联合训练在算法上并没有太本质的差别。 在这里，我们先按照分步训练的方法介绍，再推广到联合训练方法。

我们将训练流程总结在下图中。

![](/files/-MMQKC1PC9G7NvN_RtR-)

### 训练卷积网络

训练一个图像分类的卷积网络是非常简单的： 使用 ImageNet 预训练的模型进行初始化，把最后用于分类的全连接层换掉，再使用拉伸后的图片对其进行训练即可。

训练图像分类网络需要图片和对应类别的标签。 这里，图片就是裁剪拉伸后的图像区域，而标签并不存在。 selective serach 算法并不会为每个候选区域生成类别标注，这些候选框也不是数据集中的原始标注。

这并不是 RCNN 独有的问题，任何基于区域的方法都面临这个问题。

为了能使用这些图像区域训练卷积网络，我们就必须为这些图片生成一个合理的类别标签。 生成标签的思路也非常直观：如果一个候选区域与图像中已有的标注框有较大的重叠， 我们就认为这个候选区域与标注框中包含同一个物体， 进而将这个候选区域标注为这个标注框的类别。 这种包含物体的候选框我们成为**前景**，或**正样本**。

如果一个候选区域与所有的标注框都没有重叠，那么我们就认为这个候选区域内不包含物体， 进而将其标注为**背景**类别。 这种候选框我们称为**负样本**。

这个过程称为**候选区域的分配**（assigment of proposals）。 在这个过程中，我们需要为每一个候选框分配一个标注框，或者分配为背景。并根据分配的结果，为每个候选框生成类别、位置等标注，用于训练模型。

通常，负样本的数量远大于正样本。 为了解决训练样本不平衡问题，我们还需要丢弃一部分**负样本**。

总而言之，分配过程将候选区域分为以下三类：

1. 用于训练的前景，且分配一个对应的标注框
2. 用于训练的背景
3. 不用于训练的背景

在 RCNN 的训练过程中，每次迭代随机选取 32 个正样本，再选取 96 个负样本，组成一个 batch 用于训练。

### 训练回归模型

回归模型根据图像特征预测候选框与真实框之间的差别。 我们可以使用卷积网络从候选区域中提取图像特征，再根据对应的标注框计算出二者的差值，作为预测值，就可以用于训练回归模型。 由于背景并没有位置的概念，因此我们只需基于正样本训练回归模型即可。

### 多任务训练

由于回归和分类共享卷积网络输出的特征，我们自然可以使用多任务学习（multi-task learning）的方式联合训练三个模块。

## 总结

以相对现代的观点来看，RCNN 方法中似乎还有很多不直观的地方，例如并没有使用 FC 层的输出作为分类，而是重新训练了 ovr 的 SVM。

在 RCNN 中，神经网络的作用是替代传统方法中的各种特征提取算法，以得到语义层面上更好的图像特征。整个检测系统的构建仍然依赖了许多传统视觉算法或者浅层的机器学习模型。整个系统也仍然是多阶段的（multi-staged）的。

现代方法更倾向构建从头到尾可微分的模型，并使用大量数据进行端到端的训练。 而在深度学习兴起的初期、受思路以及实验工具的限制，最终发表出来的 RCNN 算法仍然留有大量经典视觉算法的影子。 但 RCNN 的思路仍然是具有启发性的，也给后续 Fast RCNN 以及 Faster RCNN 等经典两阶段方法的提出奠定了基础。

## 外部资料

* [R-CNN](https://arxiv.org/abs/1311.2524) on Arxiv
* [R-CNN](https://ieeexplore.ieee.org/document/7112511) on TPAMI
* [More resource from author's homepage](https://www.rossgirshick.info/)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://openmmlabbook.gitbook.io/openmmlab-book/object-detection/intro-1/rcnn.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
