PyTorch的Conv2d真的没有填充=相同的选项吗?



我目前正在构建一个卷积神经网络(CNN(,该网络将处理金融时间序列数据。输入形状为(100, 40)- 100 个时间戳,包含 40 个要素。

我正在使用的CNN使用非对称内核大小(即1 x 24 x 1(以及不对称的步幅(即1 x 2用于1 x 2图层,1 x 1用于4 x 1图层(。

为了保持高度维度保持100,我需要填充数据。在我的研究中,我注意到使用 TensorFlow 或 Keras 的人只是使用padding='same';但这个选项显然在 PyTorch 中不可用。

根据 tf.nn.max_pool of tensorflow 中的"SAME"和"VALID"填充有什么区别?中的一些答案,以及 PyTorch 论坛上的这个答案,我可以手动计算我需要如何填充我的数据,并使用torch.nn.ZeroPad2d来解决问题 - 因为显然正常的torch.nn.Conv2d层不支持非对称填充(我相信我需要的总填充是 3 高度和 0 宽度(。

我尝试了以下代码:

import torch
import torch.nn as nn
conv = nn.Conv2d(1, 1, kernel_size=(4, 1))
pad = nn.ZeroPad2d((0, 0, 2, 1)) # Add 2 to top and 1 to bottom.
x = torch.randint(low=0, high=9, size=(100, 40))
x = x.unsqueeze(0).unsqueeze(0)
y = pad(x)
x.shape # (1, 1, 100, 40)
y.shape # (1, 1, 103, 40)
print(conv(x.float()).shape)
print(conv(y.float()).shape)
# Output
# x -> (1, 1, 97, 40)
# y -> (1, 1, 100, 40)

从某种意义上说,它确实有效,即数据形状保持不变。但是,真的没有可用的padding='same'选项吗?另外,我们如何决定垫哪一边?

前段时间我遇到了同样的问题,所以我自己使用ZeroPad2d层实现了它,就像你尝试做的那样。这是正确的公式:

from functools import reduce
from operator import __add__
kernel_sizes = (4, 1)
# Internal parameters used to reproduce Tensorflow "Same" padding.
# For some reasons, padding dimensions are reversed wrt kernel sizes,
# first comes width then height in the 2D case.
conv_padding = reduce(__add__, 
[(k // 2 + (k - 2 * (k // 2)) - 1, k // 2) for k in kernel_sizes[::-1]])
pad = nn.ZeroPad2d(conv_padding)
conv = nn.Conv2d(1, 1, kernel_size=kernel_sizes)
print(x.shape) # (1, 1, 103, 40)
print(conv(y.float()).shape) # (1, 1, 103, 40)

此外,正如@akshayk07和@Separius所提到的,我可以确认是pytorch的动态性质使它变得困难。这是一篇来自 Pytorch 开发人员的关于这一点的文章。

根据文档,现在看起来有,在 pytorch1.9.1中。

padding='valid'与无填充相同。padding='same'垫 输入,因此输出将形状作为输入。但是,此模式 不支持 1 以外的任何步幅值。

padding='same'padding='valid'在 Pytorch 1.10.0+中是可能的。但是,stride > 1时无法'same'和填充'valid'

最新更新