前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Mask RCNN介绍

Mask RCNN介绍

作者头像
算法之名
发布2022-05-06 10:27:59
9190
发布2022-05-06 10:27:59
举报
文章被收录于专栏:算法之名算法之名

Mask RCNN是何凯明大神以及Faster RCNN作者Ross B. Girshick等多人发表于ICCV 2017。我们知道对于图像分类来说

将一张图片送进神经网络之后得到其分类的概率。对于目标检测来说

我们将图像送进神经网络之后得到目标边框和分类概率。这是一个FPN的过程。对于语义分割来说

我们将图像送进神经网络之后得到每一个像素的前景和背景。这相当于对像素进行一个二分类。这是一个FCN的过程。

Mask RCNN和Faster RCNN的结构是非常相似的,最大的不同就在于在最后的输出的时候增加了一个多任务网络Mask分支的结构,对于这个分支我们就可以对于每一个要检测的目标去生成Mask分割蒙版。关于这个Mask分支有两个版本

上图中左边的是不带有特征金字塔结构的版本,右边是带有特征金字塔结构(FPN)的,我们比较常用的是右边这种结构。在Faster RCNN中,特征层通过RPN网络后,紧跟着是一个ROI Pooling层,但是在Mask RCNN中被替换成了ROI Align。

上图中的AP是精准率和召回率所围成的面积,具体可以参考机器学习算法整理(三) 中的精准率和召回率的平衡。通过上图我们可以看出使用了ROI Align替换了ROI Pooling之后,不论是bounding box的AP值还是Mask的AP值都有所提升,而且幅度还很大。

ROI Pooling的作用是将所有不同尺寸feature map裁剪的目标区域都调整成相同尺寸的输出,再统一传递给FC层。这里我们假设一个feature map相对原图的降采样为32倍。

我们假设有一个目标,它对应的原图左上角的坐标为10,10,它的右下角对应原图的坐标为124,124。因为是原图坐标,我们要将其映射到feature map上,所以需要对坐标值/32。10/32是不能被整除的,在ROI Pooling当中,经过四舍五入,得到feature map上的点是0,0。同样124/32经过四舍五入后得到的坐标点为4,4。在上图中的第一个表格中,我们将0~4的格子用黑色区域给标记出来,就是目标在feature map上的区域。这是第一次取整的情况。

此时我们将这个5*5的区域再进行一次2倍的最大池化降采样,需要得到一个2*2区域大小的feature map。由于5无法被2整除,所以会将整个区域划分成一个3*3、3*2、2*3、2*2的区域,最后我们得到的就是[1.6871,0.4676,2.0242,2.3571]的矩阵,也就是上图中下面表格中蓝色区域的数字。

代码语言:javascript
复制
import torch
from torchvision.ops import RoIPool

if __name__ == '__main__':

    torch.manual_seed(1)
    x = torch.randn((1, 1, 6, 6))
    print(f"feature map: \n{x}")

    proposal = [torch.Tensor([[10, 10, 124, 124]])]
    roi_pool = RoIPool(output_size=2, spatial_scale=1/32)
    roi = roi_pool(x, proposal)
    print(f"roi pool: \n{roi}")

运行结果

代码语言:javascript
复制
feature map: 
tensor([[[[-1.5256, -0.7502, -0.6540, -1.6095, -0.1002, -0.6092],
          [-0.9798, -1.6091, -0.7121,  0.3037, -0.7773, -0.2515],
          [-0.2223,  1.6871,  0.2284,  0.4676, -0.6970, -1.1608],
          [ 0.6995,  0.1991,  0.1991,  0.0457,  0.1530, -0.4757],
          [-1.8821, -0.7765,  2.0242, -0.0865,  2.3571, -1.0373],
          [ 1.5748, -0.6298,  2.4070,  0.2786,  0.2468,  1.1843]]]])
roi pool: 
tensor([[[[1.6871, 0.4676],
          [2.0242, 2.3571]]]])

我们再来看一下ROI Align,条件跟上面一样。

此处我们对原图的坐标对feature map的映射不进行取整了,直接得到小数。10/32=0.3125,124/32=3.875。我们将feature map上的每个元素给抽象成下图中的一个个黑点,左上角的坐标就是0,0,那么我们的目标框对应的feature map上的坐标0.3125,0.3125就是蓝色框的左上角的点。目标框对应的feature map上的坐标3.875,3.875就是蓝色框右下角的点。此时我们就将目标框给映射到feature map上了,且是没有进行四舍五入的。此时我们同样要将该蓝色框给降采样成2*2的区域,所以我们将该蓝色区域给四等份。那么我们该如何对每一个四等份区域进行一个输出呢?这里涉及到一个sampling ratio,我们这里取1。我们可以计算出四个等份区域的中心点的坐标,我们以第一个等份区域为例

再使用双线性插值,得到第一个四等份区域的降采样值为

这里的f1、f2、f3、f4是离这个中心点最近的四个黑点的值

,u是中心点距离左边黑边的距离,v是中心点距离上边黑边的距离。最终得到的降采样值为-0.8546。同样第二个四等份中心点坐标为

降采样值为

同样第三个四等份中心点坐标为

降采样值为

同样第四个四等份中心点坐标为

降采样值为

代码语言:javascript
复制
import torch
from torchvision.ops import RoIAlign

if __name__ == '__main__':

    torch.manual_seed(1)
    x = torch.randn((1, 1, 6, 6))
    print(f"feature map: \n{x}")

    proposal = [torch.Tensor([[10, 10, 124, 124]])]
    roi_align = RoIAlign(output_size=2, spatial_scale=1/32, sampling_ratio=1)
    roi = roi_align(x, proposal)
    print(f"roi pool: \n{roi}")

运行结果

代码语言:javascript
复制
feature map: 
tensor([[[[-1.5256, -0.7502, -0.6540, -1.6095, -0.1002, -0.6092],
          [-0.9798, -1.6091, -0.7121,  0.3037, -0.7773, -0.2515],
          [-0.2223,  1.6871,  0.2284,  0.4676, -0.6970, -1.1608],
          [ 0.6995,  0.1991,  0.1991,  0.0457,  0.1530, -0.4757],
          [-1.8821, -0.7765,  2.0242, -0.0865,  2.3571, -1.0373],
          [ 1.5748, -0.6298,  2.4070,  0.2786,  0.2468,  1.1843]]]])
roi pool: 
tensor([[[[-0.8546,  0.3236],
          [ 0.2177,  0.0546]]]])

根据这里,我们可以看到ROI Align中,坐标值在降采样过程中没有取整,它的定位会更加的准确。作者在论文中提到,关于最终的采样结果对采样点位置,以及采样点的个数并不敏感。在源码中使用的sampling ratio=2。

双线性插值

线性插值是指插值函数为一次多项式的插值方式。线性插值的几何意义即为利用过A点和B点的直线来近似表示原函数。线性插值可以用来近似代替原函数,也可以用来计算得到查表过程中表中没有的数值。

那么如上图所示,假设已知y1=f(x1),y2=f(x2),现在要通过线性插值的方式得到区间x1,x2内任何一点的f(x)值。我们很容易得到以下公式

变换可以得到

我们也可以写成

双线性插值,又称为双线性内插。在数学上,双线性插值是有两个变量的插值函数的线性插值扩展,其核心思想是在两个方向分别进行一次线性插值。双线性插值就是分别在两个方向上分别进行一次简单的线性插值即可。

在上图中,每个点的值是由z=f(x,y)的二元函数决定。已知Q11、Q12、Q22、Q21四个点的值,现在要在这四个点中插入一个点P,并算出P点的值。根据上图我们已知Q11、Q12、Q22、Q21四个点的值

在求P点的值之前,首先根据线性插值的方法求得R1、R2的值。对于R1点,可以根据Q11、Q21两个点根据线性插值的办法得到。而Q11和Q21两个点的y值是相同的,所以两点的连线可看作只关于x一个变量的函数。

同理R2的值为

得到R1、R2的插值后,接着我们去计算P点的值。R1、R2两个点的x值是相同的,所以两点的连线可看作只关于y一个变量的函数,通过线性插值公式可得

代入f(R1)、f(R2)后可得

图像处理中的双线性插值

由于Q11、Q12、Q22、Q21四个点是图像中相邻的像素,故有

代入公式可得

我们令

那么有

进一步代入公式得

这就是我们在ROI Align中得到的降采样值的计算公式。

Mask分支

在这张图的右边部分,我们可以看到它进行多任务网络的处理,虽然在进行目标框回归、分类任务和Mask任务都使用了Roi Align,但是这两个ROI是两个不同的ROI,它们不共用ROI Align。在上面的分支中通过ROI Align得到的ROI是7*7的,而下面的分支则是14*14的。因为对于分割任务而言,要求的分割结果精度要更高一些,所以我们需要保留更多的细节信息。所以这里没有池化到7*7大小,而是池化到了14*14,这有助于保留分割更好的结果。

假设这里输入的目标区域大小为H*W*256,那么通过RoiAlign之后被池化成了14*14*256,再依次通过四个卷积层,再通过一个反卷积,得到一个28*28*256的输出,再通过一个1*1的卷积层,得到一个28*28*numclass的数据。也就是说对于每一个类别,我们都去预测了一个蒙版,并且这个蒙版都是一个28*28大小的。作者在论文中提到过,在Mask RCNN中,对预测Mask以及Class进行了解耦。

FCN中针对每一个像素对每一个类别都会预测一个概率分数,我们会针对每一个像素沿它的通道方向去做一个softmax处理,通过softmax处理之后,我们就能得到每一个像素它归属每一个类别的概率分数,这样不同类别之间是存在一个竞争关系的。因为通过softmax之后,每一个像素在通道方向的概率之和为1,对于某一个类别的概率分数大的话,那么其他类别的概率分数肯定就要变小,所以它们是存在竞争关系的。这里Mask与Class是一个耦合的状态。但是在Mask RCNN中是将它们进行了解耦,在之前我们说了会对每一个类别都预测出一个蒙版,但是不会针对每一个数据沿通道方向去做softmax处理,而是根据Faster RCNN分支中预测针对该目标的类别信息将Mask分支当中针对该类别的蒙版给提取出来,然后拿去直接使用。这样类别与类别之间是不存在竞争关系的,因为这里运用的是Faster RCNN分支当中预测的类别信息。这样就实现了Mask与Class解耦的过程。

这里我们可以看到在FCN中,直接使用softmax,也就是Mask与Class是一个耦合的状态,它的AP值只有24.8。而采用解耦的方式,也就是对应sigmoid这一行,它能达到的AP能达到30.3,提升了5.5之多,故在Mask RCNN中对其解耦是非常必要的。

还有一点非常重要的就是,在训练网络的时候,输入Mask分支的目标是由RPN网络提供的,即Proposals,它们全部都是正样本。它是在Faster RCNN分支进行正负样本匹配的时候得到的,也就是说将Proposals输入到Faster RCNN分支中会进行正负样本的匹配,此时就会得知每一个Proposal到底是属于正样本还是负样本,以及这个Proposal所对应的ground truth的类别是什么。这之后才将所有的正样本传递给Mask分支。但是在预测过程当中,输入Mask的目标是由Faster RCNN提供的,不再是RPN网络提供的。

由RPN网络提供的目标边界边框可能并不是那么准确,可能对于一个目标,可能提供了多个目标边界框。由于输入给Mask分支的目标边界框都是正样本,所以它必定跟目标是有交集的。那么这些Proposals都可以提供给Mask分支进行训练。这就相当于扩充了Mask分支训练的样本的个数,有点像随机裁剪数据增强。但是在直接预测的时候是直接采用Faster RCNN的直接输出了,对于最终预测的时候我们只需要最准确的目标边界框,对于Faster RCNN得到的目标可能就只有一个目标边界框,将这个目标输入给Mask分支之后就可以得到一个更加精准的目标分割图了。通过Faster RCNN之后是通过nms(非极大值抑制)过滤掉很多重合的目标边界框,输入给Mask分支的目标也会更少一些,目标少就意味着计算量会更小。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-05-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档