プーリングと畳み込み演算は、入力テンソル全体に「ウィンドウ」をスライドさせます。tf.nn.conv2d
例として使用:入力テンソルに4つの次元がある場合: [batch, height, width, channels]
たたみ込みは、次元の2Dウィンドウで動作しますheight, width
。
strides
各次元でウィンドウがどれだけシフトするかを決定します。通常の使用では、最初(バッチ)と最後(深度)のストライドを1に設定します。
非常に具体的な例を使用してみましょう:32x32グレースケール入力画像に対して2次元畳み込みを実行します。入力画像はdepth = 1なので、グレースケールと言います。これは単純さを保つのに役立ちます。その画像を次のようにします。
00 01 02 03 04 ...
10 11 12 13 14 ...
20 21 22 23 24 ...
30 31 32 33 34 ...
...
1つの例(バッチサイズ= 1)に対して2x2のたたみ込みウィンドウを実行してみましょう。コンボリューションの出力チャネル深度を8にします。
畳み込みへの入力にはがありshape=[1, 32, 32, 1]
ます。
で指定strides=[1,1,1,1]
した場合padding=SAME
、フィルターの出力は[1、32、32、8]になります。
フィルターは最初に次の出力を作成します。
F(00 01
10 11)
そして次に:
F(01 02
11 12)
等々。次に、2行目に移動して計算します。
F(10, 11
20, 21)
その後
F(11, 12
21, 22)
ストライドを[1、2、2、1]に指定すると、ウィンドウのオーバーラップは行われません。それは計算します:
F(00, 01
10, 11)
その後
F(02, 03
12, 13)
ストライドは、プーリングオペレーターと同様に動作します。
質問2:なぜconvnetsの[1、x、y、1]をストライドするか
最初の1つはバッチです。通常、バッチ内の例をスキップしたくないか、最初にそれらを含めるべきではありませんでした。:)
最後の1つは畳み込みの深さです。同じ理由で、通常は入力をスキップしたくありません。
conv2d演算子はより一般的です。そのため、ウィンドウを他の次元に沿ってスライドさせる畳み込みを作成できますが、これはconvnetsの一般的な使用法ではありません。典型的な用途は、それらを空間的に使用することです。
-1に再形成する理由 -1は、「完全なテンソルに必要なサイズに一致するように必要に応じて調整する」というプレースホルダーです。これは、コードを入力バッチサイズから独立させるための方法です。これにより、パイプラインを変更でき、コード内のすべての場所でバッチサイズを調整する必要がなくなります。