mask rcnn 召回率_[代码解析]Mask R-CNN介绍与实现(转)

本文详细介绍了Mask R-CNN的工作原理,包括其在Faster R-CNN基础上增加的掩膜分支,多任务损失函数,RoIAlign层的作用,以及在实际操作中的数据预处理步骤。此外,还提供了代码解析,展示了如何使用预训练模型进行实例分割,并探讨了模型的优缺点和应用场景。
摘要由CSDN通过智能技术生成

52af9fb2d559a2eed57e279ad8a7eadc.png

简介

代码源于matterport的工作组,可以在github上fork它们组的工作。

软件必备

复现的Mask R-CNN是基于Python3,Keras,TensorFlow。

Python 3.4+

TensorFlow 1.3+

Keras 2.0.8+

Jupyter Notebook

Numpy, skimage, scipy

建议配置一个高版本的Anaconda3+TensorFlow-GPU版本。

Mask R-CNN论文回顾

Mask R-CNN(简称MRCNN)是基于R-CNN系列、FPN、FCIS等工作之上的,MRCNN的思路很简洁:Faster R-CNN针对每个候选区域有两个输出:种类标签和bbox的偏移量。那么MRCNN就在Faster R-CNN的基础上通过增加一个分支进而再增加一个输出,即物体掩膜(object mask)。

先回顾一下Faster R-CNN, Faster R-CNN主要由两个阶段组成:区域候选网络(Region Proposal Network,RPN)和基础的Fast R-CNN模型。

RPN用于产生候选区域

b19981e97e0d322b0cda8361fd9953c5.png

Fast R-CNN通过RoIPool层对每个候选区域提取特征,从而实现目标分类和bbox回归

30030523d58c4a37660289623ed5d3d4.png

MRCNN采用和Faster R-CNN相同的两个阶段,具有相同的第一层(即RPN),第二阶段,除了预测种类和bbox回归,并且并行的对每个RoI预测了对应的二值掩膜(binary mask)。示意图如下:

73f58e8c11b985d440169bd3cb1f437f.png

这样做可以将整个任务简化为mulit-stage pipeline,解耦了多个子任务的关系,现阶段来看,这样做好处颇多。

主要工作

损失函数的定义

依旧采用的是多任务损失函数,针对每个每个RoI定义为

L=Lcls+Lbox+LmaskL=Lcls+Lbox+LmaskLcls,LboxLcls,Lbox与Faster R-CNN的定义类似,这里主要看LmaskLmask。

掩膜分支针对每个RoI产生一个Km2Km2的输出,即K个分辨率为m×mm×m的二值的掩膜,KK为分类物体的种类数目。依据预测类别分支预测的类型ii,只将第ii的二值掩膜输出记为LmaskLmask。

掩膜分支的损失计算如下示意图:

mask branch 预测KK个种类的m×mm×m二值掩膜输出

依据种类预测分支(Faster R-CNN部分)预测结果:当前RoI的物体种类为ii

第ii个二值掩膜输出就是该RoI的损失LmaskLmask

9e53634782148cd3b40aae94f37be6b6.png

对于预测的二值掩膜输出,我们对每个像素点应用sigmoid函数,整体损失定义为平均二值交叉损失熵。

引入预测KK个输出的机制,允许每个类都生成独立的掩膜,避免类间竞争。这样做解耦了掩膜和种类预测。不像是FCN的方法,在每个像素点上应用softmax函数,整体采用的多任务交叉熵,这样会导致类间竞争,最终导致分割效果差。

掩膜表示到RoIAlign层

在Faster R-CNN上预测物体标签或bbox偏移量是将feature map压缩到FC层最终输出vector,压缩的过程丢失了空间上(平面结构)的信息,而掩膜是对输入目标做空间上的编码,直接用卷积形式表示像素点之间的对应关系那是最好的了。

输出掩膜的操作是不需要压缩输出vector,所以可以使用FCN(Full Convolutional Network),不仅效率高,而且参数量还少。为了更好的表示出RoI输入和FCN输出的feature之间的像素对应关系,提出了RoIAlign层。

先回顾一下RoIPool层:

其核心思想是将不同大小的RoI输入到RoIPool层,RoIPool层将RoI量化成不同粒度的特征图(量化成一个一个bin),在此基础上使用池化操作提取特征。

下图是SPPNet内对RoI的操作,在Faster R-CNN中只使用了一种粒度的特征图:

f33061243e7cf2fa4c86a880361f1699.png

平面示意图如下:

e00980170949c7f38ccf23251e7cd70a.png

这里面存在一些问题,在上面量操作上,实际计算中是使用的是[x/16][x/16],1616的量化的步长,[⋅][·]是舍入操作(rounding)。这套量化舍入操作在提取特征时有着较好的鲁棒性(检测物体具有平移不变性等),但是这很不利于掩膜定位,有较大负面效果。

针对这个问题,提出了RoIAlign层:避免了对RoI边界或bin的量化操作,在扩展feature map时使用双线性插值算法。这里实现的架构要看FPN论文:

0cd9a57ec4391cd518a0e8ca97892ad9.png

一开始的Faster R-CNN是基于最上层的特征映射做分割和预测的,这会丢失高分辨下的信息,直观的影响就是丢失小目标检测,对细节部分丢失不敏感。受到SSD的启发,FPN也使用了多层特征做预测。这里使用的top-down的架构,是将高层的特征反卷积带到低层的特征(即有了语义,也有精度),而在MRCNN论文里面说的双线性差值算法就是这里的top-down反卷积是用的插值算法。

总结

MRCNN有着优异的效果,除去了掩膜分支的作用,很大程度上是因为基础特征网络的增强,论文使用的是ResNeXt101+FPN的top-down组合,有着极强的特征学习能力,并且在实验中夹杂这多种工程调优技巧。

但是吧,MRCNN的缺点也很明显,需要大的计算能力并且速度慢,这离实际应用还是有很长的路,坐等大神们发力!

如何使用代码

满足运行环境

Python 3.4+

TensorFlow 1.3+

Keras 2.0.8+

Jupyter Notebook

Numpy, skimage, scipy, Pillow(安装Anaconda3直接完事)

cv2

下载代码

linux环境下直接clone到本地

git clone https://github.com/matterport/Mask_RCNN.git

Windows下下载代码即可,地址在上面

下载模型在COCO数据集上预训练权重(mask_rcnn_coco.h5),下载地址releasses Page.

如果需要在COCO数据集上训练或测试,需要安装pycocotools, clone下来,make生成对应的文件,拷贝下工程目录下即可(方法可参考下面repos内的README.md文件)。

Windows: https://github.com/philferriere/cocoapi. You must have the Visual C++ 2015 build tools on your path (see the repo for additional details)

如果使用COCO数据集,需要:

pycocotools (即第4条描述的)

MS COCO Dataset。2014的训练集数据

COCO子数据集,5K的minival和35K的validation-minus-minival。(这两个数据集下载比较慢,没有贴原地址,而是我的CSDN地址,分不够下载的可以私信我~)

下面的代码分析运行环境都是jupyter。

代码分析-数据预处理

导包

导入的coco包需要从coco/PythonAPI上下载操作数据代码,并在本地使用make指令编译.将生成的pycocotools拷贝至工程的主目录下,即和该inspect_data.ipynb文件同一目录。

import os

import sys

import itertools

import math

import logging

import json

import re

import random

from collections import OrderedDict

import numpy as np

import matplotlib

import matplotlib.pyplot as plt

import matplotlib.patches as patches

import matplotlib.lines as lines

from matplotlib.patches import Polygon

import utils

import visualize

from visualize import display_images

import model as modellib

from model import log

%matplotlib inline

ROOT_DIR = os.getcwd()

# 选择任意一个代码块

# import shapes

# config = shapes.ShapesConfig() # 使用代码创建数据集,后面会有介绍

# MS COCO 数据集

import coco

config = coco.CocoConfig()

COCO_DIR = "/root/模型复现/Mask_RCNN-master/coco" # COCO数据存放位置

加载数据集

COCO数据集的训练集内有82081张图片,共81类。

# 这里使用的是COCO

if config.NAME == 'shapes':

dataset = shapes.ShapesDataset()

dataset.load_shapes(500, config.IMAGE_SHAPE[0], config.IMAGE_SHAPE[1])

elif config.NAME == "coco":

dataset = coco.CocoDataset()

dataset.load_coco(COCO_DIR, "train")

# Must call before using the dataset

dataset.prepare()

print("Image Count: {}".format(len(dataset.image_ids)))

print("Class Count: {}".format(dataset.num_classes))

for i, info in enumerate(dataset.class_info):

print("{:3}. {:50}".format(i, info['name']))

>>>

>>>

loading annotations into memory...

Done (t=7.68s)

creating index...

index created!

Image Count: 82081

Class Count: 81

0. BG

1. person

2. bicycle

...

77. scissors

78. teddy bear

79. hair drier

80. toothbrush

随机找几张照片看看:

# 加载和展示随机几张照片和对应的mask

image_ids = np.random.choice(dataset.image_ids, 4)

for image_id in image_ids:

image = dataset.load_image(image_id)

mask, class_ids = dataset.load_mask(image_id)

visualize.display_top_masks(image, mask, class_ids, dataset.class_names)

9b22c7183cd32a2625e343fd07455f1f.png

4c10d44a8b13fcd3de2a4e631d81ac66.png

e0c8d464dd7d30f683257a2925b82ab1.png

9b2332696f4f5f1897764a9d7b5c45ef.png

Bounding Boxes(bbox)

这里我们不使用数据集本身提供的bbox坐标数据,取而代之的是通过mask计算出bbox,这样可以在不同的数据集下对bbox使用相同的处理方法。因为我们是从mask上计算bbox,相比与从图片计算bbox转换来说,更便于放缩,旋转,裁剪图像。

# Load random image and mask.

image_id = random.choice(dataset.image_ids)

image = dataset.load_image(image_id)

mask, class_ids = dataset.load_mask(image_id)

# Compute Bounding box

bbox = utils.extract_bboxes(mask)

# Display image and additional stats

print("image_id ", image_id, dataset.image_reference(image_id))

log("image", image)

log("mask", mask)

log("class_ids", class_ids)

log("bbox", bbox)

# Display image and instances

visualize.display_instances(image, bbox, mask, class_ids, dataset.class_names)

>>>

>>>

image_id 41194 http://cocodataset.org/#explore?id=190360

image shape: (428, 640, 3) min: 0.00000 max: 255.00000

mask shape: (428, 640, 5) min: 0.00000 max: 1.00000

class_ids shape: (5,) min: 1.00000 max: 59.00000

bbox shape: (5, 4) min: 1.00000 max: 640.00000

8ff3a7f61a364daebe07bc4602c09115.png

调整图片大小

因为训练时是批量处理的,每次batch要处理多张图片,模型需要一个固定的输入大小。故将训练集的图片放缩到一个固定的大小(1024×1024),放缩的过程要保持不变的宽高比,如果照片本身不是正方形,那边就在边缘填充0.(这在R-CNN论文里面论证过)。

需要注意的是:原图片做了放缩,对应的mask也需要放缩,因为我们的bbox是依据mask计算出来的,这样省了修改程序了~

# Load random image and mask.

image_id = np.random.choice(dataset.image_ids, 1)[0]

image = dataset.load_image(image_id)

mask, class_ids = dataset.load_mask(image_id)

original_shape = image.shape

# 调整到固定大小

image, window, scale, padding = utils.resize_image(

image,

min_dim=config.IMAGE_MIN_DIM,

max_dim=config.IMAGE_MAX_DIM,

padding=config.IMAGE_PADDING)

mask = utils.resize_mask(mask, scale, padding) # mask也要放缩

# Compute Bounding box

bbox = utils.extract_bboxes(mask)

# Display image and additional stats

print("image_id: ", image_id, dataset.image_reference(image_id))

print("Original shape: ", original_shape)

log("image", image)

log("mask", mask)

log("class_ids", class_ids)

log("bbox", bbox)

# Display image and instances

visualize.display_instances(image, bbox, mask, class_ids, dataset.class_names)

>>>

>>>

image_id: 6104 http://cocodataset.org/#explore?id=139889

Original shape: (426, 640, 3)

image shape: (1024, 1024, 3) min: 0.00000 max: 255.00000

mask shape: (1024, 1024, 2) min: 0.00000 max: 1.00000

class_ids shape: (2,) min: 24.00000 max: 24.00000

bbox shape: (2, 4) min: 169.00000 max: 917.00000

原图片从(426, 640, 3)放大到(1024, 1024, 3),图片的上下两端都填充了0(黑色的部分):

dd43938254f6f770fd0e6e69318ecec2.png

Mini Mask

训练高分辨率的图片时,表示每个目标的二值mask也会非常大。例如,训练一张1024×1024的图片,其目标物体对应的mask需要1MB的内存(用boolean变量表示单点),如果1张图片有100个目标物体就需要100MB。讲道理,如果是五颜六色就算了,但实际上表示mask的图像矩阵上大部分都是0,很浪费空间。

为了节省空间同时提升训练速度,我们优化mask的表示方式,不直接存储那么多0,而是通过存储有值坐标的相对位置来压缩表示数据的内存,原理和压缩算法差类似。

我们存储在对象边界框内(bbox内)的mask像素,而不是存储整张图片的mask像素,大多数物体相对比于整张图片是较小的,节省存储空间是通过少存储目标周围的0实现的。

将mask调整到小尺寸56×56,对于大尺寸的物体会丢失一些精度,但是大多数对象的注解并不是很准确,所以大多数情况下这些损失是可以忽略的。(可以在config类中设置mini mask的size。)

说白

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值