《Mask R-CNN》ICCV2017
论文链接:https://arxiv.org/abs/1703.06870
官方代码链接:https://github.com/facebookresearch/Detectron
摘要
Mask R-CNN是一个小巧、灵活的通用对象实例分割框架(object instance segmentation)。它不仅可对图像中的目标进行检测,还可以对每一个目标给出一个高质量的分割结果。该算法在单GPU上的运行速度差不多是5 fps。Mask RCNN沿用了Faster RCNN
的思想,特征提取采用ResNet-FPN
的架构,并行地在bounding box recognition分支上添加一个用于预测目标掩模
(object mask)的新分支。该网络还很容易扩展到其他任务中,比如估计人的姿势,也就是关键点识别(person keypoint detection)。该框架在COCO的一些列挑战任务重都取得了最好的结果,包括实例分割(instance segmentation)、候选框目标检测(bounding-box object detection)和人关键点检测(person keypoint detection)。
一、Faster RCNN
Faster RCNN是两阶段的目标检测算法,包括阶段一的Region proposal以及阶段二的bounding box回归和分类。
Faster RCNN使用CNN提取图像特征,然后使用region proposal network(RPN)去提取出ROI,然后使用ROI pooling将这些ROI全部变成固定尺寸,再喂给全连接层进行Bounding box回归和分类预测。
二、ResNet-FPN
多尺度检测在目标检测中变得越来越重要,对小目标的检测尤其如此。现在主流的目标检测方法很多都用到了多尺度的方法,包括最新的yolo v3。Feature Pyramid Network (FPN)则是一种精心设计的多尺度检测方法,下面就开始简要介绍FPN。
FPN结构中包括自下而上,自上而下和横向连接三个部分,如下图所示。这种结构可以将各个层级的特征进行融合,使其同时具有强语义信息和强空间信息,在特征学习中算是一把利器了。
FPN实际上是一种通用架构,可以结合各种骨架网络使用,比如VGG,ResNet等。Mask RCNN文章中使用了ResNNet-FPN网络结构。如下图:
自下而上
从下到上路径。可以明显看出,其实就是简单的特征提取过程,和传统的没有区别。具体就是将ResNet作为骨架网络,根据feature map的大小分为5个stage。stage2,stage3,stage4和stage5各自最后一层输出conv2,conv3,conv4和conv5分别定义为 [C2,C3,C4,C5] ,他们相对于原始图片的stride是{4,8,16,32}。需要注意的是,考虑到内存原因,stage1的conv1并没有使用。
自上而下和横向连接
自上而下是从最高层开始进行上采样,这里的上采样直接使用的是最近邻上采样
,而不是使用反卷积操作,一方面简单,另外一方面可以减少训练参数。横向连接则是将上采样的结果和自底向上生成的相同大小的feature map进行融合。具体就是对 [C2,C3,C4,C5] 中的每一层经过一个conv 1x1操作(1x1卷积用于降低通道数),无激活函数操作,输出通道全部设置为相同的256通道,然后和上采样的feature map进行加和
操作。在融合之后还会再采用3*3的卷积核对已经融合的特征进行处理,目的是消除上采样的混叠效应(aliasing effect)。
实际上,上图少绘制了一个分支:M5经过步长为2的max pooling下采样得到 P6,作者指出使用P6是想得到更大的anchor尺度512×512。但P6是只用在 RPN中用来得到region proposal的,并不会作为后续Fast RCNN的输入。
总结一下,ResNet-FPN作为RPN输入的feature map是 ,而作为后续Fast RCNN的输入则是
三、ResNet-FPN+Fast RCNN
将ResNet-FPN和Fast RCNN进行结合,实际上就是Faster RCNN的了,但与最初的Faster RCNN不同的是,FPN产生了特征金字塔 ,而并非只是一个feature map。金字塔经过RPN之后会产生很多region proposal。这些region proposal是分别由 经过RPN
产生的,但用于输入到Fast RCNN中的是 ,也就是说要在 中根据region proposal切出ROI进行后续的分类和回归预测。问题来了,我们要选择哪个feature map来切出这些ROI区域呢?实际上,我们会选择最合适的尺度的feature map来切ROI。具体来说,我们通过一个公式来决定宽 w 和 高 h 的 ROI
到底要从哪个来切:
224是ImageNet的标准输入,k0是基准值,设置为5,代表P5层的输出(原图大小就用P5层),w和h是ROI区域的长和宽,假设ROI是112 * 112的大小,那么k = k0-1 = 5-1 = 4,意味着该ROI应该使用P4的特征层。k值应该会做取整处理,防止结果不是整数。
然后,因为作者把conv5也作为了金字塔结构的一部分,那么从前全连接层的那个作用怎么办呢?这里采取的方法是增加两个1024维的轻量级全连接层,然后再跟上分类器和边框回归,认为这样还能使速度更快一些。
这种做法很合理,大尺度的ROI要从低分辨率的feature map上切,有利于检测大目标,小尺度的ROI要从高分辨率的feature map上切,有利于检测小目标。
四、ResNet-FPN+Fast RCNN+mask
我们再进一步,将ResNet-FPN+Fast RCNN+mask,则得到了最终的Mask RCNN,如下图:
Mask RCNN的构建很简单,只是在ROI pooling(实际上用到的是ROIAlign
,后面会讲到)之后添加卷积层,进行mask预测的任务。
下面总结一下Mask RCNN的网络:
- 骨干网络
ResNet-FPN
,用于特征提取,另外,ResNet还可以是:ResNet-50,ResNet-101,ResNeXt-50,ResNeXt-101; - 头部网络,包括边界框识别(分类和回归)+mask预测。头部结构见下图:
第二个分支对每一个感兴趣区域(Region of Interest,RoI)预测分割掩模,它利用了一个小的全卷积网络
结构[2](Fully Convolutional Network,FCN)
为了产生对应的Mask,文中提出了两种架构,即左边的Faster R-CNN/ResNet和右边的Faster R-CNN/FPN,如下图所示。
对于左边的架构,我们的backbone使用的是预训练好的ResNet,使用ResNet倒数第4层的网络。输入的ROI首先获得7x7x1024的ROI feature,然后将其升维到2048个通道(这里修改了原始的ResNet网络架构),然后有两个分支,上面的分支负责分类和回归,下面的分支负责生成对应的mask。由于前面进行了多次卷积和池化,减小了对应的分辨率,mask分支开始利用反卷积进行分辨率的提升,同时减少通道的个数,变为14x14x256,最后输出了14x14x80的mask模板。
而右边使用到的backbone是FPN网络,这是一个新的网络,通过输入单一尺度的图片,最后可以对应的特征金字塔,如果想要了解它的细节,请参考该链接。得到证实的是,该网络可以在一定程度上面提高检测的精度,当前很多的方法都用到了它。由于FPN网络已经包含了res5,可以更加高效的使用特征,因此这里使用了较少的filters。该架构也分为两个分支,作用于前者相同,但是分类分支和mask分支和前者相比有很大的区别。可能是因为FPN网络可以在不同尺度的特征上面获得许多有用信息,因此分类时使用了更少的滤波器。而mask分支中进行了多次卷积操作,首先将ROI变化为14x14x256的feature,然后进行了5次相同的操作(不清楚这里的原理,期待着你的解释),然后进行反卷积操作,最后输出28x28x80的mask。即输出了更大的mask,与前者相比可以获得更细致的mask。
五、ROI Align(重点)
实际上,Mask RCNN中还有一个很重要的改进,就是ROIAlign
。Faster R-CNN存在的问题是:特征图与原始图像是不对准的(mis-alignment),所以会影响检测精度。而Mask R-CNN提出了RoIAlign的方法来取代ROI pooling,RoIAlign可以保留大致的空间位置。
为了讲清楚ROI Align,这里先插入两个知识,双线性插值和ROI pooling。
1.双线性插值
在讲双线性插值之前,还得看最简单的线性插值。
线性插值
双线性插值双线性插值本质上就是在两个方向上做线性插值。双线性插值是一种比较好的图像缩放算法,它充分的利用了原图中虚拟点(比如20.56这个浮点数,像素位置都是整数值,没有浮点值)四周的四个真实存在的像素值来共同决定目标图中的一个像素值,即可以将20.56这个虚拟的位置点对应的像素值估计出来
2.ROIpoolingROI pooling就不多解释了,直接通过一个例子来形象理解。假设现在我们有一个8x8大小的feature map,我们要在这个feature map上得到ROI,并且进行ROI pooling到2x2大小的输出。
将它划分为2x2的网格,因为ROI的长宽除以2是不能整除的,所以会出现每个格子大小不一样的情况。
进行max pooling的最终2x2的输出为:
3. ROI Align
在Faster RCNN中,有两次整数化的过程:
- RPN网络会提出若干RoI的坐标以[x,y,w,h]表示,通常是小数,但是为了方便操作会把它整数化。
- 将整数化后的边界区域平均分割成 k x k 个单元,对每一个单元的边界进行整数化。
两次整数化的过程如下图所示:
事实上,经过上述两次整数化,此时的候选框已经和最开始回归出来的位置有一定的偏差,这个偏差会影响检测或者分割的准确度。由于分类问题对平移问题比较鲁棒,所以影响比较小。但是这在预测像素级精度的掩模时会产生一个非常的大的负面影响。在论文里,作者把它总结为“不匹配问题”(misalignment)。
为了解决这个问题,ROI Align方法取消整数化操作,保留了小数,使用以上介绍的双线性插值的方法获得坐标为浮点数的像素点上的图像数值。但在实际操作中,ROI Align并不是简单地补充出候选区域边界上的坐标点,然后进行池化,而是重新进行设计。
下面通过一个例子来讲解ROI Align操作。如下图所示,虚线部分表示feature map,实线表示ROI,这里将ROI切分成2x2的单元格。如果采样点数是4,那我们首先将每个单元格子均分成四个小方格(如红色线所示),每个小方格中心就是采样点。这些采样点的坐标通常是浮点数,所以需要对采样点像素进行双线性插值(如四个箭头所示,由4个点处的像素值进行插值估计),就可以得到采样点所对应的像素值了。然后对每个单元格内的四个采样点进行maxpooling,就可以得到最终的ROIAlign的结果。
需要说明的是,在相关实验中,作者发现将采样点设为4会获得最佳性能,甚至直接设为1在性能上也相差无几。事实上,ROI Align 在遍历取样点的数量上没有ROIPooling那么多,但却可以获得更好的性能,这主要归功于解决了misalignment的问题。我们注意到,只要不进行量化,结果对精确的采样位置或采样的多少点并不敏感。ROIPooling和ROIAlign对比处理流程如下:
六、损失
在训练阶段,作者对于每个采样的RoI
定义一个多任务损失函数
Mask(每个类别使用sigmoid输出,即逐像素的sigmoid)。需要注意的是,计算loss的时候,并不是每个类别的sigmoid输出都计算二值交叉熵损失,而是该像素属于哪个类,哪个类的sigmoid输出才要计算损失
(如图红色方形所示),定义为平均二值交叉熵损失(the average binary cross-entropy loss)。即对于一个属于第k个类别的RoI,Lmask仅仅考虑第k个mask(其他的掩模输入不会贡献到损失函数中)
。这样的定义会允许对每个类别都会生成掩模,并且不会存在类间竞争。并且在测试的时候,我们是通过分类分支预测的类别来选择相应的mask预测。这样,mask预测和分类预测就彻底解耦了。
将掩模预测和分类预测拆解
该框架对每个类别独立地预测一个二值掩模,没有引入类间竞争,每个二值掩模的类别依靠网络RoI分类分支给出的分类预测结果。这与FCNs方法是不同,FCNs是对每个像素进行多类别softmax分类,然后计算交叉熵损失,很明显,这种做法是会造成类间竞争的,而每个类别使用sigmoid输出并计算二值损失,可以避免类间竞争。实验表明,通过这种方法,可以较好地提升性能。
实验结果
参考(感谢):
(推荐)
https://zhuanlan.zhihu.com/p/37998710 https://zhuanlan.zhihu.com/p/31426458 https://zhuanlan.zhihu.com/p/25954683