Prune和Bharat的答案给出了"Python"
层的总体目的:这是一个通用层,与C++不同,它是用Python语言实现的。
本文旨在作为使用"Python"
层的教程。
"Python"
层教程"Python"
层是什么?为了使用"Python"
层,您需要使用标志编译caffe。
WITH_PYTHON_LAYER := 1
在'Makefile.config'
中进行设置。
"Python"
层?一个"Python"
层应该被实现为一个继承自caffe.Layer
基类的python类。这个类必须具有以下四种方法:
import caffe
class 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中还有一个非常简化的示例。
有关详情,请参见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 module name where your implementation is
layer: 'AnchorTargetLayer' # the name of the class implementation
param_str: "'feat_stride': 16" # optional parameters to the layer
}
}
"Python"
层?非常简单:
import caffe
from caffe import layers as L
ns = caffe.NetSpec()
# define layers here...
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, # tell caffe to expect four output blobs
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 np
from test_gradient_for_python_layer import test_gradient_for_python_layer
# set the inputs
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]
# call the test
test_gradient_for_python_layer(input_names_and_values, output_names,
py_module, py_layer, param_str,
propagate_down)
# you are done!
值得注意的是,Python代码只能在CPU上运行。因此,如果您计划在网络的中间使用Python层,且想要使用GPU,则会看到显著的性能下降。这是因为Caffe需要在调用Python层之前从GPU复制数据块到CPU,然后再将其复制回GPU以进行前向/反向传递。
如果Python层是输入层或最上层损失层,则这种下降的程度要小得多。
更新:于2017年9月19日,PR#5904已合并到主分支。该PR通过Python接口公开了数据块的GPU指针。您可以直接从Python访问blob._gpu_data_ptr和blob._gpu_diff_ptr,但需自担风险。
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'
layer: 'AnchorTargetLayer'
param_str: "'feat_stride': 16"
}
}