padding='same' 转换为 PyTorch padding=#
padding='same' conversion to PyTorch padding=#
我正在尝试将以下 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 应该有数值。我想知道是否有更简单的方法来计算这个,因为我们使用的是 padding='same'。
此外,Keras 模型的下一行如下所示:
model.add(Conv2D(128, (3, 3), padding='same'))
所以我真的需要复习一下如何计算填充,尤其是在大步之后。 粗略看来,padding 是 2 吗?
公式为:k = (n - 1) / 2,其中 n 是内核大小。这是一个可视化:
W:输入卷大小
F:内核大小
S:步幅
P:填充量
输出体积大小=(W-F+2P)/S+1
例如
输入:7x7,kernel:3x3,stride:1,pad:0
输出大小 = (7-3+2*0)/1+1 = 5 =>5x5
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),
)
完整的padding计算公式可以在PyTorch的文档中找到:
来源:https://pytorch.org/docs/master/generated/torch.nn.Conv2d.html?highlight=conv2d#torch.nn.Conv2d
该公式包括kernel size
、stride
和dilation
。
根据这个方程,您可以使用不同的 padding
大小(作为猜测)进行迭代,直到找到合适的值来求解方程。
根据图像的大小,您可以使用二进制搜索创建求解器以找到最佳 padding
值,或者如果图像不是,您可以尝试递增 padding += 1
的不同值太大了。
在 PyTorch 中,您可以直接在填充中使用整数。
在 3x3 内核的卷积填充 = 1 中,stride=1 在 keras 中是〜“相同”。
并且在 MaxPool 中,您应该设置 padding=0(默认值),对于 2x2 内核,stride=2 在 keras 中是〜“相同”。
您可以使用公式:
输出 = (W+2P-K)/S + 1
让我们看一些数学计算:
对于卷积:
案例一:
输入为30x30,kernel_size(K)为3x3,步幅=1,填充=1:
Out = (30+2*1-3)/1 + 1 = floor(29/1) + 1 = 30 即 30x30 (~ padding="same")
案例二:
输入为30x30,kernel_size(K)为3x3,步幅=1,填充=0:
Out = (30+2*0-3)/1 + 1 = floor(27/1) + 1 = 28 即 28x28 (~ padding="valid")
对于最大池化:
案例一:
输入为30x30,kernel_size(K)为2x2,步幅=2,填充=0:
Out = (30+2*0-2)/2 + 1 = floor(28/2) + 1 = 15 即 15x15 (~ padding="same")
案例二:
输入为30x30,kernel_size(K)为2x2,步幅=2,填充=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])
我正在尝试将以下 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 应该有数值。我想知道是否有更简单的方法来计算这个,因为我们使用的是 padding='same'。
此外,Keras 模型的下一行如下所示:
model.add(Conv2D(128, (3, 3), padding='same'))
所以我真的需要复习一下如何计算填充,尤其是在大步之后。 粗略看来,padding 是 2 吗?
公式为:k = (n - 1) / 2,其中 n 是内核大小。这是一个可视化:
W:输入卷大小
F:内核大小
S:步幅
P:填充量
输出体积大小=(W-F+2P)/S+1
例如
输入:7x7,kernel:3x3,stride:1,pad:0
输出大小 = (7-3+2*0)/1+1 = 5 =>5x5
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),
)
完整的padding计算公式可以在PyTorch的文档中找到:
来源:https://pytorch.org/docs/master/generated/torch.nn.Conv2d.html?highlight=conv2d#torch.nn.Conv2d
该公式包括kernel size
、stride
和dilation
。
根据这个方程,您可以使用不同的 padding
大小(作为猜测)进行迭代,直到找到合适的值来求解方程。
根据图像的大小,您可以使用二进制搜索创建求解器以找到最佳 padding
值,或者如果图像不是,您可以尝试递增 padding += 1
的不同值太大了。
在 PyTorch 中,您可以直接在填充中使用整数。
在 3x3 内核的卷积填充 = 1 中,stride=1 在 keras 中是〜“相同”。
并且在 MaxPool 中,您应该设置 padding=0(默认值),对于 2x2 内核,stride=2 在 keras 中是〜“相同”。
您可以使用公式:
输出 = (W+2P-K)/S + 1
让我们看一些数学计算:
对于卷积:
案例一:
输入为30x30,kernel_size(K)为3x3,步幅=1,填充=1:
Out = (30+2*1-3)/1 + 1 = floor(29/1) + 1 = 30 即 30x30 (~ padding="same")
案例二:
输入为30x30,kernel_size(K)为3x3,步幅=1,填充=0:
Out = (30+2*0-3)/1 + 1 = floor(27/1) + 1 = 28 即 28x28 (~ padding="valid")
对于最大池化:
案例一:
输入为30x30,kernel_size(K)为2x2,步幅=2,填充=0:
Out = (30+2*0-2)/2 + 1 = floor(28/2) + 1 = 15 即 15x15 (~ padding="same")
案例二:
输入为30x30,kernel_size(K)为2x2,步幅=2,填充=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])