2016-07-31 9 views
12

Caffeでは、convolutionレイヤーは1つのボトムブロブを取り、学習タイプのフィルタ(「Xavier」、「MSRA」などのウェイトタイプを使用して初期化されています)で畳み込みます。しかし、私の質問は、単に2つのボトムブロブを畳み込み、トップブロブを生成できるかどうかです。これを行う最もエレガントな方法は何でしょうか?これは、下部のブロブの1つがdataになり、もう1つは前のレイヤーで生成された動的フィルタ(に応じて変更)になります(私はdynamic convolutionを実装しようとしています)。Caffeで2つのブロブを畳み込む方法

私の試み:私の心に来た

一つの方法は、filler.hppを変更し、(代わりに「ザビエル」、「MSRA」などの)fillerマトリックス自体として下ブロブを割り当てることでした。それから畳み込みレイヤーがそこから拾い上げると思った。 lr = 0を設定して、カスタムフィラーによって初期化された重量を変更しないことを示すことができます。しかし、私がソースコードを見ても、それをやる方法はまだ分かりません。一方、私はcaffeのワークフローを破りたくはありません。私は、convレイヤーが正常に機能するようにしたいと思っています。

明らかに、より退屈な方法は、文字通り畳み込みを実装するためにSlicetileおよび/またはScaleレイヤの組み合わせを使用することです。私はそれがうまくいくと思うが、それは乱雑になるだろう。他の考え?

編集1:

私はカフェの畳み込み層を変更することによって、新しいレイヤーを書きました。特に、src/caffe/layers/conv_layer.cppの27行目では、fillerで定義された重みをとり、それを下のブロブと畳み込んでいます。だから、fillerからブロブを取り込む代わりに、レイヤーを2つのボトムに変更しました。ボトムの1つがフィラーに直接割り当てられます。

  1. weightブロブは、すべてのサンプルに対して同じ値を持っている:今、私のような他のいくつかの変更をしなければなりませんでした。ここでは、サンプルごとに異なる値が設定されます。
this->forward_cpu_gemm(
    bottom_data + n * this->bottom_dim_, 
    weight, 
    top_data + n * this->top_dim_); 

へ:だから私はからライン32を変更し、物事を簡単にするために

this->forward_cpu_gemm(
    bottom_data + n * bottom[1]->count(1), 
    bottom[0]->cpu_data() + n * bottom[0]->count(1), 
    top_data + n * this->top_dim_); 

私は関与なしバイアス項が存在しないと仮定し、ストライドは常に1である、パディングは常に0にすることができますしかし、私はフォワードパスをテストしたとき、それは私に奇妙な答えを与えました(単純な畳み込みカーネル= np.ones((1,1,3,3)))。このカーネルの学習率はゼロに設定されています。しかし、私は正しい答えを得ることができません。どんな提案もありがとうございます。

Slice, Eltwise, Cropなどの既存のレイヤーを使用してソリューションを提案しないでください。私はすでに実装しています - それは動作しますが、それは信じられない複雑さとメモリ非効率です。

+2

私はそれを読んで "2つのブロンドをカフェで納得させる":\ – Elazar

+0

@エラザールだから、あなたはダウン投票したのですか? (ちょうど冗談です):P –

答えて

7

私はあなたが全体として正しい方法でいると思います。「奇妙な」畳み込み結果を得るために

、私はバグが最も可能性があると思います:

は、2Dコンボリューション

検討し、caffeで畳み込みが行われるため、bottom[1]の形状が(num, channels, height, width)ある

を想定weight(畳み込みカーネルを表す)およびcol_buffer(畳み込みされるデータから再構成される)の2つの行列の乗算として、weightは、num_out行およびであるnum_outダイナミックコンボリューションの数である列、動的畳み込み層のweightブロブとして、bottom[0]の形状が良好

bottom[0]->count(1) == num_out * channels/this->group_ * kernel_h * kernel_w 

を満足する(num, num_out, channels/group, kernel_h, kernel_w)なければならないので、col_bufferが、channels/this->group_ * kernel_h * kernel_w行とheight_out * width_out列であり、レイヤーの出力フィーチャーマップ。意味

は、あなたが作る必要があり、適切にコンボリューション機能

this->forward_cpu_gemm(bottom_data + n * bottom[1]->count(1) 
        , bottom[0]->cpu_data() + n * bottom[0]->count(1) 
        , top_data + n * this->top_dim_); 

作品を作るために必ずその

bottom[0]->shape(0) == bottom[1]->shape(0) == num 
bottom[0]->count(1) == num_out * channels/this->group_ * kernel_h * kernel_w 

だから、最も可能性があなたが使用4次元np.ones((1,1,3,3))の簡単な畳み込みカーネルかもしれません上記の条件を満たしておらず、間違った畳み込み結果をもたらす。

希望して、あなたを助けてくれることを願っています。

##########アップデート1、10月10日、2016年、北京時間##########

は、私は、ダイナミックコンボリューション層hereを追加しますが、いないとユニットテストはまだありません。このレイヤーは、Caffeのワークフローを壊すことなく、保護されるBaseConvolutionクラスの一部のプライベートメンバーのみを変更します。それはcaffeにおける畳み込み層とほぼ同じ成長

include/caffe/layers/dyn_conv_layer.hpp,base_conv_layer.hpp 
src/caffe/layers/dyn_conv_layer.cpp(cu) 

、との違いは、主に以下のとおりです:関与

ファイルがある

  1. オーバーライド機能LayerSetUp()this->kernel_dim_this->weight_offset_など初期化しますコンボリューションのために適切に使用し、コンボリューション層がウェイトとバイアスを含むように定期的に使用するthis->blobs_の初期化を無視する。
  2. 関数Reshape()をオーバーライドして、カーネルコンテナとしてbottom[1]が畳み込みのための適切な形を持っていることを確認します。

私はそれをテストする時間がないので、バグがあるかもしれないので、私はあなたのフィードバックを見て非常にうれしいです。

##########アップデート2、10月12日、2016年、北京時間、私はちょうど今dynamic convolutionのためのテストケースを更新##########

。関係するファイルはsrc/caffe/test/test_dyn_convolution_layer.cppです。それはうまくいくようですが、もっと徹底したテストが必要かもしれません。

​​、cmake -DBUILD_only_tests="dyn_convolution_layer" ..make runtestでこのコーヒーを作ることができます。

+0

私はこれを3〜4日後に試して、結果をお知らせします。ありがとう! –

+1

forward_cpu_gemm()で使用されている多くの変数がそこで初期化されているので、関数BaseConvolutionLayer :: LayerSetUp()に注意する必要があります。 @ ParagS.Chandakkar – Dale

+0

2つのボトムブロブがある場合、カーネルのサイズとフィルタの数を設定する畳み込みパラメータは無視できます。これらの値は、「重み」ブロブから推測する必要があります。また、バイアス項の3番目の入力値を考慮することもできます。 – Shai

関連する問題