【问题标题】:How to calculate dimensions of first linear layer of a CNN如何计算 CNN 第一线性层的尺寸
【发布时间】:2021-09-24 15:21:41
【问题描述】:

目前,我正在使用一个 CNN,其中附加了一个完全连接的层,并且我正在使用大小为 32x32 的 3 通道图像。我想知道是否有一个一致的公式可以用来计算第一个线性层的输入尺寸和来自最后一个 conv/maxpooling 层的输入。我希望能够在仅给出最后一个 conv2d 层和稍后 maxpool 的信息的情况下计算第一个线性层的尺寸。换句话说,我希望能够计算该值而不必使用之前层的信息(因此我不必手动计算非常深的网络的权重维度)

我还想了解可接受尺寸的计算,例如这些计算的推理是什么?

出于某种原因,这些计算有效,Pytorch 接受了这些尺寸:

val = int((32*32)/4)
self.fc1 = nn.Linear(val, 200)

这也有效

self.fc1 = nn.Linear(64*4*4, 200)

为什么这些值有效,这些方法的计算是否存在限制?例如,如果我要更改步幅距离或内核大小,我觉得这会中断。

这是我使用的通用模型架构:

# define the CNN architecture
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        # convolutional layer
        self.conv1 = nn.Conv2d(in_channels=3, out_channels=16, kernel_size=3, padding=1)
        # max pooling layer
        self.pool = nn.MaxPool2d(2, 2)  


        self.conv2 = nn.Conv2d(in_channels=16, out_channels=32,kernel_size=3)
        self.pool2 = nn.MaxPool2d(2,2)

        self.conv3 = nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3)
        self.pool3 = nn.MaxPool2d(2,2)
        
        self.dropout = nn.Dropout(0.25)

        # H*W/4
        val = int((32*32)/4)
        #self.fc1 = nn.Linear(64*4*4, 200)
        ################################################
        self.fc1 = nn.Linear(val, 200)  # dimensions of the layer I wish to calculate
        ###############################################
        self.fc2 = nn.Linear(200,100)
        self.fc3 = nn.Linear(100,10)


    def forward(self, x):
        # add sequence of convolutional and max pooling layers
        x = self.pool(F.relu(self.conv1(x)))
        x = self.pool2(F.relu(self.conv2(x)))
        x = self.pool3(F.relu(self.conv3(x)))
        #print(x.shape)
        x = torch.flatten(x, 1) # flatten all dimensions except batch
        
        x = F.relu(self.fc1(x))
        x = self.dropout(x)
        x = F.relu(self.fc2(x))
        x = self.dropout(x)
        x = self.fc3(x)

        return x

# create a complete CNN
model = Net()
print(model)

谁能告诉我如何计算第一个线性层的尺寸并解释原因?

【问题讨论】:

    标签: python neural-network pytorch conv-neural-network dimensions


    【解决方案1】:

    给定输入空间维度 w,2d 卷积层将在该维度上输出具有以下大小的张量:

    int((w + 2*p - d*(k - 1) - 1)/s + 1)
    

    nn.MaxPool2d 也是如此。作为参考,您可以在 PyTorch documentation 上查看它。

    模型的卷积部分由三个 (Conv2d + MaxPool2d) 块组成。您可以使用此辅助函数轻松推断输出的空间维度大小:

    def conv_shape(x, k=1, p=0, s=1, d=1):
        return int((x + 2*p - d*(k - 1) - 1)/s + 1)
    

    递归调用,得到空间维度:

    >>> w = conv_shape(conv_shape(32, k=3, p=1), k=2, s=2)
    >>> w = conv_shape(conv_shape(w, k=3), k=2, s=2)
    >>> w = conv_shape(conv_shape(w, k=3), k=2, s=2)
    
    >>> w
    2
    

    由于您的卷积具有平方内核和相同的步幅、填充(水平等于垂直),因此上述计算适用于张量的宽度和高度尺寸。最后,查看最后一个卷积层conv3,它有 64 个过滤器,在全连接层之前每个批次元素的结果元素数为:w*w*64,即256


    但是,没有什么能阻止您调用图层来找出输出形状!

    class Net(nn.Module):
        def __init__(self):
            super().__init__()
            
            self.feature_extractor = nn.Sequential(
                nn.Conv2d(in_channels=3, out_channels=16, kernel_size=3, padding=1),
                nn.ReLU(),
                nn.MaxPool2d(2, 2),
                nn.Conv2d(in_channels=16, out_channels=32, kernel_size=3),
                nn.ReLU(),
                nn.MaxPool2d(2,2),
                nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3),
                nn.ReLU(),
                nn.MaxPool2d(2,2),
                nn.Flatten())
    
            n_channels = self.feature_extractor(torch.empty(1, 3, 32, 32)).size(-1)
    
            self.classifier = nn.Sequential(
                nn.Linear(n_channels, 200),
                nn.ReLU(),
                nn.Dropout(0.25),
                nn.Linear(200, 100),
                nn.ReLU(),
                nn.Dropout(0.25),
                nn.Linear(100, 10))
    
        def forward(self, x):
            features = self.feature_extractor(x)
            out = self.classifier(features)
            return out
    
    model = Net()
    

    【讨论】:

    • 感谢您的详细回复!我的一个问题是,对于您的递归方法,如果输入不是正方形,那么我将进行两次递归(计算 H 和 W),以便我可以计算 H*W*(out_channels of last conv layer, right) ?我还注意到,使用“64*4*4”作为尺寸也将被网络接受。出现这种情况是有原因的吗?
    • 确实,对于空间维度hw 和计算h*w*out_channels,您必须执行两次。小心:您可以使用64*4*4 初始化您的fc1,这并不意味着推断将有效:只需检查model(torch.empty(1,3,32,32)),如果您没有F.relu(self.fc1(x)),它将在F.relu(self.fc1(x)) 引发错误@ 987654338@的 in_channels 设置为 256!
    猜你喜欢
    • 2019-05-16
    • 1970-01-01
    • 2019-08-31
    • 2013-10-10
    • 1970-01-01
    • 2017-08-27
    • 1970-01-01
    • 2010-09-19
    • 1970-01-01
    相关资源
    最近更新 更多