• 在CIFAR-10数据集上构建ResNet-18模型(pytorch版)


    1. 构建ResNet模型

    我们将使用PyTorch框架来实现一个简化版的ResNet-18模型。我们的目标是构建一个可以在CIFAR-10数据集上进行分类任务的模型。

    1.1 前置条件

    pip install torch torchvision
    
    • 1

    1.2 构建Residual Block

    首先,让我们实现一个残差块。这是前面章节已经介绍过的内容。

    import torch
    import torch.nn as nn
    
    class ResidualBlock(nn.Module):
        def __init__(self, in_channels, out_channels, stride=1):
            super(ResidualBlock, self).__init__()
            self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride, padding=1)
            self.bn1 = nn.BatchNorm2d(out_channels)
            self.relu = nn.ReLU(inplace=True)
            self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=1, padding=1)
            self.bn2 = nn.BatchNorm2d(out_channels)
            
            self.shortcut = nn.Sequential()
            if stride != 1 or in_channels != out_channels:
                self.shortcut = nn.Sequential(
                    nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=stride),
                    nn.BatchNorm2d(out_channels)
                )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    1.3 构建ResNet-18

    接下来,我们使用残差块来构建完整的ResNet-18模型。

    class ResNet18(nn.Module):
        def __init__(self, num_classes=10):
            super(ResNet18, self).__init__()
            self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1)
            self.bn1 = nn.BatchNorm2d(64)
            self.relu = nn.ReLU(inplace=True)
            self.layer1 = self._make_layer(64, 64, 2)
            self.layer2 = self._make_layer(64, 128, 2, stride=2)
            self.layer3 = self._make_layer(128, 256, 2, stride=2)
            self.layer4 = self._make_layer(256, 512, 2, stride=2)
            self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
            self.fc = nn.Linear(512, num_classes)
    
        def _make_layer(self, in_channels, out_channels, blocks, stride=1):
            layers = []
            layers.append(ResidualBlock(in_channels, out_channels, stride))
            for _ in range(1, blocks):
                layers.append(ResidualBlock(out_channels, out_channels))
            return nn.Sequential(*layers)
    
        def forward(self, x):
            x = self.conv1(x)
            x = self.bn1(x)
            x = self.relu(x)
            x = self.layer1(x)
            x = self.layer2(x)
            x = self.layer3(x)
            x = self.layer4(x)
            x = self.avgpool(x)
            x = torch.flatten(x, 1)
            x = self.fc(x)
            return x
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    以上代码定义了一个用于CIFAR-10分类任务的ResNet-18模型。在这个模型中,我们使用了前面定义的ResidualBlock类,并通过_make_layer函数来堆叠多个残差块。

    1.4 模型测试

    接下来,我们可以测试这个模型以确保其结构是正确的。

    # 创建一个模拟输入
    x = torch.randn(64, 3, 32, 32)
    
    # 实例化模型
    model = ResNet18(num_classes=10)
    
    # 前向传播
    output = model(x)
    
    # 输出形状应为(64, 10),因为我们有64个样本和10个类别
    print(output.shape)  # 输出:torch.Size([64, 10])
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    2. 训练与评估

    在成功构建了ResNet-18模型之后,下一步就是进行模型的训练和评估。在这一部分,我们将介绍如何在CIFAR-10数据集上完成这两个步骤。

    2.1 数据预处理与加载

    首先,我们需要准备数据。使用PyTorch的torchvision库,我们可以非常方便地下载和预处理CIFAR-10数据集。

    import torch
    import torchvision
    import torchvision.transforms as transforms
    
    # 数据预处理
    transform = transforms.Compose([
        transforms.RandomCrop(32, padding=4),
        transforms.RandomHorizontalFlip(),
        transforms.ToTensor(),
        transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)),
    ])
    
    # 加载数据集
    trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)
    trainloader = torch.utils.data.DataLoader(trainset, batch_size=128, shuffle=True)
    
    testset = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform)
    testloader = torch.utils.data.DataLoader(testset, batch_size=128, shuffle=False)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    2.2 模型训练

    训练模型通常需要指定损失函数和优化器,并反复进行前向传播、计算损失、反向传播和参数更新。

    import torch.optim as optim
    
    # 实例化模型并移至GPU
    model = ResNet18(num_classes=10).cuda()
    
    # 定义损失函数和优化器
    criterion = nn.CrossEntropyLoss()
    optimizer = optim.SGD(model.parameters(), lr=0.1, momentum=0.9, weight_decay=5e-4)
    
    # 训练模型
    for epoch in range(10):  # 运行10个周期
        for i, data in enumerate(trainloader, 0):
            inputs, labels = data
            inputs, labels = inputs.cuda(), labels.cuda()
    
            # 清零梯度缓存
            optimizer.zero_grad()
    
            # 前向传播,计算损失,反向传播
            outputs = model(inputs)
            loss = criterion(outputs, labels)
            loss.backward()
    
            # 更新参数
            optimizer.step()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    2.3 模型评估

    训练完成后,我们需要评估模型的性能。这通常通过在测试集上计算模型的准确率来完成。

    # 切换模型为评估模式
    model.eval()
    
    correct = 0
    total = 0
    with torch.no_grad():
        for data in testloader:
            images, labels = data
            images, labels = images.cuda(), labels.cuda()
            outputs = model(images)
            _, predicted = torch.max(outputs.data, 1)
            total += labels.size(0)
            correct += (predicted == labels).sum().item()
    
    print(f'Accuracy of the network on the 10000 test images: {100 * correct / total}%')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    Reference

    理论内容:https://blog.csdn.net/magicyangjay111/article/details/132553872

  • 相关阅读:
    Acwing-反转链表
    通过jsonobject.tostring 传字符串为有空格问题
    Java工程maven中排包exclude的操作
    Linux系统编程:makefile以及文件系统编程
    Vue+nodejs服装库存管理系统-vscode前后端分离
    Git命令语句
    Python基础--PART2
    【数据结构】队列的实现与优化指南
    【Solution】商品秒杀之Redis缓存与MQ异步优化以及超卖一人一单等问题的解决
    vue3 api笔记
  • 原文地址:https://blog.csdn.net/JishuFengyang/article/details/132752869