web-dev-qa-db-ja.com

caffeの「Python」レイヤーとは何ですか?

Caffeにはレイヤータイプ"Python"

たとえば、このレイヤータイプは 損失レイヤー として使用できます。
それ以外の場合は 入力層 として使用されます。

このレイヤータイプは何ですか?
このレイヤーはどのように使用できますか?

19
Shai

PruneBharat の回答は、"Python"レイヤーの全体的な目的を提供します。C++ではなくpythonで実装される汎用レイヤーです。

この回答は、"Python"レイヤーを使用するためのチュートリアルとして機能することを意図しています。


"Python"レイヤーのチュートリアル

"Python"レイヤーとは

Prune および Bharat の優れた答えをご覧ください。

前提条件

'Python"レイヤーを使用するには、フラグ付きのカフェをコンパイルする必要があります

WITH_PYTHON_LAYER := 1

'Makefile.config'で設定します。

"Python"レイヤーを実装するには?

"Python"レイヤーは、caffe.Layer基本クラスから派生したpythonクラスとして実装する必要があります。このクラス must には、次の4つのメソッドがあります。

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):このメソッドは、カフェがネットを構築するときに一度呼び出されます。この関数は、入力の数(len(bottom))と出力の数(len(top))が期待どおりであることを確認する必要があります。
ネットの内部パラメータもここに割り当てる必要があります(つまり、self.add_blobs())。詳細は this thread を参照してください。
このメソッドは、self.param_str-プロトテキストからレイヤーに渡される文字列にアクセスできます。詳細は this thread を参照してください。

def reshape(self, bottom, top):このメソッドは、カフェがネットを再形成するたびに呼び出されます。この関数は、出力(各top blob)を割り当てる必要があります。出力の形状は通常、bottoms 'の形状に関連しています。

def forward(self, bottom, top)bottomからtopへの転送パスを実装します。

def backward(self, top, propagate_down, bottom):このメソッドは逆伝播を実装し、topからbottomへの勾配を伝播します。 propagate_downlen(bottom)のブールベクトルで、グラデーションをbottomsのどれに伝播するかを示します。

this post にあるbottomおよびtop入力に関する詳細情報。


簡略化されたpythonレイヤー herehere および here の例をいくつか示します。
「移動平均」出力レイヤーの例を見つけることができます ここ

トレーニング可能なパラメータ
"Python"レイヤーは、トレーニング可能なパラメーター("Conv""InnerProduct"など)を持つことができます。
this thread および this one に、トレーニング可能なパラメータの追加に関する詳細情報があります。 caffe git にも非常に簡略化された例があります。

プロトテキストに"Python"レイヤーを追加する方法は?

詳細は Bharat の回答を参照してください。
以下をプロトテキストに追加する必要があります:

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にあることを確認してください。これにより、カフェ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メソッドのテストは easy です。このメソッドは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でのみ実行されることに注意してください。したがって、ネットのmiddleにPythonレイヤーを配置する場合は、 significant が表示されますGPUの使用を計画している場合、パフォーマンスの低下。これは、カフェがpythonレイヤーを呼び出す前にGPUからCPUにblobをコピーし、次にGPUにコピーしてフォワード/バックワードパスを続行する必要があるために発生します。
pythonレイヤーが入力レイヤーまたは最上位の損失レイヤーのいずれかである場合、この低下はそれほど重要ではありません。
更新:2017年9月19日に PR#5904 がマスターに統合されました。このPRは、pythonインターフェイスを介してblobのGPUポインターを公開します。 blob._gpu_data_ptrとblob._gpu_diff_ptrには、python から直接ご自身の責任で直接アクセスできます

35
Shai

非常に簡単に言うと、これは、youが実装コードを提供するレイヤーであり、事前定義されたタイプの1つを使用するのではなく、すべて効率的な機能。

カスタム損失関数を定義する場合は、先に進んでください。自分で記述し、タイプPythonでレイヤーを作成してください。非標準の入力が必要な場合、おそらくデータ固有の前処理があれば問題ありません。自分で記述し、タイプPythonでレイヤーを作成します。

8
Prune

Pythonレイヤーは、コンパイルする必要があるC++レイヤーとは異なり、それらのパラメーターをprotoファイルに追加する必要があり、最後にレイヤーをlayer_factoryに登録する必要があります。 pythonレイヤーを作成する場合、これらのことについて心配する必要はありません。レイヤーパラメーターは、Pythonで文字列としてアクセス可能な文字列として定義できます。次に例を示します。レイヤーにパラメーターがある場合、prototxtファイルでparam_strが定義されていれば、 'self.param_str'を使用してそのパラメーターにアクセスできます。他のレイヤーと同様に、次の関数でクラスを定義する必要があります。

  • セットアップ-レイヤー変数から取得したパラメーターを使用してレイヤーを初期化する
  • フォワード-レイヤーの入力と出力になるもの
  • 後方-次のレイヤーからの予測と勾配を考慮して、前のレイヤーの勾配を計算します
  • Reshape-必要に応じてブロブを再形成します

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"
  }
}

ここで、レイヤーの名前はrpn-dataで、下と上はそれぞれレイヤーの入力と出力の詳細です。 python_paramは、Python=レイヤーのパラメーターを定義します。「モジュール」は、レイヤーのファイル名を指定します。「anchor_target_layer.py」というファイルが「rpn」というフォルダー内にある場合'、パラメーターは' rpn.anchor_target_layer 'になります。'layer'パラメーターはクラスの名前、この場合は 'AnchorTargetLayer'です。'param_str 'はレイヤーのパラメーターで、キー「feat_stride」。

C++/CUDAレイヤーとは異なり、Pythonレイヤーは現在のところcaffeのマルチGPU設定では機能しないため、それらを使用することの欠点です。

7
Bharat