从源码解读Faster-RCNN--(1)知识点梳理

主要参考以下文章以及视频教程,十分感谢:
Faster rcnn/Mask rcnn/FPN
逐字理解目标检测simple-faster-rcnn-pytorch-master代码
Faster_RCNN 2.模型准备(上)
faster rcnn代码来自simple-faster-rcnn-pytorch
因为Faster-RCNN也是从RCNN逐步发展过来的,这里从RCNN–> Fast RCNN --> Faster RCNN逐步讲起。

第一部分 RCNN前后

我们知道对于一些分类网络的原理比较简单,但是对于目标检测来说,是肯定需要用到这些分类网络提取特征来进行识别,那么怎么确定需要识别的位置呢?这些方法也是逐步演进过来的,这里从最初的讲起。

基于滑动窗口的目标检测

滑动窗口
滑动窗口是最开始我们能想到的方法,缩放不同的尺寸,从左到右逐个遍历,当然这种方法是比较耗时的。

Selective Search (RCNN)

Selective Search
RCNN采用Selective Search方法,根据颜色或者纹理将相似的区域聚集到一起,得到外围的Bounding Box进行作为识别的候选框。
RCNN

Bounding-Box regression (RCNN)

这里的Bounding-Box回归一直沿用到faster-RCNN,这里我们结合代码讲解一下
Bounding-Box regression
加入我们利用Selective Search得到一个Proposal(图中车身蓝色框),而我们的Ground truth为车身的红色框,得到蓝色框和红色框存在一定的偏移。
因为这里的Proposal产生的Bounding-Box一般是固定的,而和Grond truth存在偏差变换我们要从网络中学习,这里使用dx,dy,dw,dh来作为我们要学习的参数。
图左下角的Mapping表示的就是这种变换,而右下角的tx,ty,tw,th是对应的dx,dy,dw,dh就是我们要学到的目标。
我们在faster-RCNN的代码中可以找到这段的实现,在model/utils/bbox_tools.py中的loc2bbox函数中可以找到

def loc2bbox(src_bbox, loc):
    if src_bbox.shape[0] == 0:
        return xp.zeros((0, 4), dtype=loc.dtype)

    src_bbox = src_bbox.astype(src_bbox.dtype, copy=False)

    src_height = src_bbox[:, 2] - src_bbox[:, 0]
    src_width = src_bbox[:, 3] - src_bbox[:, 1]
    src_ctr_y = src_bbox[:, 0] + 0.5 * src_height
    src_ctr_x = src_bbox[:, 1] + 0.5 * src_width

    dy = loc[:, 0::4]
    dx = loc[:, 1::4]
    dh = loc[:, 2::4]
    dw = loc[:, 3::4]

    ctr_y = dy * src_height[:, xp.newaxis] + src_ctr_y[:, xp.newaxis]
    ctr_x = dx * src_width[:, xp.newaxis] + src_ctr_x[:, xp.newaxis]
    h = xp.exp(dh) * src_height[:, xp.newaxis]
    w = xp.exp(dw) * src_width[:, xp.newaxis]

    dst_bbox = xp.zeros(loc.shape, dtype=loc.dtype)
    dst_bbox[:, 0::4] = ctr_y - 0.5 * h
    dst_bbox[:, 1::4] = ctr_x - 0.5 * w
    dst_bbox[:, 2::4] = ctr_y + 0.5 * h
    dst_bbox[:, 3::4] = ctr_x + 0.5 * w

    return dst_bbox

代码中loc就是需要学习的变换,在faster RCNN 的RPN中候选框的生成中,需要用到此函数。

在RCNN也是比较耗时,主要原因有:Selective Search要产生2000个Bounding Box比较耗时,产生的ROI都要送入到网络中训练,其中有很多重复计算。

第二部分 Fast RCNN

Fast RCNN
主要观点有:直接在feature map上将ROI拿出来,在进行后续的计算,将原图中ROI位置映射到feature map上,这里提取出来的ROI大小是不一样的,这里使用ROI pooling得到大小一样的,然后送入到后续分类网络中。

ROI pooling

ROI pooling
如上图所示,假如我们拿到的feature map为Input为8×8大小,而我们的Region proposal为左下5×7大小,而我们最终需要这个proposal要输出一定大小的特征,加入我们这里定义为2×2大小,那么就将proposal切成2×2大小,再对每个格子进行maxpooling.
我们在Faster RCNN找到这部分代码,在model/roi_module.py我们可以找到RoIPooling2D类

class RoIPooling2D(t.nn.Module):
    def __init__(self, outh, outw, spatial_scale):
        super(RoIPooling2D, self).__init__()
        self.RoI = RoI(outh, outw, spatial_scale)
    def forward(self, x, rois):
        return self.RoI(x, rois)

通过定义其中self.RoI我们可以在model/utils/roi_cupy.py找到ROI Pooling实现

    float maxval = is_empty ? 0 : -1E+37;
    // If nothing is pooled, argmax=-1 causes nothing to be backprop'd
    int maxidx = -1;
    const int data_offset = (roi_batch_ind * channels + c) * height * width;
    for (int h = hstart; h < hend; ++h) {
        for (int w = wstart; w < wend; ++w) {
            int bottom_index = h * width + w;
            if (bottom_data[data_offset + bottom_index] > maxval) {
                maxval = bottom_data[data_offset + bottom_index];
                maxidx = bottom_index;
            }
        }
    }
    top_data[idx]=maxval;
    argmax_data[idx]=maxidx;
    }

值得注意的是,代码是借助cuda编程实现的,其中每个ROI里面的小块单独分配了一个线程块。

fast rcnn同样需要从2000个proposal中去识别,所以还是比较耗时的

第三部分 Faster RCNN

faster R-CNN

RPN网络

anchor的概念
Faster RCNN网络中使用RPN网络去代替Fast RCNN网络中的 Region proposal网络,首先我们先要理解anchor的概念
anchor
假如我们拿到的feature map大小是8×8大小,那么这上面的每个点都进行预测,每个点实际上对应9个anchor,每个anchor对应不同的大小和长宽比,例如下图:
anchor2
右图实际上是左图中心那个点对应的anchors图,右图上的9个框分别代表不同长宽比和大小的anchor,例如红色框就代表1:1、1:2、2:1不同长宽比的anchor,绿色框和蓝色框达标相同比例下不同大小的anchor. 注意的是每个size下的面积是相同的,例如所有红色框面积一样,绿色框面积一样…。
每个anchor的作用是负责预测该区域是不是存在有物体(二分类,有或者没有)以及Bounding Box的回归,不同大小的anchor面向的是不同大小的物体。所以faster RCNN是稠密预测的网络。
如果不同的框都预测到该框里面有物体,那么如何确定是哪个框呢?这里使用IOU(交并比)来进行区分。
这里关于anchor的生成,我们在model/utils/bbox_tools.py中generate_anchor_base函数中可以找到其实现:

def generate_anchor_base(base_size=16, ratios=[0.5, 1, 2],
                         anchor_scales=[8, 16, 32]):
    py = base_size / 2.
    px = base_size / 2.

    anchor_base = np.zeros((len(ratios) * len(anchor_scales), 4),
                           dtype=np.float32)
    for i in six.moves.range(len(ratios)):
        for j in six.moves.range(len(anchor_scales)):
            h = base_size * anchor_scales[j] * np.sqrt(ratios[i])
            w = base_size * anchor_scales[j] * np.sqrt(1. / ratios[i])

            index = i * len(anchor_scales) + j
            anchor_base[index, 0] = py - h / 2.
            anchor_base[index, 1] = px - w / 2.
            anchor_base[index, 2] = py + h / 2.
            anchor_base[index, 3] = px + w / 2.
    return anchor_base                         

可以看到其生成的9个anchor.
两个bbox的IOU计算,在model/utils/bbox_tools.py中generate_anchor_base函数中可以看到:

def bbox_iou(bbox_a, bbox_b):
    if bbox_a.shape[1] != 4 or bbox_b.shape[1] != 4:
        raise IndexError

    # top left
    tl = xp.maximum(bbox_a[:, None, :2], bbox_b[:, :2])
    # bottom right
    br = xp.minimum(bbox_a[:, None, 2:], bbox_b[:, 2:])

    area_i = xp.prod(br - tl, axis=2) * (tl < br).all(axis=2)
    area_a = xp.prod(bbox_a[:, 2:] - bbox_a[:, :2], axis=1)
    area_b = xp.prod(bbox_b[:, 2:] - bbox_b[:, :2], axis=1)
    return area_i / (area_a[:, None] + area_b - area_i)

至此,Faster RCNN所有知识点,但是Faster RCNN有一个缺点,只是一个单尺度的目标检测算法,那怎么改进呢,见补充部分。

补充

faster rcnn
如上图VGG网络图中,Faster RCNN可能从后面的7×7×512的feature map中来进行识别,其对应的224×224大小的输入图像已经损失很多了,特别对一些小目标。

FPN网络

为了解决掉此问题,FPN就设法用到一些浅层的feature map,又因为浅层的网络层提取的特征信息比较少,不利于分类识别。
FPN
我们先看一下对于多尺度识别物体一般是怎么做的,上图中,红色框代表图像数据,蓝色框代表送入网络中训练得到的feature map,首先(a)图中是利用图像金字塔去做,将不同尺度的图像送到网络中预测,这种方法需要输入多个图像,比较耗时;(b)中是直接对最后一层feature map去预测,Faster RCNN就是采取这种做法;(c)是SSD中用到的一种方法,用到低层和高层特征,但是由于低层的特征信息较弱,可能会存在分类错误;(d)FPN:特征金字塔网络,将低层特征和高层特征进行融合,网络右边采取上采样和相加连接方式做多次的特征融合。
FPN2
bootom-up采用特征提取网络例如VGG;Top-down采用上采样方法,上采样方法可以采用双线性插值或者反卷积;
![RPN](https://img-blog.csdnimg.cn/202001051946229.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTMyNDE1ODM=,size_16,color_FFFFFF,t_70 = =530x400)
FPN可以用到不同的网络中去,这里以ResNet作为骨架的FPN例子,网络右侧从M2,M3,M4,M5得到不同尺度的feature map作为Faster RCNN中 RPN网络的输入,下图是结合FPN后的Faster RCNN:
FPN Faster rcnn
FPN就是一种特殊的特征融合方法,那么对应不同尺度的feature map我们的ROI应该从那个feature map中去提取呢?
FRN
上面的公式给出了不同ROI大小对应的feature map的层数,这里的ROI是指从RPN网络中给出的proposal,所以我们就可以针对不同大小的proposal找到对应的feature map.

Faster rcnn/Mask rcnn/FPN课程中从54分钟起开始讲解Mask RCNN,感兴趣的可以去看看。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值