Two ways of padding convolution "SAME" and "VALID"

Conv2d is commonly used to implement convolution. When Tensorflow calls Conv's API, the commonly used code is as follows:

View: https://tensorflow.google.cn/api_docs/python/tf/nn/conv2d


tf.nn.conv2d(
    input,
    filter,
    strides,
    padding,
    use_cudnn_on_gpu=True,
    data_format='NHWC',
    dilations=[1, 1, 1, 1],
    name=None
)

The understanding of one of the parameters padding is:

padding: A `string` from: `"SAME", "VALID"`.
      The type of padding algorithm to use.

There are two options for padding: "SAME" and "VALID"

Give two chestnuts:

One:padding='SAME'

import tensorflow as tf

input = tf.Variable(tf.random_normal([1,5,5,3]))
filter = tf.Variable(tf.random_normal([3,3,3,7]))

result = tf.nn.conv2d(input, filter, strides=[1,2,2,1],padding='SAME')
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init)
print(sess.run(result))
print(result.shape)
sess.close()

The result is: 

[[[[  6.88815355e-01  -1.58929396e+00  -8.13352680e+00   3.47248018e-01
     -2.10637522e+00  -2.47548366e+00  -3.29180861e+00]
   [ -1.50164223e+00  -2.82424307e+00  -2.40781856e+00  -2.55665493e+00
     -3.89841533e+00  -6.71445191e-01   3.10867667e+00]
   [ -3.39479542e+00  -1.40321875e+00   2.29996824e+00  -3.98842275e-01
      7.90905952e-03  -1.71421432e+00  -5.47636747e-01]]

  [[ -1.07995415e+00  -2.21969414e+00  -1.43076777e-01   2.65041399e+00
     -4.38491011e+00  -4.83550358e+00   8.30997753e+00]
   [  1.35791779e+00  -1.38357902e+00  -4.50581169e+00   1.22106361e+00
     -1.36877072e+00  -1.19497585e+00  -3.64005876e+00]
   [ -3.07881045e+00   1.33630781e+01  -4.33032846e+00   1.98507690e+00
     -1.34837186e+00  -3.44964921e-01  -5.76371312e-01]]

  [[ -4.02724743e-01  -3.08082283e-01   1.51205099e+00  -2.11967897e+00
      8.77675891e-01  -3.89271736e-01   1.28933489e+00]
   [  1.05681574e+00   3.83993292e+00   1.46158600e+00   5.12251711e+00
     -4.37659168e+00  -5.88564873e-02   8.72927666e-01]
   [  3.13625002e+00  -2.52725768e+00  -1.89247894e+00  -2.89734745e+00
      2.49475980e+00  -7.85117006e+00   4.73596001e+00]]]]
(1, 3, 3, 7)

Two:padding='VALID'

import tensorflow as tf

input = tf.Variable(tf.random_normal([1,5,5,3]))
filter = tf.Variable(tf.random_normal([3,3,3,7]))

result = tf.nn.conv2d(input, filter, strides=[1,2,2,1],padding='VALID')
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init)
print(sess.run(result))
print(result.shape)
sess.close()

The result is:

[[[[  3.30246162e+00   1.00174313e+01   1.02988682e+01  -3.38870287e+00
      3.57620907e+00   9.25950432e+00   1.40226996e+00]
   [  2.39865661e+00   4.90117121e+00   6.27546692e+00  -7.14295626e+00
     -1.87810266e+00   4.73461962e+00  -8.87438393e+00]]

  [[  5.66498578e-01   1.21167574e+01  -2.98488545e+00   2.54433393e+00
     -4.40911025e-01  -4.96578693e-01   2.93070102e+00]
   [ -5.70178509e+00   1.09887476e+01   2.36247849e+00   2.91668701e+00
     -1.77950829e-01   1.17763281e-02  -9.67830420e-01]]]]
(1, 2, 2, 7)

For another example, let's take another chestnut. If x is a 2 × 3 matrix, the max pooling window is 2 × 2, and the stride is strides = 2.

For the first time because the window can be covered, the orange area does max pooling:

Since the step length is 2, after sliding two steps to the right, the VALID method finds that the remaining window is not available, so the third column is directly discarded, so the result is smaller than the original;

The SAME method is consistent with the original size, so it needs to be filled and filled with zero padding;

In addition, how do we calculate these two methods?

 If padding == "SAME":
      output_spatial_shape[i] = ceil(input_spatial_shape[i] / strides[i])

    If padding == "VALID":
      output_spatial_shape[i] =
        ceil((input_spatial_shape[i] -
              (spatial_filter_shape[i]-1) * dilation_rate[i])
              / strides[i])

dilation_rate is an optional parameter and defaults to 1.

padding = “SAME”:

S is the step size.

padding = “VALID”:

The output size is equal to the input size minus the filter size plus 1, and finally divided by the step size (f is the size of the filter and S is the step size).

Finally, it is interesting to give a few small chestnuts and say some padding = "SAME" how to fill zeros:

For the case where the original image does not match the convolution kernel, it is necessary to fill in the boundary of the image. The specific filling method is related to the number of elements that are different:

1. All 1 image of 28x28, 5x5 of convolution kernel all 1, two ends of each direction are filled with a 0, forming a 30x30 image with 0 all around

import tensorflow as tf

input = tf.Variable(tf.ones([1,28,28,1]))
filter = tf.Variable(tf.ones([5,5,1,1]))
op = tf.nn.conv2d(input,filter,strides=[1,5,5,1],padding='SAME')

with tf.Session() as sess:
	sess.run(tf.global_variables_initializer())
	res = sess.run(op)
	print("res.shape")
	print(res.shape)
	output = tf.reshape(res,[6,6])
	print(sess.run(output))

The result is:

res.shape
(1, 6, 6, 1)
[[ 16.  20.  20.  20.  20.  16.]
 [ 20.  25.  25.  25.  25.  20.]
 [ 20.  25.  25.  25.  25.  20.]
 [ 20.  25.  25.  25.  25.  20.]
 [ 20.  25.  25.  25.  25.  20.]
 [ 16.  20.  20.  20.  20.  16.]]

 2. All 1 images of 29x29

import tensorflow as tf

input = tf.Variable(tf.ones([1,29,29,1]))
filter = tf.Variable(tf.ones([5,5,1,1]))
op = tf.nn.conv2d(input,filter,strides=[1,5,5,1],padding='SAME')

with tf.Session() as sess:
	sess.run(tf.global_variables_initializer())
	res = sess.run(op)
	print("res.shape")
	print(res.shape)
	output = tf.reshape(res,[6,6])
	print(sess.run(output))

A 0 is added at the end of each row and column, and the result is:

res.shape
(1, 6, 6, 1)
[[ 25.  25.  25.  25.  25.  20.]
 [ 25.  25.  25.  25.  25.  20.]
 [ 25.  25.  25.  25.  25.  20.]
 [ 25.  25.  25.  25.  25.  20.]
 [ 25.  25.  25.  25.  25.  20.]
 [ 20.  20.  20.  20.  20.  16.]]

 3. All 1 images of 27x27

import tensorflow as tf

input = tf.Variable(tf.ones([1,27,27,1]))
filter = tf.Variable(tf.ones([5,5,1,1]))
op = tf.nn.conv2d(input,filter,strides=[1,5,5,1],padding='SAME')

with tf.Session() as sess:
	sess.run(tf.global_variables_initializer())
	res = sess.run(op)
	print("res.shape")
	print(res.shape)
	output = tf.reshape(res,[6,6])
	print(sess.run(output))

 A 0 is added at the beginning of each direction, and two 0s are added at the end. The result is:

res.shape
(1, 6, 6, 1)
[[ 16.  20.  20.  20.  20.  12.]
 [ 20.  25.  25.  25.  25.  15.]
 [ 20.  25.  25.  25.  25.  15.]
 [ 20.  25.  25.  25.  25.  15.]
 [ 20.  25.  25.  25.  25.  15.]
 [ 12.  15.  15.  15.  15.   9.]]

4. 26 × 26 All 1 image

import tensorflow as tf

input = tf.Variable(tf.ones([1,26,26,1]))
filter = tf.Variable(tf.ones([5,5,1,1]))
op = tf.nn.conv2d(input,filter,strides=[1,5,5,1],padding='SAME')

with tf.Session() as sess:
	sess.run(tf.global_variables_initializer())
	res = sess.run(op)
	print("res.shape")
	print(res.shape)
	output = tf.reshape(res,[6,6])
	print(sess.run(output))

 Two zeros are added at the beginning and end. The result is:

res.shape
(1, 6, 6, 1)
[[  9.  15.  15.  15.  15.   9.]
 [ 15.  25.  25.  25.  25.  15.]
 [ 15.  25.  25.  25.  25.  15.]
 [ 15.  25.  25.  25.  25.  15.]
 [ 15.  25.  25.  25.  25.  15.]
 [  9.  15.  15.  15.  15.   9.]]

The conclusions obtained are:

When the difference even number of elements is half of the first and the last complement, when the odd number is odd, the odd number is filled before and the even number is filled after 

The specific difference is closely related to the size of the selected convolution kernel and the sliding step, so what effect does the sliding step have? If the sliding step is changed to 1,

import tensorflow as tf

input = tf.Variable(tf.ones([1,26,26,1]))
filter = tf.Variable(tf.ones([5,5,1,1]))
op = tf.nn.conv2d(input,filter,strides=[1,1,1,1],padding='SAME')

with tf.Session() as sess:
	sess.run(tf.global_variables_initializer())
	res = sess.run(op)
	print("res.shape")
	print(res.shape)
	output = tf.reshape(res,[26,26])
	print(sess.run(output))

The result is:

res.shape
(1, 26, 26, 1)
[[  9.  12.  15.  15.  15.  15.  15.  15.  15.  15.  15.  15.  15.  15.
   15.  15.  15.  15.  15.  15.  15.  15.  15.  15.  12.   9.]
 [ 12.  16.  20.  20.  20.  20.  20.  20.  20.  20.  20.  20.  20.  20.
   20.  20.  20.  20.  20.  20.  20.  20.  20.  20.  16.  12.]
 [ 15.  20.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.
   25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  20.  15.]
 [ 15.  20.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.
   25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  20.  15.]
 [ 15.  20.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.
   25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  20.  15.]
 [ 15.  20.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.
   25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  20.  15.]
 [ 15.  20.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.
   25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  20.  15.]
 [ 15.  20.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.
   25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  20.  15.]
 [ 15.  20.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.
   25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  20.  15.]
 [ 15.  20.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.
   25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  20.  15.]
 [ 15.  20.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.
   25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  20.  15.]
 [ 15.  20.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.
   25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  20.  15.]
 [ 15.  20.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.
   25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  20.  15.]
 [ 15.  20.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.
   25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  20.  15.]
 [ 15.  20.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.
   25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  20.  15.]
 [ 15.  20.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.
   25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  20.  15.]
 [ 15.  20.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.
   25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  20.  15.]
 [ 15.  20.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.
   25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  20.  15.]
 [ 15.  20.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.
   25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  20.  15.]
 [ 15.  20.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.
   25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  20.  15.]
 [ 15.  20.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.
   25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  20.  15.]
 [ 15.  20.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.
   25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  20.  15.]
 [ 15.  20.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.
   25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  20.  15.]
 [ 15.  20.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.
   25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  20.  15.]
 [ 12.  16.  20.  20.  20.  20.  20.  20.  20.  20.  20.  20.  20.  20.
   20.  20.  20.  20.  20.  20.  20.  20.  20.  20.  16.  12.]
 [  9.  12.  15.  15.  15.  15.  15.  15.  15.  15.  15.  15.  15.  15.
   15.  15.  15.  15.  15.  15.  15.  15.  15.  15.  12.   9.]]

 Replace it with padding = "VALID"

import tensorflow as tf

input = tf.Variable(tf.ones([1,26,26,1]))
filter = tf.Variable(tf.ones([5,5,1,1]))
op = tf.nn.conv2d(input,filter,strides=[1,1,1,1],padding='VALID')

with tf.Session() as sess:
	sess.run(tf.global_variables_initializer())
	res = sess.run(op)
	print("res.shape")
	print(res.shape)
	output = tf.reshape(res,[22,22])
	print(sess.run(output))

The result is:

res.shape
(1, 22, 22, 1)
[[ 25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.
   25.  25.  25.  25.  25.  25.  25.  25.]
 [ 25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.
   25.  25.  25.  25.  25.  25.  25.  25.]
 [ 25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.
   25.  25.  25.  25.  25.  25.  25.  25.]
 [ 25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.
   25.  25.  25.  25.  25.  25.  25.  25.]
 [ 25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.
   25.  25.  25.  25.  25.  25.  25.  25.]
 [ 25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.
   25.  25.  25.  25.  25.  25.  25.  25.]
 [ 25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.
   25.  25.  25.  25.  25.  25.  25.  25.]
 [ 25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.
   25.  25.  25.  25.  25.  25.  25.  25.]
 [ 25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.
   25.  25.  25.  25.  25.  25.  25.  25.]
 [ 25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.
   25.  25.  25.  25.  25.  25.  25.  25.]
 [ 25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.
   25.  25.  25.  25.  25.  25.  25.  25.]
 [ 25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.
   25.  25.  25.  25.  25.  25.  25.  25.]
 [ 25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.
   25.  25.  25.  25.  25.  25.  25.  25.]
 [ 25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.
   25.  25.  25.  25.  25.  25.  25.  25.]
 [ 25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.
   25.  25.  25.  25.  25.  25.  25.  25.]
 [ 25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.
   25.  25.  25.  25.  25.  25.  25.  25.]
 [ 25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.
   25.  25.  25.  25.  25.  25.  25.  25.]
 [ 25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.
   25.  25.  25.  25.  25.  25.  25.  25.]
 [ 25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.
   25.  25.  25.  25.  25.  25.  25.  25.]
 [ 25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.
   25.  25.  25.  25.  25.  25.  25.  25.]
 [ 25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.
   25.  25.  25.  25.  25.  25.  25.  25.]
 [ 25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.  25.
   25.  25.  25.  25.  25.  25.  25.  25.]]

 in conclusion:

        The size of the convolution kernel and the sliding step directly affect the size of the final convolution result. When padding is in SAME mode, the original image is filled first, and then the convolution is performed. The filling value must be determined according to the size of the convolution kernel and the sliding step. ; When padding is in VALID mode, it is very simple and rough to start convolution directly from the first segment of the original image, and to the end can not directly match the part of the convolution kernel.

Reference article: https://blog.csdn.net/wuzqChom/article/details/74785643

Reference article: https://blog.csdn.net/syyyy712/article/details/80272071?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

Reference article: https://blog.csdn.net/zhaozx19950803/article/details/80409502?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

Reference article: https://blog.csdn.net/qq_17272679/article/details/79591540?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

 
Published 128 original articles · Like 132 · Visits 170,000+

Guess you like

Origin blog.csdn.net/yql_617540298/article/details/105127745