FPN: 一种高效的CNN特征提取方法

介绍

FPN是一种利用常规CNN模型来高效提取图片中各维度特征的方法。在计算机视觉学科中,多维度的目标检测一直以来都是通过将缩小或扩大后的不同维度图片作为输入来生成出反映不同维度信息的特征组合。这种办法确实也能有效地表达出图片之上的各种维度特征,但却对硬件计算能力及内存大小有较高要求,因此只能在有限的领域内部使用。

FPN通过利用常规CNN模型内部从底至上各个层对同一scale图片不同维度的特征表达结构,提出了一种可有效在单一图片视图下生成对其的多维度特征表达的方法。它可以有效地赋能常规CNN模型,从而可以生成出表达能力更强的feature maps以供下一阶段计算机视觉任务像object detection/semantic segmentation等来使用。本质上说它是一种加强主干网络CNN特征表达的方法。

Featurized image pyramid

下图中描述了四种不同的得到一张图片多维度特征组合的方法。

四种不同的生成多维度特征组合的方法

上图(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基本架构

FPN会使用CNN网络中每一层的信息来生成最后的表达特征组合。下图是它的基本架构。从中我们能看到FPN会模型每个CNN层的特征输出进行处理以生成反映此维度信息的特征。而自上至下处理后所生成出的特征之间也有个关联关系,即上层high level的特征会影响下一层次的low level特征表达。最终所有的特征一起用来作为下一步的目标检测或类别分析等任务的输入。

FPN基本架构

FPN详细介绍

FPN是传统CNN网络对图片信息进行表达输出的一种增强。它目的是为了改进CNN网络的特征提取方式,从而可以使最终输出的特征更好地表示出输入图片各个维度的信息。它的基本过程有三个分别为:自下至上的通路即自下至上的不同维度特征生成;自上至下的通路即自上至下的特征补充增强;CNN网络层特征与最终输出的各维度特征之间的关联表达。

我们在下图中能看出这三个过程的细粒度表示。

FPN的特征组合详细描述
  • 自下至上的通路(Bottom-top pathway):这个没啥奇怪就是指的普通CNN特征自底至上逐层浓缩表达特征的一个过程。此过程很早即被认识到了即较底的层反映较浅层次的图片信息特征像边缘等;较高的层则反映较深层次的图片特征像物体轮廓、乃至类别等;
  • 自上至下的通路(Top-bottome pathway):上层的特征输出一般其feature map size比较小,但却能表示更大维度(同时也是更加high level)的图片信息。此类high level信息经实验证明能够对后续的目标检测、物体分类等任务发挥关键作用。因此我们在处理每一层信息时会参考上一层的high level信息做为其输入(这里只是在将上层feature map等比例放大后再与本层的feature maps做element wise相加);
  • CNN层特征与每一级别输出之间的表达关联:在这里作者实验表明使用1x1的Conv即可生成较好的输出特征,它可有效地降低中间层次的channels 数目。最终这些1x1的Convs使得我们输出不同维度的各个feature maps有着相同的channels数目(本文用到的Resnet-101主干网络中,各个层次特征的最终输出channels数目为256)。

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"
  }
}

参考文献

  • Feature Pyramid Networks for Object Detection, Tsung-Yi Lin, 2017
  • https://github.com/unsky/FPN

你可能感兴趣的:(FPN: 一种高效的CNN特征提取方法)