(5)Faster R-CNN:Region Proposal Network + Real-Time 我们联合!

Faster R-CNN: Towards Real-Time Object Detection with Region Proposal Networks 2016 年

前面 R-CNN 和 SPP-Net 不是都还算 PipeLine “缝合怪”嘛,到 Fast R-CNN 把后面分类和回归任务联合了,不过 region proposal 任务仍然是单独用的 Selective Search。到 Faster R-CNN 这里,终于对 Selective Search 动手了,用 Region Proposal Network “优化”掉了 Selective Search

Abstract

  • 就差 region proposal 当计算瓶颈了,提出 Region Proposal Network 和 detection 部分共享全图特征,来实现区域推荐,变快了很多。
  • RPN 是全卷积、端到端网络,预测每个位置的边界和分数,预测出来的位置框给 Fast R-CNN 用来做检测
  • 通过 attention 机制,共享特征,合并了 RPN 和 Fast R-CNN,RPN 是“眼睛”,告诉整个网络应该“看”哪里
  • 使用 VGG-16,完成整个步骤每秒处理 5 帧。

Introduction

又强调了很多遍,目前目标检测任务中,最拉跨的就是 region proposal,耗时比较长。Region propasl 的工作都是在 CPU 上计算,别的都已经放在 GPU 上了,所以如果能把 region proposal 也放到 GPU 上来做,肯定就能提升整体的运算。

但是如果仅仅是移到 GPU 上就有点单一了。Faster R-CNN 要做的是,联合 region proposal 和 detection 两部分一起,在保证了 detection 部分需要的信息前提下,region proposal 相当于是买一赠一。仅仅加了几个卷积层来构建 RPN,就能和 detection 部分共享特征信息,实现对每个位置预测 BoundingBox 和对应的 score。

RPN 要高效地完成预测一系列 scale 和 aspect ratio 的任务,它没有使用金字塔等方法,而是使用 anchor boxes 的概念,对应多个 scale 和 aspect ration,其实就是相当于金字塔,只不过避免了枚举各种 scale 和 ratio 的图像以及卷积核。好处就是我就在一个 scale 上做运算就行,所以速度比较快。

在联合 RPN 和 Fast R-CNN 的时候,先 fine-tuning RPN,然后 freeze RPN 再去 fine-tuning Fast R-CNN。

Related Work

不想写了,老家族传统了。

Faster R-CNN

两大模块:RPN + Fast R-CNN。RPN 是“眼睛”,输出 region proposal 给 Fast R-CNN 用,整体是连贯统一的网络。

在这里插入图片描述
从上图中可以大致看出,包含了 RPN 在内的网络整体,以原图 image 作为输入,经过多层卷积层后得到 feature map;此后整个网络产生了两个分支,一个分支即 RPN,输出 BoundingBox 及 score;RPN 分支的输出以及分支前共享的 feature map 一起作为 detection 部分的输入,再产生分类和 BoundingBox 回归。

所以位置框的回归一共有两次,一次在 RPN 中用 anchor 当作 reference 来回归的,一次在 detection 工作部分回归的。

Region Proposal Networks

RPN 是全卷积网络,可以接收任意大小的输入图片,输出一系列矩形框的 proposal 及 score(算是两个相关的任务,所以 RPN 输出也有两个分支)。因为是冲着和后面 Fast R-CNN 共享计算的,所以 RPN 和 Fast R-CNN 之间有共享卷积层

从共享卷积层 conv feature map 开始分支,进入 RPN。RPN 会在这个feature map 上密集地一个挨一个地做滑窗,窗口大小是 n × n(论文里用的就是 3 × 3,padding 是 1,stride 也是 1,相当于就是 “valid” 模式),会跟一个 relu,输出一个较为低维的向量(使用 ZF 的话就是 256-d,使用 VGG 的话就是 512-d;感受野分别是 171 和 228)。从这个向量开始,又产生了两个分支,一个是 box-regression layer reg 做框位置的回归,另一个是 box-classification layer cls 做框对应类别的分类。这两个分支本质都是全连接,都通过 1 × 1 卷积完成即可。

Anchors

每次单独的滑窗的目的是,根据当前滑窗位置的特征信息,“枚举”多种大小及形状的框(当然也会带着 score)。之所以叫“枚举”是因为最早基于滑窗的方法本来就是暴力枚举,但是 Faster R-CNN 在这里通过设计了 “anchor” 这一概念,完成了“非暴力”枚举。

自问自答吧。
anchor 数量是多少?具体什么 size 和 ratio?

每个滑窗位置会产生 k (论文用的 k = 9)个大小和形状不同的 proposal,k 就是 anchor 的数量。Faste R-CNN 采用了 3 个 size 和 3 个 ratio 一共 9 种。其中 size 按照面积来确定,分别是 128 × 128, 256 × 256, 512 × 512;ratio 按照 2:1,1:1, 1:2

这个数量够用吗?
9 个大小形状其实也不够多、不够细致的,这就体现了 RPN 中靠后部分两个分支,其中那个 reg 分支的作用了(而且 reg 之后仅仅是给 detection 用,detection 过程中靠后部分也还有一次 reg 过程)。所以,这里产生 9 个也还是能够适应不同的比例大小的物体,得到比较不错的效果,比如下面的图示。

在这里插入图片描述

anchor 到底担任什么角色?
总结来讲,原文对 anchor 有两种描述吧。

一种是 reference box,从这个点理解,我认为如果在 feature map 平面上给每个点都分 9 个anchor 的话,那就算对 proposal 的“初始化”了,后面各个层的处理,都相当于在这个初始化基础上做调整和优化。

还有一种就是前面 Introduction 部分说的。说 anchor 自带的 size 和 ratio 可以使得整个 scheme 类似一个回归参考的金字塔,这避免了枚举图像/特征或者卷积核。

Our scheme can be thought of as a pyramid of regression references (Figure 1, c), which avoids enumerating images or filters of multiple scales or aspect ratios. This

从最早看到 Introduction 部分这段,我就总是自以为地、提前代入地认为,总之 anchor 的机制肯定是能适应多尺度的。这一点提前的认知倒也不算错,但是当时我看到 anchor 分不同 size 和ratio 的时候,总会不自觉地认为,网络里面肯定有“映射”到原图 anchor 对应的图像部分的特征的。所以我试图在全文寻找关于这部分的介绍,怕理解错还确认了官方 faster R-CNN 的 caffe 代码,真的没有哦,就是“想多了”,实际过程就是下面 RPN 的示意图。

在这里插入图片描述
feature map 上的每个位置,直接就分出来 9 个 anchor 哦,直接通过 RPN 部分的loss “黑盒”训练的,学习到当前这个位置有多大概率包含那么一个接近某个 size 和 ratio 的 anchor 的物体,以及在对应这个 anchor 时具体的回归变换应该是多少(毕竟 anchor 仅仅是参考框嘛)。

在 feature map 上的每个位置,对每个 anchor 都会做上面这个工作,其中概率部分论文是用 softmax 做的,所以输出是 2k 分类信息 和 4k 位置回归信息


这部分是穿插进来的 RPN 部分对照模型的代码。

从模型结构上可以和论文语言描述互相证明,anchor 确实仅仅担任了多尺度 reference 的工作而已,并不是按照 anchor 取原图对应部分的特征图(是我当初想多了/(ㄒoㄒ)/~~)。

Faster R-CNN 原代码是基于 Caffe 框架的,拿到模型描述文件,通过可视化工具就可以查看模型结构(把文件内容粘贴在左栏即可)。

该文件中,共享卷积层使用的 VGG(所以 RPN 中应该是 512-d 向量),anchor 数量不是 9 而是 12,所以 RPN 后面部分中的两个分支中,分类为 2 × 12,回归为 4 × 12。前面 VGG 不再细说了,我们主要看 RPN 部分吧。

#========= RPN ============

layer {
  name: "rpn_conv/3x3"
  type: "Convolution"
  bottom: "conv5_3"
  top: "rpn/output"
  param { lr_mult: 1.0 decay_mult: 1.0 }
  param { lr_mult: 2.0 decay_mult: 0 }
  convolution_param {
    num_output: 512
    kernel_size: 3 pad: 1 stride: 1
    weight_filler { type: "gaussian" std: 0.01 }
    bias_filler { type: "constant" value: 0 }
  }
}
layer {
  name: "rpn_relu/3x3"
  type: "ReLU"
  bottom: "rpn/output"
  top: "rpn/output"
}

layer {
  name: "rpn_cls_score"
  type: "Convolution"
  bottom: "rpn/output"
  top: "rpn_cls_score"
  param { lr_mult: 1.0 decay_mult: 1.0 }
  param { lr_mult: 2.0 decay_mult: 0 }
  convolution_param {
    num_output: 24   # 2(bg/fg) * 12(anchors)
    kernel_size: 1 pad: 0 stride: 1
    weight_filler { type: "gaussian" std: 0.01 }
    bias_filler { type: "constant" value: 0 }
  }
}
layer {
  name: "rpn_bbox_pred"
  type: "Convolution"
  bottom: "rpn/output"
  top: "rpn_bbox_pred"
  param { lr_mult: 1.0 decay_mult: 1.0 }
  param { lr_mult: 2.0 decay_mult: 0 }
  convolution_param {
    num_output: 48   # 4 * 12(anchors)
    kernel_size: 1 pad: 0 stride: 1
    weight_filler { type: "gaussian" std: 0.01 }
    bias_filler { type: "constant" value: 0 }
  }
}
layer {
   bottom: "rpn_cls_score"
   top: "rpn_cls_score_reshape"
   name: "rpn_cls_score_reshape"
   type: "Reshape"
   reshape_param { shape { dim: 0 dim: 2 dim: -1 dim: 0 } }
}

对应的模型结构图如下,为了直观看到 RPN 前后的连接,所以我多截了一部分,把 VGG 卷积部分的输出和 Fast R-CNN 中的 ROI pooling 也放进去了。由于篇幅不再贴细节图了,在可视化界面可以看到,对特征图上的 14 × 14 个位置遍历,每个位置 512 向量分支预测 24 个分类和 48 个回归。

relu5_3 输出的 shape 是 [1, 512, 14, 14],rpn_conv/3×3 就是 kernel size 3,stride 1,padding 1 的卷积;
rpn_relu/3×3 输出 [1, 512, 14, 14];
rpn_cls_score 输出 [1, 24, 14, 14];
rpn_bbox_pred 输出 [1, 48, 14, 14]
在这里插入图片描述


回到论文

Translation-Invariant Anchors

这里的理解弄得我有点难受(⊙o⊙)…我搜到很多博客到这里就照着论文念一遍或者简单翻译一遍就完了,根本也没说为啥 anchor 是 translation invariant,我直觉上对这个词很关注。

首先标题 Translation-Invariant 是 平移不变性,经常与这个不变性混淆(或者放到一起讨论)的是卷积(对,单指卷积,不是指 CNN)的固有属性 Translation-Equivariant 平移同变性。不变性指的是,输入有位置变化而输出完全不受影响;同变性指的是,输入有位置变化而输出会跟随位置变化响应。这完全是 两码事,甚至都可以说是 完全相反的概念。

那这俩在图像任务中到底哪个好哪个有害啊?我自己的理解是,看任务需求,还要再看特定任务中具体的输入情况。

更希望 平移不变性的情况:
如果你要做 分类任务,目标在图像中都有较大的占比,符合人类朴素地对“特写”的要求,在这种情况下,如果目标在图中位置稍微变化,变化前后会得到完全一样的结果(特征图不变 + 分类结果不变)。如何可以实现呢,卷积层 + 池化可以约等于平移不变性(而且是 池化占了主导地位来保证平移不变性)。

但是如果同样是分类任务,目标在图像中占比很小,根本看不出主体是这个目标,这种情况下,目标在图中位置无论是稍微变化还是剧烈变化,想要得到比较满意的分类结果都是很难的。这个时候平移不变性也根本保证不了。

更希望 平移同变性的情况:
比如检测任务,目标在图像中占比会出现较大的变化,位置也会有较大的变化。如果先只谈位置变化的话,对于检测任务肯定是希望输出/响应能够跟着目标在图中的位置 变化而变化的(不然做哪门子检测啊,位置信息根本不敏感啊)。目标在左上角出现,那么特征图上就应该在左上角响应这个目标;目标出现在右上角,特征图上就应该在右上角响应这个目标(这也符合单纯卷积的特征)。

Faster R-CNN 这里在讲 proposal,所以是位置,物体检测位置信息是比较关注的,是要对位置信息敏感一些才对的。所以我认为 Faster R-CNN 这里应该是更追求 平移同变性才对,那为啥标题叫 invariant((╯﹏╰)) ?然后看这部分段落具体怎么写的吧,我觉得几个句子之间也是有点矛盾或者不够清楚。

论文先说 anchor 这个策略的一个重要性质是 translation-invariant,对 anchor 和 proposal 与 anchor 之间的映射都是这样。这句目前还看不出来 invariant 到底指 invariant 还是其实是 equivalent。

An important property of our approach is that it is translation invariant, both in terms of the anchors and the functions that compute proposals relative to the anchors.

接着开始说点具体的,说图像中的一个物体如果被移动了,那么对应的 proposal 也应该移动,相应的 proposal 和 anchor 之间的映射也应该还能 work(对啊,没毛病啊,但是这不就是 equivalent 了吗,不是 invariant 啊)。然后就说这个特性可以得到保证,援引了全卷积,说 “translation invariant up to the network’s total stride”。(我已经懵了,这个援引明显又反过来在特指 invariant 吧,不是 equivalent,因为都带上说可以 invariant 最大到整个网络的总 stride。总不能移动小于总 stride 你就能同变性,大于 stride 就不能同变性吧?)我的意思就是,好像是用 不变性的例证来为自己 同变性站台?不应该找同变性的例证吗?

If one translates an object in an image, the proposal should translate and the same function should be able to predict the proposal in either location. This translation-invariant property is guaranteed by our method 5.

As is the case of FCNs [7], our network is translation invariant up to the network’s total stride.

然后开始 cue MultiBox,先说 MultiBox 没有 translation invariant,然后就是下面这句。下面这句是说 MultiBox 不能保证 “如果目标平移了,产生一样的 proposal” 吧?也就是在和同行比较,凸显自己的优势,也就是说 Faster R-CNN 能做到这一点,也就是 Faster R-CNN 能做到“如果目标平移了,产生一样的 proposal”。等一下,大佬你前面不是说的了吗, “如果目标平移了,proposal 应该也跟着平移”?就在前面啊,原句“ If one translates an object in an image, the proposal should translate ”。所以你到底是要产生同样的 proposal 还是跟着变化的 proposal 啊?来回来去变什么呢?

So MultiBox does not guarantee that the same proposal is generated if an object is translated.

所以,我看这段有点生理不适,虽然是大佬,我心里还是有点叨逼叨吧。总的来讲,这块我不知道是我自己理解有误还是大佬讲述有问题,我感觉这部分的讲述一会儿在说不变性一会儿在说同变性,细节部分很多矛盾。总之,站在人对机器学习/深度学习的 预期角度来讲,如果根据平移量/物体尺度之间的比例来界定,比例小就叫“小位移”,比例大就叫“大位移”,那么小位移应该要满足“不变性”,大位移要满足“同变性”。

Multi-Scale Anchors as Regression References

在这里插入图片描述
这里不想说的那么细致了,总之就是 anchor 这个机制能够做不同尺度比例的物体检测。

Loss Function

要训练 RPN 就得先做好标记/label。我们要给特征图出来的 W × H × k 个 anchor 贴 label,label 当然也分两个方面:

(1)这个 anchor 是不是个 object,也就是分类标记
有点像两轮竞赛,一轮角逐 positive,一轮角逐 negative。获得第一轮 positive 标记的 anchor 不允许参见后面的竞赛。两轮竞赛都没有拿到标记的 anchor 直接当透明人了,完全不参与训练。

第一轮 positive 竞赛,当然 anchor 不需要和真实物体位置一样,满足下面两点就可以获得 positive 标记:
- 站在真实物体位置 ground truth 角度,对于每个 gt 框可能会和多个 anchor 有 IoU,最大的那个 anchor 会被分配 positive,也就是“是物体”。这里 IoU 只要满足最大就行,不一定非常接近 1,没准儿低于 50 %呢。这一小条约束,其实是给下面一小条约束的保险
- 站在每个 anchor 的角度上,只要这个 anchor 和图像中的多个 gt 框之中的任何一个之间的 IoU 大于 70% 就可以得到 positive 的标记。这里没准儿某个 anchor 和多个 gt 框的 IoU 都满足条件哦,但是也有极少情况会出现,anchor 找不到任何 gt 框满足大于 70% 的条件,所以需要上面一小条来做保险。

第二轮 negative 竞赛,那什么情况下 anchor 会获得 negative 的标记呢?就是不满足上面 positive 条件的 anchor 中(也就是没有获得 positive 的 anchor 才可以参加这里的评选哦),如果某个 anchor 和所有的 gt 框 IoU 都小于 30%,就会被分配 negative 标记。

好了,“是不是个 object” 标记工作结束了,散伙。

(2)这个 anchor 与对应的 gt 框之间的映射/变换关系是什么,也就是回归标记
某个 anchor 的 BoundingBox: x a x_a xa y a y_a ya w a w_a wa h a h_a ha
这个 anchor 对应的 gt BoundingBox: x ∗ x^* x y ∗ y^* y w ∗ w^* w h ∗ h^* h (所以这里一定会保证,是 positive 的anchor 一定会有唯一的一个 gt 和它对应吧)
根据这个 anchor 预测的 BoundingBox: x x x y y y w w w h h h
因为 Faster R-CNN anchor 的机制就是作为 reference,所以回归变换的预测和真实情况都是把 anchor 作为中间媒介来做。
从 anchor 到 gt BoundingBox 的变换: t x ∗ t^*_x tx t y ∗ t^*_y ty t w ∗ t^*_w tw t h ∗ t^*_h th
t x ∗ = ( x ∗ − x a ) / w a t y ∗ = ( y ∗ − y a ) / h a t w ∗ = l o g ( w ∗ / w a ) t h ∗ = l o g ( h ∗ / h a ) \begin {aligned} t^*_x &= (x^* - x_a) / w_a \\ t^*_y &= (y^* - y_a) / h_a \\ t^*_w &= log(w^* / w_a) \\ t^*_h &= log(h^* / h_a) \\ \end {aligned} txtytwth=(xxa)/wa=(yya)/ha=log(w/wa)=log(h/ha)
从 anchor 到预测 BoundingBox 的变换: t x t_x tx t y t_y ty t w t_w tw t h t_h th
t x = ( x − x a ) / w a t y = ( y − y a ) / h a t w = l o g ( w / w a ) t h = l o g ( h / h a ) \begin {aligned} t_x &= (x - x_a) / w_a \\ t_y &= (y - y_a) / h_a \\ t_w &= log(w / w_a) \\ t_h &= log(h / h_a) \\ \end {aligned} txtytwth=(xxa)/wa=(yya)/ha=log(w/wa)=log(h/ha)
至此,label 的两部分分类和回归都定义好了,就可以写出来 RPN 部分的 loss 了。

L ( { p i } , { t i } ) = 1 N c l s Σ L c l s ( p i , p i ∗ ) + λ 1 N r e g Σ i p i ∗ L r e g ( t i , t i ∗ ) L(\{p_i \}, \{ t_i\}) = \frac{1}{N_{cls}} \Sigma L_{cls}(p_i, p^*_i) + \lambda \frac{1}{N_{reg}} \Sigma_ip^*_iL_{reg}(t_i, t^*_i) L({pi},{ti})=Ncls1ΣLcls(pi,pi)+λNreg1ΣipiLreg(ti,ti)

其中 N c l s N_{cls} Ncls N r e g N_{reg} Nreg归一化系数,按照 batchsize 来设置的。 N c l s = 256 N_{cls} = 256 Ncls=256 N r e g ≈ 2400 N_{reg} \approx 2400 Nreg2400 λ = 10 \lambda = 10 λ=10,这样分类项和回归项基本持平。不过发现 λ \lambda λ 并没有那么敏感,可以在较大的范围内取值,并不一定必须取 10。

Training RPNs

这里的一个 mini-batch 中的图片是沿袭了 Fast R-CNN 的,也就是从一张图片上找多个来组成一个 batch。

这里没有用所有的 anchor 来参与训练,因为负样本远远比正样本要多。一张图片,选 256 个,128 个正,128 个负;正的不够的时候,才用负的凑出来 256。就是尽量保证正负样本接近 1:1。

前面卷积层是共享的,训练 RPN 的时候仅对新层从头进行初始化。至此,单独 RPN 的理论和训练已经告一段落了。

Sharing Features for RPN and Fast R-CNN

此前,已经讨论了抛开 detection 部分的 RPN 部分。现在要把 RPN 和 Fast R-CNN 合在一起了,共用前面的卷积层。 一共有三种方式来训练这个联合的网络:
(1)首先训练 RPN,然后用 RPN 的结果微调 Fast R-CNN,微调后的 Fast R-CNN 再反过来用来初始化 RPN。这个过程迭代地进行,论文里面的实验都是这样做的。
(2)近似联合训练,可以降低 25 ~50% 运行时间。之所以是近似,是因为 RPN 的 region proposal 被当做是预计算好的固定的(也就是不更新 RPN 独有层的参数?)来训练 Fast R-CNN。这种方案是忽略了 proposal 的坐标梯度的。实验发现这种方案可以输出较为接近的结果。这个方式有代码。
(3)完全联合训练,这里就是把上面缺的补上了。但是并不属于这篇论文的范畴。

4-Step Alternating Training
  • 先训 RPN;
  • 用 RPN 的 proposal 训 Fast R-CNN;至此,两个的卷积层不共享。
  • 用 Fast R-CNN 初始化 RPN,单独训 RPN 的独有层;已经共享卷积层了。
  • 单独训 Fast R-CNN 的独有层。

Implementation Details

图像短边 600。

ZF 和 VGG 的总 stride 都是 16,在 PASCAL 数据集上,一般会得到边长为 10 pixel 的 feature map,即使如此,效果也还不错。如果 stride 更小一点,预期会得到更好的效果。

anchor 的尺寸和比例并没有经过非常精细的挑选。但尽管如此,论文发现也不需要图像金字塔或者特征金字塔。

训练的时候,anchor 和图像边界交叠的,都被删去了。对于 1000 × 600 的输入图像,会得到大概 60 × 40 × 9 大约 20000 个anchor。按照刚刚说的条件删掉之后,会得到大概 6000 个 anchor。

预测的时候,如果出现了和图像边缘交叠的,都被强行调整了。

刚刚提到的 6000 个 anchor 之间,也会有很多交叠,按照分数排序进行 0.7 的 NMS 继续删除 anchor,就剩下 2000 个左右。训练就可以用这 2000 个,问题不大。预测的时候,甚至可以在这 2000 个上直接取 top-N 个进行检测,也问题不大。

Conclusion

总之就是,anchor 真牛 + 联合了 = 真好 + 问题不大。
完。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值