转自:FPN: 一种高效的CNN特征提取方法https://www.jianshu.com/p/5a28ae9b365d
FPN是一种利用常规CNN模型来高效提取图片中各维度特征的方法。在计算机视觉学科中,多维度的目标检测一直以来都是通过将缩小或扩大后的不同维度图片作为输入来生成出反映不同维度信息的特征组合。这种办法确实也能有效地表达出图片之上的各种维度特征,但却对硬件计算能力及内存大小有较高要求,因此只能在有限的领域内部使用。
FPN通过利用常规CNN模型内部从底至上各个层对同一scale图片不同维度的特征表达结构,提出了一种可有效在单一图片视图下生成对其的多维度特征表达的方法。它可以有效地赋能常规CNN模型,从而可以生成出表达能力更强的feature maps以供下一阶段计算机视觉任务像object detection/semantic segmentation等来使用。本质上说它是一种加强主干网络CNN特征表达的方法。
下图中描述了四种不同的得到一张图片多维度特征组合的方法。
四种不同的生成多维度特征组合的方法
上图(a)中的方法即为常规的生成一张图片的多维度特征组合的经典方法。即对某一输入图片我们通过压缩或放大从而形成不同维度的图片作为模型输入,使用同一模型对这些不同维度的图片分别处理后,最终再将这些分别得到的特征(feature maps)组合起来就得到了我们想要的可反映多维度信息的特征集。此种方法缺点在于需要对同一图片在更改维度后输入处理多次,因此对计算机的算力及内存大小都有较高要求。
图(b)中的方法则只拿单一维度的图片做为输入,然后经CNN模型处理后,拿最终一层的feature maps作为最终的特征集。显然此种方法只能得到单一维度的信息。优点是计算简单,对计算机算力及内存大小都无过高需求。此方法为大多数R-CNN系列目标检测方法所用像R-CNN/Fast-RCNN/Faster-RCNN等。因此最终这些模型对小维度的目标检测性能不是很好。
图(c)中的方法同样是拿单一维度的图片做为输入,不过最终选取用于接下来分类或检测任务时的特征组合时,此方法不只选用了最后一层的high level feature maps,同样也会选用稍靠下的反映图片low level 信息的feature maps。然后将这些不同层次(反映不同level的图片信息)的特征简单合并起来(一般为concat处理),用于最终的特征组合输出。此方法可见于SSD当中。不过SSD在选取层特征时都选用了较高层次的网络。比如在它以VGG16作为主干网络的检测模型里面所选用的最低的Convolution的层为Conv4,这样一些具有更低级别信息的层特征像Conv2/Conv3就被它给漏掉了,于是它对更小维度的目标检测效果就不大好。
图(d)中的方法同图(c)中的方法有些类似,也是拿单一维度的图片作为输入,然后它会选取所有层的特征来处理然后再联合起来做为最终的特征输出组合。(作者在论文中拿Resnet为实例时并没选用Conv1层,那是为了算力及内存上的考虑,毕竟Conv1层的size还是比较大的,所包含的特征跟直接的图片像素信息也过于接近)。另外还对这些反映不同级别图片信息的各层自上向下进行了再处理以能更好地组合从而形成较好的特征表达(详细过程会在下面章节中进一步介绍)。而此方法正是我们本文中要讲的FPN CNN特征提取方法。
FPN会使用CNN网络中每一层的信息来生成最后的表达特征组合。下图是它的基本架构。从中我们能看到FPN会模型每个CNN层的特征输出进行处理以生成反映此维度信息的特征。而自上至下处理后所生成出的特征之间也有个关联关系,即上层high level的特征会影响下一层次的low level特征表达。最终所有的特征一起用来作为下一步的目标检测或类别分析等任务的输入。
FPN基本架构
FPN是传统CNN网络对图片信息进行表达输出的一种增强。它目的是为了改进CNN网络的特征提取方式,从而可以使最终输出的特征更好地表示出输入图片各个维度的信息。它的基本过程有三个分别为:自下至上的通路即自下至上的不同维度特征生成;自上至下的通路即自上至下的特征补充增强;CNN网络层特征与最终输出的各维度特征之间的关联表达。
我们在下图中能看出这三个过程的细粒度表示。
FPN的特征组合详细描述
以下为一个FPN特征提取方法在RCNN目标检测框架中应用的例子。从中我们可以更加详细地了解到它的具体实现。
FPN在RCNN目标检测框架中的应用.JPG
以下为p4与p3层之间Up-bottom pathway及各自层上的lateral connections处理。其它层次之间的关系与此类似。
layer {
bottom: "p4"
top: "p4_lateral"
name: "p4_lateral"
param {
lr_mult: 1.0
}
param {
lr_mult: 2.0
}
type: "Convolution"
convolution_param {
num_output: 256
kernel_size: 1
weight_filler { type: "gaussian" std: 0.001 }
bias_filler { type: "constant" value: 0.0 }
}
}
layer {
name: "upP4"
type: "Deconvolution"
bottom: "p4_lateral"
top: "upP4"
convolution_param {
kernel_h : 4
kernel_w : 4
stride_h: 2
stride_w: 2
pad_h: 1
pad_w: 1
num_output: 256
group: 256
bias_term: false
weight_filler {
type: "bilinear"
}
}
param { lr_mult: 0 decay_mult: 0 }
}
layer {
bottom: "res3d"
top: "c3"
name: "newC3"
param {
lr_mult: 1.0
}
param {
lr_mult: 2.0
}
type: "Convolution"
convolution_param {
num_output: 256
kernel_size: 1
weight_filler { type: "gaussian" std: 0.001 }
bias_filler { type: "constant" value: 0.0 }
}
}
layer {
name: "p3"
type: "Eltwise"
bottom: "c3"
bottom: "upP4"
top: "p3"
eltwise_param {
operation: SUM
}
}
layer {
bottom: "p3"
top: "p3_lateral"
name: "p3_lateral"
param {
lr_mult: 1.0
}
param {
lr_mult: 2.0
}
type: "Convolution"
convolution_param {
num_output: 256
kernel_size: 1
weight_filler { type: "gaussian" std: 0.001 }
bias_filler { type: "constant" value: 0.0 }
}
}
以下几层则为由p3的feature maps所生成的RPN网络。在test网络上,它就会生成出一些region proposals来。
#========= RPN/p3 ============
layer {
name: "rpn_conv/3x3/p3"
type: "Convolution"
bottom: "p3"
top: "rpn/output/p3"
param { lr_mult: 1.0
name: "rpn_conv_3x3_w"
}
param { lr_mult: 2.0
name: "rpn_conv_3x3_b"
}
convolution_param {
num_output: 512
kernel_size: 3 pad: 1 stride: 1
weight_filler { type: "gaussian" std: 0.001 }
bias_filler { type: "constant" value: 0 }
}
}
layer {
name: "rpn_relu/3x3/p3"
type: "ReLU"
bottom: "rpn/output/p3"
top: "rpn/output/p3"
}
layer {
name: "rpn_cls_score/p3"
type: "Convolution"
bottom: "rpn/output/p3"
top: "rpn_cls_score/p3"
param { lr_mult: 1.0
name: "rpn_cls_score_w"
}
param { lr_mult: 2.0
name: "rpn_cls_score_b"
}
convolution_param {
num_output: 12 # 2(bg/fg) * 9(anchors)
kernel_size: 1 pad: 0 stride: 1
weight_filler { type: "gaussian" std: 0.001 }
bias_filler { type: "constant" value: 0 }
}
}
layer {
name: "rpn_bbox_pred/p3"
type: "Convolution"
bottom: "rpn/output/p3"
top: "rpn_bbox_pred/p3"
param { lr_mult: 1.0
name:"rpn_bbox_pred_w"
}
param { lr_mult: 2.0
name:"rpn_bbox_pred_b"
}
convolution_param {
num_output: 24 # 4 * 9(anchors)
kernel_size: 1 pad: 0 stride: 1
weight_filler { type: "gaussian" std: 0.001 }
bias_filler { type: "constant" value: 0 }
}
}
######
layer {
bottom: "rpn_cls_score/p3"
top: "rpn_cls_score_reshape_/p3"
name: "rpn_cls_score_reshape_/p3"
type: "Reshape"
reshape_param { shape {dim: 0 dim: 2 dim: -1 dim:0} }
}
layer {
bottom: "rpn_bbox_pred/p3"
top: "rpn_bbox_pred_reshape/p3"
name: "rpn_bbox_pred_reshape/p3"
type: "Reshape"
reshape_param { shape { dim: 0 dim: 0 dim: -1 } }
}
layer {
bottom: "rpn_cls_score_reshape_/p3"
top: "rpn_cls_score_reshape/p3"
name: "rpn_cls_score_reshape/p3"
type: "Reshape"
reshape_param { shape {dim: 0 dim: 2 dim: -1 } }
}
以下为各个特征层所生成出的region proposal 集合。它们将用于接下来的RCNN的输入。
#========= RoI Proposal ============
layer {
name: 'proposal'
type: 'Python'
bottom: 'im_info'
bottom: 'rpn_bbox_pred/p2'
bottom: 'rpn_bbox_pred/p3'
bottom: 'rpn_bbox_pred/p4'
bottom: 'rpn_bbox_pred/p5'
bottom: 'rpn_bbox_pred/p6'
bottom: 'fpn_out_reshape/p2'
bottom: 'fpn_out_reshape/p3'
bottom: 'fpn_out_reshape/p4'
bottom: 'fpn_out_reshape/p5'
bottom: 'fpn_out_reshape/p6'
top: 'rpn_rois'
python_param {
module: 'rpn.proposal_layer'
layer: 'ProposalLayer'
param_str: "'feat_stride': 4,8,16,32,64"
}
}
以下为结合了ROI proposals与bottom data后所生成的对RCNN的正式输入。
#================rois process======================
layer {
name: 'roi-data'
type: 'Python'
bottom: 'rpn_rois'
bottom: 'gt_boxes'
bottom: 'data'
top: 'rois/h2'
top: 'rois/h3'
top: 'rois/h4'
top: 'rois/h5'
top: 'labels'
top: 'bbox_targets'
top: 'bbox_inside_weights'
top: 'bbox_outside_weights'
python_param {
module: 'rpn.proposal_target_layer'
layer: 'ProposalTargetLayer'
param_str: "'num_classes': 21"
}
}