反卷积(deconv)+ tf.nn.conv2d_transpose函数

最近在看有关图像分割的论文,遇到 tf.nn.conv2d_transpose 函数,即反卷积,下面我将介绍它的原理。

反卷积主要用于增大图像尺寸,是upsampling的一种,而空洞卷积并没有做upsampling,它是为了增大感受野,可以不改变图像的大小。对于反卷积简单理解就是在输入特征矩阵中插入空白点,再进行卷积,这样卷积后输出的特征矩阵就变大了。它的核心是在原来图像上插入空白数据,而空洞卷积就是在卷积核插入空白数据,普通卷积只会对边界进行填充。
反卷积图解请看 here

函数 tf.conv2d_transpose(value, filter, output_shape, strides, padding=“SAME”, data_format=“NHWC”, name=None)
name参数用以指定该操作的name,其余六个参数:
第一个参数value:指需要做反卷积的输入图像,它要求是一个Tensor
第二个参数filter:卷积核,它要求是一个Tensor,具有[filter_height, filter_width, out_channels, in_channels]这样的shape,具体含义是[卷积核的高度,卷积核的宽度,卷积核个数,图像通道数]
第三个参数output_shape:反卷积操作输出的shape,卷积操作是没有这个参数的
第四个参数strides:反卷积时在图像每一维的步长,这是一个一维的向量,长度4
第五个参数padding:string类型的量,只能是"SAME","VALID"其中之一,这个值决定了不同的卷积方式
第六个参数data_format:string类型的量,'NHWC’和’NCHW’其中之一,这是tensorflow新版本中新加的参数,它说明了value参数的数据格式。'NHWC’指tensorflow标准的数据格式[batch, height, width, in_channels],‘NCHW’指Theano的数据格式,[batch, in_channels,height, width],当然默认值是’NHWC’。

下面的图解讲的还算明白:
反卷积(deconv)+ tf.nn.conv2d_transpose函数_第1张图片
例子:
正向卷积流程:
input_shape = [1,5,5,3]
kernel_shape=[2,2,3,1]
strides=[1,2,2,1]
padding = “SAME”
out_shape 应该是[1,3,3,1] ,是只有一个通道的3*3的图片,
然后我们就对它进行反向操作:
设x=out_shape,#[1,3,3,1]

    import tensorflow as tf
    tf.set_random_seed(1)
    x = tf.random_normal(shape=[1,3,3,1])#正向卷积的结果,要作为反向卷积的输出
    kernel = tf.random_normal(shape=[2,2,3,1])#正向卷积的kernel的模样
 
    # strides 和padding也是假想中 正向卷积的模样。
    y = tf.nn.conv2d_transpose(x,kernel,output_shape=[1,5,5,3],
    strides=[1,2,2,1],padding="SAME")
    # 在这里,output_shape=[1,6,6,3]也可以,考虑正向过程,[1,6,6,3]时,然后通过
    # kernel_shape:[2,2,3,1],strides:[1,2,2,1]也可以
    # 获得x_shape:[1,3,3,1]。
    # output_shape 也可以是一个 tensor
    sess = tf.Session()
    tf.global_variables_initializer().run(session=sess)
    print(y.eval(session=sess))

然后输出的y就是最上面的input_shape。

我想到了一个很合理的方法就是这样定制你的反卷积网络,也即是你在进行反卷积之前,你要推算一下正向卷积所需要的路径,然后把正向卷积所需要的kernel,和strides写入tf.conv2d_transpose()函数就行了,当然输入和输出要互相对换一下就行了,
下面是3维反卷积操作,原理是一样的:

    import tensorflow as tf
  
    kernel1 = tf.constant(1.0, shape=[3,3,3,512,512]) #正向卷积核
    kernel2 = tf.constant(1.0, shape=[3,3,3,512,512]) #反向卷积核
    x3 = tf.constant(1.0, shape=[10,2,7,7,512])#正向卷积输入
    y2 = tf.nn.conv3d(x3, kernel1, strides=[1,1,1,1,1], padding="SAME") #正向卷积
    pool=tf.nn.max_pool3d(y2,ksize=[1,2,2,2,1],strides=[1,2,2,2,1],padding='SAME')#池化
 
    sess=tf.Session()
    sess.run(tf.global_variables_initializer())
    sess.run(pool)
    print(pool.shape)#(10,1,4,4,512)
 
    #反向卷积
    y3 = tf.nn.conv3d_transpose(pool,kernel2,output_shape=[10,2,7,7,512], 
    strides=[1,2,2,2,1],padding="SAME")
    sess.run(y3)
    print(y3.shape)#(10,2,7,7,512)

上面的例子是由[10,2,7,7,512]–>卷积池化到–>[10,1,4,4,512]–>反卷积到–>[10,2,7,7,512]

你可能感兴趣的:(反卷积(deconv)+ tf.nn.conv2d_transpose函数)