[Pytorch案例实践004]CIFAR-100图像分类

时间:2025-03-17 07:56:10

一、项目概述

        这个项目旨在基于 PyTorch 框架构建和训练一个卷积神经网络(CNN),用于对 CIFAR-100 数据集进行分类。CIFAR-100 是一个更复杂的数据集,包含 100 类不同的图像,每类图像有 600 张,总计 60,000 张彩色图像。

主要步骤
  1. 数据预处理和加载

    • 加载 CIFAR-100 数据集,进行数据增强和归一化处理,以适应神经网络的输入。
    • 使用 DataLoader 创建数据加载器,支持高效的批量数据处理。
  2. 模型构建

    • 使用 构建一个卷积神经网络,网络结构包括多个卷积层、ReLU 激活函数、最大池化层、展平层和全连接层。
    • 增加模型复杂度,以适应 CIFAR-100 的多类别分类任务。
  3. 训练和验证

    • 训练过程中使用交叉熵损失函数和 Adam 优化器,模型的参数通过反向传播更新。
    • 训练完成后,使用验证集数据评估模型的泛化能力,记录损失和准确率。
  4. 模型保存

    • 在每个 epoch 结束时,保存验证集准确率最高的模型权重,确保保存的模型具有最佳性能。
  5. 结果可视化

    • 绘制并保存训练和验证过程中的损失和准确率曲线,以便后续分析。

二、数据集介绍

概述

        CIFAR-100 数据集是由加拿大多伦多大学的 Alex Krizhevsky 和 Geoffrey Hinton 在 2009 年推出的,用于训练机器学习和计算机视觉算法。CIFAR-100 是 CIFAR 系列中的一员,另一个常用的数据集是 CIFAR-10。与 CIFAR-10 的 10 个类别不同,CIFAR-100 包含 100 个不同的类别,每类图像都相对少量,但总共包含 60,000 张彩色图像。

数据集组成
  • 类别:100 个类别,每个类别有 600 张图像。
    • 500 张图像用于训练。
    • 100 张图像用于测试。
  • 图像尺寸:每张图像为 32x32 像素,彩色图像(3 个通道,RGB)。
  • 总样本数量:共 60,000 张图像,其中 50,000 张用于训练,10,000 张用于测试。
类别组织

CIFAR-100 的 100 个类别进一步分为 20 个超类(superclasses),每个超类下包含 5 个细类。每个图像都有一个 "fine" 标签(对应具体类别)和一个 "coarse" 标签(对应超类)。

例如,"superclass" 和 "fine" 类别的示例:

  • 超类 (Superclass): “鱼类 (fish)”
    • 细类 (Fine classes):
      • 鳗鱼 (aquarium fish)
      • 鲸鱼 (whale)
      • 鲸鲨 (shark)
      • 剑鱼 (swordfish)
      • 比目鱼 (flatfish)
数据集特点
  1. 复杂度高:相比 CIFAR-10 的 10 个类别,CIFAR-100 的类别数目多达 100 个,因此分类任务更具挑战性。
  2. 多样性:数据集中包含了不同类型的物体,涵盖了动植物、交通工具、日常用品等多个领域。
  3. 图像质量:图像为 32x32 像素,这种较小的尺寸对图像分类算法提出了较高的要求,需要模型具备较强的特征提取能力。

三、完整代码

import torch
import  as nn
import  as optim
import torchvision
import  as transforms
from  import DataLoader
from tqdm import tqdm
import  as plt

# 设置设备(使用GPU如果可用,否则使用CPU)
device = ('cuda' if .is_available() else 'cpu')

# 数据预处理,转为Tensor并归一化
transform = ([
    (),  # 转为Tensor
    ((0.5,), (0.5,))  # 归一化
])

# 加载Fashion-MNIST训练集
trainset = (root='./data', train=True, download=True, transform=transform)
trainloader = DataLoader(trainset, batch_size=100, shuffle=True, num_workers=2)

# 加载Fashion-MNIST测试集
testset = (root='./data', train=False, download=True, transform=transform)
testloader = DataLoader(testset, batch_size=100, shuffle=False, num_workers=2)

# 构建简单的卷积神经网络
class SimpleCNN():
    def __init__(self):
        super(SimpleCNN, self).__init__()
         = (
            nn.Conv2d(1, 32, kernel_size=3, padding=1),  # 卷积层1
            (),  # 激活函数
            nn.MaxPool2d(kernel_size=2, stride=2),  # 池化层1

            nn.Conv2d(32, 64, kernel_size=3, padding=1),  # 卷积层2
            (),  # 激活函数
            nn.MaxPool2d(kernel_size=2, stride=2),  # 池化层2

            nn.Conv2d(64, 128, kernel_size=3, padding=1),  # 卷积层3
            (),  # 激活函数
            nn.MaxPool2d(kernel_size=2, stride=2),  # 池化层3


            (),  # 展平
            (128*3*3, 256),  # 全连接层1
            (),  # 激活函数
            (256, 10)  # 全连接层2(输出层)
        )

    def forward(self, x):
        return (x)

# 定义训练和验证的主函数
def main():
    # 实例化网络并移动到设备(GPU或CPU)
    net = SimpleCNN().to(device)

    # 定义损失函数和优化器
    criterion = ()
    optimizer = ((), lr=0.001)

    # 训练和验证
    num_epochs = 30  # 训练的轮数
    best_acc = 0.0  # 初始化最佳准确率
    train_losses = []  # 用于保存训练损失
    test_losses = []  # 用于保存测试损失
    train_accuracies = []  # 用于保存训练准确率
    test_accuracies = []  # 用于保存测试准确率

    for epoch in range(num_epochs):
        ()  # 设置网络为训练模式
        running_loss = 0.0
        correct = 0
        total = 0

        # 使用tqdm显示训练进度条
        train_bar = tqdm(trainloader, desc=f'Training Epoch {epoch+1}/{num_epochs}')
        for inputs, labels in train_bar:
            inputs, labels = (device), (device)

            optimizer.zero_grad()  # 梯度清零
            outputs = net(inputs)  # 前向传播
            loss = criterion(outputs, labels)  # 计算损失
            ()  # 反向传播
            ()  # 优化器更新参数

            running_loss += ()
            _, predicted = (1)  # 获取预测结果
            total += (0)
            correct += (labels).sum().item()

            # 更新进度条信息
            train_bar.set_postfix(loss=running_loss/(len(train_bar)*trainloader.batch_size), acc=100.*correct/total)

        train_loss = running_loss / len(trainloader)
        train_acc = 100. * correct / total
        train_losses.append(train_loss)
        train_accuracies.append(train_acc)

        ()  # 设置网络为评估模式
        test_loss = 0.0
        correct = 0
        total = 0
        with torch.no_grad():  # 禁用梯度计算
            # 使用tqdm显示验证进度条
            test_bar = tqdm(testloader, desc=f'Validating Epoch {epoch+1}/{num_epochs}')
            for inputs, labels in test_bar:
                inputs, labels = (device), (device)
                outputs = net(inputs)
                loss = criterion(outputs, labels)
                test_loss += ()
                _, predicted = (1)
                total += (0)
                correct += (labels).sum().item()
                test_bar.set_postfix(loss=test_loss/(len(test_bar)*testloader.batch_size), acc=100.*correct/total)

        test_loss = test_loss / len(testloader)
        test_acc = 100. * correct / total
        test_losses.append(test_loss)
        test_accuracies.append(test_acc)

        # 保存最好的模型
        if test_acc > best_acc:
            best_acc = test_acc
            (net.state_dict(), 'best_model.pth')

    # 绘制损失和准确率曲线并保存
    (figsize=(12, 5))

    # 绘制损失曲线
    (1, 2, 1)
    (range(num_epochs), train_losses, label='Training Loss')
    (range(num_epochs), test_losses, label='Validation Loss')
    ('Epoch')
    ('Loss')
    ()
    ('Loss Curve')

    # 绘制准确率曲线
    (1, 2, 2)
    (range(num_epochs), train_accuracies, label='Training Accuracy')
    (range(num_epochs), test_accuracies, label='Validation Accuracy')
    ('Epoch')
    ('Accuracy')
    ()
    ('Accuracy Curve')

    # 保存图像
    ('loss_accuracy_curves.png')
    ()

if __name__ == "__main__":
    main()

四、总结

        本项目使用 PyTorch 框架构建了一个卷积神经网络(CNN)模型,针对 CIFAR-100 数据集进行了图像分类任务的实现。CIFAR-100 数据集具有 100 个类别,每个类别包含 600 张图像,是一个复杂的、多类别的图像分类任务。通过这个项目,我们对如何使用深度学习技术来处理图像分类问题有了深入的理解。我们不仅熟悉了使用 PyTorch 构建和训练卷积神经网络的全过程,还掌握了如何处理更复杂的多类别图像分类问题。尽管项目取得了一定的成功,但也暴露了在更大规模数据集上训练的挑战,如需要更多的计算资源、更深的网络结构或更复杂的模型调整策略。

未来的工作可以包括:

  • 尝试使用预训练模型进行迁移学习,以提升模型性能。
  • 引入更先进的网络架构,如 ResNet 或 DenseNet,以进一步提高分类准确率。
  • 优化数据预处理流程,探索更有效的数据增强方法。

        这个项目为后续更复杂的深度学习任务打下了坚实的基础。通过持续学习和实验,不断提升模型的性能和效率,将能够在实际应用中取得更好的结果。