之前看了Google官网的object_dectect 的源码,感觉Google大神写的还不错。最近想玩下Mask RCNN,就看了下源码,这里刚好当做总结和梳理。链接如下:
Google官网的object_dectect:https://github.com/tensorflow/models/tree/master/research/object_detection
Mask RCNN: https://github.com/matterport/Mask_RCNN
一个使用tensorflow 写的,一个是用keras写的,我自己是对tensorflow 会熟悉,但是kearas没用过,不过不影响看代码哈。有个比较困惑的地方,
好像我记得faster rcnn 中的rpn网络first stage的loss是proposals 和 gt_box的loss,而mask rcnn 是调出来进入第二步骤的正样本的proposals 和对应gt_box的loss,
虽然实际training中可能结果是一样的(我们一般会设置一个比较大的值,使得图像中所有的正样本都被框中,且进入second stage training).恩,废话不多说,开始
写mask rcnn 的源码阅读理解啦。这里简单的梳理下数据流向,就是图像被处理的一个个步骤,不过得对faster rcnn 和 fpn两个网络有所了解才好。
(一般阅读代码,使用py的文件比较多,进入函数,单步调试之类的,mask rcnn的例子都是ipynb,一般调成.py,在pycharm上单步调试。)
简而言之,mask rcnn 使用的是faster rcnn 的框架,和使用fpn的网络提取特征,在这个基础上增加了mask的预测。
事前准备:
训练数据 image
数据label:关于image的目标分割图
label的特征是对目标可以分割出来
然后,处理流程是这样的:
输入一张图,然后进入使用fpn网络提取特征,基本特征网络结构是resnet,框架是fpn的金字塔结构,如下图:
简要介绍是:
1-卷积过程:
一张图进入,resnet 不是有4个block,每个block提取的特征输出保存住,构成list [ c2,c3,c4,c5],代码如下:
2-上采样过程
将顶端的c5进行上采样,生成list [p2,p3,p4,p5,p6],其中p6是通过p5,加一次池化polling得到的。代码如下:
得到以后,first stage 和second stage的公共部分就得到啦,现在要分别处理了哦:
然后,就是两个过程,一个是 rpn过程,一个是mrcnn过程:
1-rnp过程:
rpn做啥???全称是Region Proposal Network,就是生成目标的矩形块,在faster rcnn中,只有一个feature map最终
的输出作为rpn的输入,就是 一个feature map 加上几层卷积,fully connect network ,然后就输出了rpn_bbox,rpn_prob,rpn_logit,
代码如下,输入的 x就是feature map
然而!!!,fpn网络是有多个 feature map 作为支撑输出 rpn的,所有作者这里就 把rpn网络包装成一个model,然后,
rpn_feature_map 中有的p2,p3,p4,p5,p6,一个个输入,再一个个输出,就可以的得到不同尺度的proposals box:
包装成model:
一个个提取proposals box:
这时候我们肯定会有疑问啦,不同尺寸的bbox可以放在一起吗?答案是可以的,因为,他们是归一化以后的,就像1/2 =2/4,一个样子。
接下来怎么办?,rpn还没有结束,rpn要变成roi,就是生成的框还要挑选下,变成生成的框+感兴趣的框(interest),所以要进入nms:
这里有几点要注意,就是rpn网络预测的实际上不是 object bbox,而是基于anchor的deata,就是图片中本来就有bbox(anchor),rpn预测的只是
这些anchor 离object 的bbox的中心偏差多少,长宽比偏差多少?示意图如下:
这里的rpn讲的不错:http://www.cnblogs.com/dudumiaomiao/p/6560841.html
到此,first stage 基本结束,其实first stage做的是将目标找出来(不管目标是哪一个类别),接下来就是生成first stage rpn 和 anchor 一起生成bbox的过程(在Google object detection 代码中
这个过程叫做解码,把bbox信息解码出来):
自此,first stage 暂时到这里,就是输出了 bbox proposals ,object_classifier_prob,(目的是是否目标)
2-mrcnn过程:
对于DEtectionTargetLayer 这个函数对于:功能是
1、通过first stage 生成的proposals 和gt_box计算出iou矩阵 ,并通过iou值,取(crop)出正样本的feature map 和负样本的feature map (
为什么这么搞,因为后期训练需要正负样本才能训练,如果全是正样本那就模型失效啦,为什么coco数据集是默认0.33正样本,因为其实我们
经常识别的目标在场景中都是占的比例是较少的,所以这里训练时给个经验值让正样本偏少些,但是正负样本比例不能差距太大,不然就训练
不收敛,假如0.1,则不训练随机猜测为负样本的准确率都有90%),其中正负样本比例通过config.ROI_POSITIVE_RATIO设置。
代码如下:
同时通过proposals和gt_box的偏差获得mask的偏差
这里大家可能有疑问:不是得用image height和width吗?为什么这里分母是:gt_h,gt_w,且mask又是怎样的一个形式。在config中有一个
配置项:config.USE_MINI_MASK,这个配置项目默认值是True,目的是为了在存储使用mask的时候使用小mask,也就是以object的bbox
为height和width(这样多余的0就不需要存储了)。所以就有了上面的gt_h,gt_w,当时看到这里的时候在想,不是得用image height和width
吗?后面看到 if config.USE_MINI_MASK就明白啦。
这里再多说两句,关于mask又是怎样的一个形式:
我们使用load_mask()函数,输出的是一个个和图像一样大小的mask,且该图像中有多少个目标,就mask就有多少个channal,一个目标
一个channal,用以后期提取bbox方便。然后,config.USE_MINI_MASK = True,就会再配置
这样,一张和图片同样大小的mask输入后,先将目标的bbox提取出来,再从大图片中crop出目标,然后在resize到(56*56),这样就节省
内存啦。
至此,准备工作做好了,接下来就是要求出每个proposals的类别(是人,还是自行车。。。。),并refine bbox和预测mask.
接下来讲两个函数,一个是fpn_classifier_graph,一个是build_fpn_mask_graph。前面的是对proposals中预测类别,后面的是预测mask,输入的都是
mrcnn_featur_map.
2、通过fpn_classifier_graph,
(更新)这里有个挺有趣的,就是,我们得到proposals后,要获得目标的feature map 信息,但是
我们的特征是 金字塔的(pyramid)的,从哪个图层crop下来呢?这里就有一个根据你的框的大小定位到一个图层的计算公式:
具体公式看fpn 那篇论文,表达的是框越小,level 越小,(目标小,level低的图层保留信息较完善,所以crop level低的图层)
目标识别的传统操作,输出logits,probs,bbox。
2、通过buil_fpn_mask_grph,都是传统操作,卷积、fully connect,输出想要的结果:
至此,程序就差不多结束啦,后面就是loss了:
(更新)对于loss的简要介绍:
rpn_class_loss_graph:是 在rpn阶段识别的前景/背景的loss计算,这种分类的一般是交叉熵loss,见下:
:这个是rpn bbox loss,有一个trick 就是,这里只统计偏差(diff,见下面代码)比例小于1的,因为大于1的没有必要
就像faster rcnn选择iou > 0.7,为正样本,小于0.3的为负样本,当偏差大于1的时候,距离太远了,iou肯定是小的,这种loss不计算在内:
:同样的,对于类别分类使用交叉熵,这里就不给出了。
:使用l1 loss 为什么和上面不一样呢?实际和rpn bbox 差不多,就是取差值
:使用的是binary 交叉熵,做损失统计,我记得之前传统的分割方法,比如(
FC-DenseNet56)等,使用的loss是cross_entropy 有,还有一种是lovasz
Q/A(更新):
1、mask cnn引入预测K个输出的机制,允许每个类都生成独立的掩膜,避免类间竞争。这样做解耦了掩膜和种类预测,这句话的理解?
嗯,其实就是对于一个目标(或proposal)都生成number_classes 的mask,然后,只有与预测相一致类别的mask才会对loss有贡献,
并且,使用binary cross-entropy loss (具体是tf.nn.sigmoid_cross_entropy_with_logits)进行训练,这和传统的图像分割不一样,传统的图像经过fcn网络在像素级上分割,每个像素进行分类,这样就会导致类间的区域竞争,最后识别分割的结果出现颗粒感比较重的感觉,fcn使用的loss计算是SoftmaxLoss(具体是:tf.nn.softmax_cross_entropy_with_logits)。其实,binary cross-entropy loss常用在2分类,SoftmaxLoss是在多分类的,基本计算loss的原理都差不多,都是和ground truth的差(或“距离”)。
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
最最后面放一下我的笔记,按我的建议是不建议大家看的,主要目的是笔记本的笔记容易丢,放在网上看的时候方便,给我自己看的哈(字漂,一般人都看不懂!)