我很难理解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
有人可以解释吗?
非常感谢,
朱利安
答案 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
所以回答我自己的问题:
答案 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用于促进不同的后端。