了解keras Conv2DTranspose的输出形状

时间:2019-02-18 16:29:40

标签: keras layer shapes

我很难理解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,但是相反。

由于将Conv2D的kernel_size =(3,3),跨步=(10,10)和padding =“ same”应用于200x200图像,将输出20x20图像, 我假设将Conv2DTranspose的kernel_size =(3,3),步幅=(10,10)和padding =“ same”应用于20x20图像将输出200x200图像。

此外,将Conv2D的kernel_size =(3,3),步幅=(10,10)和padding =“ same”应用于195x195图像也将输出20x20图像。

因此,我了解到在应用带有kernel_size =(3,3),步幅=(10,10)和padding =“ same”的Conv2DTranspose时,输出形状上存在歧义(用户可能希望输出到是195x195或200x200或许多其他兼容的形状。

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

这说,我不太了解

  • “ output_padding”参数的含义

  • 参数“ padding”和“ output_padding”之间的相互作用

  • 函数keras.conv_utils.deconv_length

  • 中的各种公式

有人可以解释吗?

非常感谢,

朱利安

2 个答案:

答案 0 :(得分:0)

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

我在Pytorch文档中找到了它,在我看来,比在这个主题上的Keras文档更加清楚。

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

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

  

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

ALL 的n输出尺寸为4x4。

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

因此,当应用内核大小为3x3,跨度为7x7且填充为“相同”的Conv2DTranspose时,输出尺寸会模糊不清。

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

参数output_paddinbg是一种通过明确选择输出尺寸来解决歧义的方法。

在我的示例中,最小输出大小为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不支持);
    • 填充=='有效'的公式似乎正确(可以通过反转Conv2D的公式来计算)
    • 我的填充公式=='same'似乎不正确,以防kernel_size是偶数。 (事实上​​,当尝试使用input_dimension = 5x5,kernel_size = 2x2,stride = 7x7和padding ='same'构建Conv2DTranspose层时,keras崩溃。此主题的另一个主题...)

答案 1 :(得分:0)

Conv2DTranspose中的outpadding也是我在设计自动编码器时所关心的。

假设跨度始终为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,则必须仔细计算要添加多少输出填充。

在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一起填充的像素数。基于上面的讨论,张量流上没有'full'选项,我们将不得不使用out_padding来恢复其对应的Con2D的输入大小。

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

因此,总而言之,我认为out_padding用于促进不同的后端。