以下内容翻译自: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默认辅助函数
要获取有关这些函数的更多详细信息,请访问算子目录。
- accuracy
- add_weight_decay
- average_pool
- concat
- conv
- conv_nd
- conv_transpose
- depth_concat
- dropout
- fc
- fc_decomp
- fc_prune
- fc_sparse
- group_conv
- group_conv_deprecated
- image_input
- instance_norm
- iter
- lrn
- max_pool
- max_pool_with_index
- packed_fc
- prelu
- softmax
- spatial_bn
- relu
- sum
- transpose
- video_input
brew
的出发点
感谢您阅读关于brew
的全面概述!恭喜你阅读到这来!简而言之,我们试图将模型构建过程和模型存储分离。在我们看来,ModelHelper
类只能包含网络定义和参数信息。brew
模块将具备构建网络和初始化参数的功能。
与之前包揽模型存储和模型构建的巨型CNNModelHelper
相比,ModelHelper
+ brew
模型构建方式更加模块化,更易于扩展。就命名而言,由于Caffe2系列支持多种网络,包括MLP、RNN和CNN,之前的类也更令人困惑。我们希望本教程能帮助您更快更容易地构建模型,同时更深入地了解Caffe2。在python/brew_test.py中有一个brew使用的详细示例。如果您有任何关于brew
的问题,请随时联系我们,并在repo中提出问题。再次感谢您拥抱新的brew
API。