TensorFlow的`conv2d_transpose()`操作做什么?
conv-neural-network
tensorflow
9
0

conv2d_transpose()操作的文档没有明确说明其作用:

conv2d的转置。

反卷积网络之后 ,此操作有时称为“反卷积”,但实际上是conv2d的转置(渐变),而不是实际的反卷积。

我浏览了文档所指向的论文,但没有帮助。

该操作有什么作用,为什么要使用它呢?

参考资料:
Stack Overflow
收藏
评论
共 4 个回答
高赞 时间 活跃

conv2d_transpose()只是将权重转置并将其翻转180度。然后,它应用标准的conv2d()。 “转置”实际上意味着它会更改权重张量中“列”的顺序。请检查以下示例。

这里有一个使用stride = 1和padding ='SAME'的卷积的例子。这是一个简单的案例,但其他案例也可以采用相同的推理。

说我们有:

  • 输入:28x28x1的MNIST图像,形状= [28,28,1]
  • 卷积层:32个7x7的滤镜,权重形状= [7,7,1,32],名称= W_conv1

如果我们对输入进行卷积,则的激活将具有以下形状:[1,28,28,32]。

 activations = sess.run(h_conv1,feed_dict={x:np.reshape(image,[1,784])})

哪里:

 W_conv1 = weight_variable([7, 7, 1, 32])
 b_conv1 = bias_variable([32])
 h_conv1 = conv2d(x, W_conv1, strides=[1, 1, 1, 1], padding='SAME') + b_conv1

要获得“解卷积”或“转置卷积”,我们可以通过以下方式对卷积激活使用conv2d_transpose():

  deconv = conv2d_transpose(activations,W_conv1, output_shape=[1,28,28,1],padding='SAME')

或使用conv2d()我们需要转置和翻转权重:

  transposed_weights = tf.transpose(W_conv1, perm=[0, 1, 3, 2])

在这里,我们将“列”的顺序从[0,1,2,3]更改为[0,1,3,2]。因此,从[7,7,1,32]中,我们将获得一个张量,其形状为= [7,7,32,1]。然后我们翻转权重:

  for i in range(n_filters):
      # Flip the weights by 180 degrees
      transposed_and_flipped_weights[:,:,i,0] =  sess.run(tf.reverse(transposed_weights[:,:,i,0], axis=[0, 1]))

然后我们可以使用conv2d()计算卷积:

  strides = [1,1,1,1]
  deconv = conv2d(activations,transposed_and_flipped_weights,strides=strides,padding='SAME')

我们将获得与以前相同的结果。同样,使用conv2d_backprop_input()也可以使用以下方法获得相同的结果:

   deconv = conv2d_backprop_input([1,28,28,1],W_conv1,activations, strides=strides, padding='SAME')

结果显示在这里:

测试conv2d(),conv2d_tranposed()和conv2d_backprop_input()

我们可以看到结果是相同的。要以更好的方式查看它,请在以下位置查看我的代码:

https://github.com/simo23/conv2d_transpose

在这里,我使用标准conv2d()复制conv2d_transpose()函数的输出。

收藏
评论

这是从“渐变”角度来看的另一种观点,即TensorFlow文档为何说conv2d_transpose()实际上是“ conv2d_transpose()的转置( 梯度 ),而不是实际的反卷积”。 有关conv2d_transpose完成的实际计算的更多详细信息,我强烈建议从第19页开始的这篇文章

四个相关功能

tf.nn ,有4个紧密相关且令人困惑的2d卷积函数:

  • tf.nn.conv2d
  • tf.nn.conv2d_backprop_filter
  • tf.nn.conv2d_backprop_input
  • tf.nn.conv2d_transpose

一句话总结: 它们都是二维卷积 。它们的区别在于输入参数的顺序,输入旋转或转置,步幅(包括小步幅大小),填充等。有了tf.nn.conv2d ,一个人就可以通过转换输入并更改输入来实现其他三个操作。 conv2d参数。

问题设定

  • 前进和后退计算:
# forward
out = conv2d(x, w)

# backward, given d_out
=> find d_x?
=> find d_w?

在正向计算中,我们用滤波器w计算输入图像x的卷积,结果为out 。在向后计算中,假定给定d_out ,即梯度wrt out 。我们的目标是找到d_xd_w ,分别是wrt xw的梯度。

为了便于讨论,我们假设:

  • 所有步幅均为1
  • 所有in_channelsout_channels均为1
  • 使用VALID填充
  • 奇数过滤器大小,这避免了一些不对称形状问题

简短答案

从概念上讲,根据上述假设,我们具有以下关系:

out = conv2d(x, w, padding='VALID')
d_x = conv2d(d_out, rot180(w), padding='FULL')
d_w = conv2d(x, d_out, padding='VALID')

rot180是旋转180度的2d矩阵(左右翻转和自上而下翻转), FULL表示“在与输入部分重叠的地方应用过滤器”(请参见theano docs )。注意, 这仅在以上假设下有效 ,但是,可以更改conv2d参数以将其概括化。

关键要点:

  • 输入梯度d_x是输出梯度d_out和权重w的卷积,并进行了一些修改。
  • 权重梯度d_w是输入x和输出梯度d_out ,进行了一些修改。

长答案

现在,让我们给出一个实际的工作代码示例,该示例d_x如何使用上述4个函数来计算d_xd_w给定d_out 。这显示conv2dconv2d_backprop_filterconv2d_backprop_inputconv2d_transpose相互关联。 请在此处找到完整的脚本

用4种不同的方式计算d_x

# Method 1: TF's autodiff
d_x = tf.gradients(f, x)[0]

# Method 2: manually using conv2d
d_x_manual = tf.nn.conv2d(input=tf_pad_to_full_conv2d(d_out, w_size),
                          filter=tf_rot180(w),
                          strides=strides,
                          padding='VALID')

# Method 3: conv2d_backprop_input
d_x_backprop_input = tf.nn.conv2d_backprop_input(input_sizes=x_shape,
                                                 filter=w,
                                                 out_backprop=d_out,
                                                 strides=strides,
                                                 padding='VALID')

# Method 4: conv2d_transpose
d_x_transpose = tf.nn.conv2d_transpose(value=d_out,
                                       filter=w,
                                       output_shape=x_shape,
                                       strides=strides,
                                       padding='VALID')

用3种不同的方式计算d_w

# Method 1: TF's autodiff
d_w = tf.gradients(f, w)[0]

# Method 2: manually using conv2d
d_w_manual = tf_NHWC_to_HWIO(tf.nn.conv2d(input=x,
                                          filter=tf_NHWC_to_HWIO(d_out),
                                          strides=strides,
                                          padding='VALID'))

# Method 3: conv2d_backprop_filter
d_w_backprop_filter = tf.nn.conv2d_backprop_filter(input=x,
                                                   filter_sizes=w_shape,
                                                   out_backprop=d_out,
                                                   strides=strides,
                                                   padding='VALID')

请参阅完整脚本 ,了解tf_rot180tf_pad_to_full_conv2dtf_NHWC_to_HWIO 。在脚本中,我们检查不同方法的最终输出值是否相同。 numpy实现也可用。

收藏
评论

这是我在网上看到的最好的解释是如何卷积转置的工作原理是在这里

我将简短说明。它采用分数步长进行卷积。换句话说,将输入值(带零)隔开以将过滤器应用于可能小于过滤器尺寸的区域。

至于为什么要使用它。与双线性插值法或某种其他固定形式的上采样相反,它可以用作一种具有学习权重的上采样。

收藏
评论

conv2d_transpose的一个应用程序是升频,这是一个解释其工作方式的示例:

a = np.array([[0, 0, 1.5],
              [0, 1, 0],
              [0, 0, 0]]).reshape(1,3,3,1)

filt = np.array([[1, 2],
                 [3, 4.0]]).reshape(2,2,1,1)

b = tf.nn.conv2d_transpose(a,
                           filt,
                           output_shape=[1,6,6,1],
                           strides=[1,2,2,1],
                           padding='SAME')

print(tf.squeeze(b))

tf.Tensor(
[[0.  0.  0.  0.  1.5 3. ]
 [0.  0.  0.  0.  4.5 6. ]
 [0.  0.  1.  2.  0.  0. ]
 [0.  0.  3.  4.  0.  0. ]
 [0.  0.  0.  0.  0.  0. ]
 [0.  0.  0.  0.  0.  0. ]], shape=(6, 6), dtype=float64)
收藏
评论
新手导航
  • 社区规范
  • 提出问题
  • 进行投票
  • 个人资料
  • 优化问题
  • 回答问题

关于我们

常见问题

内容许可

联系我们

@2020 AskGo
京ICP备20001863号