ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

目标检测 Two Stage Detection(RCNN 系列)

2021-04-07 13:00:39  阅读:295  来源: 互联网

标签:ROI log Two rank Detection score RCNN RPN


在这里插入图片描述

目标检测 Two Stage Detection(RCNN 系列)

  • 在没有CNN的时期,人们进行目标检测一般选择Sift/Hog/Orb等传统方法提取特征,在检测的时候用SVM等传统的分类器进行分类和选框回归,然而有了CNN之后,只要有输入就可以自动得到结果,使得我们只需要关心CNN模型的搭建,不需要关心如何人工提取特征,筛选特征。最终搭建模型变成下图所示的工作。
    1617770830904)(目标检测 Two Stage Detection(RCNN 系列).assets/image-20210406222152769.png)]

  • RCNN开启了两阶段目标检测的新时代,目前目标检测准确率最高的模型普遍是Two Stage 模型。让我们来看看这个开山模型吧。

RCNN

总流程梳理:

  • 先使用Select Search算法进行Region proposal的提取,一共提取2000个。Region proposal经过CNN之后进行ROI Pooling,最后送入FC层分别进行SVM分类和BBox回归。流程图如下:

  • 在选择Region Proposal的时候,用的是SS算法,这个算法现在已经没有人用了,是一个被淘汰的算法,因为它计算起来很慢,还有一些问题,它是无监督的算法,在fast RCNN也有用到。
  • RCNN采用的backbone是Alexnet,还有它的预训练权重。在训练的时候用真实的dataset进行微调。在训练的时候,作者严格控制正负样本比例。在送入CNN之前,batch_size是128,正负样本是32:96。其中负样本指的是IOU<0.5的region proposal。
  • 作者在用SVM分类的时候用的负样本的IOU是小于0.3的。显然,SVM分类的时候筛选更加严格了。然而在之前的CNN用0.5的阈值训练样本,为什么要改变标准和样本个数呢?CNN样本需要特别多,所以筛选比较宽松。而SVM是比较慢的,而且只有支持向量能够参与训练,所以就严格控制样本数量。
  • BBox回归的时候采用的是回归差值的方法,换句话说,BBox回归的时候是进行dx dy dw dh回归。这样对小物体会友好一些,而且偏移量会比较好拟合。

NMS:

  • Non Maximum Suppression,非极大值抑制一直是CV方向爱考的算法之一,一般来说在面试的时候可能会直接让你敲NMS,所以要注意了。

  • NMS的主要思想是,先排序BBox,找到Iou最大的BBox。之后用其他的BBox和这个Iou最大的BBox计算Iou,然后把Iou值比较大的框去掉。之后不断重复以上步骤直到没有BBox剩下来为止。
    -

  • NMS的伪代码如下图所示。其实NMS也会有很多问题,比如无法分辨距离靠的很近的物体,还有非黑即白,会把一些比较好的选框白白删掉。所以其实还可以用softNMS解决部分的NMS的问题。

  • NMS代码实现:

import numpy as np
import matplotlib.pyplot as plt
# 自己定义的二维数组
boxes = np.array([[100, 100, 210, 210, 0.72],
                  [250, 250, 420, 420, 0.8],
                  [220, 220, 320, 330, 0.92],
                  [100, 100, 210, 210, 0.72],
                  [230, 240, 325, 330, 0.81],
                  [220, 230, 315, 340, 0.9]])
def my_nms(arr,thresh=0.6):
    x1 = arr[:,0]
    y1 = arr[:,1]
    x2 = arr[:,2]
    y2 = arr[:,3]
    score = arr[:,4]
    # 计算各个框框的面积
    area = (x2-x1+1)*(y2-y1+1)
    # 定义一个放置最大分数的序号的列表
    score_rank_list = []
    # 按分数高低把序号列表排列出来
    score_rank = score.argsort()[::-1]
    while score_rank.size >0:
        # 把最大的分数对应序号添加到score_rank_list 中
        i = score_rank[0]
        score_rank_list.append(i)

        # 计算每一个方框和它的重复overlap area
        x11 = np.maximum(x1[i],x1[score_rank[1:]])
        x22 = np.minimum(x2[i],x2[score_rank[1:]])
        y11 = np.maximum(y1[i],y1[score_rank[1:]])
        y22 = np.minimum(y2[i],y2[score_rank[1:]])

        high = np.maximum(0,y22-y11+1)
        wide = np.maximum(0,x22-x11+1)
        overlap_area = high*wide
        # 计算重叠的面积
        ious = overlap_area/(area[i]+area[score_rank[1:]]-overlap_area)
        # 把大于thresh 的ious给去掉,然后取得生成符合条件的元组的序号
        # left_ious是一个列表,通过里面的列表的值如[2,3,4]才可以选出score_rank里面连续的值
        left_ious = np.where(ious<=thresh)[0]
        # 对score_rank进行切片,获得符合条件的序号最小值,把符合条件的score全部删除
        # +1是为了把最高的那个给排除了
        score_rank = score_rank[left_ious+1]
    # return千万不要放在循环里面
    return score_rank_list


def box_show(arr,type = 'c'):
    x1 = arr[:, 0]
    y1 = arr[:, 1]
    x2 = arr[:, 2]
    y2 = arr[:, 3]

    plt.plot([x1, x2], [y1, y1], type)
    plt.plot([x1, x1], [y1, y2], type)
    plt.plot([x1, x2], [y2, y2], type)
    plt.plot([x2, x2], [y1, y2], type)
    plt.title(" nms")


plt.figure(1)
ax1 = plt.subplot(1, 2, 1)
ax2 = plt.subplot(1, 2, 2)

plt.sca(ax1)
box_show(boxes, 'k')  # before nms

keep = my_nms(boxes, thresh=0.01)
plt.sca(ax2)
box_show(boxes[keep], 'r')  # after nm
plt.show()
  • 在RCNN中,作者也用到了ROI Pooling,这个做法在接下来fast RCNN讲

Fast RCNN

  • RCNN最让人头痛的就是超级慢,大约50-60s才能处理一张图片。远远不能达到实际要求,其实是因为它把2000个region proposal独立地送入网络中,而且还要用svm分类。真的太慢了。而且把检测分成了三部分,ss,svm ,cnn都相互独立,比较难受。

  • 所以,作者提出了Fast RCNN,让检测的速度大约在2s一张图片。Fast RCNN流程如下图所示:

总体流程:

  • 首先先和RCNN一样,找到region proposal,其中region proposal也还是用SS算法去找的。将整张图片送入到CNN网络中,得到feature map,通过ROI projection(就是把原图的ROI投射到中feature map上)。之后把feature map上的ROI送到pooling里面,变成长宽一样的feature map。最终通过softmax进行分类,进行BBOX的回归。

ROI projection:

  • 作者把整张图片放到CNN一次性卷积,那么我们要如何才能找到我们想要的ROI对应的feature map呢?作者发现,其实对应的feature map和原图的区域其实就是一一对应的关系,就是简单的除法映射。比如1024*1024->128 * 128,就是除以8的关系。feature map的位置其实就是原图除以8。
  • 找到了region proposal对应的feature map的位置,就可以把这些东西拿到网络中去了。但是网络中有全连接层,输入的size必须要一样,作者就采用了第二种方法,ROI Pooling

ROI Pooling:

  • Pooling就是把所有的特征图变成7*7,然后方便接下来的网络计算。如何变成7x7呢?就是通过打格子,对格子内部的像素进行max pooling处理。

  • 然后不同size的ROI就变成一样的了。
    1617770830906)(目标检测 Two Stage Detection(RCNN 系列).assets/image-20210407001837179.png)]

  • 我们在这个时候发现:fast RCNN其实做了两次量化的过程,一次是在ROI projection的时候,把横纵坐标对应到feature map上的时候,进行了一次量化(比如除以16除不尽就直接删了),还有ROI Pooling的时候也是一次量化过程。这两次量化对图像的精度会产生比较大的影响。如果是大物体损失的信息还不会很多,但是如果是小物体,损失的像素占原来的比例就很可怕了。

ROI Align:

  • 为了减少两次量化的损失,首先何凯明大神提出了ROI Align
    1617770830908)(目标检测 Two Stage Detection(RCNN 系列).assets/image-20210407002247841.png)]

  • 首先获得红色框,就是ROIprojection的结果,之后进行打格子,在绿色格子中打成黑色格子,在黑色格子之后取得中点, 之后再进行pooling。

  • 对于粉色格点的计算是通过双线性插值完成的,这个时候就可以保住一定的量化精度。

  • 然而何大神还是有一些问题没考虑到。这种差值方法参与计算的点其实就只有像素旁边的4个点而已,其实小块图像中每一个点对我们要计算的点都有作用。还有为什么要在绿色的格子里面要去取4个格子呢?不同的数据集, 这个N是比较没有道理的,是要基于特定数据集才有道理的.真正的场景中.只有部分的点参与了计算,这时候还是会抹杀了很多的信息.

  • 为了改进双线性插值的不足,有人提出了Precise ROI Pooling

Precise ROI Pooling:

1617770830909)(目标检测 Two Stage Detection(RCNN 系列).assets/image-20210407091721261.png)]

  • 如上图所示。对每一个点进行红点的双线性插值计算,然后对红点画出来的圈圈进行ROI Pooling。这样子,所有的点都能参与运算,量化的损失也基本没有了。

Faster RCNN:

  • Fast RCNN还不够快,天下武功无快不破。Fast RCNN用了超级慢的SS算法,使得网络并不是一个端到端的模型。所以加上了一个RPN网络(region proposal network),这也是faster RCNN比较精华的部分

  • 我们还是先从流程说起:

  • 首先将图片送入(VGG网络)backbone进行feature map的提取,然后也送入RPN网络提取出ROI。剩下的流程和

    fast RCNN基本一样,进行ROI Pooling后分类和回归。最重要的是RPN网络。

RPN:

  • RPN+BBox回归其实就是Two Stage Detection名字的由来,这也是为什么二阶段的精确度一直都比一阶段好的原因。

  • RPN的架构在train 和test的时候其实是不一样的网络大概结构如下:

1617770830910)(目标检测 Two Stage Detection(RCNN 系列).assets/image-20210407093005546.png)]

  • 为了在RPN中产生出Region proposal,作者引入了anchor(这个东西在Yolo模型也用到了),anchor的大小和长宽比是可以自己定制的,在开源的代码中,一般一个像素会产生9个anchor,其中有3个scale和3个ratios,这样它就更有可能贴近我们需要寻找的那个物体。

  • 以下是test时候的RPN网络:
    1617770830910)(目标检测 Two Stage Detection(RCNN 系列).assets/image-20210407093418519.png)]

  • 经过3 * 3之后的通道数作者没有标注出来,因为最重要的事情是在1*1的卷积之后,通道数要是18 和 36, 这个是必须的。上面的18 其实是用来分类的,因为我们有9个anchor,还有每个anchor都有2个向量,表示是背景和前景的概率(看到进行了softmax就知道这进行了分类操作了)。下面的36输出的是9个anchor的x,y,w,h,所以有36个channel,最后把这些东西拼接起来就得到的我们需要的ROI的信息了。
    -

  • 当IOU>0.7的时候当做正样本,IOU<0.3的时候当做负样本,IOU不包括计算和其他anchor的IOU。在训练的时候要保证正负样本比是1:3.

损失函数:

Smooth L1 Loss:

  • 公式如下:
  • f ( x ) = { ( σ x ) 2 2 ,  if  x < 1 / σ 2 ∣ x ∣ − 0.5 σ 2 ,  otherwise  f(x)=\left\{\begin{array}{ll}\frac{(\sigma x)^{2}}{2}, & \text { if } x<1 / \sigma^{2} \\ |x|-\frac{0.5}{\sigma^{2}}, & \text { otherwise }\end{array}\right. f(x)={2(σx)2​,∣x∣−σ20.5​,​ if x<1/σ2 otherwise ​
  • 这个公式其实应该是非常熟悉了,它可以除去L1 Loss在原点不连续的问题,也可以让下降时候的梯度有所变化,在最低点的时候梯度小一些,方便训练。

残差拟合:

  • RPN网络拟合的是残差量,dx,dy,dw,dh,公式如下图所示:

    f ( x ) = { t x p = x p − x a w a , t y p = y p − y a h a t w p = log ⁡ ( w p w a ) , t h p = log ⁡ ( h p h a ) t x g = x g − x a w a , t y g = y g − y a h a t w g = log ⁡ ( w g w a ) , t h g = log ⁡ ( h g h a ) f(x)=\left\{\begin{array}{c}t_{x}^{p}=\frac{x_{p}-x_{a}}{w_{a}}, t_{y}^{p}=\frac{y_{p}-y_{a}}{h_{a}} \\ t_{w}^{p}=\log \left(\frac{w_{p}}{w_{a}}\right), t_{h}^{p}=\log \left(\frac{h_{p}}{h_{a}}\right) \\ t_{x}^{g}=\frac{x_{g}-x_{a}}{w_{a}}, t_{y}^{g}=\frac{y_{g}-y_{a}}{h_{a}} \\ t_{w}^{g}=\log \left(\frac{w_{g}}{w_{a}}\right), t_{h}^{g}=\log \left(\frac{h_{g}}{h_{a}}\right)\end{array}\right. f(x)=⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧​txp​=wa​xp​−xa​​,typ​=ha​yp​−ya​​twp​=log(wa​wp​​),thp​=log(ha​hp​​)txg​=wa​xg​−xa​​,tyg​=ha​yg​−ya​​twg​=log(wa​wg​​),thg​=log(ha​hg​​)​

    predicated bbox: x p , y p , w p , h p x_{p}, y_{p}, w_{p}, h_{p} xp​,yp​,wp​,hp​
    anchor bbox: x a , y a , w a , h a x_{a}, y_{a}, w_{a}, h_{a} xa​,ya​,wa​,ha​
    ground truth bbox: x g , y g , w g , h g x_{g}, y_{g}, w_{g}, h_{g} xg​,yg​,wg​,hg​

  • 我们最想做的事情就是让 t x x g t^{g}_{xx} txxg​ 和 t x x p t^{p}_{xx} txxp​ 接近,这样我们预测的框框就比较好了。在反向传播的时候,损失函数就用Smooth L1损失去做就可以了,把 t x x g t^{g}_{xx} txxg​ 和 t x x p t^{p}_{xx} txxp​ 的损失加起来就可以了。在进行w和h的预测的时候加了log,这是为了抑制大物体的Loss,使得它和小物体比较接近,不然,网络只会学到大物体的特征,小物体就会比较忽视了。 t x x g t^{g}_{xx} txxg​ 和 t x x p t^{p}_{xx} txxp​ 相对于anchor做归一化也是这个道理。
    -

  • 只要把残差量给拟合好了,那么网络就训练完成了。

训练过程:

  • Faster RCNN是一张比较庞大的网络,在训练的时候如果暴力一起训练的话,比较难以收敛。

  • 所以作者选择了比较复杂的训练过程:

    1. 首先选取VGG的backbone,固定参数,训练RPN的参数生成ROI。
    2. RPN训练好之后固定RPN的参数,结合ROI Pooling训练功能头和对Backbone进行微调
    3. 再用backbone重新训练RPN网络
    4. 把Backbone和RPN固定,训练功能头。
  • 经过这些折腾之后,网络就训练得差不多了。这也是以RCNN系列的大致经典内容了。

标签:ROI,log,Two,rank,Detection,score,RCNN,RPN
来源: https://blog.csdn.net/Sakura_day/article/details/115482930

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有