Mask R-CNN的源码是随着FAIR的物体检测平台detectron公布的,detectron囊括了从Fast R-CNN到Mask R-CNN所有重要的物体检测算法,整个平台基于caffe2实现。本文主要从代码层面介绍Mask R-CNN具体的实现过程。
caffe2是在caffe的基础上的进化版,最大的特色就是引入了operator的概念,取代了caffe中layer作为net的基本构造单位。
由于operator定义很基础,很抽象,因此caffe2中的权值初始化、前传、反传、梯度更新都可以用operator实现,所以solver、layer类在caffe2中都不是必要的。在caffe2中,对应的基础组成有:
所以在使用caffe2之前,需要先将caffe2.python.core和caffe2.python.workspace导入,这里边有常用的一些类和函数。
from caffe2.python import core, workspace
下面介绍caffe2比较重要的几个点:
workspace是caffe2新引入的一个概念,顾名思义就是工作区的意思,类似于Matlab中管理变量的工作区,caffe2里的变量一般就是指blob里存储的变量。
对模型的训练测试等操作都是在workspace中进行的,如运行一个网络,即调用workspace中的RunNet方法,输入参数为网络的名字和迭代轮数。具体的workspace中的方法可以查阅官方文档。
在caffe2中创建一个operator的一般方法是使用core.CreateOperator,但在实际情况下,我们创建网络时不会直接创建每个operator,这样太麻烦,一般使用modelhelper来帮忙我们创建网络。
以创建一个relu operator举例:
# Create an operator.
op = core.CreateOperator(
"Relu", # The type of operator that we want to run
["X"], # A list of input blobs by their names
["Y"], # A list of output blobs by their names
)
# and we are done!
这里我们创建了一个relu运算符。值得注意的是,这里我们仅是定义了一个relu运算符,却没有运行它。如果要运行这个运算符,需要先在当前工作区内添加一个输入的变量(一个blob变量),然后运行这个运算符,这里就需要用到workspace中的方法。
workspace.FeedBlob("X", np.random.randn(2, 3).astype(np.float32)) # add a Blob called X
workspace.RunOperatorOnce(op) # run the operator once
Nets是一系列operator的集合,从本质上,是由operator构成的计算图。Caffe2中core.net 封装了源码中 NetDef 类。
同样,定义一个网络的工作完成后,实际上并没有进行net的计算。
当我们在python运行网络时,实际上在c++层面做了两件事情:
在python中有两种方法来运行一个net:
在operator的介绍中提到,一般来说我们是不用operator来直接创建网络的,每一层(包括数据输入权值初始化等)都要创建一个operator并为它设置初值,过于麻烦了。于是就有了用modelhelper来创建网络。
在caffe中所说的一个模型,其实就是一个网络,一个net。而在caffe2中,通常使用modelhelper来表示一个模型,这个模型里可以包含多个网络。一般来说一个模型包含一个param_init_net和一个net两个网络。modelhelper是在caffe2\python\model_helper.py中定义的一个类。详细说明如下:
class ModelHelper(object):
"""A helper model so we can manange models more easily. It contains net def
and parameter storages. You can add an Operator yourself, e.g.
model = model_helper.ModelHelper(name="train_net")
# init your weight and bias as w and b
w = model.param_init_net.XavierFill(...)
b = model.param_init_net.ConstantFill(...)
fc1 = model.FC([input, w, b], output, **kwargs)
or you can use helper functions in brew module without manually
defining parameter initializations and operators.
model = model_helper.ModelHelper(name="train_net")
fc1 = brew.fc(model, input, output, dim_in, dim_out, **kwargs)
"""
ModelHelper包含了网络的定义和参数的存储,并且可以在此基础上自行添加operator。
比较有趣的是,在上面代码段说明的下半段,开发者提供了另一种建立模型的方式,即使用brew这个包。在caffe2中,为了便于开发者搭建网络,caffe2在python/helpers中提供了许多help函数,像上面例子中的FC层,使用python/helpers/fc.py来构造,非常简单就一行代码:
fc1 = brew.fc(model, input, output, dim_in, dim_out, **kwargs)
# returns a blob reference
这里面help函数能够帮助我们将权值初始化和计算网络自动分开到两个网络,这样一来就简单多了。caffe2为了更方便调用和管理,把这些帮助函数集合到一起,放在brew这个包里面。可以通过导入brew这个包来调用这些帮助函数。
两种方法来构造网络的原理是一样的,只是使用brew这个包能使网络建立的过程大大简化,所以目前官方给出的建议是尽量使用brew来构造网络。
对于caffe2的介绍到这里就结束了,下篇将开始详细分析detectron中Mask R-CNN的代码执行过程。
Reference:
1. caffe2官网:https://caffe2.ai/
2. caffe2 教程入门(python版)
3. Caffe2 - (十四) 网络构建API之 brew