微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何计算 CNN 的第一个线性层的维度

如何解决如何计算 CNN 的第一个线性层的维度

目前,我正在使用一个 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)

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

解决方法

给定输入空间维度 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),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.Conv2d(in_channels=32,out_channels=64,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.Dropout(0.25),nn.Linear(200,100),nn.Linear(100,10))

    def forward(self,x):
        features = self.feature_extractor(x)
        out = self.classifier(features)
        return out

model = Net()

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。