Help us understand the problem. What is going on with this article?

Tensorflow - padding = VALID/SAMEの違いについて

More than 3 years have passed since last update.

はじめに

Tensorflowの畳込み層やプーリング層のパラメータの一つpadding
これについて迷ったので備忘までに記述します

畳み込み、プーリング層からの出力テンソル次元数

例えば下記の様なコードがあったとします

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
1. 入力イメージ => 28x28x3
2. conv1 => (28 - 5) / 1 + 1 = 24 
3. pool1 => (24 - 2) / 2 + 1 = 12 
4. conv2 => (12 - 5) / 1 + 1 = 8
5. pool2 => (8 - 2) / 2 + 1 = 4 =====> よって  4x4x64 のテンソルが得られる

しかし、このコードでは最終的に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 のテンソルが得られる

つまりフィルタ分を補うようにゼロパディングされているというわけです

逆に「padding='VALID'」というパラメータでは以下の様な計算をすると考えられます

※計算式: (inputのx(y)軸の要素数 - filter(weight)のx(y)軸の要素数 + 1) / strideの要素数
1. 入力イメージ => 28x28x3
2. conv1 => (28 - 5 + 1) / 1 = 24 
3. pool1 => (24 - 2 + 1) / 2 = 11.5 => 12 (ceil処理のため)
4. conv2 => (12 - 5 + 1) / 1  = 8
5. pool2 => (8 - 2 + 1) / 2 = 3.5 => 4 =====> よって  4x4x64 のテンソルが得られる

マニュアル

具体的にどういう計算式になるかというのは以下に記載しています
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の割り算で済むので、こちらを使ってあげればいいのかなあというざっくりとした感想ですかね

tadOne
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした