【问题标题】:understanding output shape of keras Conv2DTranspose理解 keras Conv2DTranspose 的输出形状
【发布时间】:2019-02-18 16:29:40
【问题描述】:

我很难理解 keras.layers.Conv2DTranspose 的输出形状

这是原型:

keras.layers.Conv2DTranspose(
    filters,
    kernel_size,
    strides=(1, 1),
    padding='valid',
    output_padding=None,
    data_format=None,
    dilation_rate=(1, 1),
    activation=None,
    use_bias=True,
    kernel_initializer='glorot_uniform',
    bias_initializer='zeros',
    kernel_regularizer=None,
    bias_regularizer=None,
    activity_regularizer=None,
    kernel_constraint=None,
    bias_constraint=None
)

在文档 (https://keras.io/layers/convolutional/) 中,我读到:

If output_padding is set to None (default), the output shape is inferred.

在代码(https://github.com/keras-team/keras/blob/master/keras/layers/convolutional.py)中,我读到:

out_height = conv_utils.deconv_length(height,
                                      stride_h, kernel_h,
                                      self.padding,
                                      out_pad_h,
                                      self.dilation_rate[0])
out_width = conv_utils.deconv_length(width,
                                     stride_w, kernel_w,
                                     self.padding,
                                     out_pad_w,
                                     self.dilation_rate[1])
if self.data_format == 'channels_first':
    output_shape = (batch_size, self.filters, out_height, out_width)
else:
    output_shape = (batch_size, out_height, out_width, self.filters)

和(https://github.com/keras-team/keras/blob/master/keras/utils/conv_utils.py):

def deconv_length(dim_size, stride_size, kernel_size, padding, output_padding, dilation=1):

    """Determines output length of a transposed convolution given input length.
    # Arguments
        dim_size: Integer, the input length.
        stride_size: Integer, the stride along the dimension of `dim_size`.
        kernel_size: Integer, the kernel size along the dimension of `dim_size`.
        padding: One of `"same"`, `"valid"`, `"full"`.
        output_padding: Integer, amount of padding along the output dimension, can be set to `None` in which case the output length is inferred.
        dilation: dilation rate, integer.
    # Returns
        The output length (integer).
    """

    assert padding in {'same', 'valid', 'full'}
    if dim_size is None:
        return None

    # Get the dilated kernel size
    kernel_size = kernel_size + (kernel_size - 1) * (dilation - 1)

    # Infer length if output padding is None, else compute the exact length
    if output_padding is None:
        if padding == 'valid':
            dim_size = dim_size * stride_size + max(kernel_size - stride_size, 0)
        elif padding == 'full':
            dim_size = dim_size * stride_size - (stride_size + kernel_size - 2)
        elif padding == 'same':
            dim_size = dim_size * stride_size
    else:
        if padding == 'same':
            pad = kernel_size // 2
        elif padding == 'valid':
            pad = 0
        elif padding == 'full':
            pad = kernel_size - 1

        dim_size = ((dim_size - 1) * stride_size + kernel_size - 2 * pad + output_padding)

    return dim_size

我知道 Conv2DTranspose 是一种 Conv2D,但相反。

由于将 kernel_size = (3, 3)、strides = (10, 10) 和 padding = "same" 的 Conv2D 应用到 200x200 图像将输出 20x20 图像, 我假设将 kernel_size = (3, 3)、strides = (10, 10) 和 padding = "same" 的 Conv2DTranspose 应用于 20x20 图像将输出 200x200 图像。

此外,将 kernel_size = (3, 3)、strides = (10, 10) 和 padding = "same" 的 Conv2D 应用到 195x195 图像也会输出 20x20 图像。

所以,我知道在应用具有 kernel_size = (3, 3)、strides = (10, 10) 和 padding = "same" 的 Conv2DTranspose 时,输出形状存在某种歧义(用户可能希望输出到是 195x195 或 200x200 或许多其他兼容的形状)。

我假设“输出形状是推断出来的”。表示根据层的参数计算默认输出形状,并且我假设有一种机制可以指定与默认输出形状不同的输​​出形状,如果需要的话。

这个说的,我不太明白

  • “output_padding”参数的含义

  • 参数“padding”和“output_padding”的交互作用

  • keras.conv_utils.deconv_length函数中的各种公式

有人能解释一下吗?

非常感谢,

朱利安

【问题讨论】:

  • 我坚信“output_padding”正是您正在寻找的用于创建不同输出大小的参数。
  • 是的我怀疑,现在我想要的是(1)“output_padding”参数的具体含义(2)参数“padding”和“output_padding”之间的相互作用(3)一个解释keras.conv_utils.deconv_length函数中的各种公式
  • 这没有帮助吗? keras.io/layers/convolutional 它似乎包含大量相关文档。
  • @MandyShaw 这个文档(我在我的问题中提到)提供了转置卷积的高级一般概念。它没有提供我需要的详细解释,这就是我首先在 SO 上发布的原因。
  • 好的,很抱歉没有提供帮助。

标签: keras layer shapes


【解决方案1】:

我可能找到了(部分)答案。

我是在 Pytorch 文档中找到的,它似乎比 Keras 文档关于这个主题要清晰得多。

当对尺寸接近的图像应用步幅大于 1 的 Conv2D 时,我们会得到相同尺寸的输出图像。

例如,当应用内核大小为 3x3、步幅为 7x7 且填充“相同”的 Conv2D 时,以下图像尺寸

22x22、23x23、...、28x28、22x28、28x22、27x24 等(7x7 = 49 组合)

全部产生 4x4 的输出尺寸。

那是因为 output_dimension = ceiling(input_dimension / stride)。

因此,当应用内核大小为 3x3、步幅为 7x7 且填充“相同”的 Conv2DTranspose 时,输出维度存在歧义。

49 个可能的输出维度中的任何一个都是正确的。

参数 output_padding 是一种通过明确选择输出维度来解决歧义的方法。

在我的示例中,最小输出大小为 22x22,并且 output_padding 提供了要在输出图像底部添加的行数(0 到 6 之间)和要添加的列数(0 到 6 之间)输出图像的右侧。

如果我使用 outout_padding = (2, 3),我可以获得 output_dimensions = 24x25

然而,我仍然不明白的是,当未指定 output_padding 时(当它“推断”输出形状时),keras 用于选择某个输出图像尺寸的逻辑

几点建议:

https://pytorch.org/docs/stable/nn.html#torch.nn.ConvTranspose2d https://discuss.pytorch.org/t/the-output-size-of-convtranspose2d-differs-from-the-expected-output-size/1876/5 https://discuss.pytorch.org/t/question-about-the-output-padding-in-nn-convtrasnpose2d/19740 https://discuss.pytorch.org/t/what-does-output-padding-exactly-do-in-convtranspose2d/2688

所以回答我自己的问题:

  • “output_padding”参数的含义:见上
  • 参数“padding”和“output_padding”之间的相互作用:这些参数是独立的
  • 函数keras.conv_utils.deconv_length中的各种公式
    • 目前,我不明白 output_padding 为 None 的部分;
    • 我忽略了 padding == 'full' 时的情况(Conv2DTranspose 不支持);
    • padding == 'valid' 的公式似乎是正确的(可以通过反转 Conv2D 的公式来计算)
    • 填充 == 'same' 的公式对我来说似乎不正确,以防 kernel_size 是偶数。 (事实上​​,keras 在尝试使用 input_dimension = 5x5、kernel_size = 2x2、stride = 7x7 和 padding = 'same' 构建 Conv2DTranspose 层时崩溃。在我看来,keras 中存在错误,我将开始此主题的另一个线程...)

【讨论】:

  • 这是一个有见地的讨论。对于自动编码器,具有相同的输出维度至关重要。玩弄输出填充似乎是一种指定输出尺寸的倾斜方式......
  • 您好, output_padding 是调整输出维度的正确参数。这正是它的目的。但是keras有个bug,输出维度的公式不正确。
【解决方案2】:

Conv2DTranspose 中的外边距也是我在设计自动编码器时关心的问题。

假设 stride 始终为 1。沿着编码器路径,对于每个卷积层,我选择了 padding='valid',这意味着如果我的输入图像是 HXW,并且过滤器的大小为 mXn,则该层的输出将为 (H-(m-1))X(W-(n-1))。

在沿着解码器路径对应的Con2DTranspose层中,如果我使用Theano,为了恢复其对应Con2D的输入大小,我必须选择padding='full',并且out_padding = None或者0(没有区别) ,这意味着输入大小将在其周围扩展[m-1,n-1],即顶部和底部为(m-1)/2,左右为(n-1)/2。

如果我使用 tensorflow,我将不得不选择 padding = 'same' 和 out_padding = 2*((filter_size-1)//2),我认为这是 Keras 的预期行为。

如果步幅不是 1,那么您必须仔细计算要添加多少输出填充。

In Conv2D out_size = floor(in_size+2*padding_size-filter_size)/stride+1)

如果我们选择 padding = 'same',Keras 会自动设置 padding = (filter_size-1)/2;而如果我们选择“有效”,则 padding_size 将设置为 0,这是任何 N-D 卷积的惯例。

反之,在 Con2DTranspose 中 out_size = (in_size-1)*stride+filter_size-2*padding_size

其中 padding_size 指的是由 'padding' 选项和 out_padding 一起实际填充多少像素。根据上面的讨论,tensorflow 上没有 'full' 选项,我们将不得不使用 out_padding 来恢复其对应 Con2D 的输入大小。

您能否尝试看看它是否正常工作并告诉我,好吗?

所以总的来说,我认为 out_padding 用于促进不同的后端。

【讨论】:

    【解决方案3】:

    output_padding=None 时,Keras 使用deconv_output_length 方法计算输出长度,将其设置为:

    if padding == 'valid':
       length = input_length * stride + max(filter_size - stride, 0)
    elif padding == 'same':
       length = input_length * stride
    

    现在在文档中说如果设置了output_padding,输出长度将为

    ((input_length - 1) * stride + filter_size - 2 * padding + output_padding
    

    所以使用它我们可以找出默认的output_padding 是什么。

    • padding='valid'的情况下,上面的padding = 0,所以求解output_padding

      output_padding = max(stride - filter_size, 0)
      

    padding='valid'

    在这种情况下,上面是padding = 0,所以求解output_padding

      output_padding = max(stride - filter_size, 0)
    

    并且可以检查设置此结果是否与将其设置为 None 相同

    padding = 'same'

    这种情况要神秘得多,实际上通过将其设置为任何整数似乎都不可能得到与output_padding=None相同的值。例如对于strides=2kernel_size=2,对于大于1 的output_padding,它会给出一个警告,即步幅必须大于输出填充。对于小于 1 的任何内容,它都会发出警告,指出 out_backprop 的大小与计算的不匹配。所以唯一有效的值是 1,但这会导致与 None 不同的输出形状。

    实际上它并不是通过将output_padding设置为某个默认值来实现的,它只是用于计算输出形状,然后用于卷积方法中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-11-23
      • 1970-01-01
      • 1970-01-01
      • 2021-06-25
      • 1970-01-01
      • 1970-01-01
      • 2017-03-01
      相关资源
      最近更新 更多