webooru
webooru copied to clipboard
一文读懂Faster RCNN - 知乎
经过 R-CNN 和 Fast RCNN 的积淀,Ross B. Girshick 在 2016 年提出了新的 Faster RCNN,在结构上,Faster RCNN 已经将特征抽取 (feature extraction),proposal 提取,bounding box regression(rect refine),classification 都整合在了一个网络中,使得综合性能有较大提高,在检测速度方面尤为明显。
目录
1 Conv layers
2 Region Proposal Networks(RPN)
- 2.1 多通道图像卷积基础知识介绍
- 2.2 anchors
- 2.3 softmax 判定 positive 与 negative
- 2.4 bounding box regression 原理
- 2.5 对 proposals 进行 bounding box regression
- 2.6 Proposal Layer
3 RoI pooling- 3.1 为何需要 RoI Pooling
- 3.2 RoI Pooling 原理
4 Classification
5 Faster RCNN 训练- 5.1 训练 RPN 网络
- 5.2 通过训练好的 RPN 网络收集 proposals
- 5.3 训练 Faster RCNN 网络
Questions and Answer
图 1 Faster RCNN 基本结构(来自原论文)
依作者看来,如图 1,Faster RCNN 其实可以分为 4 个主要内容:
- Conv layers。作为一种 CNN 网络目标检测方法,Faster RCNN 首先使用一组基础的 conv+relu+pooling 层提取 image 的 feature maps。该 feature maps 被共享用于后续 RPN 层和全连接层。
- Region Proposal Networks。RPN 网络用于生成 region proposals。该层通过 softmax 判断 anchors 属于 positive 或者 negative,再利用 bounding box regression 修正 anchors 获得精确的 proposals。
- Roi Pooling。该层收集输入的 feature maps 和 proposals,综合这些信息后提取 proposal feature maps,送入后续全连接层判定目标类别。
- Classification。利用 proposal feature maps 计算 proposal 的类别,同时再次 bounding box regression 获得检测框最终的精确位置。
所以本文以上述 4 个内容作为切入点介绍 Faster R-CNN 网络。
图 2 展示了 python 版本中的 VGG16 模型中的 faster_rcnn_test.pt 的网络结构,可以清晰的看到该网络对于一副任意大小 PxQ 的图像,首先缩放至固定大小 MxN,然后将 MxN 图像送入网络;而 Conv layers 中包含了 13 个 conv 层 + 13 个 relu 层 + 4 个 pooling 层;RPN 网络首先经过 3x3 卷积,再分别生成 positive anchors 和对应 bounding box regression 偏移量,然后计算出 proposals;而 Roi Pooling 层则利用 proposals 从 feature maps 中提取 proposal feature 送入后续全连接和 softmax 网络作 classification(即分类 proposal 到底是什么 object)。
图 2 faster_rcnn_test.pt 网络结构 (pascal_voc/VGG16/faster_rcnn_alt_opt/faster_rcnn_test.pt)
本文不会讨论任何关于 R-CNN 家族的历史,分析清楚最新的 Faster R-CNN 就够了,并不需要追溯到那么久。实话说我也不了解 R-CNN,更不关心。有空不如看看新算法。
1 Conv layers
Conv layers 包含了 conv,pooling,relu 三种层。以 python 版本中的 VGG16 模型中的 faster_rcnn_test.pt 的网络结构为例,如图 2,Conv layers 部分共有 13 个 conv 层,13 个 relu 层,4 个 pooling 层。这里有一个非常容易被忽略但是又无比重要的信息,在 Conv layers 中:
- 所有的 conv 层都是:kernel_size=3,pad=1,stride=1
- 所有的 pooling 层都是:kernel_size=2,pad=1,stride=1
,
,
为何重要?在 Faster RCNN Conv layers 中对所有的卷积都做了扩边处理( pad=1,即填充一圈 0),导致原图变为 (M+2)x(N+2) 大小,再做 3x3 卷积后输出 MxN 。正是这种设置,导致 Conv layers 中的 conv 层不改变输入和输出矩阵大小。如图 3:
图 3 卷积示意图
类似的是,Conv layers 中的 pooling 层 kernel_size=2,stride=2。这样每个经过 pooling 层的 MxN 矩阵,都会变为 (M/2)x(N/2) 大小。综上所述,在整个 Conv layers 中,conv 和 relu 层不改变输入输出大小,只有 pooling 层使输出长宽都变为输入的 1/2。
那么,一个 MxN 大小的矩阵经过 Conv layers 固定变为 (M/16)x(N/16)!这样 Conv layers 生成的 feature map 中都可以和原图对应起来。
2 Region Proposal Networks(RPN)
经典的检测方法生成检测框都非常耗时,如 OpenCV adaboost 使用滑动窗口 + 图像金字塔生成检测框;或如 R-CNN 使用 SS(Selective Search) 方法生成检测框。而 Faster RCNN 则抛弃了传统的滑动窗口和 SS 方法,直接使用 RPN 生成检测框,这也是 Faster R-CNN 的巨大优势,能极大提升检测框的生成速度。
图 4 RPN 网络结构
上图 4 展示了 RPN 网络的具体结构。可以看到 RPN 网络实际分为 2 条线,上面一条通过 softmax 分类 anchors 获得 positive 和 negative 分类,下面一条用于计算对于 anchors 的 bounding box regression 偏移量,以获得精确的 proposal。而最后的 Proposal 层则负责综合 positive anchors 和对应 bounding box regression 偏移量获取 proposals,同时剔除太小和超出边界的 proposals。其实整个网络到了 Proposal Layer 这里,就完成了相当于目标定位的功能。
2.1 多通道图像卷积基础知识介绍
在介绍 RPN 前,还要多解释几句基础知识,已经懂的看官老爷跳过就好。
- 对于单通道图像 + 单卷积核做卷积,第一章中的图 3 已经展示了;
- 对于多通道图像 + 多卷积核做卷积,计算方式如下:
图 5 多通道卷积计算方式
如图 5,输入有 3 个通道,同时有 2 个卷积核。对于每个卷积核,先在输入 3 个通道分别作卷积,再将 3 个通道结果加起来得到卷积输出。所以对于某个卷积层,无论输入图像有多少个通道,输出图像通道数总是等于卷积核数量!
对多通道图像做 1x1 卷积,其实就是将输入图像于每个通道乘以卷积系数后加在一起,即相当于把原图像中本来各个独立的通道 “联通” 在了一起。
2.2 anchors
提到 RPN 网络,就不能不说 anchors。所谓 anchors,实际上就是一组由 rpn/generate_anchors.py 生成的矩形。直接运行作者 demo 中的 generate_anchors.py 可以得到以下输出:
[[ -84. -40. 99. 55.]
[-176. -88. 191. 103.]
[-360. -184. 375. 199.]
[ -56. -56. 71. 71.]
[-120. -120. 135. 135.]
[-248. -248. 263. 263.]
[ -36. -80. 51. 95.]
[ -80. -168. 95. 183.]
[-168. -344. 183. 359.]]
其中每行的 4 个值
表矩形左上和右下角点坐标。9 个矩形共有 3 种形状,长宽比为大约为
三种,如图 6。实际上通过 anchors 就引入了检测中常用到的多尺度方法。
图 6 anchors 示意图
注:关于上面的 anchors size,其实是根据检测图像设置的。在 python demo 中,会把任意大小的输入图像 reshape 成 800x600(即图 2 中的 M=800,N=600)。再回头来看 anchors 的大小,anchors 中长宽 1:2 中最大为 352x704,长宽 2:1 中最大 736x384,基本是 cover 了 800x600 的各个尺度和形状。
那么这 9 个 anchors 是做什么的呢?借用 Faster RCNN 论文中的原图,如图 7,遍历 Conv layers 计算获得的 feature maps,为每一个点都配备这 9 种 anchors 作为初始的检测框。这样做获得检测框很不准确,不用担心,后面还有 2 次 bounding box regression 可以修正检测框位置。
图 7
解释一下上面这张图的数字。
- 在原文中使用的是 ZF model 中,其 Conv Layers 中最后的 conv5 层 num_output=256,对应生成 256 张特征图,所以相当于 feature map 每个点都是 256-dimensions
- 在 conv5 之后,做了 rpn_conv/3x3 卷积且 num_output=256,相当于每个点又融合了周围 3x3 的空间信息(猜测这样做也许更鲁棒?反正我没测试),同时 256-d 不变(如图 4 和图 7 中的红框)
- 假设在 conv5 feature map 中每个点上有 k 个 anchor(默认 k=9),而每个 anhcor 要分 positive 和 negative,所以每个点由 256d feature 转化为 cls=2k scores;而每个 anchor 都有 (x, y, w, h) 对应 4 个偏移量,所以 reg=4k coordinates
- 补充一点,全部 anchors 拿去训练太多了,训练程序会在合适的 anchors 中随机选取 128 个 postive anchors+128 个 negative anchors 进行训练(什么是合适的 anchors 下文 5.1 有解释)
注意,在本文讲解中使用的 VGG conv5 num_output=512,所以是 512d,其他类似。
其实 RPN 最终就是在原图尺度上,设置了密密麻麻的候选 Anchor。然后用 cnn 去判断哪些 Anchor 是里面有目标的 positive anchor,哪些是没目标的 negative anchor。所以,仅仅是个二分类而已!
那么 Anchor 一共有多少个?原图 800x600,VGG 下采样 16 倍,feature map 每个点设置 9 个 Anchor,所以:
其中 ceil() 表示向上取整,是因为 VGG 输出的 feature map size= 50*38。
图 8 Gernerate Anchors
2.3 softmax 判定 positive 与 negative
一副 MxN 大小的矩阵送入 Faster RCNN 网络后,到 RPN 网络变为 (M/16)x(N/16),不妨设 W=M/16,H=N/16。在进入 reshape 与 softmax 之前,先做了 1x1 卷积,如图 9:
图 9 RPN 中判定 positive/negative 网络结构
该 1x1 卷积的 caffe prototxt 定义如下:
layer {
name: "rpn_cls_score"
type: "Convolution"
bottom: "rpn/output"
top: "rpn_cls_score"
convolution_param {
num_output: 18 # 2(positive/negative) * 9(anchors)
kernel_size: 1 pad: 0 stride: 1
}
}
可以看到其 num_output=18,也就是经过该卷积的输出图像为 WxHx18 大小(注意第二章开头提到的卷积计算方式)。这也就刚好对应了 feature maps 每一个点都有 9 个 anchors,同时每个 anchors 又有可能是 positive 和 negative,所有这些信息都保存 WxHx(9*2) 大小的矩阵。为何这样做?后面接 softmax 分类获得 positive anchors,也就相当于初步提取了检测目标候选区域 box(一般认为目标在 positive anchors 中)。
那么为何要在 softmax 前后都接一个 reshape layer?其实只是为了便于 softmax 分类,至于具体原因这就要从 caffe 的实现形式说起了。在 caffe 基本数据结构 blob 中以如下形式保存数据:
blob=[batch_size, channel,height,width]
对应至上面的保存 positive/negative anchors 的矩阵,其在 caffe blob 中的存储形式为[1, 2x9, H, W]。而在 softmax 分类时需要进行 positive/negative 二分类,所以 reshape layer 会将其变为[1, 2, 9xH, W] 大小,即单独 “腾空” 出来一个维度以便 softmax 分类,之后再 reshape 回复原状。贴一段 caffe softmax_loss_layer.cpp 的 reshape 函数的解释,非常精辟:
"Number of labels must match number of predictions; "
"e.g., if softmax axis == 1 and prediction shape is (N, C, H, W), "
"label count (number of labels) must be N*H*W, "
"with integer values in {0, 1, ..., C-1}.";
综上所述,RPN 网络中利用 anchors 和 softmax 初步提取出 positive anchors 作为候选区域(另外也有实现用 sigmoid 代替 softmax,原理类似)。
2.4 bounding box regression 原理
如图 9 所示绿色框为飞机的 Ground Truth(GT),红色为提取的 positive anchors,即便红色的框被分类器识别为飞机,但是由于红色的框定位不准,这张图相当于没有正确的检测出飞机。所以我们希望采用一种方法对红色的框进行微调,使得 positive anchors 和 GT 更加接近。
图 10
对于窗口一般使用四维向量
表示,分别表示窗口的中心点坐标和宽高。对于图 11,红色的框 A 代表原始的 positive Anchors,绿色的框 G 代表目标的 GT,我们的目标是寻找一种关系,使得输入原始的 anchor A 经过映射得到一个跟真实窗口 G 更接近的回归窗口 G',即:
图 11
那么经过何种变换F才能从图 10 中的 anchor A 变为 G'呢? 比较简单的思路就是:
- 先做平移
- 再做缩放
观察上面 4 个公式发现,需要学习的是
这四个变换。当输入的 anchor A 与 GT 相差较小时,可以认为这种变换是一种线性变换, 那么就可以用线性回归来建模对窗口进行微调(注意,只有当 anchors A 和 GT 比较接近时,才能使用线性回归模型,否则就是复杂的非线性问题了)。
接下来的问题就是如何通过线性回归获得
了。线性回归就是给定输入的特征向量 X, 学习一组参数 W, 使得经过线性回归后的值跟真实值 Y 非常接近,即
。对于该问题,输入 X 是 cnn feature map,定义为Φ;同时还有训练传入 A 与 GT 之间的变换量,即
。输出是
四个变换。那么目标函数可以表示为:
其中
是对应 anchor 的 feature map 组成的特征向量,
是需要学习的参数,
是得到的预测值(* 表示 x,y,w,h,也就是每一个变换对应一个上述目标函数)。为了让预测值
与真实值
差距最小,设计 L1 损失函数:
函数优化目标为:
为了方便描述,这里以 L1 损失为例介绍,而真实情况中一般使用 soomth-L1 损失。
需要说明,只有在 GT 与需要回归框位置比较接近时,才可近似认为上述线性变换成立。
说完原理,对应于 Faster RCNN 原文,positive anchor 与 ground truth 之间的平移量
与尺度因子
如下:
对于训练 bouding box regression 网络回归分支,输入是 cnn feature Φ,监督信号是 Anchor 与 GT 的差距
,即训练目标是:输入 Φ的情况下使网络输出与监督信号尽可能接近。那么当 bouding box regression 工作时,再输入Φ时,回归网络分支的输出就是每个 Anchor 的平移量和变换尺度
,显然即可用来修正 Anchor 位置了。
2.5 对 proposals 进行 bounding box regression
在了解 bounding box regression 后,再回头来看 RPN 网络第二条线路,如图 12。
图 12 RPN 中的 bbox reg
先来看一看上图 11 中 1x1 卷积的 caffe prototxt 定义:
layer {
name: "rpn_bbox_pred"
type: "Convolution"
bottom: "rpn/output"
top: "rpn_bbox_pred"
convolution_param {
num_output: 36 # 4 * 9(anchors)
kernel_size: 1 pad: 0 stride: 1
}
}
可以看到其 num_output=36,即经过该卷积输出图像为 WxHx36,在 caffe blob 存储为[1, 4x9, H, W],这里相当于 feature maps 每个点都有 9 个 anchors,每个 anchors 又都有 4 个用于回归的
变换量。
回到图 8,VGG 输出
的特征,对应设置
个 anchors,而 RPN 输出:
- 大小为
的 positive/negative softmax 分类特征矩阵
- 大小为
的 regression 坐标回归特征矩阵
恰好满足 RPN 完成 positive/negative 分类 + bounding box regression 坐标回归.
2.6 Proposal Layer
Proposal Layer 负责综合所有
变换量和 positive anchors,计算出精准的 proposal,送入后续 RoI Pooling Layer。还是先来看看 Proposal Layer 的 caffe prototxt 定义:
layer {
name: 'proposal'
type: 'Python'
bottom: 'rpn_cls_prob_reshape'
bottom: 'rpn_bbox_pred'
bottom: 'im_info'
top: 'rois'
python_param {
module: 'rpn.proposal_layer'
layer: 'ProposalLayer'
param_str: "'feat_stride': 16"
}
}
Proposal Layer 有 3 个输入:positive vs negative anchors 分类器结果 rpn_cls_prob_reshape,对应的 bbox reg 的 
变换量 rpn_bbox_pred,以及 im_info;另外还有参数 feat_stride=16,这和图 4 是对应的。
首先解释 im_info。对于一副任意大小 PxQ 图像,传入 Faster RCNN 前首先 reshape 到固定 MxN,im_info=[M, N, scale_factor] 则保存了此次缩放的所有信息。然后经过 Conv Layers,经过 4 次 pooling 变为 WxH=(M/16)x(N/16) 大小,其中 feature_stride=16 则保存了该信息,用于计算 anchor 偏移量。
图 13
Proposal Layer forward(caffe layer 的前传函数)按照以下顺序依次处理:
- 生成 anchors,利用
对所有的 anchors 做 bbox regression 回归(这里的 anchors 生成和训练时完全一致)
- 按照输入的 positive softmax scores 由大到小排序 anchors,提取前 pre_nms_topN(e.g. 6000) 个 anchors,即提取修正位置后的 positive anchors
- 限定超出图像边界的 positive anchors 为图像边界,防止后续 roi pooling 时 proposal 超出图像边界(见文章底部 QA 部分图 21)
- 剔除尺寸非常小的 positive anchors
- 对剩余的 positive anchors 进行 NMS(nonmaximum suppression)
- Proposal Layer 有 3 个输入:positive 和 negative anchors 分类器结果 rpn_cls_prob_reshape,对应的 bbox reg 的 (e.g. 300) 结果作为 proposal 输出
之后输出 proposal=[x1, y1, x2, y2],注意,由于在第三步中将 anchors 映射回原图判断是否超出边界,所以这里输出的 proposal 是对应 MxN 输入图像尺度的,这点在后续网络中有用。另外我认为,严格意义上的检测应该到此就结束了,后续部分应该属于识别了。
RPN 网络结构就介绍到这里,总结起来就是:
生成 anchors -> softmax 分类器提取 positvie anchors -> bbox reg 回归 positive anchors -> Proposal Layer 生成 proposals
3 RoI pooling
而 RoI Pooling 层则负责收集 proposal,并计算出 proposal feature maps,送入后续网络。从图 2 中可以看到 Rol pooling 层有 2 个输入:
- 原始的 feature maps
- RPN 输出的 proposal boxes(大小各不相同)
3.1 为何需要 RoI Pooling
先来看一个问题:对于传统的 CNN(如 AlexNet 和 VGG),当网络训练好后输入的图像尺寸必须是固定值,同时网络输出也是固定大小的 vector or matrix。如果输入图像大小不定,这个问题就变得比较麻烦。有 2 种解决办法:
- 从图像中 crop 一部分传入网络
- 将图像 warp 成需要的大小后传入网络
图 14 crop 与 warp 破坏图像原有结构信息
两种办法的示意图如图 14,可以看到无论采取那种办法都不好,要么 crop 后破坏了图像的完整结构,要么 warp 破坏了图像原始形状信息。
回忆 RPN 网络生成的 proposals 的方法:对 positive anchors 进行 bounding box regression,那么这样获得的 proposals 也是大小形状各不相同,即也存在上述问题。所以 Faster R-CNN 中提出了 RoI Pooling 解决这个问题。不过 RoI Pooling 确实是从Spatial Pyramid Pooling发展而来,但是限于篇幅这里略去不讲,有兴趣的读者可以自行查阅相关论文。
3.2 RoI Pooling 原理
分析之前先来看看 RoI Pooling Layer 的 caffe prototxt 的定义:
layer {
name: "roi_pool5"
type: "ROIPooling"
bottom: "conv5_3"
bottom: "rois"
top: "pool5"
roi_pooling_param {
pooled_w: 7
pooled_h: 7
spatial_scale: 0.0625 # 1/16
}
}
其中有新参数 pooled_w 和 pooled_h,另外一个参数 spatial_scale 认真阅读的读者肯定已经知道知道用途。RoI Pooling layer forward 过程:
- 由于 proposal 是对应 MXN 尺度的,所以首先使用 spatial_scale 参数将其映射回 (M/16)X(N/16) 大小的 feature map 尺度;
- 再将每个 proposal 对应的 feature map 区域水平分为
的网格;
- 对网格的每一份都进行 max pooling 处理。
这样处理后,即使大小不同的 proposal 输出结果都是
固定大小,实现了固定长度输出。
图 15 proposal 示意图
4 Classification
Classification 部分利用已经获得的 proposal feature maps,通过 full connect 层与 softmax 计算每个 proposal 具体属于那个类别(如人,车,电视等),输出 cls_prob 概率向量;同时再次利用 bounding box regression 获得每个 proposal 的位置偏移量 bbox_pred,用于回归更加精确的目标检测框。Classification 部分网络结构如图 16。
图 16 Classification 部分网络结构图
从 RoI Pooling 获取到 7x7=49 大小的 proposal feature maps 后,送入后续网络,可以看到做了如下 2 件事:
- 通过全连接和 softmax 对 proposals 进行分类,这实际上已经是识别的范畴了
- 再次对 proposals 进行 bounding box regression,获取更高精度的 rect box
这里来看看全连接层 InnerProduct layers,简单的示意图如图 17,
图 17 全连接层示意图
其计算公式如下:
其中 W 和 bias B 都是预先训练好的,即大小是固定的,当然输入 X 和输出 Y 也就是固定大小。所以,这也就印证了之前 Roi Pooling 的必要性。到这里,我想其他内容已经很容易理解,不在赘述了。
5 Faster RCNN 训练
Faster R-CNN 的训练,是在已经训练好的 model(如 VGG_CNN_M_1024,VGG,ZF)的基础上继续进行训练。实际中训练过程分为 6 个步骤:
- 在已经训练好的 model 上,训练 RPN 网络,对应 stage1_rpn_train.pt
- 利用步骤 1 中训练好的 RPN 网络,收集 proposals,对应 rpn_test.pt
- 第一次训练 Fast RCNN 网络,对应 stage1_fast_rcnn_train.pt
- 第二训练 RPN 网络,对应 stage2_rpn_train.pt
- 再次利用步骤 4 中训练好的 RPN 网络,收集 proposals,对应 rpn_test.pt
- 第二次训练 Fast RCNN 网络,对应 stage2_fast_rcnn_train.pt
可以看到训练过程类似于一种 “迭代” 的过程,不过只循环了 2 次。至于只循环了 2 次的原因是应为作者提到:"A similar alternating training can be run for more iterations, but we have observed negligible improvements",即循环更多次没有提升了。接下来本章以上述 6 个步骤讲解训练过程。
下面是一张训练过程流程图,应该更加清晰(图来源)。
图 18 Faster RCNN 训练步骤
5.1 训练 RPN 网络
在该步骤中,首先读取 RBG 提供的预训练好的 model(本文使用 VGG),开始迭代训练。来看看 stage1_rpn_train.pt 网络结构,如图 19。
图 19 stage1_rpn_train.pt(考虑图片大小,Conv Layers 中所有的层都画在一起了,如红圈所示,后续图都如此处理)
与检测网络类似的是,依然使用 Conv Layers 提取 feature maps。整个网络使用的 Loss 如下:
上述公式中
表示 anchors index,
表示 positive softmax probability,
代表对应的 GT predict 概率(即当第 i 个 anchor 与 GT 间 IoU>0.7,认为是该 anchor 是 positive,
;反之 IoU<0.3 时,认为是该 anchor 是 negative,
;至于那些 0.3<IoU<0.7 的 anchor 则不参与训练);
代表 predict bounding box,
代表对应 positive anchor 对应的 GT box。可以看到,整个 Loss 分为 2 部分:
- cls loss,即 rpn_cls_loss 层计算的 softmax loss,用于分类 anchors 为 positive 与 negative 的网络训练
- reg loss,即 rpn_loss_bbox 层计算的 soomth L1 loss,用于 bounding box regression 网络训练。注意在该 loss 中乘了  ,相当于只关心 positive anchors 的回归(其实在回归中也完全没必要去关心 negative)。
由于在实际过程中,
和
差距过大,用参数λ平衡二者(如
,
时设置
),使总的网络 Loss 计算过程中能够均匀考虑 2 种 Loss。这里比较重要是
使用的 soomth L1 loss,计算公式如下:
了解数学原理后,反过来看图 18:
- 在 RPN 训练阶段,rpn-data(python AnchorTargetLayer)层会按照和 test 阶段 Proposal 层完全一样的方式生成 Anchors 用于训练
- 对于 rpn_loss_cls,输入的 rpn_cls_scors_reshape 和 rpn_labels 分别对应
与
,  参数隐含在
与
的 caffe blob 的大小中
- 对于 rpn_loss_bbox,输入的 rpn_bbox_pred 和 rpn_bbox_targets 分别对应
与
,rpn_bbox_inside_weigths 对应
,rpn_bbox_outside_weigths 未用到(从 soomth_L1_Loss layer 代码中可以看到),而  同样隐含在 caffe blob 大小中
这样,公式与代码就完全对应了。特别需要注意的是,在训练和检测阶段生成和存储 anchors 的顺序完全一样,这样训练结果才能被用于检测!
5.2 通过训练好的 RPN 网络收集 proposals
在该步骤中,利用之前的 RPN 网络,获取 proposal rois,同时获取 positive softmax probability,如图 20,然后将获取的信息保存在 python pickle 文件中。该网络本质上和检测中的 RPN 网络一样,没有什么区别。
图 20 rpn_test.pt
5.3 训练 Faster RCNN 网络
读取之前保存的 pickle 文件,获取 proposals 与 positive probability。从 data 层输入网络。然后:
- 将提取的 proposals 作为 rois 传入网络,如图 21 蓝框
- 计算 bbox_inside_weights+bbox_outside_weights,作用与 RPN 一样,传入 soomth_L1_loss layer,如图 21 绿框
这样就可以训练最后的识别 softmax 与最终的 bounding box regression 了。
图 21 stage1_fast_rcnn_train.pt
之后的 stage2 训练都是大同小异,不再赘述了。Faster R-CNN 还有一种 end-to-end 的训练方式,可以一次完成 train,有兴趣请自己看作者 GitHub 吧。
rbgirshick py-faster-rcnngithub.com
QA
此篇文章初次成文于 2016 年内部学习分享,再后来经多次修正和完善成为现在的样子。感谢大家一直以来的支持,现在总结常见疑问回答如下:
- 为什么 Anchor 坐标中有负数
回顾 anchor 生成步骤:首先生成 9 个 base anchor,然后通过坐标偏移在
大小的
下采样 FeatureMap 每个点都放上这 9 个 base anchor,就形成了
个 anhcors。至于这 9 个 base anchor 坐标是什么其实并不重要,不同代码实现也许不同。
显然这里面有一部分边缘 anchors 会超出图像边界,而真实中不会有超出图像的目标,所以会有 clip anchor 步骤。
图 21 clip anchor
- Anchor 到底与网络输出如何对应
VGG 输出
的特征,对应设置
个 anchors,而 RPN 输出
的分类特征矩阵和
的坐标回归特征矩阵。
图 22 anchor 与网络输出如何对应方式
其实在实现过程中,每个点的
个分类特征与
回归特征,与
个 anchor 逐个对应即可,这实际是一种 “人为设置的逻辑映射”。当然,也可以不这样设置,但是无论如何都需要保证在训练和测试过程中映射方式必须一致。
- 为何有 ROI Pooling 还要把输入图片 resize 到固定大小的 MxN
由于引入 ROI Pooling,从原理上说 Faster R-CNN 确实能够检测任意大小的图片。但是由于在训练的时候需要使用大 batch 训练网络,而不同大小输入拼 batch 在实现的时候代码较为复杂,而且当时以 Caffe 为代表的第一代深度学习框架也不如 Tensorflow 和 PyTorch 灵活,所以作者选择了把输入图片 resize 到固定大小的 800x600。这应该算是历史遗留问题。
另外很多问题,都是属于具体实现问题,真诚的建议读者阅读代码自行理解。
参考文献
Object Detection and Classification using R-CNNswww.telesens.co
拓展
检测算法的评价指标:
请问目标检测中的 detection performance 一般是指那个指标,还是一个统称?www.zhihu.com
Faster RCNN 在文字检测中的应用:CTPN
场景文字检测—CTPN 原理与实现zhuanlan.zhihu.com
Faster RCNN 在高德导航中的应用: