Brewing Models

Brewing Models


brew是Caffe2创建模型的新API。过去,CNNModelHelper充当了这个角色。但是由于Caffe2已经不仅仅是一个卓越的CNN库,所以提供一个更通用的ModelHelper是十分有必要的。你可能会注意到,新的ModelHelper具备与CNNModelHelper大致相同的功能。brew封装了ModelHelper,使得构造模型比以前更容易。

模型构建与brew的辅助函数

在这个概述中,我们将介绍brew,一个轻量级的辅助函数集合,以帮助您构建模型。本文首先解释Ops与Helper Function的关键概念。然后将会展示brew的使用——它如何作为ModelHelper的接口,以及arg_scope语法糖(syntax sugar)。 最后讨论引入brew的动机。

概念:算子与辅助函数

在探究brew之前,我们需要回顾一下Caffe2和神经网络层表示的一些约定。Caffe2中的深度学习网络由算子(operator)构建而成。通常,这些算子使用C++编写以获得最大的性能。Caffe2提供了Python API来封装这些C++算子,所以你可以更灵活地实验并打造原型。在Caffe2中,算子采用驼峰命名法,而其Python辅助函数的名称相似但为小写形式。这方面的例子如下。

Ops

我们经常将算子称为“Op”或者称算子的集合作为“Ops”。例如,FC Op表示一个全连接算子,具有与前一层中每个神经元的加权连接。 例如可以使用以下方式创建FC Op:

model.net.FC([blob_in, weights, bias], blob_out)

或者你可以创建一个Copy Op:

model.net.Copy(blob_in, blob_out)

ModelHelper处理的算子列表位于本文档的底部,包含目前最常使用的29种算子。这是本文撰写时,Caffe2中400多个Op的一个子集。

还应该注意的是,你也可以创建一个运算符而不注释网络。例如,就像在前面的例子中,我们创建了一个Copy Op,我们可以使用以下代码在model.net上创建一个Copy运算符:

model.Copy(blob_in, blob_out)

辅助函数

仅使用运算符构建模型/网络显然会很困难,因为你必须自己进行参数初始化,选择设备/引擎(但这也是Caffe2如此之快的原因)。例如,要构建FC层,我们需要许多行代码来准备权重和偏差,然后将其提供给Op。

手动方式比较长:

model = model_helper.ModelHelper(name="train")
# initialize your weight
weight = model.param_init_net.XavierFill(
    [],
    blob_out + '_w',
    shape=[dim_out, dim_in],
    **kwargs, # maybe indicating weight should be on GPU here
)
# initialize your bias
bias = model.param_init_net.ConstantFill(
    [],
    blob_out + '_b',
    shape=[dim_out, ],
    **kwargs,
)
# finally building FC
model.net.FC([blob_in, weights, bias], blob_out, **kwargs)

幸运的是Caffe2辅助函数在此次能提供帮助。辅助函数封装了为模型创建完整层的功能。辅助函数通常将处理参数初始化、算子定义以及引擎选择。Caffe2的默认辅助函数以Python PEP8函数规范命名。例如,借助python/helpers/fc.py,通过辅助函数fc实现FC Op要简单得多:

使用辅助函数的方式更简单:

fcLayer = fc(model, blob_in, blob_out, **kwargs) # returns a blob reference

一些辅助函数构建不止1个运算符。例如,python/rnn_cell.py中的LSTM函数可以帮助我们构建网络中一个完整的LSTM单元。

查看repo获得更多非常酷的辅助函数!

brew

现在,我们已经介绍了算子和辅助函数,让我们来看看brew如何使模型构建更加简单。brew是一个敏捷的辅助函数集合。我们仅需要导入brew模块就可以使用Caffe2所有的辅助函数。我们现在可以使用以下方法添加FC层:

from caffe2.python import brew

brew.fc(model, blob_in, blob_out, ...)

这与直接使用辅助函数几乎一样,但是当模型变得更加复杂,brew就开始显露出优势。以下是从MNIST教程中提取的LeNet模型构建示例。

from caffe2.python import brew

def AddLeNetModel(model, data):
    conv1 = brew.conv(model, data, 'conv1', 1, 20, 5)
    pool1 = brew.max_pool(model, conv1, 'pool1', kernel=2, stride=2)
    conv2 = brew.conv(model, pool1, 'conv2', 20, 50, 5)
    pool2 = brew.max_pool(model, conv2, 'pool2', kernel=2, stride=2)
    fc3 = brew.fc(model, pool2, 'fc3', 50 * 4 * 4, 500)
    fc3 = brew.relu(model, fc3, fc3)
    pred = brew.fc(model, fc3, 'pred', 500, 10)
    softmax = brew.softmax(model, pred, 'softmax')

示例中每个层都使用brew创建,而Brew又使用其算子钩子来实例化每个Op。

arg_scope

arg_scope是一种语法糖,可以在其上下文中设置辅助函数飞默认参数值。例如,假设你想在ResNet-150训练脚本中尝试不同的初始化权重,可以进行如下设置:

# change all weight_init here
brew.conv(model, ..., weight_init=('XavierFill', {}),...)
...
# repeat 150 times
...
brew.conv(model, ..., weight_init=('XavierFill', {}),...)

或者在arg_scope的帮助下,你可以

with brew.arg_scope([brew.conv], weight_init=('XavierFill', {})):
     brew.conv(model, ...) # no weight_init needed here!
     brew.conv(model, ...)
     ...

自定义辅助函数

当我们更频繁地使用brew,并且需要目前brew没有实现的Op时,我们将需要编写自己的辅助函数。我们需要注册辅助函数,以便统一管理和使用语法糖。

我们只需定义新的辅助函数,使用.Register函数进行注册,然后用brew.new_helper_function调用它。

def my_super_layer(model, blob_in, blob_out, **kwargs):
"""
   100x faster, awesome code that you'll share one day.
"""

brew.Register(my_super_layer)
brew.my_super_layer(model, blob_in, blob_out)

如果你认为你的辅助函数可能对Caffe2社区的其他人有帮助,请记住分享它,并创建一个pull请求。

Caffe2默认辅助函数

要获取有关这些函数的更多详细信息,请访问算子目录

brew的出发点

感谢您阅读关于brew的全面概述!恭喜你阅读到这来!简而言之,我们试图将模型构建过程和模型存储分离。在我们看来,ModelHelper类只能包含网络定义和参数信息。brew模块将具备构建网络和初始化参数的功能。

与之前包揽模型存储和模型构建的巨型CNNModelHelper相比,ModelHelper + brew模型构建方式更加模块化,更易于扩展。就命名而言,由于Caffe2系列支持多种网络,包括MLP、RNN和CNN,之前的类也更令人困惑。我们希望本教程能帮助您更快更容易地构建模型,同时更深入地了解Caffe2。在python/brew_test.py中有一个brew使用的详细示例。如果您有任何关于brew的问题,请随时联系我们,并在repo中提出问题。再次感谢您拥抱新的brewAPI。

猜你喜欢

转载自blog.csdn.net/yiran103/article/details/78364105
今日推荐