Mask-RCNN
本文主要记录个人在学习Mask-RCNN算法中的个人理解。
摘要
Mask-RCNN1(是一个实例分割(Instance segmentation)算法,当然也能用在语义分割中,这两个目标分割的小领域的区别可以从下图中看出,实例分割将同种类的每个物品都区分开来,故其相对于语义分割要做更多的区分。
由于Mask-RCNN算法的特点,其在保持高速、高准确率的同时还可以做不同的调整修改(整个网络可以看成多种不同功能的网络拼接而成,可以按照需求添加修改不同的模块),以用到各种其他不同的任务中,比如目标检测、语义分割、关键点检测等等。
算法细节
上图是Mask-RCNN的结构示意图,具体来自一篇后续的综述文章(DOI:10.1109/ACCESS.2019.2956508)。其实Mask-RCNN的算法实现思路非常直接简单,针对目标检测算法Faster-RCNN加入语义分割算法FCN,使得完成目标检测的同时也得到语义分割的结果,算法对Faster-RCNN的一些细节做了调整,最终的组成部分是RPN + ROIAlign + Fast-rcnn + FCN。所以要了解Mask-RCNN的细节就需要了解RCNN、Fast-RCNN、Faster-RCNN这一系列算法的实现过程,下面是这一系列算法用在Mask-RCNN中的部分,按照Mask-RCNN数据计算的前后顺序整理。
主干结构(backbone)
和前作Faster RCNN一样,Mask RCNN的第一部分是一个标准的CNN卷积网络(一般是ResNet50或者ResNet101),目的用来提取图像中的信息。除此之外,Mask-RCNN还使用了FPN(Feature Pyramid Networks 特征金字塔网络)来提升网络的性能。
CNN
CNN算法可以说是深度学习在图像领域的基础,其思想脱胎于卷积的思想,目的是提取图像(一个大的2D矩阵)中的信息。CNN网络结构一般是卷积层和池化层交替出现,卷积网络类似下图所示,这里在矩阵外圈补0以使输入输出矩阵大小一致(具体网络是否补0或是否间隔由CNN所处理的问题而定)。
残差结构
为提高准确度一般使用ResNet残差网络来实现多层预测。使用残差块可以使得当CNN层数增加时,准确度也随之增加结果不会变差。一般的残差结构如下图所示,其核心思想非常简单,即为一般的卷积计算输出增加一个直接相连的输入项,将网络计算结果与输入相加后作为整体输出。
最初ResNet残差网络是针对ImageNet图像分类数据集设计的,原文使用也是后来其他模型常用的几种架构如下:
前文Mask-RCNN结构图中所使用的ResNet 50/101就是常用的两种残差网络结构。
FPN
FPN(Feature Pyramid Networks)意为特征金字塔网络2,其设计目标比较好理解,早期CNN的设计最终目标是图像分类,具体在使用时一般卷积层池化层交替使用,这样可以大幅削减计算开支,但如果将CNN用作实例分割的第一步,会出现一个明显的弊端,矩阵长宽尺寸变小后会丢失大量的像素级信息,从而导致实例分隔的边界准确度大大降低。因此为提高预测精度,需要使用一些前面中间层的输出。
下图是FPN的基本结构,具体思想是将尺寸小但特征信息多的层做反卷积与尺寸大但特征提取得少的前几层结果做融合,将整合后的数据做后续预测。在相加前,原CNN中间层做了
从图中我们还可以得到另外的一些信息,FPN会输出多个结果,这些结果的大小依次差距2倍,将这些结果分别输入到下一步的RPN网络结构中,同一张图片的各个输出结果可以共享后续的检测框参数(经作者测试,各个结果使用单独的检测框精度相差不大,而共享参数可以大幅减少计算量)
RPN
RPN(Region Proposal Network)的主要功能是产生物品检测框。相对于传统方法,RPN生成检测框的速度大大提高,这也是Faster RCNN/Mask RCNN的重要优势,能极快又准地实现预测。
RPN的核心操作是根据特征图按照一定规律生成一系列锚框(anchor box),假设特征图的尺寸为
根据上述操作,我们生成了大量的锚框,忽略掉跨越边界的锚框后一般仍有几千至几万个,这些锚框对应的候选框之间存在着大量的重叠,RPN采用非极大至抑制的方法,IoU设置为0.7,这样候选框数量大致可以减少到两千个。在这些锚框中进行初步筛选得到固定数量(256个)的锚框用于后续计算,为使得数据平衡,这些锚框中正样本与负样本(背景)的数量要大致相当。
在得到这些锚框后,RPN中还需要完成两项工作,首先判断这个锚框中是否存在待识别的物体,这是一个二分类问题,第二项工作是怎样调整锚框才能使得其和真实值更接近。观察整个RPN网络的具体结构,可以看到RPN网络可以分为两部分,分别用来解决这两个问题:计算分类误差损失以及边界框回归损失。第一部分的输出是一个大小为
ROI
ROI意为Region of Interest 即感兴趣的区域。从Mask-RCNN的架构可以看出,ROI有两部分输入,第一部分是由backbone生成的特征图像(feature map),另一部分是由RPN生成的检测框(proposal),ROI这一部分的主要职责就是把生成的检测框对应到特征图像上。
RoIPooling
RoIPooling是Faster-RCNN提取特征的模块。整个RoIPooling可以分成前后两步,第一步将候选框缩放到特征层上,对于非整数的情况四舍五入取整。第二步操作类似MaxPooling,将刚得到的区域缩放到一个预定义的大小(比如
RoIAlign
RoIAlign是Mask-RCNN对RoIPooling的改进,也是用于提取特征,主要是针对RoIPooling中的取整操作带来的误差(misalignment)。ROIPooling主要有两部分取整带来的误差,第一个是候选框对应到特征层上时的取整,第二个是区域缩放时不能整除时对边界的取整。RoIAlign主要就是对这两个地方进行优化,对于没有落在真实像素点的计算,不再取整改用最近的四个点进行双线性插值。下面是Mask-RCNN原论文中RoIAlign的示意图,保留每一步的计算精度不取整直至最后,利用双线性插值计算每个子区域四个点,比较出最大值作为这一部分的输出(最终的采样结果对采样点位置以及采用点个数并不敏感,所以一般都直接使用四个采样点)。
误差损失计算
经过RoI处理后的特征矩阵一般有确定大小(原论文是
类别损失
第一种输出种类类别的预测器非常简单,与普通的CNN模型后面类似,一系列全连接层激活函数层最后加一层softmax层预测各个种类的概率,损失函数使用的是多类别的交叉熵损失函数。
边界框回归损失
第二部分损失是用来物品边界框回归器用来计算边界框的损失。对于每种类别的候选边界框有4个回归参数:
Mask损失
第三部分损失是物品准确边界的计算损失。在这一部分中, Mask-RCNN中选取了FCN算法作为Mask的预测方法。FCN算法可以对任意大小的矩阵做像素级分类,具体的算法细节可以参考先前的博文。
其实,在Mask分支计算损失时,模型有两种不同的结构,上面介绍的是更直接的更易于理解的第一种结构,下面是结果准确度更高更常用的第二种结构。两种结构的对比如图所示: 可以看到第二种方法针对Mask使用了不同的RoI,这样Mask使用的RoI输出大小更大,预测可以做的更精细。 另外,Mask分支在训练和预测时也有一些小差异,训练网络时的目标是由RPN提供的(Proposal),但在预测时的目标是由其他两个分支(Faster-RCNN)提供的,这样做辅助提高了训练模型的能力以及预测的准确度(RPN提供的类别都是准确的正样本但是完整边界不准确,而预测时Faster-RCNN提供的边界是准确的)。
总损失
其实Mask-RCNN的扩展性非常强,模型结构可以按照具体的问题进行调整,比如在关键点检测中,就可以像Mask分支一样再并联一个关键点检测分支。最后的整体误差损失是各个部分的损失加在一起,对于标准的Mask-RCNN,总损失有5部分:类别误差、回归框误差、Mask预测误差、RPN类别误差损失、RPN边界框误差损失,将这些误差损失求和就是整体误差,用来训练评估模型。
Pytorch 实现
Mask-rcnn算法在torch vision中有直接实现,可以直接引用使用在自己的工作中。(此部分代码源码写的很好,有兴趣可以去查看一下有帮助我们加深理解。) 1
2import torchvision
model = torchvision.models.detection.maskrcnn_resnet50_fpn(weights=MaskRCNN_ResNet50_FPN_Weights.DEFAULT)
当然,如果有更复杂的定制需求,可以使用facebook基于pytorch专门用于图像识别检测的代码库detectron2(也是原论文作者代码的官方维护升级版)。
Mask RCNN原始论文https://arxiv.org/abs/1703.06870↩
FPN特征金字塔原文链接https://arxiv.org/abs/1612.03144↩
ROI Pooling示例动图来源:https://deepsense.ai/region-of-interest-pooling-explained/↩