ChatGPT解决这个技术问题 Extra ChatGPT

张量流的 tf.nn.max_pool 中的“SAME”和“VALID”填充有什么区别?

tensorflowtf.nn.max_pool 中的“SAME”和“VALID”填充有什么区别?

在我看来,“有效”意味着当我们做最大池时,边缘之外不会有零填充。

根据A guide to convolution arithmetic for deep learning,它表示池运算符中不会有填充,即只使用tensorflow的'VALID'。但是 tensorflow 中最大池的“相同”填充是什么?

查看 tensorflow.org/api_guides/python/… 了解详情,这就是 tf 的做法。
这是一个漂亮的detailed answer with visualizations
查看这些令人惊叹的 GIF 以了解 padding 和 stride 的工作原理。 Link
@GabrielChu 您的链接似乎已经失效,现在重定向到一般概述。
随着 Tensorflow 升级到 2.0,Keras 将取代这些东西,我相信您可以在 Keras 文档中找到池化信息。 @马特

M
MiniQuark

如果你喜欢 ascii 艺术:

“有效” = 无填充:输入:1 2 3 4 5 6 7 8 9 10 11 (12 13) |________________|掉了|_________________|

"SAME" = 零填充:pad| |填充输入:0 |1 2 3 4 5 6 7 8 9 10 11 12 13|0 0 |________________| |_________________| |________________|

在这个例子中:

输入宽度 = 13

过滤器宽度 = 6

步幅 = 5

笔记:

“VALID”只删除最右边的列(或最底部的行)。

“SAME”试图左右均匀填充,但如果要添加的列数是奇数,它会将额外的列添加到右侧,就像本例中的情况一样(垂直应用相同的逻辑:可能有底部有一行额外的零)。

编辑:

关于名称:

使用“SAME”填充,如果您使用 1 的步幅,则图层的输出将具有与其输入相同的空间维度。

使用“有效”填充,没有“虚构”填充输入。该层仅使用有效的输入数据。


公平地说“SAME”意味着“如果图像宽度不是过滤器宽度的倍数或图像高度不是过滤器高度的倍数,则使用零填充来确保过滤器大小不必改变“?如,如果宽度是问题,“用零填充到过滤器宽度的倍数”?
回答我自己的问题:不,这不是零填充的重点。您选择过滤器大小以处理输入(包括零填充),但您不选择过滤器大小之后的零填充。
我不明白你自己的答案@StatsSorceress。在我看来,您添加了足够的零(以尽可能对称的方式),以便所有输入都被某个过滤器覆盖,对吗?
很好的答案,只是补充一下:如果张量值可以是负数,max_pooling 的填充是 -inf
如果在 ksize=2、stride=2 且填充相同的情况下输入宽度是偶数怎么办?...那么它不应该是零填充的吗?....当我查看暗流代码 repo 时,我是这么说的,他们使用 SAME pad,stride=2,ksize=2 for maxpool....在 maxpooling 图像宽度从 416 像素宽度减少到 208 像素之后。谁能澄清这一点?
Y
YvesgereY

stride 为 1(卷积比池化更典型)时,我们可以想到以下区别:

“SAME”:输出大小与输入大小相同。这需要过滤器窗口滑出输入映射,因此需要填充。

“VALID”:过滤器窗口保持在输入映射内的有效位置,因此输出大小缩小 filter_size - 1。不发生填充。


这终于有帮助了。到目前为止,似乎 SAMEVALID 也可能被称为 foobar
我认为“输出大小与输入大小相同”仅在步长为 1 时才成立。
O
Olivier Moindrot

我将举一个例子使其更清楚:

x: 形状为 [2, 3] 的输入图像,1 通道

valid_pad:具有 2x2 内核、步幅 2 和 VALID 填充的最大池。

same_pad:具有 2x2 内核、步幅 2 和 SAME 填充的最大池(这是经典的方法)

输出形状为:

valid_pad:这里没有填充,所以输出形状是 [1, 1]

same_pad:在这里,我们将图像填充到形状 [2, 4](使用 -inf 然后应用 max pool),因此输出形状为 [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.]


n
n8yoder

TensorFlow Convolution 示例概述了 SAMEVALID 之间的区别:

对于相同的填充,输出高度和宽度计算为: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(跨步[2]))


z
zmx

作为 YvesgereY 出色答案的补充,我发现这种可视化非常有帮助:

https://i.stack.imgur.com/0rs9l.gif

填充“有效”是第一个数字。过滤器窗口停留在图像内。

填充“相同”是第三个数字。输出大小相同。

在这个 article 上找到它

可视化学分:vdumoulin@GitHub


非常直接的答案!
这对我来说是最好的解决方案。可视化讲述了这个故事。谢谢
S
Salvador Dali

填充是增加输入数据大小的操作。如果是一维数据,您只需在数组中附加/前置一个常数,在二维中,您可以用这些常数包围矩阵。在 n-dim 中,你用常数包围你的 n-dim 超立方体。在大多数情况下,该常数为零,称为零填充。

https://i.stack.imgur.com/84NMg.png

您可以为内核使用任意填充,但某些填充值的使用频率高于其他值:

有效的填充。最简单的情况,意味着根本没有填充。只需让您的数据保持原样即可。

相同的填充有时称为半填充。之所以称为 SAME,是因为对于步幅 = 1 的卷积(或对于池化),它应该产生与输入大小相同的输出。之所以称为 HALF,是因为对于大小为 k 的内核

FULL padding 是最大填充,不会导致仅填充元素的卷积。对于大小为 k 的内核,此填充等于 k - 1。

要在 TF 中使用任意填充,您可以使用 tf.pad()


S
Shital Shah

快速说明

VALID:不应用任何填充,即假设所有尺寸都有效,以便输入图像完全被您指定的过滤器和步幅覆盖。

SAME:对输入应用填充(如果需要),以便输入图像完全被您指定的过滤器和步幅覆盖。对于步幅 1,这将确保输出图像大小与输入图像大小相同

笔记

这同样适用于 conv 层和 max pool 层

术语“有效”有点用词不当,因为如果您丢弃部分图像,事情不会变得“无效”。有时你甚至可能想要那个。这可能应该被称为 NO_PADDING 。

术语“相同”也是用词不当,因为当输出维度与输入维度相同时,只有步幅为 1 才有意义。例如,对于 2 的步幅,输出尺寸将是一半。这可能应该被称为 AUTO_PADDING 。

在 SAME(即自动填充模式)下,Tensorflow 将尝试在左右两侧均匀分布填充。

在 VALID(即无填充模式)下,如果您的过滤器和步幅未完全覆盖输入图像,Tensorflow 将删除右侧和/或底部单元格。


V
Vaibhav Dixit

我从官方 tensorflow 文档中引用了这个答案https://www.tensorflow.org/api_guides/python/nn#Convolution 对于“相同”填充,输出高度和宽度计算为:

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

对于“有效”填充,输出高度和宽度计算为:

out_height = ceil(float(in_height - filter_height + 1) / float(strides[1]))
out_width  = ceil(float(in_width - filter_width + 1) / float(strides[2]))

并且填充值始终为零。


坦率地说,这是唯一有效和完整的答案,不仅限于 1 的步幅。而且只需要引用文档。 +1
有这个答案非常有用,特别是因为您指向的链接不再起作用,而且 Google 似乎从 tf 网站上删除了该信息!
这应该是问题的答案!确实是唯一完整的答案。
C
Change-the-world

填充有三种选择:有效(无填充)、相同(或一半)、完整。您可以在此处找到解释(在 Theano 中):http://deeplearning.net/software/theano/tutorial/conv_arithmetic.html

有效或无填充:

有效填充不涉及零填充,因此它仅涵盖有效输入,不包括人为生成的零。如果步幅 s=1,则对于内核大小 k,输出长度为 ((输入长度) - (k-1))。

相同或半填充:

当 s=1 时,相同的填充使输出的大小与输入的大小相同。如果 s=1,则填充的零数为 (k-1)。

全填充:

完全填充意味着内核运行在整个输入上,因此在最后,内核可能会遇到唯一的一个输入而其他输入为零。如果 s=1,则填充的零数为 2(k-1)。如果 s=1,则输出的长度为 ((输入的长度) + (k-1))。

因此,填充的数量:(有效)<=(相同)<=(完整)


C
Cabbage soup

有效填充:这是零填充。希望没有混乱。

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 中提到的两个条件。

https://latex.codecogs.com/gif.latex?n_i

https://latex.codecogs.com/gif.latex?n_i&space;%5Cmod&space;s&space;=&space;0

https://latex.codecogs.com/gif.latex?n_i&space;%5Cmod&space;s&space;%5Cneq&space;0

https://latex.codecogs.com/gif.latex?p_i

让我们来看看这个例子:

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):

https://latex.codecogs.com/gif.latex?n_i&space;=&space;3,&space;k&space;=2,&space;s&space;=2,&space;p_i&space;=&space;2&space;-&space;(3%5Cmod&space;2)&space;=&space;1,&space;n_0&space;=&space;int&space;(%5Cfrac%7B3-2+2*1%7D%7B2%7D&space;+&space;1)&space;=&space;2

如果取垂直方向(4):

https://latex.codecogs.com/gif.latex?n_i&space;=&space;4,&space;k&space;=2,&space;s&space;=2,&space;p_i&space;=&space;2&space;-&space;2&space;=&space;0,&space;n_0&space;=&space;int&space;(%5Cfrac%7B3-2+2*0%7D%7B2%7D&space;+&space;1)&space;=&space;2

希望这将有助于理解 SAME 填充在 TF 中的实际工作原理。


F
Frederick Hong

总而言之,“有效”填充意味着没有填充。卷积层的输出大小根据输入大小和内核大小而缩小。

相反,“相同”填充意味着使用填充。当 stride 设置为 1 时,卷积层的输出大小通过在计算卷积时在输入数据周围附加一定数量的 '0-border' 来保持输入大小。

希望这个直观的描述有所帮助。


a
ahmedhosny

根据解释 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')

L
Laine Mikael

填充开/关。确定输入的有效大小。

VALID: 无填充。卷积等操作仅在“有效”的位置执行,即不太靠近张量的边界。
使用 3x3 的内核和 10x10 的图像,您将在边界内的 8x8 区域上执行卷积。

SAME: 提供了填充。每当您的操作引用一个邻域(无论有多大)时,当该邻域延伸到原始张量之外时,将提供零值,以允许该操作也适用于边界值。
使用 3x3 的内核和 10x10 的图像,您将在整个 10x10 区域上执行卷积。


S
Shivam Kushwaha

https://i.stack.imgur.com/uamYe.png

这里,W 和 H 是输入的宽度和高度,F 是过滤器尺寸,P 是填充大小(即要填充的行数或列数)

对于相同的填充:

https://i.stack.imgur.com/Q1X1b.png

对于有效的填充:

https://i.stack.imgur.com/CaSbW.png


T
Tensorflow Support

Tensorflow 2.0 兼容答案:上面已经提供了关于“有效”和“相同”填充的详细说明。

但是,为了社区的利益,我将在 Tensorflow 2.x (>= 2.0) 中指定不同的池化函数及其各自的命令。

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_v2tf.compat.v2.nn.max_pool(如果从 1.x 迁移到 2.x)。

tf.keras.layers.MaxPool2D 如果用于 2.x 和

tf.compat.v1.keras.layers.MaxPool2Dtf.compat.v1.keras.layers.MaxPooling2Dtf.compat.v2.keras.layers.MaxPool2Dtf.compat.v2.keras.layers.MaxPooling2D,如果从 1.x 迁移而来到 2.x。

Average Pooling => tf.nn.avg_pool2dtf.keras.layers.AveragePooling2D(如果用于 TF 2.x 和

tf.compat.v1.nn.avg_pool_v2tf.compat.v2.nn.avg_pooltf.compat.v1.keras.layers.AveragePooling2Dtf.compat.v1.keras.layers.AvgPool2Dtf.compat.v2.keras.layers.AveragePooling2D tf.compat.v2.keras.layers.AvgPool2D (如果从 1.x 迁移到 2.x)。

有关从 TensorFlow 1.x 迁移到 2.x 的更多信息,请参阅此Migration Guide


s
shahab4ai

有效的填充是没有填充。相同的填充是以输出与输入具有相同大小的方式填充。


这没有提供问题的答案。一旦你有足够的reputation,你就可以comment on any post;相反,provide answers that don't require clarification from the asker。 - From Review
@FranciscoMariaCalisto,你是对的,我直到最后才读到这个问题。也感谢您的评论。