Faster-R-CNN网络学习与总结(带一些个人理解)

1. 背景

Faster R-CNN 发表于 NIPS 2015,其后出现了很多改进版本,后面会进行介绍.

R-CNN - Rich feature hierarchies for accurate object detection and semantic segmentation 是 Faster R-CNN 的启发版本. R-CNN 是采用 Selective Search 算法来提取(propose)可能的 RoIs(regions of interest) 区域,然后对每个提取区域采用标准 CNN 进行分类.

出现于 2015 年早期的 Fast R-CNN 是 R-CNN 的改进,其采用兴趣区域池化(Region of Interest Pooling,RoI Pooling) 来共享计算量较大的部分,提高模型的效率.

Faster R-CNN 随后被提出,其是第一个完全可微分的模型. Faster R-CNN 是 R-CNN 论文的第三个版本.

R-CNNFast R-CNNFaster R-CNN 作者都有 Ross Girshick.

Faster-RCNN发展史
RCNN→Fast R-CNN→Faster R-CNN先简单介绍一下前两个算法

R-CNN

在这里插入图片描述
1.region proposal
由于R-CNN对特定区域算法是不关心的,所以我们采用了选择性搜索(selective search)以方便和前面的工作进行可控的比较
图中的roi 然后进行warped image regions 这一步过于暴力之后的sppnet算法对这块进行改动,用多尺度方法来解决图片尺寸问题

2.Feature extraction
对每个推荐区域抽取一个4096维度的特征向量把一个输入为277*277大小的图片,通过五个卷积层和两个全连接层进行前向传播,最终得到一个4096-D的特征向量。读者可以参考AlexNet获得更多的网络架构细节。

3.计算loss
对每个类别训练出的SVM给整个特征向量中的每个类别单独打分。
然后给出一张图像中所有的打分区域,然后使用NMS(每个类别是独立进行的),拒绝掉一些和高分区域的IOU大于阈值的候选框

Fast R-CNN

在这里插入图片描述
大体结构:
一张输入图片和多个 RoIs 作为全卷积网络的输入,每个 RoI 被池化到一个固定尺寸的特征图,并采用全连接层映射为一个特征向量. 对于每个 RoI,网络有两个输出向量:softmax 概率和 per-class bounding-box 回归偏移值. 网络是采用 multi-task loss 进行 end-to-end 训练的.

1.RoI Pooling 层
RoI max-pooling 层通过将 h ∗ w h∗w hw 的 RoI windows 分割为 H ∗ W H∗W HW 的 sub-windows 网格,共 h / H ∗ w / W h/H∗w/W h/Hw/W, 并对每个 sub-windows 的值进行 max-pooling 处理,得到对应的输出网格单元. 对每个 feature map channel 分别 pooling 处理,类似于 标准 max-pooling.

有的学习总结说fast rcnn比rcnn强在就输入一张image
但论文上也说了是image加ROI
2.网络部分
在这里插入图片描述
Fast R-CNN 训练过程中,SGD 先采样 N 张图像,再对每张图片采样 R/N个 RoIs,以分层采样 mini-batches.

相同图片的 RoIs 在前向和反向传播过程中,共享计算和内存.

Fast R-CNN 联合训练 softmax 分类器和 bounding-box 回归起,而分别训练 softmax 分类器,SVMs,回归器采用 multi-task loss 联合训练分类和边界框回归

Faster R-CNN

先上图
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
图片真的很容易解释

  • 计算图片的卷积特征图conv feature map;
  • 然后采用 RPN 对卷积特征图处理,得到 object proposals;
  • 再利用 RoI Pooling 对每个 proposal 提取特征;
  • 最后,利用提取特征进行分类.
  • R-CNN 是 Faster R-CNN 框架中的最后一个步骤.(这里R-CNN是region cnn的意思,并不是那个前身)

几个当初不懂的地方:

  1. 与其他前身不同之处在于RPN先进行object的定位
    在这里插入图片描述
    在这里插入图片描述

  2. RPN详解
    RPN部分流程图在这里插入图片描述
    RPN代码部分

    1.第一层:3*3的卷积层

    rpn = slim.conv2d(net_conv, 512, [3, 3], trainable=is_training, weights_initializer=initializer,
                        scope="rpn_conv/3x3")
    

    2.第二层:两个分支,都用了1*1的卷积核;第一支得到特征图(height, width, 9x2),用于判断bbox中是否含有物体;第二支得到特征图 (height, width, 9x4),用于得到bbox的坐标。
    Softmax Classification:对于RPN网络的分类层(cls),其向量维数为2k = 18,考虑整个特征图conv5-3,则输出大小为 W × H × 18 W×H×18 W×H×18,正好对应conv5-3上每个点有9个anchors,而每个anchor又有两个score(fg/bg)输出,对于单个anchor训练样本,其实是一个二分类问题。为了便于Softmax分类,需要对分类层执行reshape操作,这也是由底层数据结构决定的。在caffe中,Blob的数据存储形式为 B l o b = [ b a t c h s i z e , c h a n n e l , h e i g h t , w i d t h ] Blob=[batch_size,channel,height,width] Blob=[batchsize,channel,height,width],而对于分类层(cls),其在Blob中的实际存储形式为 [ 1 , 2 k , H , W ] [1,2k,H,W] [1,2k,H,W],而Softmax针对每个anchor进行二分类,所以需要在分类层后面增加一个reshape layer,将数据组织形式变换为 [ 1 , 2 , k ∗ H , W ] [1,2,k∗H,W] [1,2,kH,W],之后再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 NHW, "
    “with integer values in {0, 1, …, C-1}.”;

    # shape = (1, ?, ?, 18) , 其中,batchsize=1
    # reshape成这个形状是因为有9个anchor boxes,乘2是因为foreground和background
    rpn_cls_score = slim.conv2d(rpn, self._num_anchors * 2, [1, 1], trainable=is_training,
                                weights_initializer=initializer,
     # change it so that the score has 2 as its channel size
     # 单独“腾空”出来一个维度以便softmax分类
     # shape = (1, ?, ?, 2)
    rpn_cls_score_reshape = self._reshape_layer(rpn_cls_score, 2, 'rpn_cls_score_reshape')
     # shape = (1, ?, ?, 2)
    rpn_cls_prob_reshape = self._softmax_layer(rpn_cls_score_reshape, "rpn_cls_prob_reshape")
     # shape = (?,)
    rpn_cls_pred = tf.argmax(tf.reshape(rpn_cls_score_reshape, [-1, 2]), axis=1, name="rpn_cls_pred")
     # shape = (1, ?, ?, 18)
    rpn_cls_prob = self._reshape_layer(rpn_cls_prob_reshape, self._num_anchors * 2, "rpn_cls_prob")
     # shape = (1, ?, ?, 36)
    rpn_bbox_pred = slim.conv2d(rpn, self._num_anchors * 4, [1, 1], trainable=is_training,
                                weights_initializer=initializer,
                                padding='VALID', activation_fn=None, scope='rpn_bbox_pred')
    

    rpn_bbox_inside_weights用于把是object的box过滤出来,因为并不是所有的anchors都是有object的。rpn_bbox_inside_weights用于设置标记为1的box和标记为0的box的权值比率。
    bbox_outside_weights该权值用来设置在所有样本中,positive和negitive的权值

    Q:RPN进行过一次回归,然后之后又做一次回归?
    个人觉得是因为roi pooling 改变了rpn提取的坐标,或者说2次调整效果更好。2019.02.15 rpn是一个筛选roi的过程,减少后面proposal个数。

  3. ROI部分
    ROI Pooling的意思是 对RPN的结果去对应到第一步卷积输出的特征图,对特征图进行提取,将不同尺寸ROI对应的特征图采样为相同尺寸
    github代码

    if cfg.POOLING_MODE == 'crop':
            pool5 = self._crop_pool_layer(net_conv, rois, "pool5")
          else:
            raise NotImplementedError
            ……
    def _crop_pool_layer(self, bottom, rois, name):
    	 …
    	 bboxes = tf.stop_gradient(tf.concat([y1, x1, y2, x2], axis=1))
         pre_pool_size = cfg.POOLING_SIZE * 2
         crops = tf.image.crop_and_resize(bottom, bboxes, tf.to_int32(batch_ids), [pre_pool_size, pre_pool_size], name="crops")
    
         return slim.max_pool2d(crops, [2, 2], padding='SAME')
    

    上面这部分代码相对好懂
    2019.02.18 看了maskrcnn 之后发现这块有其它的意义和ROIAlign代码类似,也许是一种改进

    而由于我看的是其他文章他roi是这么写的:

    loat bin_size_h = (float)(roi_height) / (float)(pooled_height);  // 9/7
    float bin_size_w = (float)(roi_width) / (float)(pooled_width);  // 7/7=1
    for (ph = 0; ph < pooled_height; ++ph){
      for (pw = 0; pw < pooled_width; ++pw){
        int hstart = (floor((float)(ph) * bin_size_h));  
        int wstart = (floor((float)(pw) * bin_size_w));
        int hend = (ceil((float)(ph + 1) * bin_size_h));
        int wend = (ceil((float)(pw + 1) * bin_size_w));
        hstart = fminf(fmaxf(hstart + roi_start_h, 0), data_height);
        hend = fminf(fmaxf(hend + roi_start_h, 0), data_height);
        wstart = fminf(fmaxf(wstart + roi_start_w, 0), data_width);
        wend = fminf(fmaxf(wend + roi_start_w, 0), data_width);
    // ......
    // 经过计算后w步长为1,窗口为1,没有overlap,h窗口步长不定都有overlap,注意在ph=3时窗口为3了
    // 注意边界 pw=pooled_width-1时 wend=(ceil((float)(pw + 1) * bin_size_w))
    //  =(ceil((float)pooled_width * (float)(roi_width) / (float)
    //  =(pooled_width)))=ceil(roi_width)=roi_width
    //  刚好把所有roi对应的feature map覆盖完,hend同理
    //  roi_height roi_width小于pooled_height pooled_width时overlap就多一点
    
    

在这里插入图片描述
对每个划分的pool bin进行max或者average pooling最后得到7*7的feature map
感觉是Fast-RCNN的roi pooling 但存在小数然后进行了什么操作
这块操作不是很明白

最后放几个链接用于加深印象:
代码部分:Faster Rcnn代码走读(一) 网络框架(PRN层)Faster R-CNN 源码解析(Tensorflow版)
算法部分:Mask-RCNN但详细介绍了Faster-RCNNFaster-RCNN详解
其它:YOLO v3、SSD、Faster-RCNN目标检测算法对比

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值