tensorflow 卷积以及反卷积函数 相关参数 shape计算

最近又要做一些深度学习的东西,哎,tensorflow一更新,好多自己原来的代码都运行不了,而且好久没弄也忘了,痛苦,复习也是学习。。。

tf.nn.conv2d:

第一个参数input:指需要做卷积的输入图像,它要求是一个Tensor,具有[batch, in_height, in_width, in_channels]这样的shape,具体含义是[训练时一个batch的图片数量, 图片高度, 图片宽度, 图像通道数],注意这是一个4维的Tensor,要求类型为float32和float64其中之一

第二个参数filter:相当于CNN中的卷积核,它要求是一个Tensor,具有[filter_height, filter_width, in_channels, out_channels]这样的shape,具体含义是[卷积核的高度,卷积核的宽度,图像通道数,卷积核个数],要求类型与参数input相同,有一个地方需要注意,第三维in_channels,就是参数input的第四维,第四维是卷积核的个数,那也就是这个卷积核过后新的input的channel数

第三个参数strides:卷积时在图像每一维的步长,这是一个一维的向量,长度4,这个和input去对应,第一个参数是在batch的数据上遍历,你肯定是一个一个的遍历,所以第一位肯定是1,第四个参数因为filter上的卷积核的深度和图片的channel是一样的,所以也不需要这么走,所以第四维的参数也应该是1,中间两个一般相同
官方源码是这样说的:
Must have strides[0] = strides[3] = 1. For the most common case of the same horizontal and vertices strides, strides = [1, stride, stride, 1].

第四个参数padding:string类型的量,只能是”SAME”,”VALID”其中之一,这个值决定了不同的卷积方式
same就是会用0填充,保证size形状相同;valid就是不填充

关于输出的结果,其实反卷积的时候就是一个逆函数

The TensorFlow Convolution example gives an overview about the difference between SAME and VALID :

For the SAME padding, the output height and width are computed as:

out_height = ceil(float(in_height) / float(strides[1]))

out_width = ceil(float(in_width) / float(strides[2]))

And

For the VALID padding, the output height and width are computed as:

out_height = ceil(float(in_height - filter_height + 1) / float(strides1))

out_width = ceil(float(in_width - filter_width + 1) / float(strides[2]))

tf.nn.max_pool:

tf.nn.max_pool(value, ksize, strides, padding, name=None)
参数是四个,和卷积很类似,池化层神经网络不会改变三维矩阵的深度,但是它可以缩小矩阵的大小。

第一个参数value:需要池化的输入,一般池化层接在卷积层后面,所以输入通常是feature map,依然是[batch, height, width, channels]这样的shape

第二个参数ksize:池化窗口的大小,取一个四维向量,一般是[1, height, width, 1],因为我们不想在batch和channels上做池化,所以这两个维度设为了1

第三个参数strides:和卷积类似,窗口在每一个维度上滑动的步长,一般也是[1, stride,stride, 1]

第四个参数padding:和卷积类似,可以取’VALID’ 或者’SAME’

跟上面的一样,结果的size只和原始的size和strides有关系

tf.nn.conv2d_transpose:

反卷积或者解卷积:动图可以在这看

  1. value: A 4-D Tensor of type float and shape [batch, height, width, in_channels] for NHWC data format or [batch, in_channels, height, width] for NCHW data format.
  2. filter: A 4-D Tensor with the same type as value and shape [height, width, output_channels, in_channels]. filter's in_channels dimension must match that of value.
  3. output_shape: A 1-D Tensor representing the output shape of the deconvolution op.
  4. strides: A list of ints. The stride of the sliding window for each dimension of the input tensor.
  5. padding: A string, either 'VALID' or 'SAME'. The padding algorithm.

这里面的output_shape和strides有耦合关系,步长很小,input也很小,output很大肯定不行的。
用相同的kernel和strides以及padding方式,肯定能变成原来的形状,但是也能output_shape大一个或者小一个,所以你应该大致想一下有哪些shape用这个kernel和strides能变成这个value 的shape就行了

layers.conv2d_transpose:

layers是更高级的api,一般推荐使用这个下面封装的,和上面的对比的一些区别

  1. inputs: Input tensor.
  2. filters: Integer, the dimensionality of the output space (i.e. the number of filters in the convolution).
  3. kernel_size: A tuple or list of 2 positive integers specifying the spatial dimensions of the filters. Can be a single integer to specify the same value for all spatial dimensions.
  4. strides: A tuple or list of 2 positive integers specifying the strides of the convolution. Can be a single integer to specify the same value for all spatial dimensions.
  5. padding: one of "valid" or "same" (case-insensitive).
我的理解:

filters 就一位数,决定输出的shape的最后一维大小。
Kernel_size 就两位数,决定了核尺寸,影响不大,但对shape肯定有影响,两种方式和tf.nn.conv2d的计算结果就是in是out,out是in就行,same直接(in * 步长),valid就是 (in * strides)-1+卷积核的大小
filters和Kernel_size就是表示了一个卷积核,但是它减少了1个纬度。其实你相信因为卷积过程的时候,卷积核filter的第三位一定是input的第四维,其实都写死了,所以反卷积的时候也是一样,有一个纬度是input的最后一维已经决定了。
而对于Strides这个参数,原来也说了,两边固定都是1,也给省略了,所以它也省略了

具体测试代码

import tensorflow as tf
from tensorflow import layers

x1 = tf.constant(1.0, shape=[1, 3, 3, 1])
kernel = tf.constant(1.0, shape=[3, 3, 3, 2])

# x2 = tf.constant(1.0, shape=[1, 6, 6, 3])
x3 = tf.constant(1.0, shape=[1, 5, 5, 3])

y2 = tf.nn.conv2d(x3, kernel, strides=[1, 2, 2, 1], padding="SAME")
y_d = tf.nn.conv2d_transpose(y2, kernel, output_shape=[1, 5, 5, 3], strides=[1, 2, 2, 1], padding='SAME')
y_d2 = layers.conv2d_transpose(y2, 3, kernel_size=(4, 4), strides=(2, 2), padding="same")
y3 = tf.nn.max_pool(y2, [1, 2, 2, 1], [1, 2, 2, 1], padding='SAME')
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    yr = sess.run(y2)
    yr1 = sess.run(y3)
    yr2 = sess.run(y_d)
yr3 = sess.run(y_d2)
print(yr.shape)
# print(yr1.shape)
print(yr2.shape)
print(yr3.shape)

发表评论

电子邮件地址不会被公开。