padding='same' 在张量流 Conv2D 中到底意味着什么?是最小填充还是 input_shape == output_shape

Des*_*wal 3 numpy computer-vision deep-learning keras tensorflow

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

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

这个答案说的

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

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

另外,让我困扰的是张量流的官方文档,他们说:

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

那么正确答案是什么呢?

这是我为填充编写的代码

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

Run Code Online (Sandbox Code Playgroud)

该层的完整代码如下所示

小智 8

根据这个SO答案,名称'SAME'填充只是来自当步幅等于1时,输出空间形状与输入空间形状相同的属性。

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

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

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

那么张量流应用填充的方式是什么?

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

#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]
Run Code Online (Sandbox Code Playgroud)

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

其次,第二维所需的填充是奇数。然后,张量流将在起始端填充更少的零。

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

参考:

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