参数
conv2d_transpose(
inputs,
filters,
kernel_size,
strides=(1, 1),
padding=’valid’,
data_format=’channels_last’,
activation=None,
use_bias=True,
kernel_initializer=None,
bias_initializer=tf.zeros_initializer(),
kernel_regularizer=None,
bias_regularizer=None,
activity_regularizer=None,
kernel_constraint=None,
bias_constraint=None,
trainable=True,
name=None,
reuse=None
)
比较关注的参数:
- inputs: 输入的张量
- filters: 输出卷积核的数量
- kernel_size : 在卷积操作中卷积核的大小
- strides: (不太理解,我直接理解成放大的倍数)
- padding : ‘valid’ 或者 ‘same’。
观察之后看到,补0 过程分为两个部分:元素之间和外轮廓
1 、当padding = ‘valid’时:
元素之间补0:(input_size - 1)×(strides - 1)
外轮廓补0:(kernel_size - 1)× 2
output_size = (input_size + (input_size - 1)×(strides - 1) +(kernel_size - 1)× 2 - kernel_size ) / 1 + 1
2、当padding = ‘same’时:
output_size = input_size × strides
他是通过调整外轮廓的补0 数量实现的,如果不够,我个人觉得可能元素之间补0也会减少
img = np.random.randint(0, 255, (5, 16, 16, 32)).astype(np.float32)
img_t = tf.constant(img, tf.float32)
transpose_v = tf.layers.conv2d_transpose(inputs=img_t, filters=16, kernel_size=(6, 6), strides=(2, 2), padding='valid')
transpose_s = tf.layers.conv2d_transpose(inputs=img_t, filters=16, kernel_size=(6, 6), strides=(2, 2), padding='same')
print('valid 输出尺寸:', transpose_v.shape)
print('same 输出尺寸: ', transpose_s.shape)
valid 输出尺寸: (5, 36, 36, 16)
same 输出尺寸: (5, 32, 32, 16)
反卷积的过程
- Step 1 扩充: 将 inputs 进行填充扩大。扩大的倍数与strides有关。扩大的方式是在元素之间插strides - 1 个 0
- Step 2 卷积: 对扩充变大的矩阵,用大小为kernel_size卷积核做卷积操作,这样的卷积核有filters个,并且这里的步长为1(与参数strides无关,一定是1)
举个例子:
- inputs:[ [1, 1], [2,2] ]
- strides = 2(扩大2倍)
- filters = 1
- kernel_size = 3(假设核的值都是1)
- padding = ‘same’
Step 1:[2,2] 扩大至 [4,4]
- 问题描述:一个矩阵XX,通过 3*3 大小的卷积核,以 ‘same’的padding形式,步长为2做卷积,得到 [[1,1],[2,2]],问XX长啥样
通过填充,让原来2*2的矩阵变成4*4。填充的方式是我自己根据代码给出的结果猜的,大概就是先在元素之间插strides - 1个0,然后在填充边缘使矩阵达到目标尺寸。
目标尺寸可以根据下面的公式来求:
其中 x为目标尺寸,k是卷积核的尺寸, p表示填充的个数, o表示输出的尺寸,s表示步长。
在这里,k,p,s,o都是已知的,求x即可。但是因为有取整操作,实际上会有两个值符合x,似乎是取大的那个。
在这个例子中k=3,p=1,s=2,o=2,得到x=4或x=3或x=3,取大的那个,所以x=4
Step 2 : 做卷积,卷积核大小3*3, 步长为1
这一步就是普通的做卷积操作。
代码验证
a = np.array([[1,1],[2,2]], dtype=np.float32)
# [[1,1],
# [2,2]]
# tf.layers.conv2d_transpose 要求输入是4维的
a = np.reshape(a, [1,2,2,1])
# 定义输入
x = tf.constant(a,dtype=tf.float32)
# 进行tf.layers.conv2d_transpose
upsample_x = tf.layers.conv2d_transpose(x, 1, 3, strides=2, padding='same', kernel_initializer=tf.ones_initializer())
with tf.Session() as sess:
tf.global_variables_initializer().run()
print(sess.run(upsample_x))
# [[[[1],[1],[2],[1]],
# [[1],[1],[2],[1]],
# [[3],[3],[6],[3]],
# [[2],[2],[4],[2]]]]