tensorflow
TFの高度な例を用いた2D畳み込みの背後にある数学
サーチ…
前書き
2D畳み込みは、 1D畳み込みを計算するのと同様の方法で計算されます。入力にカーネルをスライドさせ、要素ごとの乗算を計算して合計します。しかし、あなたのカーネル/入力の代わりに配列、ここでは行列です。
パディングなし、ストライド= 1
これは、最も簡単な計算で最も基本的な例です。あなたのinput
とkernel
が以下のものであると仮定しましょう:
あなたのカーネルが次の出力を受け取るでしょう: これは次のように計算されます。
- 14 = 4 * 1 + 3 * 0 + 1 * 1 + 2 * 2 + 1 * 1 + 0 * 0 + 1 * 0 + 2 * 0 + 4 * 1
- 6 = 3 * 1 + 1 * 0 + 0 * 1 + 1 * 2 + 0 * 1 + 1 * 0 + 2 * 0 + 4 * 0 + 1 * 1
- 6 = 2 * 1 + 1 * 0 + 0 * 1 + 1 * 2 + 2 * 1 + 4 * 0 + 3 * 0 + 1 * 0 + 0 * 1
- 12 = 1 * 1 + 0 * 0 + 1 * 1 + 2 * 2 + 4 * 1 + 1 * 0 + 1 * 0 + 0 * 0 + 2 * 1
TFのconv2d関数は、バッチでコンボリューションを計算し、わずかに異なる形式を使用します。入力の場合[batch, in_height, in_width, in_channels]
[filter_height, filter_width, in_channels, out_channels]
のカーネルの[filter_height, filter_width, in_channels, out_channels]
です。したがって、正しい形式でデータを提供する必要があります。
import tensorflow as tf
k = tf.constant([
[1, 0, 1],
[2, 1, 0],
[0, 0, 1]
], dtype=tf.float32, name='k')
i = tf.constant([
[4, 3, 1, 0],
[2, 1, 0, 1],
[1, 2, 4, 1],
[3, 1, 0, 2]
], dtype=tf.float32, name='i')
kernel = tf.reshape(k, [3, 3, 1, 1], name='kernel')
image = tf.reshape(i, [1, 4, 4, 1], name='image')
その後、畳み込みは次のように計算されます。
res = tf.squeeze(tf.nn.conv2d(image, kernel, [1, 1, 1, 1], "VALID"))
# VALID means no padding
with tf.Session() as sess:
print sess.run(res)
手で計算したものと同等になります。
いくつかのパディング、ストライド= 1
パディングはちょうどあなたの入力行列をいくつかの定数で囲むことを伝える素晴らしい名前です。ほとんどの場合、定数はゼロです。これが人々がゼロ埋め込みと呼ぶ理由です。したがって、最初の入力で1のパディングを使用する場合( padding=0, strides=1
の最初の例を確認してください)、マトリックスは次のようになります。
畳み込みの値を計算するには、同じスライディングを行います。私たちの場合、真ん中の多くの値を再計算する必要はないことに注意してください(前の例と同じですが、ここではすべての計算を表示しません)。結果は次のとおりです。
どこで
- 5 = 0 * 1 + 0 * 0 + 0 * 1 + 0 * 2 + 4 * 1 + 3 * 0 + 0 * 0 + 0 * 1 + 1 * 1
- ...
- 6 = 4 * 1 + 1 * 0 + 0 * 1 + 0 * 2 + 2 * 1 + 0 * 0 + 0 * 0 + 0 * 0 + 0 * 1
TFは、 conv2d関数内の任意のパディングをサポートしていないので、サポートされていないパディングが必要な場合は、 tf.pad()を使用してください 。幸いなことに、パディング 'SAME'はパディング= 1に等しくなりますので、前の例ではほとんど変更する必要はありません:
res = tf.squeeze(tf.nn.conv2d(image, kernel, [1, 1, 1, 1], "SAME"))
# 'SAME' makes sure that our output has the same size as input and
# uses appropriate padding. In our case it is 1.
with tf.Session() as sess:
print sess.run(res)
答えが手で計算されたものと同じであることを確認できます。
パディングとストライド(最も一般的なケース)
ここでは、先に説明したパッド付きの例にストライドされた畳み込みを適用し、 p = 1, s = 2
畳み込みを計算します
以前はstrides = 1
を使用していましたが、スライディングウィンドウは1つの位置に移動し、 strides = s
でs
位置を移動します( s^2
要素を少なく計算する必要がありますが、私たちはすでにs = 1
値を計算していたので、私たちの場合、それぞれの2番目の要素をつかむことができます。
したがって、解がs = 1
場合
s = 2
場合は次s = 2
ようになります。
前のマトリックスの値14,2,12,6の位置を確認します。コードで実行する必要があるのは、幅と高さの次元(2-nd、3-rd)に対してストライドを1から2に変更することだけです。
res = tf.squeeze(tf.nn.conv2d(image, kernel, [1, 2, 2, 1], "SAME"))
with tf.Session() as sess:
print sess.run(res)
ところで、さまざまな次元に対して異なるストライドを使用するのを止めるものはありません。