如何在简单的pytorch模型中重构cnn层的输出张量以供线性层使用

时间:2020-10-08 13:42:13

标签: python deep-learning pytorch

给出一个维度为pytorch的输入数据集:

dat.shape = torch.Size([128, 3, 64, 64])

enter image description here

这是一个监督学习问题:对于每个输入观察,我们都有一个单独的labels.txt文件,其中包含C类之一。 C的值是由labeles文件中不同值的数量计算出来的,目前以一位数字表示。

我可以在如何对执行多类分类的卷积和线性图层网络的简单混合的图层进行网格化方面提供帮助。目的是要通过:

  • 两个cnn层,每个层之后都有maxpooling
  • 线性“读数”层
  • 在输出/标签之前激活softmax

这是我(故障/断开)网络的核心。我无法确定所需的正确尺寸/形状:

 Output of Convolutional layer -> Input of Linear [Readout] layer
class CNNClassifier(torch.nn.Module):

    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(3, 16, 3)
        self.maxpool = nn.MaxPool2d(kernel_size=3,padding=1)
        self.conv2 = nn.Conv2d(16, 32, 3)
        self.linear1 = nn.Linear(32*16*16, C)
        self.softmax1 = nn.LogSoftmax(dim=1)

    def forward(self, x):
        x = self.conv1(x)
        x = self.maxpool(F.leaky_relu(x))
        x = self.conv2(x)
        x = self.maxpool(F.leaky_relu(x))
        x = self.linear1(x)  # Size mismatch error HERE 
        x = self.softmax1(x)
        return x

模型的培训始于:

        Xout = model(dat)

结果为:

RuntimeError:大小不匹配,m1:[128 x 1568],m2:[8192 x 6]

linear1输入中输入

。这里需要什么?请注意,我已经看到了通配符输入大小的用法,例如通过view

    ..
    x = x.view(x.size(0), -1)
    x = self.linear1(x)  # Size mismatch error HERE 

如果包含该内容,则错误更改为

RuntimeError:大小不匹配,m1:[28672 x 7],m2:[8192 x 6]

对于如何思考和计算cnn层/线性层输入/输出大小的一些指示将不胜感激。

2 个答案:

答案 0 :(得分:2)

错误

您已经错误地计算了卷积堆栈的输出大小。实际上是[batch, 32, 7, 7]而不是[batch, 32, 16, 16]

您必须使用reshape(或view),因为Conv2d的输出具有4个维度([batch, channels, width, height]),而nn.Linear的输入则需要有2个维度([batch, features])。

将此用于nn.Linear

self.linear1 = nn.Linear(32 * 7 * 7, C)

这在forward中:

x = self.linear1(x.view(x.shape[0], -1))

其他可能性

当前的新体系结构使用跨渠道的池化(通常称为全局池化)。在PyTorch中有一个torch.nn.AdaptiveAvgPool2d(或Max池)。使用此方法可以使输入图像的高度和宽度大小可变,因为每个通道仅一个值用作nn.Linear的输入。看起来是这样:

class CNNClassifier(torch.nn.Module):
    def __init__(self, C=10):
        super().__init__()
        self.conv1 = nn.Conv2d(3, 16, 3)
        self.maxpool = nn.MaxPool2d(kernel_size=3, padding=1)
        self.conv2 = nn.Conv2d(16, 32, 3)
        self.pooling = torch.nn.AdaptiveAvgPool2d(output_size=1)
        self.linear1 = nn.Linear(32, C)
        self.softmax1 = nn.LogSoftmax(dim=1)

    def forward(self, x):
        x = self.conv1(x)
        x = self.maxpool(F.leaky_relu(x))
        x = self.conv2(x)
        x = self.maxpool(F.leaky_relu(x))
        x = self.linear1(self.pooling(x).view(x.shape[0], -1))
        x = self.softmax1(x)
        return x

因此现在torch.Size([128, 3, 64, 64])torch.Size([128, 3, 128, 128])的图像可以传递到网络了。

答案 1 :(得分:2)

问题在于您定义nn.Linear的方式。您将输入大小设置为32*16*16,它不是输出图像的形状,但是数字32 / 16代表Conv2d期望的“通道”暗淡的数量输入和输出内容。

如果您要在完全连接的层的入口之前添加print(x.shape),则会得到:

torch.Size([Batch, 32, 7, 7])

所以您的计算应该是7*7*32

self.linear1 = nn.Linear(32*7*7, C)

然后使用:

x = x.view(x.size(0), -1)
x = self.linear1(x)

可以正常工作。您可以在How does the "view" method work in PyTorch?

中了解view的用途。