【发布时间】:2017-05-11 16:21:05
【问题描述】:
【问题讨论】:
标签: python machine-learning neural-network deep-learning caffe
【问题讨论】:
标签: python machine-learning neural-network deep-learning caffe
很简单,它是一个您提供实现代码的层,而不是使用一种预定义的类型——它们都由高效的函数支持。
如果您想定义自定义损失函数,请继续:自己编写,然后使用 Python 类型创建层。如果您有非标准输入需求,也许是一些特定于数据的预处理,没问题:自己编写,然后使用 Python 类型创建层。
【讨论】:
Python层不同于C++层需要编译,它们的参数需要添加到proto文件中,最后你需要在layer_factory中注册层。如果你写了一个 python 层,你不需要担心这些事情。层参数可以定义为字符串,在 python 中可以作为字符串访问。例如:如果你在一个层中有一个参数,你可以使用'self.param_str'来访问它,如果你的prototxt文件中定义了param_str。与其他层一样,您需要定义一个具有以下功能的类:
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"
}
}
这里,layer的名字是rpn-data,bottom和top分别是layer的输入和输出细节。 python_param 定义了 Python 层的参数。 'module' 指定图层的文件名。如果名为“anchor_target_layer.py”的文件位于名为“rpn”的文件夹中,则参数将为“rpn.anchor_target_layer”。 'layer' 参数是你的类的名称,在本例中是'AnchorTargetLayer'。 'param_str' 是层的参数,其中包含键 'feat_stride' 的值 16。
与 C++/CUDA 层不同,Python 层目前无法在 caffe 的多 GPU 设置中工作,因此这是使用它们的一个缺点。
【讨论】:
Prune 和Bharat 的回答给出了"Python" 层的总体用途:一个用python 而不是c++ 实现的通用层。
我打算将此答案用作使用"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()),有关详细信息,请参阅this thread。
此方法可以访问self.param_str - 从 prototxt 传递到层的字符串。请参阅this thread 了解更多信息。
def reshape(self, bottom, top):每当 caffe 重塑网络时,都会调用此方法。这个函数应该分配输出(每个top blob)。输出的形状通常与bottoms 的形状有关。
def forward(self, bottom, top):实现从bottom到top的前向传递。
def backward(self, top, propagate_down, bottom):这个方法实现了反向传播,它将梯度从top传播到bottom。 propagate_down 是 len(bottom) 的布尔向量,指示应将梯度传播到 bottoms 中的哪一个。
您可以在this post 中找到有关bottom 和top 输入的更多信息。
示例
你可以看到一些简化的python层的例子here、here和here。
“移动平均”输出层的例子可以在here找到。
可训练参数"Python" 层可以有可训练参数(如"Conv"、"InnerProduct" 等)。
您可以在this thread 和this one 中找到有关添加可训练参数的更多信息。 caffe git 中还有一个非常简化的示例。
"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 module name where your implementation is
layer: 'AnchorTargetLayer' # the name of the class implementation
param_str: "'feat_stride': 16" # optional parameters to the layer
}
}
NetSpec接口添加"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 imports 时可以找到它。
例如,如果您的模块 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 层之前将 blob 从 GPU 复制到 CPU,然后再复制回 GPU 以继续进行前向/后向传递。
如果 python 层是输入层或最顶层的损失层,则这种降级要小得多。
更新: 2017 年 9 月 19 日,PR #5904 被合并到 master。此 PR 通过 python 接口公开 blob 的 GPU 指针。
您可以直接从 python 访问 blob._gpu_data_ptr 和 blob._gpu_diff_ptr风险自负。
【讨论】: