卷积和反卷积中的output shape计算

Conv2D

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import tensorflow as tf

input_shape = (4, 28, 28, 3)
x = tf.random.normal(input_shape)

y1 = tf.keras.layers.Conv2D(2, 3, activation='relu', input_shape=input_shape[1:],padding='valid')(x) # output_shape= (input_shape - filter_size + 1) * (input_shape - filter_size + 1)
print(y.shape)
>>(4, 26, 26, 2)

y2 = tf.keras.layers.Conv2D(2, 3, activation='relu', input_shape=input_shape[1:],padding="same")(x)
print(y.shape)
>>(4, 28, 28, 2)

y3 = tf.keras.layers.Conv2D(2, 3, activation='relu', input_shape=input_shape[1:],padding="valid",strides=2)(x)
print(y.shape) # output_shape= [(input_shape - filter_size)/strides + 1] * [(input_shape - filter_size)/strides + 1]
>>(4, 13, 13, 2)

y4 = tf.keras.layers.Conv2D(2, 3, activation='relu', input_shape=input_shape[1:],padding="same",strides=2)(x)
print(y.shape) # output_shape= (input_shape - filter_size + 1) * (input_shape - filter_size + 1)
>>(4, 14, 14, 2)

上例中输入是(28,28,3)shape。 我们在推算output shape时要分两种情况:

  1. padding="valid": output_shape= [(input_shape - filter_size)/strides + 1] * [(input_shape - filter_size)/strides + 1]。如果strides除不尽,则向下取整(取比该数小的那个整数)。所以y3shape是13
  2. padding="same": 当padding="same"时计算很简单,得到的outputshape一定是input_shape/strides。所以当strides=1时,输入和输出的shape时相等的,比如上面的y2

如果需要更细节的原理可以参考博客。这篇文章讲的特别好!重点推荐。

Conv2DTranspose

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
y1 = tf.keras.layers.Conv2DTranspose(2, 3, activation='relu', input_shape=input_shape[1:],padding="valid")(x)
print(y.shape)
>>(4, 30, 30, 2)

y2 = tf.keras.layers.Conv2DTranspose(2, 3, activation='relu', input_shape=input_shape[1:],padding="same")(x)
print(y.shape)
>>(4, 28, 28, 2)

y3 = tf.keras.layers.Conv2DTranspose(2, 3, activation='relu', input_shape=input_shape[1:],padding="valid",strides=2)(x)
print(y.shape)
>>(4, 57, 57, 2)

y4 = tf.keras.layers.Conv2DTranspose(2, 3, activation='relu', input_shape=input_shape[1:],padding="same",strides=2)(x)
print(y.shape)
>>(4, 56, 56, 2)

同样的总结下这个反卷积我们在推算output shape时也是分两种情况: 1. padding="valid": output_length = input_length * stride + max(filter_size - stride, 0) 2. padding="same": output_shape=input_shape * strides。当strides=1时,输出shape等于输入shape

padding=valid时的计算有点复杂。再细究一下的话,tensorflowConv2DTranspose还接受output_padding这个参数。如果有这个参数的话(默认是None),可以参考tensorflow官方文档给出的公式