tensorflow Conv2D 中的 padding='same' 到底是啥意思?是最小填充还是 input_shape == output_shape

Posted

技术标签:

【中文标题】tensorflow Conv2D 中的 padding=\'same\' 到底是啥意思?是最小填充还是 input_shape == output_shape【英文标题】:What does padding='same' exactly mean in tensorflow Conv2D? Is it minimum padding or input_shape == output_shapetensorflow Conv2D 中的 padding='same' 到底是什么意思?是最小填充还是 input_shape == output_shape 【发布时间】:2021-09-03 04:59:27 【问题描述】:

TL;DR:如何修改下面给出的代码以合并padding = 'same' 方法?

我试图使用numpy 构建自己的CNN,但由于padding = 'same' 的两个答案而感到困惑。

This Answer says那个

Keras 中的 padding='Same' 表示当输入大小和内核大小不完全匹配时,根据需要添加填充以弥补重叠

所以据此,same 表示每个方向所需的最小填充。如果是这样的话,这不应该是双方平等的吗?或者,如果 minimum 所需的填充是 2,那么这不应该是填充均匀分布在所有 4 个边上的有效候选者。如果所需的填充只有 3 怎么办?然后会发生什么?

另外,困扰我的是the official documentation of tensorflow 他们说:

“相同”导致在输入的左/右或上/下均匀填充零,以使输出具有与输入相同的高度/宽度尺寸。

那么正确答案是什么?

这是我为填充编写的代码

def add_padding(X:np.ndarray, pad_size:Union[int,list,tuple], pad_val:int=0)->np.ndarray:
    '''
    Pad the input image array equally from all sides
    args:
        x: Input Image should be in the form of [Batch, Width, Height, Channels]
        pad_size: How much padding should be done. If int, equal padding will done. Else specify how much to pad each side (height_pad,width_pad) OR (y_pad, x_pad)
        pad_val: What should be the value to be padded. Usually it os 0 padding
    return:
        Padded Numpy array Image
    '''
    assert (len(X.shape) == 4), "Input image should be form of [Batch, Width, Height, Channels]"
    if isinstance(pad_size,int):
        y_pad = x_pad = pad_size
    else:
        y_pad = pad_size[0]
        x_pad = pad_size[1]

    pad_width = ((0,0), (y_pad,y_pad), (x_pad,x_pad), (0,0)) # Do not pad first and last axis. Pad Width(2nd), Height(3rd) axis with  pad_size
    return np.pad(X, pad_width = pad_width, mode = 'constant', constant_values = (pad_val,pad_val))


# Another part of my Layer
# New Height/Width is dependent on the old height/ width, stride, filter size, and amount of padding
h_new = int((h_old + (2 * padding_size) - filter_size) / self.stride) + 1
w_new = int((w_old + (2 * padding_size) - filter_size) / self.stride) + 1

Full Code for this layer is presented here

【问题讨论】:

其实两者都是真的。 padding=same 指定填充,如果步幅为 1,则输出形状等于输入形状。但如果您指定步幅其他值,则会得到不同的结果。 不知道是什么问题。文档非常清楚:用零填充,以便输出与输入具有相同的大小。不管你垫多少,“最低限度”都是多余的。如果你填充更多,你只是在浪费空间。输出大小已给出。 【参考方案1】:

根据这个SO answer,名称'SAME' padding 只是来自当stride 等于1 时,输出空间形状与输入空间形状相同的属性。

但是,当步幅不等于 1 时,情况并非如此。输出空间形状由以下公式确定。

对于所有情况,“SAME”的定义意味着以张量流方式应用填充,这样

对于每个空间维度 i, output_spatial_shape[i] = ceil(input_spatial_shape[i] / strides[i])

那么 tensorflow 应用填充的方式是什么?

首先,每个空间维度所需的填充由以下算法确定。

#e.g. for 2D image, num_spatial_dim=2
def get_padding_needed(input_spatial_shape,filter_shape,strides):
  num_spatial_dim=len(input_spatial_shape)
  padding_needed=[0]*num_spatial_dim

  for i in range(num_spatial_dim):
    if input_spatial_shape[i] % strides[i] == 0:
      padding_needed[i] = max(filter_shape[i]-strides[i],0)
    else:
      padding_needed[i] = max(filter_shape[i]-(input_spatial_shape[i]%strides[i]),0)

  return padding_needed

#example
print(get_padding_needed(input_spatial_shape=[2000,125],filter_shape=[8,4],strides=[4,1]))
#[4,3]

如您所见,第一个空间维度所需的填充是偶数 4。这很简单,只需在第一个空间维度的每一端填充 2 个零即可。

第二,第二维所需的填充是奇数。然后,tensorflow 将在起始端填充更少的零。

换句话说,如果维度是高度并且需要的填充是 3,它将在顶部填充 1 个零,在底部填充 2 个零。如果维度是宽度,并且需要的填充是5,它将在左侧填充2个零,在右侧填充3个零,等等。

参考资料:

    https://www.tensorflow.org/api_docs/python/tf/nn/convolution https://mmuratarat.github.io/2019-01-17/implementing-padding-schemes-of-tensorflow-in-python

【讨论】:

参考#1,目前有更多细节tensorflow.org/api_docs/python/tf/nn#notes_on_padding_2

以上是关于tensorflow Conv2D 中的 padding='same' 到底是啥意思?是最小填充还是 input_shape == output_shape的主要内容,如果未能解决你的问题,请参考以下文章

Tensorflow Profile 为 Conv2D 输出 2 FLOPS 而不是 1

tensorflow Conv2D 中的 padding='same' 到底是啥意思?是最小填充还是 input_shape == output_shape

TensorFlow conv2d实现卷积

tensorflow中踩过的坑

TensorFlow 中 conv2d 的确切含义

tensorflow中的卷积函数详解