前言 ¶
前两天讲了 RCNN 和 Fast-RCNN,相信对目标检测已经有了一些认识了。我们知道 RCNN 和 Fast-RCNN 都是双阶段的算法,依赖于候选框搜索算法。而搜索算法是很慢的,这就导致这两个算法不能实时。基于这个重大缺点,Faster-RCNN 算法问世。
贡献 ¶
Fast-RCNN 仍依赖于搜索候选框方法,其中以 Selective Search 为主。在 Fast-RCNN 给出的时间测试结果中,一张图片需要 2.3s 的前向推理时间,其中 2s 用于生成 2000 个 ROI。可以看到整个算法的时间消耗几乎都在区域候选框搜索这个步骤了,如果我们能去掉候选框搜索这个过程是不是实时有希望了?Faster-RCNN 就干了这件事,论文提出在内部使用深层网络代替候选区域。新的候选区域网络 (RPN) 在生成 ROI 的效率大大提升,一张图片只需要 10 毫秒!!!
网络结构 ¶
Faster-RCNN 的网络结构如下图表示:
我们可以发现除了添加一个 RPN 网络之外,其他地方和 Fast-RCNN 是完全一致的。引用知乎上看到的一张更详细的网络结构如下:
RPN 网络 ¶
RPN 网络将第一个卷积网络 (backbone,如 VGG16,ResNet) 的输出特征图作为输入。它在特征图上滑动一个3×3 的卷积核,以使用卷积网络构建与类别无关的候选区域(候选框建议网络只用关心建议出来的框是否包含物体,而不用关系那个物体是哪一类的),我们将 RPN 产生的每个框叫做 Anchor。
这里这样说肯定还是比较模糊,我引用一张训练时候的 RPN 的结构图然后固定输入分辨率和 backbone 为 VGG16 来解释一下。下面这张图是 RPN 架构:
我们可以看到 anchor 的数量是和 Feature Map 的大小相关,对于特征图中的每一个位置,RPN 会做 k 次预测。因此,在这里对每个像素,RPN 将输出4×k 个坐标和2×k 个得分。然后由于使用了 VGG16 做 Backbone,所以输入到 RPN 的特征图大小是原图H,W 的116。对于一个512×62×37 的 feature map,有 62×37×9 约等于 20000 个 anchor。 也就是对一张图片,有 20000 个左右的 anchor。这里可以看到 RPN 的高明之处,一张图片 20000 个候选框就是猜也能猜得七七八八。但是并不是 20000 个框我们都需要,我们只需要选取其中的 256 个。具体的选取规则如下:
- 对于每一个 Ground Truth Bounding Box,选择和它 IOU 最高的一个 anchor 作为正样本。
- 对于剩下的 anchor,选择和任意一个 Ground Truth Bounding Box 的 IOU 大于 0.7 的 anchor 作为正样本,正样本的数目不超过 128 个。
- 负样本直接选择和 Ground Truth Bounding Box 的 IOU<0.3 的 anchor。正负样本的总数保证为 256 个。
RPN 在产生正负样本训练的时候,还会产生 ROIs 作为 Faster-RCNN(ROI-Head) 的训练样本。RPN 生成 ROIs 的过程(网络结构图中的 ProposalCreator)如下:
- 对于每张图片,利用它的 feature map, 计算 (H/16)× (W/16)×9(大概 20000)个 anchor 属于前景的概率,以及对应的位置参数。
- 选取概率较大的 12000 个 anchor
- 利用回归的位置参数,修正这 12000 个 anchor 的位置,得到 RoIs
- 利用非极大值((Non-maximum suppression, NMS)抑制,选出概率最大的 2000 个 RoIs
在前向推理阶段,12000 和 2000 分别变为 6000 和 3000 以提高速度,这个过程不需要反向传播,所以更容易实现。
最后 RPN 的输出维度是2000×4 或者300×4 的 tensor。
损失函数 ¶
在 RPN 网络中,对于每个 Anchor,它们对应的 gt_label(就是筛选到这个 Anchor 的那个 ground truth 框的 label)要么是 1 要么是 0,1 代表前景,0 代表背景。而,gt_loc 则是由 4 个位置参数(tx,ty,tw,th) 组成,这样比直接回归坐标更好。
计算分类用的是交叉熵损失,而计算回归损失用的是 SmoothL1Loss。在计算回归损失的时候只统计前景的损失,忽略背景的损失。
网络在最后对每一个框都有两种损失,即物体属于哪一类的分类损失 (21 类,加了个背景),位置在哪的回归损失。所以整个 Faster-RCNN 的损失是这 4 个损失之和。网络的目标就是最小化这四个损失之和。
训练 ¶
上面讲了,RPN 会产生大约 2000 个 ROIs, 这 2000 个 ROIs 并不都拿去训练,而是利用 ProposalTargetCreator 选择 128 个 ROIs 用以训练。选择的规则如下:
- RoIs 和 gt_bboxes 的 IoU 大于 0.5 的,选择一些(比如 32 个)
- 选择 RoIs 和 gt_bboxes 的 IoU 小于等于 0(或者 0.1)的选择一些(比如 128-32=96 个)作为负样本
同时为了便于训练,对选择出的 128 个 ROIs 的对应的 ground truth bbox 的坐标进行标准化处理,即减去均值除以标准差。 对于分类问题, 直接利用交叉熵损失。 而对于位置的回归损失, 一样采用 Smooth_L1Loss, 只不过只对正样本计算损失。而且是只对正样本中的这个类别 4 个参数计算损失。举例来说:
- 一个 RoI 在经过 FC 84 后会输出一个 84 维的 loc 向量。如果这个 RoI 是负样本, 则这 84 维向量不参与计算 L1_Loss。
- 如果这个 RoI 是正样本, 属于 label K, 那么它的第 K×4, K×4+1 ,K×4+2, K×4+3 这 4 个数参与计算损失,其余的不参与计算损失。
测试 ¶
测试的时候保留大约 300 个 ROIs,对每一个计算概率,并利用位置参数调整候选框的位置。最后用 NMS 筛一遍,就得到结果了。
后记 ¶
我感觉把原理讲清楚了?但可能内容有点多,还需要仔细看下才能懂。本文的创作引用了部分知乎上的文章,地址如下,非常感谢。 https://zhuanlan.zhihu.com/p/32404424
对本文细节有质疑或者不理解的地方可以留言,也可以去查看一下上面的知乎文章。作者还实现了一个非常简化版本的 Faster-RCNN,只有 2000 行左右并且模型的 MAP 值不降反升,想进一步学习 Faster-RCNN,可以进行源码实战啦,之后有机会写一篇我自己的源码实战分享,今天就分享到这里啦。github 地址为: https://github.com/chenyuntc/simple-faster-rcnn-pytorch
本文总阅读量152次