Pytorch 深度卷积网络在 CIFAR10 上不收敛

Posted

技术标签:

【中文标题】Pytorch 深度卷积网络在 CIFAR10 上不收敛【英文标题】:Pytorch deep convolutional network does not converge on CIFAR10 【发布时间】:2019-09-19 22:30:19 【问题描述】:

我从 PyTorch 教程中复制了 CIFAR10 示例网络并添加了更多层,包括 BN。即使在 45 个 epoch 之后,网络在测试集上仍然保持 68% 的分类准确率。

网络包括:

2 个卷积层和 3x3 内核(输入大小从 32px 减少到 28px) 一个最大池化层(输入大小从 28px 减少到 14px) 3 个卷积层和 3x3 内核(输入大小从 14 像素减少到 8 像素) 具有 3 层 256->256->10 个神经元的全连接网络 批量归一化应用于所有层,包括卷积层,最后一个 FC 层除外 Relu 应用于所有卷积层和所有隐藏 FC 层

我是否构建/使用不当?

import torch
import torchvision
import torchvision.transforms as transforms
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1_1 = nn.Conv2d(3, 16, 3)  # 32 -> 30
        self.bn1_1 = nn.BatchNorm2d(16)
        self.conv1_2 = nn.Conv2d(16, 16, 3) # 30 - > 28
        self.bn1_2 = nn.BatchNorm2d(16)
        self.pool = nn.MaxPool2d(2, 2)  # 28 -> 14
        self.conv2_1 = nn.Conv2d(16, 16, 3) # 14 -> 12
        self.bn2_1 = nn.BatchNorm2d(16)
        self.conv2_2 = nn.Conv2d(16, 16, 3) # 12 -> 10
        self.bn2_2 = nn.BatchNorm2d(16)
        self.conv2_3 = nn.Conv2d(16, 16, 3) # 10 -> 8
        self.bn2_3 = nn.BatchNorm2d(16)
        self.fc1 = nn.Linear(16 * 8 * 8, 256)
        self.bn4 = nn.BatchNorm1d(256)
        self.fc2 = nn.Linear(256, 256)
        self.bn5 = nn.BatchNorm1d(256)
        self.fc3 = nn.Linear(256, 10)

    def forward(self, x):
        x = F.relu(self.bn1_1(self.conv1_1(x)))
        x = self.pool(F.relu(self.bn1_2(self.conv1_2(x))))
        x = F.relu(self.bn2_1(self.conv2_1(x)))
        x = F.relu(self.bn2_2(self.conv2_2(x)))
        x = F.relu(self.bn2_3(self.conv2_3(x)))
        x = x.view(-1, 16 * 8 * 8)
        x = F.relu(self.bn4(self.fc1(x)))
        x = F.relu(self.bn5(self.fc2(x)))
        x = self.fc3(x)
        return x

net = Net()
device = 'cuda:0'
net.to(device)
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)

transform = transforms.Compose(
        [transforms.ToTensor(),
         transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])

trainset = torchvision.datasets.CIFAR10(root='./data', train=True,
                                            download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=8,
                                              shuffle=True, num_workers=2)

for epoch in range(128):  # loop over the dataset multiple times
    for i, data in enumerate(trainloader, 0):
        # get the inputs
        inputs, labels = data
        inputs, labels = inputs.to(device), labels.to(device)

        # zero the parameter gradients
        optimizer.zero_grad()

        # forward + backward + optimize
        outputs = net(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()

注意:添加了“Python”标签以便代码高亮

注意:更新了 forward 方法以将 F.relu 应用于隐藏的 FC 层

【问题讨论】:

值得一试。也许尝试使用不同的参数显式初始化,例如nn.init.xavier_normal_,看看它是否有任何区别。 它seems like默认初始化是init.kaiming_uniform_ 顺便说一句,您的网络的完全连接层之间似乎没有非线性激活函数 @Shai 如果他在最后一层没有非线性可能会出现问题。我只记得 2 年前我使用 Keras 使用类似 VGG11 的网络获得了完全相同的准确率,约为 68%。后来我发现我忘了转调通道暗淡。然而,他在这里使用了来自 torchvision 的现成数据集 :) 你做得很好。但是您确定标准化的手段和标准差吗?我会使用 PIL 或 pyplot 来可视化一些样本并确保它们以您想要的方式提供,在 PyTorch 中是 [B,C,H,W]。从 PyTorch doc 看来,您可以获得 0-255 范围内的值。此外,我建议在卷积之前使用 BN 层(我知道这不是您经常看到的方式,但在数学上它是最有用的)并且使用 Adam 作为优化器应该会进一步改善您的结果。 【参考方案1】:

对最后一层使用 sigmoid 激活。

【讨论】:

以上是关于Pytorch 深度卷积网络在 CIFAR10 上不收敛的主要内容,如果未能解决你的问题,请参考以下文章

[Pytorch系列-45]:卷积神经网络 - 用GPU训练AlexNet+CIFAR10数据集

深度学习之卷积神经网络 CIFAR10与ResNet18实战

深度残差网络+自适应参数化ReLU激活函数(调参记录24)Cifar10~95.80%

pytorch-cifar10分类网络结构

深度残差网络+自适应参数化ReLU激活函数(调参记录23)Cifar10~95.47%

我用 PyTorch 复现了 LeNet-5 神经网络(CIFAR10 数据集篇)!