TensorFlow 反卷积 反池化

原文链接: TensorFlow 反卷积 反池化

上一篇: TensorFlow 梯度计算

下一篇: TensorFlow cifar 反卷积

参考

https://www.cnblogs.com/zyly/p/8991412.html

反卷积是指,通过测量输出和已知输入重构未知输入的过程。在神经网络中,反卷积过程并不具备学习的能力,仅仅是用于可视化一个已经训练好的卷积神经网络,没有学习训练的过程。反卷积有着许多特别的应用,一般可以用于信道均衡、图像恢复、语音识别、地震学、无损探伤等未知输入估计和过程辨识方面的问题。

在神经网络的研究中,反卷积更多的是充当可视化的作用,对于一个复杂的深度卷积网络,通过每层若干个卷积核的变换,我们无法知道每个卷积核关注的是什么,变换后的特征是什么样子。通过反卷积的还原,可以对这些问题有个清晰的可视化,以各层得到的特征图作为输入,进行反卷积得到反卷积结果,以验证显示各层提取到的特征图。

一 反卷积原理

反卷积可以理解为卷积操作的逆操作,这里千万不要当成反卷积操作可以复原卷积操作的输入值,反卷积并没有那个功能,它仅仅是将卷积变换过程中的步骤反向变换一次而已,通过将卷积核转置,与卷积后的结果再做一遍卷积,所以它还有一个名字叫做转置卷积。

举个例子:假如你想要查看Alexnet 的conv5提取到了什么东西,我们就用conv5的特征图后面接一个反卷积网络,然后通过:反池化、反激活、反卷积,这样的一个过程,把本来一张13*13大小的特征图(conv5大小为13*13),放大回去,最后得到一张与原始输入图片一样大小的图片(227*227)。

虽然它不能还原出原来卷积的样子,但是在作用上有类似的效果,你可以将带有小部分缺失的信息最大化的恢复,也可以用来恢复被卷积生成后的原始输入。

反卷积的具体操作比较复杂,这里不介绍如何具体实现反卷积,在tensorflow中反卷积的是通过函数tf.nn.conv2d_transpose()来实现的:

def conv2d_transpose(value,
                     filter,
                     output_shape,
                     strides,
                     padding="SAME",
                     data_format="NHWC",
                     name=None):

具体参数说明如下:

  • value:代表通过卷积操作之后的张量,一般用NHWC类型。如果是NHWC类型,形状[batch, height, width, in_channels],如果是NCHW类型,形状为[batch, in_channels, height, width]。
  • filter:代表卷积核,形状为[height, width, output_channels, in_channels]。
  • output_shape:反卷积输出的张量形状,它必须是能够生成value参数的原数据的形状,如果输出形状不对,函数会报错。
  • strides:代表原数据生成value时使用的步长。
  • padding:代表原数据生成value时使用的填充方式,是用来检查输入形状和输出形状是否合规的。
  • data_format: 'NHWC' and 'NCHW' 类型。
  • name:名称。

返回反卷积后的形状,按照output_shape指定的形状。

查看该函数的实现代码,我们可以看到反卷积的操作其实是使用了gen_nn_ops.conv2d_backprop_input()函数来实现的,相当于在TensorFlow中利用了卷积操作在反向传播的处理函数中做反卷积操作,即卷积操作的反向传播就是反卷积操作。

注意:在使用反卷积的网络中,定义占位符中不能存在None,必须指定具体的数,不然会报错。

import tensorflow as tf

img = tf.Variable(tf.constant(1.0, shape=[1, 4, 4, 1]))

filter = tf.Variable(tf.constant([1.0, 0, -1, -2], shape=[2, 2, 1, 1]))

conv = tf.nn.conv2d(img, filter, strides=[1, 2, 2, 1], padding='VALID')
cons = tf.nn.conv2d(img, filter, strides=[1, 2, 2, 1], padding='SAME')
print(conv.shape)
print(cons.shape)

contv = tf.nn.conv2d_transpose(conv, filter, [1, 4, 4, 1], strides=[1, 2, 2, 1], padding='VALID')
conts = tf.nn.conv2d_transpose(cons, filter, [1, 4, 4, 1], strides=[1, 2, 2, 1], padding='SAME')

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())

    print("conv:\n", sess.run([conv, filter]))
    print("cons:\n", sess.run([cons]))
    print("contv:\n", sess.run([contv]))
    print("conts:\n", sess.run([conts]))
conv:
 [array([[[[-2.],
         [-2.]],

        [[-2.],
         [-2.]]]], dtype=float32), array([[[[ 1.]],

        [[ 0.]]],


       [[[-1.]],

        [[-2.]]]], dtype=float32)]
cons:
 [array([[[[-2.],
         [-2.]],

        [[-2.],
         [-2.]]]], dtype=float32)]
contv:
 [array([[[[-2.],
         [ 0.],
         [-2.],
         [ 0.]],

        [[ 2.],
         [ 4.],
         [ 2.],
         [ 4.]],

        [[-2.],
         [ 0.],
         [-2.],
         [ 0.]],

        [[ 2.],
         [ 4.],
         [ 2.],
         [ 4.]]]], dtype=float32)]
conts:
 [array([[[[-2.],
         [ 0.],
         [-2.],
         [ 0.]],

        [[ 2.],
         [ 4.],
         [ 2.],
         [ 4.]],

        [[-2.],
         [ 0.],
         [-2.],
         [ 0.]],

        [[ 2.],
         [ 4.],
         [ 2.],
         [ 4.]]]], dtype=float32)]

反池化

反池化属于池化的逆操作,是无法通过池化的结果还原出全部的原始数据,因此池化的过程只保留主要信息,舍去部分信息。如果想从池化后的这些主要信息恢复出全部信息,由于存在着信息缺失,这时只能通过补位来实现最大程度的信息完整。

池化层常用的有最大池化和平均池化,其反池化也需要与其对应。

import tensorflow as tf


def max_pool_with_argmax(net, stride):
    _, mask = tf.nn.max_pool_with_argmax(net, ksize=[1, stride, stride, 1], strides=[1, stride, stride, 1],
                                         padding='SAME')
    mask = tf.stop_gradient(mask)
    net = tf.nn.max_pool(net, ksize=[1, stride, stride, 1], strides=[1, stride, stride, 1], padding='SAME')
    return net, mask


def unpool(net, mask, stride):
    ksize = [1, stride, stride, 1]
    input_shape = net.get_shape().as_list()
    #  calculation new shape
    output_shape = (input_shape[0], input_shape[1] * ksize[1], input_shape[2] * ksize[2], input_shape[3])
    # calculation indices for batch, height, width and feature maps
    one_like_mask = tf.ones_like(mask)
    batch_range = tf.reshape(tf.range(output_shape[0], dtype=tf.int64), shape=[input_shape[0], 1, 1, 1])
    b = one_like_mask * batch_range
    y = mask // (output_shape[2] * output_shape[3])
    x = mask % (output_shape[2] * output_shape[3]) // output_shape[3]
    feature_range = tf.range(output_shape[3], dtype=tf.int64)
    f = one_like_mask * feature_range
    # transpose indices & reshape update values to one dimension
    updates_size = tf.size(net)
    indices = tf.transpose(tf.reshape(tf.stack([b, y, x, f]), [4, updates_size]))
    values = tf.reshape(net, [updates_size])
    ret = tf.scatter_nd(indices, values, output_shape)
    return ret


img = tf.constant([
    [[0.0, 4.0], [0.0, 4.0], [0.0, 4.0], [0.0, 4.0]],
    [[1.0, 5.0], [1.0, 5.0], [1.0, 5.0], [1.0, 5.0]],
    [[2.0, 6.0], [2.0, 6.0], [2.0, 6.0], [2.0, 6.0]],
    [[3.0, 7.0], [3.0, 7.0], [3.0, 7.0], [3.0, 7.0]]
])

img = tf.reshape(img, [1, 4, 4, 2])
pooling2 = tf.nn.max_pool(img, [1, 2, 2, 1], [1, 2, 2, 1], padding='SAME')
encode, mask = max_pool_with_argmax(img, 2)
img2 = unpool(encode, mask, 2)
print(img.shape)
print(encode.shape)
print(mask.shape)
print(img2.shape)
with tf.Session() as sess:
    print("image:")
    print(sess.run(img))
    result = sess.run(pooling2)
    print("pooling2:\n", result)
    result, mask2 = sess.run([encode, mask])
    print("encode:\n", result, mask2)
    result = sess.run(img2)
    print("reslut:\n", result)
image:
[[[[0. 4.]
   [0. 4.]
   [0. 4.]
   [0. 4.]]

  [[1. 5.]
   [1. 5.]
   [1. 5.]
   [1. 5.]]

  [[2. 6.]
   [2. 6.]
   [2. 6.]
   [2. 6.]]

  [[3. 7.]
   [3. 7.]
   [3. 7.]
   [3. 7.]]]]
pooling2:
 [[[[1. 5.]
   [1. 5.]]

  [[3. 7.]
   [3. 7.]]]]
encode:
 [[[[1. 5.]
   [1. 5.]]

  [[3. 7.]
   [3. 7.]]]] [[[[ 8  9]
   [12 13]]

  [[24 25]
   [28 29]]]]
reslut:
 [[[[0. 0.]
   [0. 0.]
   [0. 0.]
   [0. 0.]]

  [[1. 5.]
   [0. 0.]
   [1. 5.]
   [0. 0.]]

  [[0. 0.]
   [0. 0.]
   [0. 0.]
   [0. 0.]]

  [[3. 7.]
   [0. 0.]
   [3. 7.]
   [0. 0.]]]]

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值