1. tadOne

    Posted

    tadOne
Changes in title
+Tensorflow - padding = VALID/SAMEの違いについて
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,94 @@
+# はじめに
+Tensorflowの畳込み層やプーリング層のパラメータの一つpadding
+これについて迷ったので備忘までに記述します
+
+# 教科書的な出力サイズの解釈
+
+例えば下記の様なコードがあったとします
+
+```py:cnn.py
+# 重みを標準偏差0.1の正規分布で初期化
+def weight_variable(shape):
+ initial = tf.truncated_normal(shape, stddev=0.1)
+ return tf.Variable(initial)
+
+# バイアスを標準偏差0.1の正規分布で初期化
+def bias_variable(shape):
+ initial = tf.constant(0.1, shape=shape)
+ return tf.Variable(initial)
+
+# 畳み込み層の作成
+def conv2d(x, W):
+ return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')
+
+# プーリング層の作成
+def max_pool_2x2(x):
+ return tf.nn.max_pool(x, ksize=[1, 2, 2, 1],
+ strides=[1, 2, 2, 1], padding='SAME')
+# 入力を28x28x3に変形
+x_images = tf.reshape(images_placeholder, [-1, 28, 28, 3])
+
+# 畳み込み層1の作成
+with tf.name_scope('conv1') as scope:
+ W_conv1 = weight_variable([5, 5, 3, 32])
+ b_conv1 = bias_variable([32])
+ h_conv1 = tf.nn.relu(conv2d(x_images, W_conv1) + b_conv1)
+
+# プーリング層1の作成
+with tf.name_scope('pool1') as scope:
+ h_pool1 = max_pool_2x2(h_conv1)
+
+# 畳み込み層2の作成
+with tf.name_scope('conv2') as scope:
+ W_conv2 = weight_variable([5, 5, 32, 64])
+ b_conv2 = bias_variable([64])
+ h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
+
+# プーリング層2の作成
+with tf.name_scope('pool2') as scope:
+ h_pool2 = max_pool_2x2(h_conv2)
+```
+
+このようなネットワーク定義があり、仮にゼロパディングをしていないとすると、以下の様な計算を経て、最終出力が得られると考えられます
+
+※計算式: (inputのx(y)軸の要素数 - filter(weight)のx(y)軸の要素数) / strideの要素数
+1. 入力イメージ => 28x28x3
+2. conv1 => (28 - 5) / 1 = 23
+3. pool1 => (23 - 2) / 2 = 11 (tensorflowは端数をceilするため)
+4. conv2 => (11 - 5) / 1 = 6
+5. pool2 => (6 - 2) / 2 = 2 =====> よって 2x2x64 のテンソルが得られる
+
+しかし、このコードでは最終的に7x7x64の結果が得られています
+これが「padding='SAME'」というパラメータの役割ですね
+実際の計算式は以下のとおりとなっています
+
+※計算式: (inputのx(y)軸の要素数) / strideの要素数
+1. 入力イメージ => 28x28x3
+2. conv1 => (28) / 1 = 28
+3. pool1 => (28) / 2 = 14
+4. conv2 => (14) / 1 = 14
+5. pool2 => (14) / 2 = 7 =====> よって 7x7x64 のテンソルが得られる
+
+つまりストライド分を補うようにゼロパディングされているというわけです
+
+#マニュアル
+具体的にどういう計算式になるかというのは以下に記載しています
+https://www.tensorflow.org/versions/r0.7/api_docs/python/nn.html#convolution
+
+padding='SAME'
+
+```
+out_height = ceil(float(in_height) / float(strides[1]))
+out_width = ceil(float(in_width) / float(strides[2]))
+```
+
+padding='VALID'
+
+```
+out_height = ceil(float(in_height - filter_height + 1) / float(strides[1]))
+out_width = ceil(float(in_width - filter_width + 1) / float(strides[2]))
+```
+
+# 結論
+全結合層においては最終プーリング層からの次元数を指定する必要があるので、どう計算されているかが非常に重要になります
+まあSAMEを指定すれば単純にstrideの割り算で済むので、こちらを使ってあげればいいのかなあというざっくりとした感想ですかね