caffe有一个名为"Python"
的层类型。
例如,这个层类型可以作为损失层使用。
在其他情况下,它可以用作输入层。
这个层类型是什么?
如何使用这个层?
回答:
Prune和Bharat的回答给出了"Python"
层的总体目的:这是一个用Python而不是C++实现的通用层。
我希望这个回答能作为使用"Python"
层的教程。
"Python"
层的教程
什么是"Python"
层?
前提条件
为了使用'Python"
层,你需要在编译caffe时设置标志
WITH_PYTHON_LAYER := 1
在'Makefile.config'
中设置。
如何实现一个"Python"
层?
一个"Python"
层应该实现为从caffe.Layer
基类派生的Python类。这个类必须有以下四个方法:
import caffeclass my_py_layer(caffe.Layer): def setup(self, bottom, top): pass def reshape(self, bottom, top): pass def forward(self, bottom, top): pass def backward(self, top, propagate_down, bottom): pass
这些方法是什么?
def setup(self, bottom, top)
: 这个方法在caffe构建网络时调用一次。这个函数应该检查输入的数量(len(bottom)
)和输出的数量(len(top)
)是否符合预期。
你也应该在这里分配网络的内部参数(即,self.add_blobs()
),更多信息请参见这个讨论。
这个方法可以访问self.param_str
– 从prototxt传递给层的字符串。更多信息请参见这个讨论。
def reshape(self, bottom, top)
: 这个方法在caffe重塑网络时调用。这个函数应该分配输出(每个top
blob)。输出的形状通常与bottom
的形状相关。
def forward(self, bottom, top)
: 实现从bottom
到top
的前向传递。
def backward(self, top, propagate_down, bottom)
: 这个方法实现反向传播,它将梯度从top
传播到bottom
。propagate_down
是len(bottom)
长度的布尔向量,表示应该将梯度传播到哪些bottom
。
关于bottom
和top
输入的更多信息,你可以在这篇文章中找到。
示例
你可以在这里看到一些简化的Python层的示例:这里,这里和这里。
“移动平均”输出层的示例可以在这里找到。
可训练参数"Python"
层可以有可训练参数(如"Conv"
、"InnerProduct"
等)。
关于添加可训练参数的更多信息,你可以在这个讨论和这个讨论中找到。在caffe git中也有一个非常简化的示例。
如何在prototxt中添加"Python"
层?
有关详细信息,请查看Bharat的回答。
你需要在你的prototxt中添加以下内容:
layer { name: 'rpn-data' type: 'Python' bottom: 'rpn_cls_score' bottom: 'gt_boxes' bottom: 'im_info' bottom: 'data' top: 'rpn_labels' top: 'rpn_bbox_targets' top: 'rpn_bbox_inside_weights' top: 'rpn_bbox_outside_weights' python_param { module: 'rpn.anchor_target_layer' # python模块名称,你的实现所在 layer: 'AnchorTargetLayer' # 类实现的名称 param_str: "'feat_stride': 16" # 层的可选参数 }}
如何使用pythonic的NetSpec
接口添加"Python"
层?
这非常简单:
import caffefrom caffe import layers as Lns = caffe.NetSpec()# 在这里定义层...ns.rpn_labels, ns.rpn_bbox_targets, \ ns.rpn_bbox_inside_weights, ns.rpn_bbox_outside_weights = \ L.Python(ns.rpn_cls_score, ns.gt_boxes, ns.im_info, ns.data, name='rpn-data', ntop=4, # 告诉caffe期望四个输出blob python_param={'module': 'rpn.anchor_target_layer', 'layer': 'AnchorTargetLayer', 'param_str': '"\'feat_stride\': 16"'})
如何使用包含"Python"
层的网络?
从caffe调用Python代码无需担心。Caffe使用boost API从编译的C++中调用Python代码。
你需要做什么?
确保实现你的层的Python模块在$PYTHONPATH
中,以便caffe在import
时可以找到它。
例如,如果你的模块my_python_layer.py
位于/path/to/my_python_layer.py
,那么
PYTHONPATH=/path/to:$PYTHONPATH $CAFFE_ROOT/build/tools/caffe train -solver my_solver.prototxt
应该可以正常工作。
如何测试我的层?
在使用你的层之前,你应该始终测试它。
测试forward
函数完全取决于你,因为每个层都有不同的功能。
测试backward
方法是容易的,因为这个方法只实现forward
的梯度,可以自动进行数值测试!
查看test_gradient_for_python_layer
测试工具:
import numpy as npfrom test_gradient_for_python_layer import test_gradient_for_python_layer# 设置输入input_names_and_values = [('in_cont', np.random.randn(3,4)), ('in_binary', np.random.binomial(1, 0.4, (3,1))]output_names = ['out1', 'out2']py_module = 'folder.my_layer_module_name'py_layer = 'my_layer_class_name'param_str = 'some params'propagate_down = [True, False]# 调用测试test_gradient_for_python_layer(input_names_and_values, output_names, py_module, py_layer, param_str, propagate_down)# 你完成了!
特别注意
值得注意的是,Python代码只能在CPU上运行。因此,如果你计划在网络的中间使用Python层,你会看到性能显著下降,如果你计划使用GPU的话。这是因为caffe需要在调用Python层之前将blob从GPU复制到CPU,然后再复制回GPU以继续进行前向/后向传递。
如果Python层是输入层或最顶层的损失层,这种性能下降的影响要小得多。
更新: 2017年9月19日,PR #5904被合并到master中。这个PR通过Python接口暴露了blob的GPU指针。你可以直接从Python访问blob._gpu_data_ptr和blob._gpu_diff_ptr,但需自担风险。