tf.nn.max_pool
的{{1}}中的'SAME'和'VALID'填充有什么区别?
在我看来,'VALID'意味着当我们做最大池时,边缘外没有零填充。
根据A guide to convolution arithmetic for deep learning,它表示池操作符中没有填充,即只使用tensorflow
的'VALID'。
但tensorflow
中最大池的'SAME'填充是什么?
答案 0 :(得分:487)
如果你喜欢ascii art:
"VALID"
=没有填充:
inputs: 1 2 3 4 5 6 7 8 9 10 11 (12 13)
|________________| dropped
|_________________|
"SAME"
=零填充:
pad| |pad
inputs: 0 |1 2 3 4 5 6 7 8 9 10 11 12 13|0 0
|________________|
|_________________|
|________________|
在这个例子中:
注意:
"VALID"
只会删除最右侧的列(或最底部的行)。"SAME"
尝试向左和向右均匀填充,但如果要添加的列数为奇数,则会向右添加额外列,如本示例中的情况(相同的逻辑适用)垂直:底部可能有一行额外的零。)答案 1 :(得分:124)
我举一个例子来说明一点:
x
:输入形状[2,3],1通道valid_pad
:带有2x2内核,步幅2和VALID填充的最大池。same_pad
:最大池,2x2内核,步幅2和SAME填充(这是经典方式)输出形状为:
valid_pad
:此处没有填充,因此输出形状为[1,1] same_pad
:在这里,我们将图像填充到形状[2,4](使用-inf
然后应用最大池),因此输出形状为[1,2] x = tf.constant([[1., 2., 3.],
[4., 5., 6.]])
x = tf.reshape(x, [1, 2, 3, 1]) # give a shape accepted by tf.nn.max_pool
valid_pad = tf.nn.max_pool(x, [1, 2, 2, 1], [1, 2, 2, 1], padding='VALID')
same_pad = tf.nn.max_pool(x, [1, 2, 2, 1], [1, 2, 2, 1], padding='SAME')
valid_pad.get_shape() == [1, 1, 1, 1] # valid_pad is [5.]
same_pad.get_shape() == [1, 1, 2, 1] # same_pad is [5., 6.]
答案 2 :(得分:121)
当e0e0e0e0e0e0e0e0e0e0e0e0e0e
为1时(卷积比汇集更典型),我们可以考虑以下区别:
stride
:输出大小与输入大小相同。这需要过滤器窗口在输入映射外滑动,因此需要填充。 "SAME"
:过滤器窗口位于输入地图内的有效位置,因此输出尺寸缩小"VALID"
。没有填充。答案 3 :(得分:77)
TensorFlow Convolution示例概述了SAME
和VALID
之间的区别:
对于SAME
填充,输出高度和宽度计算如下:
out_height = ceil(float(in_height) / float(strides[1]))
out_width = ceil(float(in_width) / float(strides[2]))
和
对于VALID
填充,输出高度和宽度计算如下:
out_height = ceil(float(in_height - filter_height + 1) / float(strides[1]))
out_width = ceil(float(in_width - filter_width + 1) / float(strides[2]))
答案 4 :(得分:43)
填充是一种增加输入数据大小的操作。在一维数据的情况下,您只需在数组中附加/前置一个常数,在二维模拟环绕矩阵中使用这些常数。在n-dim中,您可以使用常量围绕n-dim超立方体。在大多数情况下,此常量为零,称为零填充。
您可以为内核使用任意填充,但某些填充值的使用频率高于其他填充值:
k
k
的内核,此填充等于k - 1
。要在TF中使用任意填充,您可以使用tf.pad()
答案 5 :(得分:26)
与YvesgereY的出色回答相辅相成,我发现这种可视化非常有帮助:
填充“ 有效”是第一个数字。过滤器窗口停留在图像内部。
填充“ 相同”是第三个数字。输出大小相同。
在此article上找到了它。
答案 6 :(得分:23)
快速解释
VALID
:不要应用任何填充,即假设所有维度有效,以便输入图像完全被过滤器覆盖,并且您指定了步幅。
SAME
:将填充应用于输入(如果需要),以便输入图像被过滤器完全覆盖并按指定步幅。对于步幅1,这将确保输出图像大小与输入相同。
备注强>
NO_PADDING
。AUTO_PADDING
。SAME
(即自动填充模式)中,Tensorflow会尝试在左右两侧均匀分布填充。VALID
中(即无填充模式),如果您的过滤器和步幅没有完全覆盖输入图像,Tensorflow将会向右和/或底部单元格下降。答案 7 :(得分:11)
填充有三种选择:有效(无填充),相同(或一半),填充。你可以在这里找到解释(在Theano): http://deeplearning.net/software/theano/tutorial/conv_arithmetic.html
有效填充不涉及零填充,因此它仅覆盖有效输入,不包括人工生成的零。如果步幅s = 1,则输出长度为((输入长度) - (k-1))内核大小为k。
当s = 1时,相同的填充使输出的大小与输入的大小相同。如果s = 1,则填充的零数为(k-1)。
完整填充意味着内核在整个输入上运行,因此在最后,内核可能只满足一个输入和零。如果s = 1,填充的零的数量是2(k-1)。如果s = 1,则输出长度为((输入长度)+(k-1)。
因此,填充数量:(有效)< =(相同)< =(完整)
答案 8 :(得分:9)
我从官方张量流文档引用此答案https://www.tensorflow.org/api_guides/python/nn#Convolution 对于'SAME'填充,输出高度和宽度计算如下:
out_height = ceil(float(in_height) / float(strides[1]))
out_width = ceil(float(in_width) / float(strides[2]))
并且顶部和左侧的填充计算为:
pad_along_height = max((out_height - 1) * strides[1] +
filter_height - in_height, 0)
pad_along_width = max((out_width - 1) * strides[2] +
filter_width - in_width, 0)
pad_top = pad_along_height // 2
pad_bottom = pad_along_height - pad_top
pad_left = pad_along_width // 2
pad_right = pad_along_width - pad_left
对于'VALID'填充,输出高度和宽度计算如下:
out_height = ceil(float(in_height - filter_height + 1) / float(strides[1]))
out_width = ceil(float(in_width - filter_width + 1) / float(strides[2]))
,填充值始终为零。
答案 9 :(得分:5)
根据here的解释并跟进Tristan的回答,我通常会使用这些快速功能进行健全性检查。
# a function to help us stay clean
def getPaddings(pad_along_height,pad_along_width):
# if even.. easy..
if pad_along_height%2 == 0:
pad_top = pad_along_height / 2
pad_bottom = pad_top
# if odd
else:
pad_top = np.floor( pad_along_height / 2 )
pad_bottom = np.floor( pad_along_height / 2 ) +1
# check if width padding is odd or even
# if even.. easy..
if pad_along_width%2 == 0:
pad_left = pad_along_width / 2
pad_right= pad_left
# if odd
else:
pad_left = np.floor( pad_along_width / 2 )
pad_right = np.floor( pad_along_width / 2 ) +1
#
return pad_top,pad_bottom,pad_left,pad_right
# strides [image index, y, x, depth]
# padding 'SAME' or 'VALID'
# bottom and right sides always get the one additional padded pixel (if padding is odd)
def getOutputDim (inputWidth,inputHeight,filterWidth,filterHeight,strides,padding):
if padding == 'SAME':
out_height = np.ceil(float(inputHeight) / float(strides[1]))
out_width = np.ceil(float(inputWidth) / float(strides[2]))
#
pad_along_height = ((out_height - 1) * strides[1] + filterHeight - inputHeight)
pad_along_width = ((out_width - 1) * strides[2] + filterWidth - inputWidth)
#
# now get padding
pad_top,pad_bottom,pad_left,pad_right = getPaddings(pad_along_height,pad_along_width)
#
print 'output height', out_height
print 'output width' , out_width
print 'total pad along height' , pad_along_height
print 'total pad along width' , pad_along_width
print 'pad at top' , pad_top
print 'pad at bottom' ,pad_bottom
print 'pad at left' , pad_left
print 'pad at right' ,pad_right
elif padding == 'VALID':
out_height = np.ceil(float(inputHeight - filterHeight + 1) / float(strides[1]))
out_width = np.ceil(float(inputWidth - filterWidth + 1) / float(strides[2]))
#
print 'output height', out_height
print 'output width' , out_width
print 'no padding'
# use like so
getOutputDim (80,80,4,4,[1,1,1,1],'SAME')
答案 10 :(得分:4)
打开/关闭填充。确定输入的有效大小。
get
无填充。卷积运算等操作仅在“有效”位置执行,即不太靠近张量边界。
使用3x3的内核和10x10的图像,您将在边界内的8x8区域上进行卷积。
put
提供了填充。每当您的操作引用邻域(无论大小)时,当该邻域扩展到原始张量之外时,都会提供零值,以使该操作也可以处理边界值。
使用3x3内核和10x10图像,您将在整个10x10区域上进行卷积。
答案 11 :(得分:3)
VALID 填充:这是零填充。希望没有混乱。
x = tf.constant([[1., 2., 3.], [4., 5., 6.],[ 7., 8., 9.], [ 7., 8., 9.]])
x = tf.reshape(x, [1, 4, 3, 1])
valid_pad = tf.nn.max_pool(x, [1, 2, 2, 1], [1, 2, 2, 1], padding='VALID')
print (valid_pad.get_shape()) # output-->(1, 2, 1, 1)
SAME 填充:首先要理解这一点很棘手,因为我们必须分别考虑official docs中提到的两个条件。
我们将输入视为,输出为,填充为,步幅为,内核大小为(仅一维)被视为)
案例01::
案例02::
计算su可以用于填充的最小值。由于的值已知,因此可以使用此公式找到的值。
让我们来看看这个例子:
x = tf.constant([[1., 2., 3.], [4., 5., 6.],[ 7., 8., 9.], [ 7., 8., 9.]])
x = tf.reshape(x, [1, 4, 3, 1])
same_pad = tf.nn.max_pool(x, [1, 2, 2, 1], [1, 2, 2, 1], padding='SAME')
print (same_pad.get_shape()) # --> output (1, 2, 2, 1)
这里x的维数是(3,4)。然后,如果采取水平方向(3):
如果采用垂直方向(4):
希望这有助于了解实际上 SAME 填充在TF中是如何工作的。
答案 12 :(得分:3)
总而言之,“有效”填充表示没有填充。卷积层的输出大小根据输入大小和内核大小而缩小。
相反,“相同”填充表示使用填充。当跨度设置为1时,在计算卷积时,通过在输入数据周围附加一定数量的“ 0边界”,将卷积层的输出大小保持为输入大小。
希望这种直观的描述会有所帮助。
答案 13 :(得分:1)
答案 14 :(得分:0)
Tensorflow 2.0兼容答案:上面提供了有关“有效”填充和“相同”填充的详细说明。
但是,为了社区的利益,我将在 Tensorflow 2.x (>= 2.0)
中指定不同的Pooling Function及其相应的命令。
1.x中的功能:
tf.nn.max_pool
tf.keras.layers.MaxPool2D
Average Pooling => None in tf.nn, tf.keras.layers.AveragePooling2D
2.x中的功能:
tf.nn.max_pool
(如果用于2.x和 tf.compat.v1.nn.max_pool_v2
或 tf.compat.v2.nn.max_pool
)(如果已迁移)从1.x到2.x。
tf.keras.layers.MaxPool2D
(如果在2.x和
tf.compat.v1.keras.layers.MaxPool2D
或 tf.compat.v1.keras.layers.MaxPooling2D
或 tf.compat.v2.keras.layers.MaxPool2D
或 tf.compat.v2.keras.layers.MaxPooling2D
(如果从1.x迁移到2.x)。
Average Pooling => tf.nn.avg_pool2d
或 tf.keras.layers.AveragePooling2D
(如果在TF 2.x和
tf.compat.v1.nn.avg_pool_v2
或 tf.compat.v2.nn.avg_pool
或 tf.compat.v1.keras.layers.AveragePooling2D
或 tf.compat.v1.keras.layers.AvgPool2D
或 tf.compat.v2.keras.layers.AveragePooling2D
或 tf.compat.v2.keras.layers.AvgPool2D
(如果从1.x迁移到2.x)。
有关从Tensorflow 1.x到2.x迁移的更多信息,请参阅此Migration Guide。