首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >教程 | 先理解Mask R-CNN的工作原理,然后构建颜色填充器应用

教程 | 先理解Mask R-CNN的工作原理,然后构建颜色填充器应用

作者头像
朱晓霞
发布2018-04-18 11:21:39
8560
发布2018-04-18 11:21:39
举报
选自matterport

作者:Waleed Abdulla

机器之心编译

参与:刘晓坤

上年 11 月,matterport 开源了 Mask R-CNN 实现,它在 GitHub 已 fork1400 次,被用于很多项目,同时也获得了完善。作者将在本文中解释 Mask R-CNN 的工作原理,并介绍了颜色填充器的应用案例和实现过程。

  • 代码(包括作者构建的数据集和已训练的模型):https://github.com/matterport/Mask_RCNN/tree/master/samples/balloon

什么是实例分割?

实例分割是一种在像素层面识别目标轮廓的任务,相比其他相关任务,实例分割是较难解决的计算机视觉任务之一:

  • 分类:这张图像中有一个气球。
  • 语义分割:这些全是气球像素。
  • 目标检测:这张图像中的这些位置上有 7 个气球。
  • 实例分割:这些位置上有 7 个气球,并且这些像素分别属于每个气球。

Mask R-CNN

Mask R-CNN 是一个两阶段的框架,第一个阶段扫描图像并生成提议(proposals,即有可能包含一个目标的区域),第二阶段分类提议并生成边界框和掩码。Mask R-CNN 扩展自 Faster R-CNN,由同一作者在去年提出。Faster R-CNN 是一个流行的目标检测框架,Mask R-CNN 将其扩展为实例分割框架。

Mask R-CNN 的主要构建模块:

1. 主干架构

主干网络的简化图示

这是一个标准的卷积神经网络(通常来说是 ResNet50 和 ResNet101),作为特征提取器。底层检测的是低级特征(边缘和角等),较高层检测的是更高级的特征(汽车、人、天空等)。

经过主干网络的前向传播,图像从 1024x1024x3(RGB)的张量被转换成形状为 32x32x2048 的特征图。该特征图将作为下一个阶段的输入。

  • 代码提示:主干网络在 resnet_graph() 函数中。代码支持 ResNet50 和 ResNet101。

特征金字塔网络(FPN)

来源:Feature Pyramid Networks for Object Detection

上述的主干网络还可以进一步提升。由 Mask R-CNN 的同一作者引入的特征金字塔网络(FPN)是对该主干网络的扩展,可以在多个尺度上更好地表征目标。

FPN 通过添加第二个金字塔提升了标准特征提取金字塔的性能,第二个金字塔可以从第一个金字塔选择高级特征并传递到底层上。通过这个过程,它允许每一级的特征都可以和高级、低级特征互相结合。

在我们的 Mask R-CNN 实现中使用的是 ResNet101+FPN 主干网络。

  • 代码提示:FPN 在 MaskRCNN.build() 中创建,位于构建 ResNet 的部分之后。FPN 引入了额外的复杂度:在 FPN 中第二个金字塔拥有一个包含每一级特征的特征图,而不是标准主干中的单个主干特征图(即第一个金字塔中的最高层)。选用哪一级的特征是由目标的尺寸动态地确定的。

2. 区域建议网络(RPN)

展示 49 个 anchor box 的简化图示

RPN 是一个轻量的神经网络,它用滑动窗口来扫描图像,并寻找存在目标的区域。

RPN 扫描的区域被称为 anchor,这是在图像区域上分布的矩形,如上图所示。这只是一个简化图。实际上,在不同的尺寸和长宽比下,图像上会有将近 20 万个 anchor,并且它们互相重叠以尽可能地覆盖图像。

RPN 扫描这些 anchor 的速度有多快呢?非常快。滑动窗口是由 RPN 的卷积过程实现的,可以使用 GPU 并行地扫描所有区域。此外,RPN 并不会直接扫描图像,而是扫描主干特征图。这使得 RPN 可以有效地复用提取的特征,并避免重复计算。通过这些优化手段,RPN 可以在 10ms 内完成扫描(根据引入 RPN 的 Faster R-CNN 论文中所述)。在 Mask R-CNN 中,我们通常使用的是更高分辨率的图像以及更多的 anchor,因此扫描过程可能会更久。

  • 代码提示:RPN 在 rpn_graph() 中创建。anchor 的尺度和长宽比由 config.py 中的 RPN_ANCHOR_SCALES 和 RPN_ANCHOR_RATIOS 控制。

RPN 为每个 anchor 生成两个输出:

  1. anchor 类别:前景或背景(FG/BG)。前景类别意味着可能存在一个目标在 anchor box 中。
  2. 边框精调:前景 anchor(或称正 anchor)可能并没有完美地位于目标的中心。因此,RPN 评估了 delta 输出(x、y、宽、高的变化百分数)以精调 anchor box 来更好地拟合目标。

使用 RPN 的预测,我们可以选出最好地包含了目标的 anchor,并对其位置和尺寸进行精调。如果有多个 anchor 互相重叠,我们将保留拥有最高前景分数的 anchor,并舍弃余下的(非极大值抑制)。然后我们就得到了最终的区域建议,并将其传递到下一个阶段。

  • 代码提示:ProposalLayer 是一个自定义的 Keras 层,可以读取 RPN 的输出,选取最好的 anchor,并应用边框精调。

3. ROI 分类器和边界框回归器

这个阶段是在由 RPN 提出的 ROI 上运行的。正如 RPN 一样,它为每个 ROI 生成了两个输出:

阶段 2 的图示。来源:Fast R-CNN

  1. 类别:ROI 中的目标的类别。和 RPN 不同(两个类别,前景或背景),这个网络更深并且可以将区域分类为具体的类别(人、车、椅子等)。它还可以生成一个背景类别,然后就可以弃用 ROI 了。
  2. 边框精调:和 RPN 的原理类似,它的目标是进一步精调边框的位置和尺寸以将目标封装。
  • 代码提示:分类器和边框回归器已在 fpn_classifier_graph() 中创建。

ROI 池化

在我们继续之前,需要先解决一些问题。分类器并不能很好地处理多种输入尺寸。它们通常只能处理固定的输入尺寸。但是,由于 RPN 中的边框精调步骤,ROI 框可以有不同的尺寸。因此,我们需要用 ROI 池化来解决这个问题。

图中展示的特征图来自较底层。

ROI 池化是指裁剪出特征图的一部分,然后将其重新调整为固定的尺寸。这个过程实际上和裁剪图片并将其缩放是相似的(在实现细节上有所不同)。

Mask R-CNN 的作者提出了一种方法 ROIAlign,在特征图的不同点采样,并应用双线性插值。在我们的实现中,为简单起见,我们使用 TensorFlow 的 crop_and_resize 函数来实现这个过程。

  • 代码提示:ROI 池化在类 PyramidROIAlign 中实现。

4. 分割掩码

到第 3 节为止,我们得到的正是一个用于目标检测的 Faster R-CNN。而分割掩码网络正是 Mask R-CNN 的论文引入的附加网络。

掩码分支是一个卷积网络,取 ROI 分类器选择的正区域为输入,并生成它们的掩码。其生成的掩码是低分辨率的:28x28 像素。但它们是由浮点数表示的软掩码,相对于二进制掩码有更多的细节。掩码的小尺寸属性有助于保持掩码分支网络的轻量性。在训练过程中,我们将真实的掩码缩小为 28x28 来计算损失函数,在推断过程中,我们将预测的掩码放大为 ROI 边框的尺寸以给出最终的掩码结果,每个目标有一个掩码。

  • 代码提示:掩码分支网络在 build_fpn_mask_graph() 中。

建立一个颜色填充过滤器

和大多数图像编辑 app 中包含的过滤器不同,我们的过滤器更加智能一些:它能自动找到目标。当你希望把它应用到视频上而不是图像上时,这种技术更加有用。

训练数据集

通常我会从寻找包含所需目标的公开数据集开始。但在这个案例中,我想向你展示这个项目的构建循环过程,因此我将介绍如何从零开始构建一个数据集。

我在 flickr 上搜索气球图片,并选取了 75 张图片,将它们分成了训练集和验证集。找到图片很容易,但标注阶段才是困难的部分。

等等,我们不是需要数百万张图片来训练深度学习模型吗?实际上,有时候需要,有时候则不需要。我是考虑到以下两点而显著地减小了训练集的规模:

首先,迁移学习。简单来说,与其从零开始训练一个新模型,我从已在 COCO 数据集(在 repo 中已提供下载)上训练好的权重文件开始。虽然 COCO 数剧集不包含气球类别,但它包含了大量其它图像(约 12 万张),因此训练好的图像已经包含了自然图像中的大量常见特征,这些特征很有用。其次,由于这里展示的应用案例很简单,我并不需要令这个模型达到很高的准确率,很小的数据集就已足够。

有很多工具可以用来标注图像。由于其简单性,我最终使用了 VIA(VGG 图像标注器)。这是一个 HTML 文件,你可以下载并在浏览器中打开。标注最初几张图像时比较慢,不过一旦熟悉了用户界面,就能达到一分钟一个目标的速度。

VGG 图像标注器工具的用户界面

如果你不喜欢 VIA 工具,可以试试下列工具,我都测试过了:

  • LabelMe:最著名的标注工具之一,虽然其用户界面有点慢,特别是缩放高清图像时。
  • RectLabel:简单易用,只在 Mac 可用。
  • LabelBox:对于大型标记项目很合适,提供不同类型标记任务的选项。
  • COCO UI:用于标注 COCO 数据集的工具。

加载数据集

分割掩码的保存格式并没有统一的标准。有些数据集中以 PNG 图像保存,其它以多边形点保存等。为了处理这些案例,在我们的实现中提供了一个 Dataset 类,你可以通过重写几个函数来读取任意格式的图像。

VIA 工具将标注保存为 JSON 文件,每个掩码都是一系列多边形点。

  • 代码提示:通过复制 coco.py 并按你的需要修改是应用新数据集的简单方法,我将新的文件保存为 ballons.py。

我的 BalloonDataset 类是这样定义的:

load_balloons 读取 JSON 文件,提取标注,然后迭代地调用内部的 add_class 和 add_image 函数来构建数据集。

load_mask 通过画出多边形为图像中的每个目标生成位图掩码。

image_reference 返回鉴别图像的字符串结果,以进行调试。这里返回的是图像文件的路径。

你可能已经注意到我的类不包含加载图像或返回边框的函数。基础的 Dataset 类中默认的 load_image 函数可以用于加载图像,边框是通过掩码动态地生成的。

验证该数据集

为了验证我的新代码可以正确地实现,我添加了这个 Jupyter notebook:inspect_balloon_data.ipynb。它加载了数据集,并可视化了掩码、边框,还可视化了 anchor 来验证 anchor 的大小是否拟合了目标大小。以下是一个 good example。

来自 inspect_balloon_data notebook 的样本

  • 代码提示:为了创建这个 notebook 我复制了 inspect_data.ipynb(这是为 COCO 数据集写的),然后修改了代码的初始部分来加载 Balloons 数据集。

配置

这个项目的配置和训练 COCO 数据集的基础配置很相似,因此我只需要修改 3 个值。正如我对 Dataset 类所设置的,我复制了基础的 Config 类,然后添加了我的覆写:

基础的配置使用的是 1024x1024 px 的输入图像尺寸以获得最高的准确率。我保持了相同的配置,虽然图像相对较小,但模型可以自动地将它们重新缩放。

  • 代码提示:基础的 Config 类在 config.py 中,BalloonConfig 在 balloons.py 中。

训练

Mask R-CNN 是一个规模很大的模型。尤其是在我们的实现中使用了 ResNet101 和 FPN,因此你需要一个 12GB 显存的 GPU 才能训练这个模型。我使用的是 Amazon P2 实例来训练这个模型,在小规模的数据集上,训练时间不到 1 个小时。

用以下命令开始训练,以从 balloon 的目录开始运行。这里,我们需要指出训练过程应该从预训练的 COCO 权重开始。代码将从我们的 repo 中自动下载权重。

如果训练停止了,用以下命令让训练继续:

  • 代码提示:除了 balloon.py 以外,该 repo 还有两个例子:train_shapes.ipynb,它训练了一个小规模模型来检测几何形状;coco.py,它是在 COCO 数据集上训练的。

检查结果

inspect_balloon_model notebook 展示了由训练好的模型生成的结果。查看该 notebook 可以获得更多的可视化选项,并一步一步检查检测流程。

  • 代码提示:这个 notebook 是 inspect_model.ipynb 的简化版本,包含可视化选项和对 COCO 数据集代码的调试。

颜色填充

现在我们已经得到了目标掩码,让我们将它们应用于颜色填充效果。方法很简单:创建一个图像的灰度版本,然后在目标掩码区域,将原始图像的颜色像素复制上去。以下是一个 good example:

  • 代码提示:应用填充效果的代码在 color_splash() 函数中。detect_and_color_splash() 可以实现加载图像、运行实例分割和应用颜色填充过滤器的完整流程。

FAQ 环节

Q:我希望了解更多该实现的细节,有什么可读的?

A:按这个顺序阅读论文:RCNN、Fast RCNN、Faster RCNN、FPN、Mask RCNN。

Q:我能在哪里提更多的问题?

A:我们的 repo 的 Issue 页面:https://github.com/matterport/Mask_RCNN/issues

原文链接:https://engineering.matterport.com/splash-of-color-instance-segmentation-with-mask-r-cnn-and-tensorflow-7c761e238b46

本文为机器之心编译

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-03-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 目标检测和深度学习 微信公众号,前往查看

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

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

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