更改 AlexNet 的输入维度

0 conv-neural-network transfer-learning

我是初学者,我正在尝试实现 AlexNet 进行图像分类。AlexNet的pytorch实现如下:


class AlexNet(nn.Module):

    def __init__(self, num_classes=1000):
        super(AlexNet, self).__init__()
        self.features = nn.Sequential(
            nn.Conv2d(3, 64, kernel_size=11, stride=4, padding=2),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2),
            nn.Conv2d(64, 192, kernel_size=5, padding=2),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2),
            nn.Conv2d(192, 384, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(384, 256, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(256, 256, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2),
        )
        self.avgpool = nn.AdaptiveAvgPool2d((6, 6))
        self.classifier = nn.Sequential(
            nn.Dropout(),
            nn.Linear(256 * 6 * 6, 4096),
            nn.ReLU(inplace=True),
            nn.Dropout(),
            nn.Linear(4096, 4096),
            nn.ReLU(inplace=True),
            nn.Linear(4096, num_classes),
        )

    def forward(self, x):
        x = self.features(x)
        x = self.avgpool(x)
        x = x.view(x.size(0), 256 * 6 * 6)
        x = self.classifier(x)
        return x

Run Code Online (Sandbox Code Playgroud)

但是,我正在尝试为输入大小为 (3,448,224) 的网络实现类数 = 8。

我不知道如何在 forward 方法中更改 x.view 以及我应该删除多少层以获得最佳性能。请帮忙。

Dav*_* Ng 5

https://github.com/pytorch/vision/releases 所述

因为,torchvision(最新版本)中提供的大多数预训练模型已经添加self.avgpool = nn.AdaptiveAvgPool2d((size, size))来解决与输入大小的不兼容问题。所以你不必太在意它。

下面是代码,很短。

import torchvision
import torch.nn as nn

num_classes = 8
model = torchvision.models.alexnet(pretrained=True)
# replace the last classifier
model.classifier[6] = nn.Linear(4096, num_classes)

# now you can trained it with your dataset of size (3, 448, 224)
Run Code Online (Sandbox Code Playgroud)

迁移学习

有两种流行的方法可以进行迁移学习。假设我们M在非常大的数据集上训练了一个模型D_large,现在我们想将模型学到的“知识”转移M到我们的新模型中M',在其他数据集上,例如D_other(其大小小于D_large)。

  1. 使用 的(大部分)部分M作为我们新的架构,M'并使用在 上训练的权重初始化这些部分D_large。我们可以开始M'在数据集上训练模型D_other,让它学习上述部分的权重,M以在我们的新数据集上找到最佳权重。这通常称为模型微调M'

  2. 与上述方法相同,除了在训练之前M'我们冻结这些部分的所有参数并开始M'对我们的数据集进行训练D_other。在这两种情况下,这些零件M大多是模型中的第一个组件M'(基础)。然而,在这种情况下,我们在向后传递期间参考那些部分。这提高了训练速度并减少了训练过程中所需的内存。M称为从输入数据集(或特征提取器)中提取特征的模型。两种方法获得的准确度可能会有所不同。但是,这种方法可以保证模型不会在小数据集上过拟合。就准确性而言,这是一个好点。另一方面,当我们冻结 的权重时M,我们不需要在前向传递中存储一些中间值(每个隐藏层的隐藏输出),也不需要计算gradients

实施

除了Alexnet,许多 ImageNet 上的预训练模型已经由 Facebook 团队提供,例如 ResNet、VGG。

为了在模型大小方面最符合您的要求,最好使用 VGG11 和 ResNet,它们的模型系列中参数最少。

我只是以 VGG11 为例:

  1. 从 中获取预训练模型torchvision
  2. 冻结此模型的所有参数。
  3. 用新Linear层替换模型中的最后一层以执行分类。这意味着您可以重用Mto 的几乎所有内容M'
import torchvision

# obtain the pretrained model
model = torchvision.models.vgg11(pretrained=True)

# freeze the params
for param in net.parameters():
    param.requires_grad = False

# replace with your classifier
num_classes = 8
net.classifier[6] = nn.Linear(in_features=4096, out_features=num_classes)

# start training with your dataset
Run Code Online (Sandbox Code Playgroud)

警告

在旧的torchvision包版本中,没有self.avgpool = nn.AdaptiveAvgPool2d((size, size))哪个更难训练我们的输入大小,这与[3, 224, 224]训练 ImageNet 中使用的不同。你可以做一点努力,如下所示:



class OurVGG11(nn.Module):

    def __init__(self, num_classes=8):
        super(OurVGG11, self).__init__()
        self.vgg11 = torchvision.models.vgg11(pretrained=True)
        for param in self.vgg11.parameters():
            param.requires_grad = False

        # Add a avgpool here
        self.avgpool = nn.AdaptiveAvgPool2d((7, 7))

        # Replace the classifier layer
        self.vgg11.classifier[-1] = nn.Linear(4096, num_classes)


    def forward(self, x):
        x = self.vgg11.features(x)
        x = self.avgpool(x)
        x = x.view(x.size(0), 512 * 7 * 7)
        x = self.vgg11.classifier(x)
        return x

model = OurVGG11()

# now start training `model` on our dataset.
Run Code Online (Sandbox Code Playgroud)

torchvision.models.