【问题标题】:What is a `"Python"` layer in caffe?什么是 caffe 中的“Python”层?
【发布时间】:2017-05-11 16:21:05
【问题描述】:

Caffe 有一个层类型"Python"

例如,此层类型可用作loss layer
在其他情况下,它被用作input layer

这个图层类型是什么?
这层怎么用?

【问题讨论】:

    标签: python machine-learning neural-network deep-learning caffe


    【解决方案1】:

    很简单,它是一个提供实现代码的层,而不是使用一种预定义的类型——它们都由高效的函数支持。

    如果您想定义自定义损失函数,请继续:自己编写,然后使用 Python 类型创建层。如果您有非标准输入需求,也许是一些特定于数据的预处理,没问题:自己编写,然后使用 Python 类型创建层。

    【讨论】:

    • 我认为我不同意“这是一个您提供实现代码的层,而不是使用其中一种预定义类型”。您也可以实现自己的 C++ 和 CUDA 层。
    • 对……但其他用户定义车辆的存在并不能否定这句话。它是一个层,而不是唯一可能的层层。
    【解决方案2】:

    Python层不同于C++层需要编译,它们的参数需要添加到proto文件中,最后你需要在layer_factory中注册层。如果你写了一个 python 层,你不需要担心这些事情。层参数可以定义为字符串,在 python 中可以作为字符串访问。例如:如果你在一个层中有一个参数,你可以使用'self.param_str'来访问它,如果你的prototxt文件中定义了param_str。与其他层一样,您需要定义一个具有以下功能的类:

    • 设置 - 使用从图层变量获得的参数初始化图层
    • Forward - 层的输入和输出是什么
    • Backward - 给定下一层的预测和梯度,计算上一层的梯度
    • 重塑 - 如果需要,重塑你的 blob

    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 设置中工作,因此这是使用它们的一个缺点。

    【讨论】:

      【解决方案3】:

      PruneBharat 的回答给出了"Python" 层的总体用途:一个用python 而不是c++ 实现的通用层。

      我打算将此答案用作使用"Python" 层的教程。


      "Python" 层教程

      什么是"Python" 层?

      请看PruneBharat的精彩回答。

      先决条件

      为了使用'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):实现从bottomtop的前向传递。

      def backward(self, top, propagate_down, bottom):这个方法实现了反向传播,它将梯度从top传播到bottompropagate_downlen(bottom) 的布尔向量,指示应将梯度传播到 bottoms 中的哪一个。

      您可以在this post 中找到有关bottomtop 输入的更多信息。

      示例
      你可以看到一些简化的python层的例子hereherehere
      “移动平均”输出层的例子可以在here找到。

      可训练参数
      "Python" 层可以有可训练参数(如"Conv""InnerProduct" 等)。
      您可以在this threadthis one 中找到有关添加可训练参数的更多信息。 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 module name where your implementation is
          layer: 'AnchorTargetLayer'   # the name of the class implementation
          param_str: "'feat_stride': 16"   # optional parameters to the layer
        }
      }
      

      如何使用pythonic 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风险自负

      【讨论】:

      • 非常感谢您的精彩解释! python 层是否也可以在没有安装 python 的系统上工作? (那么我可以只部署 caffe 二进制文件吗?)
      • @mojovski 我认为您需要 Python 库才能使其工作。
      • @Shai 我认为 pyloss 层存在错误github.com/BVLC/caffe/blob/master/examples/pycaffe/layers/… 我认为最后一行应该是 bottom[i].diff[...] = sign * top[0].diff[ 0] * self.diff / bottom[i].num 我说的对吗?谢谢。
      • @kli_nlpr 没有考虑 top.diff 似乎很奇怪。您可以在 github 中打开一个问题来调查这一点。
      • @Shai 我在这里创建了一个 PR github.com/BVLC/caffe/pull/5407
      猜你喜欢
      • 1970-01-01
      • 2018-09-30
      • 1970-01-01
      • 2015-07-14
      • 1970-01-01
      • 1970-01-01
      • 2016-09-21
      • 2020-10-18
      相关资源
      最近更新 更多