'SAME'和& # 39;有效# 39;在tf.nn中填充。tensorflow的Max_pool ?

tensorflowtf.nn.max_pool中,'SAME'和'VALID'填充之间的区别是什么?

在我看来,'VALID'意味着当我们做max pool时,边缘外不会有零填充。

根据用于深度学习的卷积算法指南,它表示池操作符中没有填充,即只使用tensorflow的'VALID'。 但是什么是tensorflow中最大池的“SAME”填充?< / p >
379429 次浏览

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

  • 对于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]))
    

我举个例子来说明:

  • x:输入图像形状[2,3],1通道
  • valid_pad: max pool with 2x2 kernel, stride 2和VALID padding。
  • same_pad: max pool with 2x2 kernel, stride 2和SAME padding(这是经典的方式)

输出形状为:

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

如果你喜欢ascii艺术:

  • "VALID" =没有填充:

       inputs:         1  2  3  4  5  6  7  8  9  10 11 (12 13)
    |________________|                dropped
    |_________________|
    
  • "SAME" = with zero padding:

                   pad|                                      |pad
    inputs:      0 |1  2  3  4  5  6  7  8  9  10 11 12 13|0  0
    |________________|
    |_________________|
    |________________|
    

In this example:

  • Input width = 13
  • Filter width = 6
  • Stride = 5

Notes:

  • "VALID" only ever drops the right-most columns (or bottom-most rows).
  • "SAME" tries to pad evenly left and right, but if the amount of columns to be added is odd, it will add the extra column to the right, as is the case in this example (the same logic applies vertically: there may be an extra row of zeros at the bottom).

Edit:

About the name:

  • With "SAME" padding, if you use a stride of 1, the layer's outputs will have the same spatial dimensions as its inputs.
  • With "VALID" padding, there's no "made-up" padding inputs. The layer only uses valid input data.

基于在这里的解释和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')

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

  • "SAME":输出大小是相同作为输入大小。这就要求滤镜窗口要在输入贴图外滑动,因此需要垫片。
  • "VALID":过滤器窗口保持在输入映射中的有效的位置,因此输出大小缩小了filter_size - 1。没有填充。
有三种填充选择:有效(无填充),相同(或一半),满。你可以在这里(Theano)找到解释: http://deeplearning.net/software/theano/tutorial/conv_arithmetic.html < / p >
  • 有效或无填充:

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

  • 相同或半填充:

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

  • 完全填充:

完全填充意味着内核运行整个输入,因此在结束时,内核可能只满足一个输入,其他为零。如果s=1,填充的零的数量是2(k-1)。如果s=1,则输出长度为((输入长度)+ (k-1))。

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

填充是一种增加输入数据大小的操作。在一维数据中,你只需要在数组前加上一个常数,在2-dim中,你用这些常数包围矩阵。在n-dim中,用常数包围n-dim超立方体。在大多数情况下,这个常数是零,它被称为零填充。

下面是一个将p=1应用于2-d张量的零填充示例: enter image description here < / p >

你可以为你的内核使用任意填充,但是有些填充值比其他填充值使用得更频繁:

  • 有效的填充。最简单的情况,意味着根本没有填充。让你的数据保持原样。
  • 相同的填充有时被称为半填充。它被称为相同,因为对于stride=1的卷积(或池化),它应该产生与输入相同大小的输出。它被称为一半,因为对于k大小的内核enter image description here
  • 完全填充是最大填充,它不会导致对填充的元素进行卷积。对于大小为k的核,这个填充值等于k - 1

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

我引用了官方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]))

填充值总是0。

快速的解释

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

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

笔记

  • 这同样适用于conv层和max pool层
  • “有效”这个词有点用词不当,因为如果你删除图像的一部分,东西不会变成“无效”。有时候你甚至会想要那样。这个函数应该被命名为NO_PADDING
  • 术语“相同”也是一个用词不当的词,因为只有当输出维度与输入维度相同时,它才对stride为1有意义。例如,对于stride为2,输出维度将为一半。这个函数应该被命名为AUTO_PADDING
  • SAME(即自动填充模式)中,Tensorflow将尝试在左右两边均匀地分布填充。
  • VALID(即无填充模式)中,如果你的过滤器和stride没有完全覆盖输入图像,Tensorflow将删除右侧和/或底部单元格。

有效的 padding:这是零填充。希望没有混淆。

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)

相同填充:首先,这有点难以理解,因为我们必须分别考虑官方文档中提到的两个条件。

假设输入为,输出为,填充为, stride为,内核大小为(只考虑一维)

案例01::

案例02::

的计算使填充可以取的最小值。由于的值已知,所以的值可以用公式求得。

让我们来做这个例子:

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

< img src = " https://latex.codecogs.com/gif.latex?n_i&space; =空间;3、空间;k&space; = 2,与空间,太空;= 2,航天,p_i&space; =空间;2空间;空间;(3% 5 cmod&space; 2)空间;=空间;1,航天,n_0&space; =空间;int&space; (% 5 cfrac % 7 b3-2+ 2 * 7 d % 7 b2 % 7维空间1%;加上;空间;1)空间;=空间;2”title =“n_i = 3 k = 2 s = 2, p_i = 2 -(3 \国防部2)= 1,n_0 =地板(\压裂{3 - 2 + 2 * 1}{2}+ 1)= 2 " / >

若取垂直方向(4):

< img src = " https://latex.codecogs.com/gif.latex?n_i&space; =空间;4、空间;k&space; = 2,与空间,太空;= 2,航天,p_i&space; =空间;2空间;空间;2空间;=空间;0,航天,n_0&space; =空间;int&space; (% 5 cfrac % 7 b3-2+ 2 * 7 d % 7 b2 % 7维空间0%;加上;空间;1)空间;=空间;2”title =“n_i = 4 k = 2 s = 2, p_i = 2 - 2 = 0, n_0 =地板(\压裂{3 - 2 + 2 * 0}{2}+ 1)= 2 " / >

希望这将有助于理解实际上相同填充如何在TF中工作。

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

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

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

通则

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

对于相同的填充:

SAME Padding

对于有效填充:

VALID padding

总之,“有效”填充意味着没有填充。卷积层的输出大小取决于输入大小&内核大小。

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

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

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。

如果在TF 2中使用Average Pooling => tf.nn.avg_pool2dtf.keras.layers.AveragePooling2D。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.nn.avg_pool0或tf.compat.v2.nn.avg_pool1,如果从1迁移。X到2。X。

有关Tensorflow迁移的更多信息。X到2。x,请参考这个迁移向导. x。

为了补充YvesgereY的回答,我发现这个可视化非常有用:

Padding visualization

填充'有效的'是第一个数字。滤镜窗口停留在图像内部。

填充'相同'是第三个数字。输出是相同的大小。


文章上找到它

可视化致谢:vdumoulin@GitHub

有效的填充没有填充。 Same 填充是一种输出与输入大小相同的填充。