padding='same' 转换为 PyTorch padding=#

Posted

技术标签:

【中文标题】padding=\'same\' 转换为 PyTorch padding=#【英文标题】:padding='same' conversion to PyTorch padding=#padding='same' 转换为 PyTorch padding=# 【发布时间】:2020-09-21 18:57:55 【问题描述】:

我正在尝试将以下 Keras 模型代码转换为 pytorch,但在处理 padding='same' 时遇到问题。

    model = Sequential()
    model.add(Conv2D(64, (3, 3), input_shape=img_size))
    model.add(BatchNormalization(axis=1))
    model.add(Activation('relu'))
    model.add(Dropout(0.3))
    model.add(Conv2D(64, (3, 3), padding='same'))
    model.add(BatchNormalization(axis=1))
    model.add(Activation('relu'))
    model.add(MaxPooling2D(pool_size=(2,2), strides=(2,2), padding='same'))

这会产生以下摘要:

Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1 (Conv2D)            (None, 30, 30, 64)        1792      
_________________________________________________________________
batch_normalization_1 (Batch (None, 30, 30, 64)        120       
_________________________________________________________________
activation_1 (Activation)    (None, 30, 30, 64)        0         
_________________________________________________________________
dropout_1 (Dropout)          (None, 30, 30, 64)        0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 30, 30, 64)        36928     
_________________________________________________________________
batch_normalization_2 (Batch (None, 30, 30, 64)        120       
_________________________________________________________________
activation_2 (Activation)    (None, 30, 30, 64)        0         
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 15, 15, 64)        0         
=================================================================
Total params: 38,960
Trainable params: 38,840
Non-trainable params: 120

现在,我会写:

self.features = nn.Sequential(
            nn.Conv2d(3, 64, kernel_size=3,
                      bias=False),
            nn.BatchNorm2d(64),
            nn.ReLU(inplace=True),
            nn.Dropout(0.3),
            nn.Conv2d(64, 64, kernel_size=3, padding = ?
                      bias=False),
            nn.BatchNorm2d(64),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2, padding = ?),
        )

填充应该有数值。我想知道是否有更简单的方法来计算这个,因为我们使用的是 padding='same'。

此外,Keras 模型的下一行如下所示:

model.add(Conv2D(128, (3, 3), padding='same'))

所以我真的需要重新学习如何计算填充,尤其是在 stride 之后。 粗略看来,内边距是 2 吗?

【问题讨论】:

【参考方案1】:

W:输入音量大小

F:内核大小

S:步幅

P:填充量

输出体积大小 = (W-F+2P)/S+1

例如

输入:7x7,内核:3x3,步幅:1,填充:0

输出大小 = (7-3+2*0)/1+1 = 5 =>5x5

【讨论】:

【参考方案2】:
self.features = nn.Sequential(
            nn.Conv2d(3, 64, kernel_size=3,
                      bias=False),
            nn.BatchNorm2d(64),
            nn.ReLU(inplace=True),
            nn.Dropout(0.3),
            nn.Conv2d(64, 64, kernel_size=3, padding = 1
                      bias=False),
            nn.BatchNorm2d(64),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2, padding = 32),
        )

【讨论】:

总结,对于maxpooling2d,如果stride=kernel,P=W/2【参考方案3】:

公式为:k = (n - 1) / 2,其中 n 是内核大小。这是一个可视化:

【讨论】:

【参考方案4】:

计算填充的完整公式可以在 PyTorch 的文档中找到:

来源:https://pytorch.org/docs/master/generated/torch.nn.Conv2d.html?highlight=conv2d#torch.nn.Conv2d

此公式包括kernel sizestridedilation。 根据这个方程,您可以使用不同的padding 大小(作为猜测)进行迭代,直到找到一个合适的值来求解方程。

根据图像的大小,您可以使用二分搜索创建求解器以找到最佳的 padding 值,或者如果图像不太大,您可以尝试增加 padding += 1 的不同值。

【讨论】:

【参考方案5】:

在 PyTorch 中,您可以直接在填充中使用整数。

在 3x3 内核的卷积填充 = 1 中,stride=1 在 keras 中是〜“相同”。

并且在 MaxPool 中,您应该设置 padding=0(默认),对于 2x2 内核,stride=2 在 keras 中是“相同的”。

您可以使用公式:

输出 = (W+2P-K)/S + 1

让我们看一些数学计算:

对于卷积:

案例一:

输入为 30x30,kernel_size(K) 为 3x3,stride=1,padding=1:

Out = (30+2*1-3)/1 + 1 = floor(29/1) + 1 = 30 即 30x30 (~ padding="same")

案例 2:

输入为 30x30,kernel_size(K) 为 3x3,stride=1,padding=0:

Out = (30+2*0-3)/1 + 1 = floor(27/1) + 1 = 28 即 28x28 (~ padding="valid")

对于 MaxPooling:

案例一:

输入为 30x30,kernel_size(K) 为 2x2,stride=2,padding=0:

Out = (30+2*0-2)/2 + 1 = floor(28/2) + 1 = 15 即 15x15 (~ padding="same")

案例 2:

输入为 30x30,kernel_size(K) 为 2x2,stride=2,padding=1:

Out = (30+2*1-2)/2 + 1 = floor(30/2) + 1 = 16 即 16x16 (~ padding="valid")

这是一个在 PyTorch 中实现的程序,与上面的 keras 代码相同:


model = nn.Sequential(
    nn.Conv2d(3, 64, kernel_size=(3, 3), padding=1, bias=False),
    nn.BatchNorm2d(64),
    nn.ReLU(inplace=True),
    nn.Dropout(0.3),

    nn.Conv2d(64, 64, kernel_size=(3, 3), padding=1, bias=False),
    nn.BatchNorm2d(64),
    nn.ReLU(inplace=True),
    nn.MaxPool2d(kernel_size=(2, 2), stride=2, padding=0)
)

X = torch.rand((1, 3, 30, 30))

print(model)
for layer in model:
    X = layer(X)
    print(X.shape)

输出:

Sequential(
  (0): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
  (1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  (2): ReLU()
  (3): Dropout(p=0.3, inplace=False)
  (4): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
  (5): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  (6): ReLU()
  (7): MaxPool2d(kernel_size=(2, 2), stride=2, padding=0, dilation=1, ceil_mode=False)
)
torch.Size([1, 64, 30, 30])
torch.Size([1, 64, 30, 30])
torch.Size([1, 64, 30, 30])
torch.Size([1, 64, 30, 30])
torch.Size([1, 64, 30, 30])
torch.Size([1, 64, 30, 30])
torch.Size([1, 64, 30, 30])
torch.Size([1, 64, 15, 15])

【讨论】:

以上是关于padding='same' 转换为 PyTorch padding=#的主要内容,如果未能解决你的问题,请参考以下文章

在pytorch中实现与TensorFlow类似的"same"方式padding

具有 padding='SAME' 的 Tensorflow/Keras Conv2D 层表现异常

padding='same' 和 strides > 1 的 tf.keras.layers.Conv2D 表现如何?

PyTorch 的 Conv2d 真的没有 padding=same 选项吗?

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

tf.nn.conv2d 和 tf.nn.max_pool 中 padding 分别为 'VALID' 和 'SAME' 的直觉上的经验和测试代码