2016-09-24 15:40:00

NN の畳み込み処理の border=‘same’ の扱い

[トップページ] > [雑記] > NN の畳み込み処理の border=‘same’ の扱い

Convolutional Neural Networks (CNN) は多層のフィルタ処理から成っています。フィルタ処理では、長さ L の1次元データに長さ N のフィルタをかけるとき、端の処理を ‘valid’ とすると、出力の大きさは L - N + 1 になります。たとえば画像が入力されたとして、近年のニューラルネットワークはフィルタを152回かけたり1001回かけたりしますから、フィルタをかけるたびに画像が縮んでゆくと困ります。そこで一般に、フィルタをかける前にデータの両端にいくつかのゼロを加えて、フィルタの前後でデータの大きさが変わらないようにします。

さて、両端にいくつのゼロを加えるか。フィルタの長さ N が奇数のときは簡単で、両端に (N - 1) / 2 個のゼロを加えれば済みます。しかし偶数のときは厄介で、片方には N / 2 のゼロを、もう片方には N / 2 - 1 のゼロを加えなければなりません。たとえば既存手法の追試をするとして

  1. 使うライブラリは、両端で加えるゼロの数を変えることができるか
  2. 頭に加えるゼロの数は N / 2 か、それとも N / 2 - 1 か

が問題となります。

実は 1. は厄介な問題です。なぜなら、ニューラルネットワークのフィルタ処理ではほぼすべてのライブラリで CuDNN の cudnnSetConvolutionNdDescriptor() が用いられますが、この関数では両端に加えるゼロの数は同じでなければならないからです。

というわけで、いくつかのニューラルネットワーク用ライブラリ (TensorFlow, Keras/Theano, Lasagne/Theano) について、この問題をどう処理しているか調べてみました。


TensorFlow について。

API 仕様書の tf.nn.conv2d の項には

padding: A string from: “SAME”, “VALID”. The type of padding algorithm to use.

とだけ記載されており、上記 1) 2) の処理の詳細は不明です。そこで conv_ops.cc を覗いてみたところ

// Total padding on rows and cols is
// Pr = (R' - 1) * S + Kr - R
// Pc = (C' - 1) * S + Kc - C
// where (R', C') are output dimensions, (R, C) are input dimensions, S
// is stride, (Kr, Kc) are filter dimensions.
// We pad Pr/2 on the left and Pr - Pr/2 on the right, Pc/2 on the top
// and Pc - Pc/2 on the bottom.  When Pr or Pc is odd, this means
// we pad more on the right and bottom than on the top and left.

と記載されていました。つまり 1) については「可能」で、2) については「頭に加えるのは N / 2 - 1」ということになります。(こういう情報は内部のコードのコメントとしてではなく API 仕様書に記載してほしいですね。)


Keras/Theano について。

Keras の仕様書にも

border_mode: ‘valid’ or ‘same’.

以上の記述はありません。そこで theano_backend.py をチェックしてみると、どうやら Keras の border_mode の処理は thano.tensor.nnet.conv2dborder_mode='half' を与えることに当たるようです。

theano.tensor.nnet.conv2d の仕様書には

 'half': pad input with a symmetric border of filter rows // 2 rows and filter columns // 2 columns, then perform a valid convolution. For filters with an odd number of rows and columns, this leads to the output shape being equal to the input shape.

とあります。つまり 1) については「不可」で 2) については「頭にも後ろにも N / 2 を加えて、結果として出力の大きさは変わる」ということのようですね。


Lasagne/Theano について。

Lasagne は仕様書に明確に記載されています。

‘same’ pads with half the filter size (rounded down) on both sides. When stride=1 this results in an output size equal to the input size. Even filter size is not supported.

つまり Keras/Theano と同様の処理ですね。


どうやら、フィルタの大きさが偶数の場合の border_mode='same' の扱いは、ライブラリ間で統一されているわけではなさそうです。論文の追試を行おうと思うとちょっと厄介ですね。

上記については実際にコードを動かして試したわけではないので、読み落としによる間違いがあるかもしれません。ご承知ください。

[トップページ] > [雑記] > NN の畳み込み処理の border=‘same’ の扱い


Cpyright (C) 2014-2016 Hiroharu Kato. All Rights Reserved.