机器学习18:RPN区域候选网络

机器学习18:RPN区域候选网络(转载和整理)

           RPN区域候选网络是Faster R-CNN对Fast R-CNN在提取候选区域的时候所做的改进,在上一篇整理Faster R-CNN的时候读了很多关于RPN的文章和资料,只是粗略了解了RPN的功能、优势、创新点等,始终没能真正理解它的实现机制。

           直到读到深度学习:RPN(区域候选网络)RPN(区域生成网络),这两篇文章对RPN区域候选网络的结构和实现讲的是比较清楚,这篇博客整理自这两篇文章。            

1.RPN区域候选网络概述:

           RPN的本质是 “ 基于滑窗的无类别object检测器 ” ,下图显示的是Faster R-CNN的构造,RPN在其中的作用是从特征提取网络输出的特征图中提取候选区域,获取的候选区域将和特征图一同输入Roi Pooling层。

          下面的流程图显示了RPN所在Faster R-CNN结构中的位置,左侧SS算法为R-CNN、Fast R-CNN中一直采用的区域推荐算法,但左侧流程如表示的是Fast R-CNN的检测流程可能缺少了特征图提取部分:

           RPN网络的相关事项:

               1)在训练阶段,会输出约2000个候选边框,但只会抽取其中256个来训练RPN的cls+reg(分类+回归)结构,在训练过程中cls+reg(分类+回归)可以得到强监督信息(来源于ground truth),即ground truth会告诉cls+reg结构哪些才是真的前景,从而引导cls+reg结构学习正确区分前后景的能力。

                    到了reference阶段,则直接输出排序分数最高的300个候选边框,此时由于没有了监督信息,RPN并不知道这些候选区域是否为前景,整个过程只是惯性地推送无标签的候选区域给后面的Fast R-CNN网络。

               2)RPN的运用使得提取候选区域的额外开销就只有一个两层网络。

               3)如果只在最后一层特征图上映射回原图像,且初始产生的anchor被限定了尺寸下限,那么低于最小anchor尺寸的小目标虽然被圈入,在后面的过程中依然容易被漏检,而FPN的出现,大大降低了小目标的漏检率。

2.RPN区域候选网络的结构:

           RPN区域候选网络的整体结构如下图所示。

           (1)RPN头部结构:

                    在 RPN头部 ,通过以下结构生成 anchor(一些有编号有坐标的bbox):

                    论文中的这幅插图对应的就是RPN头部,而不是RPN的整体结构:

           (2)RPN中部结构:

                    在 RPN中部, 分类分支(cls) 和 边框回归分支(bbox reg) 分别对这些anchor进行计算,two stage型的检测算法在RPN 之后 还会进行 再一次 的 分类任务 和 边框回归任务,以进一步提升检测精度。:

                   

           (3)RPN末端结构:

                     在 RPN末端对 两个分支的结果进行汇总,先剔除越界的anchor,再根据cls结果通过NMS算法去重来实现对anchor的 初步筛除,根据bbox reg结果来实现初步偏移,此时输出称为Proposal 。

           (4)RPN后操作:

                     RPN之后,proposal成为RoI(感兴趣区域) ,被输入RoIPooling或RoIAlign中进行尺寸归一化。这些都是RPN网络之后的操作了,严格来说并不属于RPN的范围 。

                     下图中绿框内RPN红圈内RoI以及其对应的池化操作

3.RPN相关问题及解答:

             RPN的整个过程为一个特征图经过sliding window处理,得到256维特征,然后通过两次全连接得到结果2k个分数和4k个坐标:

           1)RPN的输入特征图指的是哪个特征图?

                    RPN的输入特征图就是Faster R-CNN的公共特征图,由输入待测图经过特征提取部分得到,也称共享Feature Map,主要用以RPN和RoI Pooling共享;

           2)为什么是用sliding window?不是用CNN么?

                    我们可以把3x3的sliding window看作是对特征图做了一次3x3的卷积操作,最后得到了一个通道数目是256的特征图,尺寸与公共特征图相同,假设为256 x (H x W);

           (3)256维特征向量如何获得的?

                    可以近似的把这个特征图看作有H x W个向量,每个向量是256维,那么图中的256维指的就是其中一个向量,然后要对每个特征向量做两次全连接操作,一个得到2个分数另一个得到4个坐标,由于我们要对每个向量做同样的全连接操作,等同于对整个特征图做两次1 x 1的卷积,得到一个2 x H x W和一个4 x H x W大小的特征图,也就是有H x W个结果,每个结果包含2个分数和4个坐标;

                    需要解释一下为何是2个分数,因为RPN是提候选框,此处不需要判断类别,所以只要求区分是不是物体就可以,那么就有两个分数,前景(物体)的分数和背景的分数; 我们还需要注意:4个坐标是指针对原图坐标的偏移

           (4)2k和4k中的k指的是什么?不同形状的矩形和Anchors如何得到?

                    H x W个结果中的每一点与原图之前都存在一一映射的关系,由于原图和特征图大小不同,所以特征图上的一个点对应原图是一个框,然而这个框很小。

                    比如8 x 8的小框,这里8是指原图和特征图的比例,那我们不妨把框的左上角或者框的中心作为锚点(Anchor),然后想象出K个框,这也就是图中所说的K anchor boxes(由锚点产生的K个框);换句话说,H x W个点,每个点对应原图有K个框,那么就有H x W x k个框在原图上,RPN的结果其实就是判断这些框是不是物体以及他们的偏移。

                    K个框的尺寸和长宽比是预先设定好的,假设共有9种组合,也就是k等于9,那么结果针对这9种组合成H x W x 9个结果,也就是18个分数和36个坐标。     

5.RPN流程总结:

                    首先通过一系列卷积得到公共特征图,假设尺寸为N x 16 x 16;

                    然后进入RPN阶段,首先经过一个3 x 3的卷积,得到一个256 x 16 x 16的特征图,也可以看作16 x 16个256维特征向量,然后经过两次1 x 1的卷积,分别得到一个18 x 16 x 16的特征图,和一个36 x 16 x 16的特征图,也就是16 x 16 x 9个结果,每个结果包含2个分数和4个坐标;

                   再结合预先定义的Anchors,经过后处理,就得到候选框。整个流程如下图所示: 

4.源代码:

                     作者的源代码请见:作者的源码 。

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

layer {
  name: "rpn_conv/3x3"
  type: "Convolution"
  bottom: "conv5"
  top: "rpn/output"
  param { lr_mult: 1.0 }
  param { lr_mult: 2.0 }
  convolution_param {
    num_output: 256
    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 }
  param { lr_mult: 2.0 }
  convolution_param {
    num_output: 18   # 2(bg/fg) * 9(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 }
  param { lr_mult: 2.0 }
  convolution_param {
    num_output: 36   # 4 * 9(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 } }
}
layer {
  name: 'rpn-data'
  type: 'Python'
  bottom: 'rpn_cls_score'
  bottom: 'gt_boxes'
  bottom: 'im_info'
  bottom: 'data'
  top: 'rpn_labels'
  top: 'rpn_bbox_targets'
  top: 'rpn_bbox_inside_weights'
  top: 'rpn_bbox_outside_weights'
  python_param {
    module: 'rpn.anchor_target_layer'
    layer: 'AnchorTargetLayer'
    param_str: "'feat_stride': 16"
  }
}
layer {
  name: "rpn_loss_cls"
  type: "SoftmaxWithLoss"
  bottom: "rpn_cls_score_reshape"
  bottom: "rpn_labels"
  propagate_down: 1
  propagate_down: 0
  top: "rpn_cls_loss"
  loss_weight: 1
  loss_param {
    ignore_label: -1
    normalize: true
  }
}
layer {
  name: "rpn_loss_bbox"
  type: "SmoothL1Loss"
  bottom: "rpn_bbox_pred"
  bottom: "rpn_bbox_targets"
  bottom: 'rpn_bbox_inside_weights'
  bottom: 'rpn_bbox_outside_weights'
  top: "rpn_loss_bbox"
  loss_weight: 1
  smooth_l1_loss_param { sigma: 3.0 }
}

#========= RoI Proposal ============

layer {
  name: "rpn_cls_prob"
  type: "Softmax"
  bottom: "rpn_cls_score_reshape"
  top: "rpn_cls_prob"
}
layer {
  name: 'rpn_cls_prob_reshape'
  type: 'Reshape'
  bottom: 'rpn_cls_prob'
  top: 'rpn_cls_prob_reshape'
  reshape_param { shape { dim: 0 dim: 18 dim: -1 dim: 0 } }
}
layer {
  name: 'proposal'
  type: 'Python'
  bottom: 'rpn_cls_prob_reshape'
  bottom: 'rpn_bbox_pred'
  bottom: 'im_info'
  top: 'rpn_rois'
#  top: 'rpn_scores'
  python_param {
    module: 'rpn.proposal_layer'
    layer: 'ProposalLayer'
    param_str: "'feat_stride': 16"
  }
}
layer {
  name: 'roi-data'
  type: 'Python'
  bottom: 'rpn_rois'
  bottom: 'gt_boxes'
  top: 'rois'
  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"
  }
}

#========= RCNN ============

layer {
  name: "roi_pool_conv5"
  type: "ROIPooling"
  bottom: "conv5"
  bottom: "rois"
  top: "roi_pool_conv5"
  roi_pooling_param {
    pooled_w: 6
    pooled_h: 6
    spatial_scale: 0.0625 # 1/16
  }
}
layer {
  name: "fc6"
  type: "InnerProduct"
  bottom: "roi_pool_conv5"
  top: "fc6"
  param { lr_mult: 1.0 }
  param { lr_mult: 2.0 }
  inner_product_param {
    num_output: 4096
  }
}
layer {
  name: "relu6"
  type: "ReLU"
  bottom: "fc6"
  top: "fc6"
}
layer {
  name: "drop6"
  type: "Dropout"
  bottom: "fc6"
  top: "fc6"
  dropout_param {
    dropout_ratio: 0.5
    scale_train: false
  }
}
layer {
  name: "fc7"
  type: "InnerProduct"
  bottom: "fc6"
  top: "fc7"
  param { lr_mult: 1.0 }
  param { lr_mult: 2.0 }
  inner_product_param {
    num_output: 4096
  }
}
layer {
  name: "relu7"
  type: "ReLU"
  bottom: "fc7"
  top: "fc7"
}
layer {
  name: "drop7"
  type: "Dropout"
  bottom: "fc7"
  top: "fc7"
  dropout_param {
    dropout_ratio: 0.5
    scale_train: false
  }
}
layer {
  name: "cls_score"
  type: "InnerProduct"
  bottom: "fc7"
  top: "cls_score"
  param { lr_mult: 1.0 }
  param { lr_mult: 2.0 }
  inner_product_param {
    num_output: 21
    weight_filler {
      type: "gaussian"
      std: 0.01
    }
    bias_filler {
      type: "constant"
      value: 0
    }
  }
}
layer {
  name: "bbox_pred"
  type: "InnerProduct"
  bottom: "fc7"
  top: "bbox_pred"
  param { lr_mult: 1.0 }
  param { lr_mult: 2.0 }
  inner_product_param {
    num_output: 84
    weight_filler {
      type: "gaussian"
      std: 0.001
    }
    bias_filler {
      type: "constant"
      value: 0
    }
  }
}
layer {
  name: "loss_cls"
  type: "SoftmaxWithLoss"
  bottom: "cls_score"
  bottom: "labels"
  propagate_down: 1
  propagate_down: 0
  top: "cls_loss"
  loss_weight: 1
  loss_param {
    ignore_label: -1
    normalize: true
  }
}
layer {
  name: "loss_bbox"
  type: "SmoothL1Loss"
  bottom: "bbox_pred"
  bottom: "bbox_targets"
  bottom: 'bbox_inside_weights'
  bottom: 'bbox_outside_weights'
  top: "bbox_loss"
  loss_weight: 1
}
 
发布了84 篇原创文章 · 获赞 13 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_39504171/article/details/103872842
RPN
今日推荐