在tensorflow的tf.nn.max_pool函数中,“SAME”和“VALID”填充有什么区别?

434

在tensorflow的tf.nn.max_pool中,“SAME”和“VALID”填充有什么区别?

我认为,“VALID”表示在进行最大池化时,边缘外部不会进行零填充。

根据用于深度学习的卷积算术指南,它说池操作中不会进行填充,即只需使用tensorflow的“VALID”。 但是,在tensorflow的最大池化中,“SAME”填充是什么意思呢?


5
请参考 https://www.tensorflow.org/api_guides/python/nn#Notes_on_SAME_Convolution_Padding 了解详情,这是 TensorFlow 的做法。 - GabrielChu
9
这里有一个相当详细的答案,附有视觉化展示,讲解了 TensorFlow 中的同填充(same padding)和有效填充(valid padding)之间的区别。 - rbinnun
6
请查看这些惊人的gif,以了解填充和步幅是如何工作的。[链接](https://github.com/vdumoulin/conv_arithmetic/tree/master/gif) - Deepak
4
@GabrielChu你的链接似乎失效了,现在重定向到一个总览页面。 - matt
1
随着Tensorflow升级到2.0,一些东西将被Keras替换,我相信您可以在Keras文档中找到池化信息。@matt - GabrielChu
有人如何投票让这篇文章超过420? - Ari
16个回答

766

如果您喜欢ASCII艺术:

  • "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
                   |________________|
                                  |_________________|
                                                 |________________|
    
  • 在这个例子中:

    • 输入宽度为13
    • 滤波器宽度为6
    • 步幅为5

    注意:

    • "VALID" 只会丢弃最右边的列(或最下面的行)。
    • "SAME" 会尝试左右均匀填充,但如果要添加的列数是奇数,则会将额外的一列添加到右边,就像这个例子中一样(垂直方向上也适用类似的逻辑:底部可能有多出一行零填充)。

    编辑

    关于名称:

    • 使用步幅为1的情况下,"SAME" 填充会使得层的输出具有与其输入相同的空间维度。
    • 使用 "VALID" 填充时,不存在“捏造”的填充输入。该层只使用有效的输入数据。

    6
    “SAME” 是否意味着“使用零填充来确保如果图像宽度不是滤波器宽度的倍数或者图像高度不是滤波器高度的倍数,则无需更改滤波器大小”是合理的吗?例如,如果宽度是问题,就可以“用零填充直到成为滤波器宽度的倍数”? - StatsSorceress
    6
    回答我自己的问题:不,这不是零填充的目的。您选择与输入一起使用(包括零填充)的滤波器大小,但您不能在滤波器大小后选择零填充。 - StatsSorceress
    2
    我不理解你的回答@StatsSorceress。在我看来,你添加了足够多的零(尽可能对称地),以便所有输入都被某个过滤器覆盖,我是对的吗? - guillefix
    4
    非常好的回答,只是补充一下:如果张量值可能为负数,则最大池化的填充应该使用“-inf”。 - Tones29
    1
    如果输入的宽度是偶数,而ksize=2,stride=2且采用SAME填充呢?...那么就不应该进行零填充了吧?...我是指当我查看darkflow代码库时,他们正在使用SAME pad,stride=2,ksize=2进行maxpool....在最大池化后,图像宽度从416像素减少到208像素。有人可以澄清这一点吗? - Kavindu Vindika
    显示剩余4条评论

    202

    stride等于1时(在卷积中更为常见),我们可以思考以下区别:

    • "SAME": 输出尺寸与输入尺寸相同。这需要过滤窗口在输入映射外滑动,因此需要填充。
    • "VALID": 过滤窗口保持在输入映射内的有效位置,因此输出尺寸会缩小filter_size - 1。不发生填充。

    85
    终于有用了。到目前为止,“SAME”和“VALID”看起来就像被称为“foo”和“bar”一样。 - omatai
    14
    只有当步长为1时,“输出大小与输入大小相同”才是正确的。 - omsrisagar

    187

    我将举一个例子以使问题更清晰:

    • 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.]
    


    106

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

    • For the SAME padding, the output height and width are computed as:

       out_height = ceil(float(in_height) / float(strides[1]))
       out_width  = ceil(float(in_width) / float(strides[2]))
      

    • For the VALID padding, the output height and width are computed as:

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

    90

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

    Padding visualization

    填充方式 'valid' 是第一种。滤波窗口保持在图像内。

    填充方式 'same' 是第三种。输出与输入大小相同。


    我在这篇文章中找到了它

    可视化制作:vdumoulin@GitHub


    5
    非常迅速的回答! - Nicola
    6
    这对我来说是最好的解决方案。可视化讲述了这个故事。谢谢。 - wbadry

    60

    填充(Padding)是一种增加输入数据大小的操作。对于一维数据,您只需使用常量附加/前置数组,在二维数据中,您需要在矩阵周围用这些常量进行包围。在n维数据中,您需要使用常量来包围n维超立方体。在大多数情况下,这个常量是零,被称为零填充。

    以下是应用p=1的零填充到2D张量的示例: enter image description here


    您可以使用任意填充(kernel),但其中一些填充值比其他填充值更常用,它们包括:

    • VALID 填充。最简单的情况,表示根本没有填充。保持数据不变即可。
    • SAME 填充有时也称为HALF 填充。称之为SAME是因为对于步长为 1 的卷积(或池化),它应该产生与输入相同大小的输出。这被称为HALF,因为对于大小为k的核enter image description here
    • FULL 填充是最大的填充,不会导致仅在填充元素上进行卷积。对于大小为k的核,此填充等于k - 1

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


    39

    简要说明

    VALID:不应用任何填充,即假定所有维度都是有效的,以便输入图像完全被你指定的过滤器和步长所覆盖。

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

    • 此适用于卷积层和最大池层以同样的方式
    • 术语“有效”有点不准确,因为如果丢弃图像的一部分,事情并不会变得“无效”。有时你甚至想要那样做。这可能应该称为NO_PADDING而不是VALID
    • 术语“SAME”也是不准确的,因为它只有在步幅为1时输出尺寸与输入尺寸相同时才有意义。例如,对于步幅为2,输出尺寸将缩小一半。这可能应该称为AUTO_PADDING而不是SAME
    • SAME(即自动填充模式)中,Tensorflow将尝试在左右两侧平均分配填充。
    • VALID(即无填充模式)中,如果你的过滤器和步幅不能完全覆盖输入图像,则Tensorflow将丢弃右边和/或底部的单元格。

    28

    我从官方 TensorFlow 文档中引用了这个答案 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]))
    

    并且填充值始终为零。


    3
    坦率地说,这是唯一一个完整且有效的答案,不仅限于1的步幅。只需要引用文档即可得到答案。+1 - P-Gn
    3
    很有用的答案,特别是因为你提供的链接已经失效了,而且谷歌似乎也将那个信息从tf网站上删除了! - Daniel
    1
    这应该是问题的答案!确实是唯一完整的答案。 - misha312

    13

    填充有三个选择:valid(无填充),same(或half),full。您可以在这里找到(Theano的)解释: http://deeplearning.net/software/theano/tutorial/conv_arithmetic.html

    • Valid或无填充:

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

    • Same或half填充:

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

    • Full填充:

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

    因此,填充数量为:(valid)≤(same)≤(full)


    12
    总之,“valid”填充意味着没有填充。卷积层的输出尺寸随输入尺寸和核尺寸而缩小。
    相反,“same”填充意味着使用填充。当步幅设置为1时,通过在计算卷积时在输入数据周围添加一定数量的“0边框”,使卷积层的输出尺寸保持与输入尺寸相同。
    希望这个直观的描述有所帮助。

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接