论文名称:Mask R-CNN
论文下载地址:https://arxiv.org/abs/1703.06870
在阅读本篇博文之前需要掌握Faster R-CNN、FPN以及FCN相关知识。
Faster R-CNN视频讲解:https://www.bilibili.com/video/BV1af4y1m7iL?p=3
FPN视频讲解:https://www.bilibili.com/video/BV1dh411U7D9
FCN视频讲解:https://www.bilibili.com/video/BV1J3411C7zd
Mask R-CNN视频讲解:https://www.bilibili.com/video/BV1ZY411774T
文章目录
Mask R-CNN是2017年发表的文章,一作是何恺明大神,没错就是那个男人,除此之外还有Faster R-CNN系列的大神Ross Girshick,可以说是强强联合。该论文也获得了ICCV 2017的最佳论文奖(Marr Prize)。并且该网络提出后,又霸榜了MS COCO的各项任务,包括目标检测、实例分割以及人体关键点检测任务。在看完这边文章后觉得Mask R-CNN的结构很简洁而且很灵活效果又很好(仅仅是在Faster R-CNN的基础上根据需求加入一些新的分支)。

注意,阅读本篇文章之前需要掌握Faster R-CNN、FPN以及FCN的相关知识,如果不了解可以参考我之前在哔哩哔哩上做的相关视频。
The method, called Mask R-CNN, extends Faster R-CNN by adding a branch for predicting an object mask in parallel with the existing branch for bounding box recognition.
Mask R-CNN是在Faster R-CNN的基础上加了一个用于预测目标分割Mask的分支(即可预测目标的Bounding Boxes信息、类别信息以及分割Mask信息)。

Moreover, Mask R-CNN is easy to generalize to other tasks, e.g., allowing us to estimate human poses in the same framework.
Mask R-CNN不仅能够同时进行目标检测与分割,还能很容易地扩展到其他任务,比如再同时预测人体关键点信息。

Our method, called Mask R-CNN, extends Faster R-CNN by adding a branch for predicting segmentation masks on each Region of Interest (RoI), in parallel with the existing branch for classification and bounding box regression (Figure 1). The mask branch is a small FCN applied to each RoI, predicting a segmentation mask in a pixel-to-pixel manner.
Mask R-CNN的结构也很简单,就是在通过RoIAlign(在原Faster R-CNN中是RoIPool)得到的RoI基础上并行添加一个Mask分支(小型的FCN)。见下图,之前Faster R-CNN是在RoI基础上接上一个Fast R-CNN检测头,即图中class, box分支,现在又并行了一个Mask分支。

注意带和不带FPN结构的Mask R-CNN在Mask分支上略有不同,对于带有FPN结构的Mask R-CNN它的class、box分支和Mask分支并不是共用一个RoIAlign。在训练过程中,对于class, box分支RoIAlign将RPN(Region Proposal Network)得到的Proposals池化到7x7大小,而对于Mask分支RoIAlign将Proposals池化到14x14大小。详情参考原论文中的图4.

Faster R-CNN was not designed for pixel-to-pixel alignment between network inputs and outputs. This is most evident in how RoIPool, the de facto core operation for attending to instances, performs coarse spatial quantization for feature extraction.
在之前的Faster RCNN中,会使用RoIPool将RPN得到的Proposal池化到相同大小。这个过程会涉及quantization或者说取整操作,这会导致定位不是那么的准确(文中称为misalignment问题)。
下面的示意图就是RoIPool的执行过程,其中会经历两次quantization。假设通过RPN得到了一个Proposal,它在原图上的左上角坐标是
(
10
,
10
)
(10,10)
(10,10),右下角的坐标是
(
124
,
124
)
(124,124)
(124,124),对应要映射的特征层相对原图的步距为32,通过RoIPool期望的输出为2x2大小:
Proposal映射到特征层上,对于左上角坐标
10
32
\frac{10}{32}
3210四舍五入后等于0,对于右下角坐标
124
32
\frac{124}{32}
32124四舍五入后等于4,即映射在特征层上的左上角坐标为
(
0
,
0
)
(0,0)
(0,0)右下角坐标为
(
4
,
4
)
(4,4)
(4,4)。对应下图特征层上从第0行到第4行,从第0列到第4列的区域(黑色矩形框)。这是第一次quantization。2x2大小,所以需要将映射在特征层上的Proposal划分成2x2大小区域。但现在映射在特征层上的Proposal是5x5大小,无法均分,所以强行划分后有的区域大有的区域小,如下图所示。这是第二次quantization。maxpool即可得到RoIPool的输出,即
(
1.6871
0.4676
2.0242
2.3571
)
\begin{pmatrix} 1.6871 & 0.4676\\ 2.0242 & 2.3571 \end{pmatrix}
(1.68712.02420.46762.3571)。在2.1章节有对应的Pytorch实验。
To fix the misalignment, we propose a simple, quantization-free layer, called RoIAlign, that faithfully preserves exact spatial locations.
为了解决这个问题,作者提出了RoIAlign方法替代RoIPool,以获得更加精确的空间定位信息。
RoIAlign has a large impact: it improves mask accuracy by relative 10% to 50%, showing bigger gains under stricter localization metrics. Second, we found it essential to decouple mask and class prediction: we predict a binary mask for each class independently, without competition among classes, and rely on the network’s RoI classification branch to predict the category.
作者在文中提到,将RoIPool替换成RoIAlign后,分割的Mask准确率相对提升了10%到50%(见下图d),并且将预测Mask和class进行了解耦,解耦后也带来了很大的提升(见下图b),这个在后面会细讲。

下面的示意图就是RoIAlign的执行过程。同样假设通过RPN得到了一个Proposal,它在原图上的左上角坐标是
(
10
,
10
)
(10,10)
(10,10),右下角的坐标是
(
124
,
124
)
(124,124)
(124,124),对应要映射的特征层相对原图的步距为32,通过RoIAlign期望的输出为2x2大小:
Proposal映射到特征层上,左上角坐标
(
0.3125
,
0.3125
)
(0.3125, 0.3125)
(0.3125,0.3125)(不进行四舍五入),右下角坐标
(
3.875
,
3.875
)
(3.875, 3.875)
(3.875,3.875)(不进行四舍五入)。为了方便理解,将特征层上的每个元素用一个点表示,就能得到图中下方的grid网格。图中蓝色的矩形框就是Proposal(没有quantization)。2x2大小,故将Proposal划分为2x2四个子区域(没有quantization)。接着根据sampling_ratio在每个子区域中设置采样点,原论文中默认设置的sampling_ratio为4,这里为了方便讲解将sampling_ratio设置成1。
这里以第一个子区域为例,因为这里将sampling_ratio设置成为1,所以每个子区域只需要设置一个采样点。第一个子区域的采样点为图中黄色的点(即为该子区域的中心点),坐标为
(
1.203125
,
1.203125
)
(1.203125,1.203125)
(1.203125,1.203125),然后找出离该采样点最近的四个点(即图中用红色箭头标出的四个黑点),然后利用双线性插值即可计算得到采样点对应的输出
−
0.8546
-0.8546
−0.8546(如果不了解双线性插值可参考我之前写的博文),又由于该子区域只有一个采样点,故该子区域的输出就为
−
0.8546
-0.8546
−0.8546。在2.2章节有对应的Pytorch实验。

We note that the results are not sensitive to the exact sampling locations, or how many points are sampled, as long as no quantization is performed.
最后作者在论文中有提到,关于最终的采样结果对采样点位置,以及采样点的个数并不敏感。
实验还是按照前面讲的内容来进行对比。

下面是使用Torchvision库中实现的RoIPool方法,通过对比计算结果和我们刚刚讲的是一样的。
import torch
from torchvision.ops import RoIPool
def main():
torch.manual_seed(1)
x = torch.randn((1, 1, 6, 6))
print(f"feature map: \n{x}")
proposal = [torch.as_tensor([[10, 10, 124, 124]], dtype=torch.float32)]
roi_pool = RoIPool(output_size=2, spatial_scale=1/32)
roi = roi_pool(x, proposal)
print(f"roi pool: \n{roi}")
if __name__ == '__main__':
main()
终端输出:
feature map:
tensor([[[[-1.5256, -0.7502, -0.6540, -1.6095, -0.1002, -0.6092],
[-0.9798, -1.6091, -0.7121, 0.3037, -0.7773, -0.2515],
[-0.2223, 1.6871, 0.2284, 0.4676, -0.6970, -1.1608],
[ 0.6995, 0.1991, 0.1991, 0.0457, 0.1530, -0.4757],
[-1.8821, -0.7765, 2.0242, -0.0865, 2.3571, -1.0373],
[ 1.5748, -0.6298, 2.4070, 0.2786, 0.2468, 1.1843]]]])
roi pool:
tensor([[[[1.6871, 0.4676],
[2.0242, 2.3571]]]])
实验还是按照前面讲的内容来进行对比。

下面是使用Torchvision库中实现的RoIAlign方法,通过对比计算结果和我们刚刚讲的是一样的。
import torch
from torchvision.ops import RoIAlign
def bilinear(u, v, f1, f2, f3, f4):
return (1-u)*(1-v)*f1 + u*(1-v)*f2 + (1-u)*v*f3 + u*v*f4
def main():
torch.manual_seed(1)
x = torch.randn((1, 1, 6, 6))
print(f"feature map: \n{x}")
proposal = [torch.as_tensor([[10, 10, 124, 124]], dtype=torch.float32)]
roi_align = RoIAlign(output_size=2, spatial_scale=1/32, sampling_ratio=1)
roi = roi_align(x, proposal)
print(f"roi align: \n{roi}")
u = 0.203125
v = 0.203125
f1 = x[0, 0, 1, 1] # -1.6091
f2 = x[0, 0, 1, 2] # -0.7121
f3 = x[0, 0, 2, 1] # 1.6871
f4 = x[0, 0, 2, 2] # 0.2284
print(f"bilinear: {bilinear(u, v, f1, f2, f3, f4):.4f}")
if __name__ == '__main__':
main()
终端输出:
feature map:
tensor([[[[-1.5256, -0.7502, -0.6540, -1.6095, -0.1002, -0.6092],
[-0.9798, -1.6091, -0.7121, 0.3037, -0.7773, -0.2515],
[-0.2223, 1.6871, 0.2284, 0.4676, -0.6970, -1.1608],
[ 0.6995, 0.1991, 0.1991, 0.0457, 0.1530, -0.4757],
[-1.8821, -0.7765, 2.0242, -0.0865, 2.3571, -1.0373],
[ 1.5748, -0.6298, 2.4070, 0.2786, 0.2468, 1.1843]]]])
roi align:
tensor([[[[-0.8546, 0.3236],
[ 0.2177, 0.0546]]]])
bilinear: -0.8546
前面有提到,对于带有FPN和不带有FPN的Mask R-CNN,他们的Mask分支不太一样。下图左边是不带FPN结构的Mask分支,右侧是带有FPN结构的Mask分支(灰色部分为原Faster R-CNN预测box, class信息的分支,白色部分为Mask分支)。

由于在我们日常使用中,一般都是使用的带有FPN的网络,所以我自己又手绘了一幅针对带有FPN结构的Mask分支:

之前在讲FCN的时候有提到过,FCN是对每个像素针对每个类别都会预测一个分数,然后通过softmax得到每个类别的概率(不同类别之间存在竞争关系),哪个概率高就将该像素分配给哪个类别。但在Mask R-CNN中,作者将预测Mask和class进行了解耦,即对输入的RoI针对每个类别都单独预测一个Mask,最终根据box, cls分支预测的classes信息来选择对应类别的Mask(不同类别之间不存在竞争关系)。作者说解耦后带来了很大的提升。下表是原论文中给出的消融实验结果,其中softmax代表原FCN方式(Mask和class未解耦),sigmoid代表Mask R-CNN中采取的方式(Mask和class进行了解耦)。

这里还有一个需要注意的细节。在训练网络的时候输入Mask分支的目标是由RPN提供的,即Proposals,但在预测的时候输入Mask分支的目标是由Fast R-CNN提供的(即预测的最终目标)。 并且训练时采用的Proposals全部是Fast R-CNN阶段匹配到的正样本。这里说下我个人的看法(不一定正确),在训练时Mask分支利用RPN提供的目标信息能够扩充训练样本的多样性(因为RPN提供的目标边界框并不是很准确,一个目标可以呈现出不同的情景,类似于围着目标做随机裁剪。从另一个方面来看,通过Fast R-CNN得到的输出一般都比较准确了,再通过NMS后剩下的目标就更少了)。在预测时为了获得更加准确的目标分割信息以及减少计算量(通过Fast R-CNN后的目标数会更少),此时利用的是Fast R-CNN提供的目标信息。
Mask R-CNN的损失就是在Faster R-CNN的基础上加上了Mask分支上的损失,即:
L
o
s
s
=
L
r
p
n
+
L
f
a
s
t
_
r
c
n
n
+
L
m
a
s
k
Loss=L_{rpn}+L_{fast\_rcnn}+L_{mask}
Loss=Lrpn+Lfast_rcnn+Lmask
关于Faster R-CNN的损失计算之前视频里讲过,这里就不在赘述。关于Mask分支上的损失就是二值交叉熵损失(Binary Cross Entropy)。
在讲Mask分支损失计算之前,我们要弄清楚logits(网络预测的输出)是什么,targets(对应的GT)是什么。前面有提到训练时输入Mask分支的目标是RPN提供的Proposals,所以网络预测的logits是针对每个Proposal对应每个类别的Mask信息(注意预测的Mask大小都是28x28)。并且这里输入的Proposals都是正样本(在Fast R-CNN阶段采样得到的),对应的GT信息(box、cls)也是知道的。
如下图所示,假设通过RPN得到了一个Proposal(图中黑色的矩形框),通过RoIAlign后得到对应的特征信息(shape为14x14xC),接着通过Mask Branch预测每个类别的Mask信息得到图中的logits(logits通过sigmoid激活函数后,所有值都被映射到0至1之间)。通过Fast R-CNN分支正负样本匹配过程我们能够知道该Proposal的GT类别为猫(cat),所以将logits中对应类别猫的预测mask(shape为28x28)提取出来。然后根据Proposal在原图对应的GT上裁剪并缩放到28x28大小,得到图中的GT mask(对应目标区域为1,背景区域为0)。最后计算logits中预测类别为猫的mask与GT mask的BCELoss(BinaryCrossEntropyLoss)即可。

这里再次强调一遍,在真正预测推理的时候,输入Mask分支的目标是由Fast R-CNN分支提供的。

如上图所示,通过Fast R-CNN分支,我们能够得到最终预测的目标边界框信息以及类别信息。接着将目标边界框信息提供给Mask分支就能预测得到该目标的logits信息,再根据Fast R-CNN分支提供的类别信息将logits中对应该类别的Mask信息提取出来,即针对该目标预测的Mask信息(shape为28x28,由于通过sigmoid激活函数,数值都在0到1之间)。然后利用双线性插值将Mask缩放到预测目标边界框大小,并放到原图对应区域。接着通过设置的阈值(默认为0.5)将Mask转换成一张二值图,比如预测值大于0.5的区域设置为前景剩下区域都为背景。现在对于预测的每个目标我们就可以在原图中绘制出边界框信息,类别信息以及目标Mask信息。

到此Mask R-CNN的内容就已经全部讲完了,完结,撒花。
我想在Ruby中创建一个用于开发目的的极其简单的Web服务器(不,不想使用现成的解决方案)。代码如下:#!/usr/bin/rubyrequire'socket'server=TCPServer.new('127.0.0.1',8080)whileconnection=server.acceptheaders=[]length=0whileline=connection.getsheaders想法是从命令行运行这个脚本,提供另一个脚本,它将在其标准输入上获取请求,并在其标准输出上返回完整的响应。到目前为止一切顺利,但事实证明这真的很脆弱,因为它在第二个请求上中断并出现错误:/usr/b
网络编程套接字网络编程基础知识理解源`IP`地址和目的`IP`地址理解源MAC地址和目的MAC地址认识端口号理解端口号和进程ID理解源端口号和目的端口号认识`TCP`协议认识`UDP`协议网络字节序socket编程接口`sockaddr``UDP`网络程序服务器端代码逻辑:需要用到的接口服务器端代码`udp`客户端代码逻辑`udp`客户端代码`TCP`网络程序服务器代码逻辑多个版本服务器单进程版本多进程版本多线程版本线程池版本服务器端代码客户端代码逻辑客户端代码TCP协议通讯流程TCP协议的客户端/服务器程序流程三次握手(建立连接)数据传输四次挥手(断开连接)TCP和UDP对比网络编程基础知识
Transformers开始在视频识别领域的“猪突猛进”,各种改进和魔改层出不穷。由此作者将开启VideoTransformer系列的讲解,本篇主要介绍了FBAI团队的TimeSformer,这也是第一篇使用纯Transformer结构在视频识别上的文章。如果觉得有用,就请点赞、收藏、关注!paper:https://arxiv.org/abs/2102.05095code(offical):https://github.com/facebookresearch/TimeSformeraccept:ICML2021author:FacebookAI一、前言Transformers(VIT)在图
是否可以在不实际下载文件的情况下检查文件是否存在?我有这么大的(~40mb)文件,例如:http://mirrors.sohu.com/mysql/MySQL-6.0/MySQL-6.0.11-0.glibc23.src.rpm这与ruby不严格相关,但如果发件人可以设置内容长度就好了。RestClient.get"http://mirrors.sohu.com/mysql/MySQL-6.0/MySQL-6.0.11-0.glibc23.src.rpm",headers:{"Content-Length"=>100} 最佳答案
我在这方面尝试了很多URL,在我遇到这个特定的之前,它们似乎都很好:require'rubygems'require'nokogiri'require'open-uri'doc=Nokogiri::HTML(open("http://www.moxyst.com/fashion/men-clothing/underwear.html"))putsdoc这是结果:/Users/macbookair/.rvm/rubies/ruby-2.0.0-p481/lib/ruby/2.0.0/open-uri.rb:353:in`open_http':404NotFound(OpenURI::HT
深度学习12.CNN经典网络VGG16一、简介1.VGG来源2.VGG分类3.不同模型的参数数量4.3x3卷积核的好处5.关于学习率调度6.批归一化二、VGG16层分析1.层划分2.参数展开过程图解3.参数传递示例4.VGG16各层参数数量三、代码分析1.VGG16模型定义2.训练3.测试一、简介1.VGG来源VGG(VisualGeometryGroup)是一个视觉几何组在2014年提出的深度卷积神经网络架构。VGG在2014年ImageNet图像分类竞赛亚军,定位竞赛冠军;VGG网络采用连续的小卷积核(3x3)和池化层构建深度神经网络,网络深度可以达到16层或19层,其中VGG16和VGG
(本文是网络的宏观的概念铺垫)目录计算机网络背景网络发展认识"协议"网络协议初识协议分层OSI七层模型TCP/IP五层(或四层)模型报头以太网碰撞路由器IP地址和MAC地址IP地址与MAC地址总结IP地址MAC地址计算机网络背景网络发展 是最开始先有的计算机,计算机后来因为多项技术的水平升高,逐渐的计算机变的小型化、高效化。后来因为计算机其本身的计算能力比较的快速:独立模式:计算机之间相互独立。 如:有三个人,每个人做的不同的事物,但是是需要协作的完成。 而这三个人所做的事是需要进行协作的,然而刚开始因为每一台计算机之间都是互相独立的。所以前面的人处理完了就需要将数据
一、什么是MQTT协议MessageQueuingTelemetryTransport:消息队列遥测传输协议。是一种基于客户端-服务端的发布/订阅模式。与HTTP一样,基于TCP/IP协议之上的通讯协议,提供有序、无损、双向连接,由IBM(蓝色巨人)发布。原理:(1)MQTT协议身份和消息格式有三种身份:发布者(Publish)、代理(Broker)(服务器)、订阅者(Subscribe)。其中,消息的发布者和订阅者都是客户端,消息代理是服务器,消息发布者可以同时是订阅者。MQTT传输的消息分为:主题(Topic)和负载(payload)两部分Topic,可以理解为消息的类型,订阅者订阅(Su
安全产品安全网关类防火墙Firewall防火墙防火墙主要用于边界安全防护的权限控制和安全域的划分。防火墙•信息安全的防护系统,依照特定的规则,允许或是限制传输的数据通过。防火墙是一个由软件和硬件设备组合而成,在内外网之间、专网与公网之间的界面上构成的保护屏障。下一代防火墙•下一代防火墙,NextGenerationFirewall,简称NGFirewall,是一款可以全面应对应用层威胁的高性能防火墙,提供网络层应用层一体化安全防护。生产厂家•联想网御、CheckPoint、深信服、网康、天融信、华为、H3C等防火墙部署部署于内、外网编辑额,用于权限访问控制和安全域划分。UTM统一威胁管理(Un
TCL脚本语言简介•TCL(ToolCommandLanguage)是一种解释执行的脚本语言(ScriptingLanguage),它提供了通用的编程能力:支持变量、过程和控制结构;同时TCL还拥有一个功能强大的固有的核心命令集。TCL经常被用于快速原型开发,脚本编程,GUI和测试等方面。•实际上包含了两个部分:一个语言和一个库。首先,Tcl是一种简单的脚本语言,主要使用于发布命令给一些互交程序如文本编辑器、调试器和shell。由于TCL的解释器是用C\C++语言的过程库实现的,因此在某种意义上我们又可以把TCL看作C库,这个库中有丰富的用于扩展TCL命令的C\C++过程和函数,所以,Tcl是