繁体   English   中英

我不明白 conv1d、conv2d 的 pytorch 输入大小

[英]I don't understand pytorch input sizes of conv1d, conv2d

我有 2 个时间序列的数据,每个序列 18 点。 所以我组织了一个 18 行 2 列的矩阵(180 个样本分为 2 个类别 - 激活和非激活)。

所以,我想用这些数据做一个 CNN,我的内核沿着线(时间)朝一个方向走。 附图示例。

我的数据 18x2

在我的代码中,与具有 3 个通道的 RGB 相比,我不知道我的通道如何。 并且不知道层的输入大小,以及如何计算才能知道全连接层。

我需要使用 conv1d 吗? conv2d? conv3d ? 基于理解 conv 1D 2D 3D ,我有 2D 输入,我想做 1D 卷积(因为我在一个方向上移动我的内核),这是正确的吗?

例如,我如何传递内核大小(3,2)?

我的数据是这种形式,使用 DataLoader 和 batch_size= 4 后:

print(data.shape, label.shape)

火炬大小([4, 2, 18]) 火炬大小([4, 1])

我的卷积模型是:

OBS:我只是放了任意数量的输入/输出大小。

# Creating our CNN Model -> 1D convolutional with 2D input (HbO, HbR)

class ConvModel(nn.Module):
    def __init__(self):
        super(ConvModel, self).__init__()
        self.conv1 = nn.Conv1d(in_channels=1,  out_channels= 18, kernel_size=3, stride = 1)
# I dont know the in/out channels of the first conv
        self.maxpool = nn.MaxPool1d(kernel_size=3, stride=3)
        self.conv2 = nn.Conv1d(18, 32, kernel_size=3)
        self.fc1 = nn.Linear(200, 100)  #What I put in/out here ?
        self.fc2 = nn.Linear(100, 50)
        self.fc3 = nn.Linear(50, 2)

    def forward(self, x):
        x = F.relu(self.mp(self.conv1(x)))
        x = self.maxpool(x)

        x = F.relu(self.mp(self.conv2(x)))
        x = self.maxpool(x)

        x = x.view(-1, ??)  # flatten the tensor, which number here ?

        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)

        return x

稍后您将需要使用双通道 conv1d 作为第一个卷积。 即它将采用形状为 [B, 2, 18] 的张量。 具有内核大小为 3 的 2 通道输入将定义形状为 [2, 3] 的内核,其中内核沿输入的最后一个维度滑动。 输出特征图中的通道数 C1 由您决定。 C1 定义了你学习了多少个独立的 [2, 3] 核。 每个带有 [2, 3] 内核的卷积都会产生一个输出通道。

请注意,如果您在 conv1d 期间没有定义任何零填充,那么大小为 3 的内核的输出将减少 2,即您将得到 [B, C1, 16]。 如果包含 1 的填充(在卷积之前用一列零有效填充输入的两侧),则输出将为 [B, C1, 18]。

最大池化不会改变通道数。 如果使用内核大小为 3、步长为 3 且没有填充,则最后一个维度将减少到floor(x.size(2) / 3) ,其中x是最大池化层的输入张量。 如果输入不是 3 的倍数,则x特征图末尾的值将被忽略(也称为内核/窗口对齐问题)。

我建议查看nn.Conv1dnn.MaxPool1d的文档,因为它提供了计算输出形状的方程。


让我们考虑两个例子。 您可以随意定义C1, C2, F1, F2 最佳值将取决于您的数据。

没有填充我们得到

class ConvModel(nn.Module):
    def __init__(self):
        # input [B, 2, 18]
        self.conv1 = nn.Conv1d(in_channels=2, out_channels=C1, kernel_size=3)
        # [B, C1, 16]
        self.maxpool = nn.MaxPool1d(kernel_size=3, stride=3)
        # [B, C1, 5]    (WARNING last column of activations in previous layer are ignored b/c of kernel alignment)
        self.conv2 = nn.Conv1d(C1, C2, kernel_size=3)
        # [B, C2, 3]
        self.fc1 = nn.Linear(C2*3, F1)
        # [B, F1]
        self.fc2 = nn.Linear(F1, F2)
        # [B, F2]
        self.fc2 = nn.Linear(F2, 2)
        # [B, 2]

    def forward(x):
        x = F.relu(self.mp(self.conv1(x)))
        x = self.maxpool(x)

        x = F.relu(self.mp(self.conv2(x)))
        x = self.maxpool(x)

        x = x.flatten(1) # flatten the tensor starting at dimension 1

        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)

        return x

请注意最大池化层的内核对齐问题。 发生这种情况是因为最大池化的输入不是 3 的倍数。为了避免内核对齐问题并使输出大小更加一致,我建议在两个卷积层都包含一个额外的 1 填充。 那么你会有

class ConvModel(nn.Module):
    def __init__(self):
        # input [B, 2, 18]
        self.conv1 = nn.Conv1d(in_channels=2, out_channels=C1, kernel_size=3, padding=1)
        # [B, C1, 18]
        self.maxpool = nn.MaxPool1d(kernel_size=3, stride=3)
        # [B, C1, 6]    (no alignment issue b/c 18 is a multiple of 3)
        self.conv2 = nn.Conv1d(C1, C2, kernel_size=3, padding=1)
        # [B, C2, 6]
        self.fc1 = nn.Linear(C2*6, F1)
        # [B, F1]
        self.fc2 = nn.Linear(F1, F2)
        # [B, F2]
        self.fc2 = nn.Linear(F2, 2)
        # [B, 2]

    def forward(x):
        x = F.relu(self.mp(self.conv1(x)))
        x = self.maxpool(x)

        x = F.relu(self.mp(self.conv2(x)))
        x = self.maxpool(x)

        x = x.flatten(1) # flatten the tensor starting at dimension 1

        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)

        return x

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM