当前位置: 首页 > article >正文

实战1. 利用Pytorch解决 CIFAR 数据集中的图像分类为 10 类的问题

实战1. 利用Pytorch解决 CIFAR 数据集中的图像分类为 10 类的问题

  • 加载数据
  • 建立模型
  • 模型训练
  • 测试评估

你的任务是建立一个用于 CIFAR 图像分类的神经网络,并实现分类质量 > 0.5。

注意:因为我们实战1里只讨论最简单的神经网络构建,所以准确率达到0.5以上就符合我们的目标,后面会不断学习新的模型进行优化

CIFAR的数据集如下图所示:
在这里插入图片描述
我们大概所需要的功能包如下:

import numpy as np

import torch
from torch import nn
from torch.nn import functional as F
from tqdm.notebook import tqdm

import torchvision
from torchvision import datasets, transforms

from matplotlib import pyplot as plt
from IPython.display import clear_output

下面我们开始构建模型

加载数据

加载数据的代码已经完全实现,不需要做任何改变。

CIFAR10 是一个分为 10 个类的彩色图像数据集。图片中有汽车、飞机和动物的图像。

train_data = datasets.CIFAR10(root="./cifar10_data", train=True, download=True, transform=transforms.ToTensor())
test_data = datasets.CIFAR10(root="./cifar10_data", train=False, download=True, transform=transforms.ToTensor())

# 将训练样本分为train和val
# 我们将把 80% 的图片纳入训练样本
train_size = int(len(train_data) * 0.8)
# 进行验证 - 剩余 20%
val_size = len(train_data) - train_size

train_data, val_data = torch.utils.data.random_split(train_data, [train_size, val_size])

# 启动数据加载器
train_loader = torch.utils.data.DataLoader(train_data, batch_size=64, shuffle=True)
val_loader = torch.utils.data.DataLoader(val_data, batch_size=64, shuffle=False)
test_loader = torch.utils.data.DataLoader(test_data, batch_size=64, shuffle=False)

在这里插入图片描述
让我们看一些图片来了解我们正在处理的事情。要绘制训练集的十张图像,请运行以下单元:

# 此函数绘制多幅图像
def show_images(images, labels):
    f, axes= plt.subplots(1, 10, figsize=(30,5))

    for i, axis in enumerate(axes):
        # 将图像从张量转换为numpy
        img = images[i].numpy()
        # 将图像转换为尺寸(长度、宽度、颜色通道)
        img = np.transpose(img, (1, 2, 0))

        axes[i].imshow(img)
        axes[i].set_title(labels[i].numpy())

    plt.show()

# 从训练数据加载器中获取一批图像
for batch in train_loader:
    # 一批图片和一批图片答案
    images, labels = batch
    break

# 调用函数绘制图像
show_images(images, labels)

在这里插入图片描述

每张图片上方都写有该图片所属类别的编号。

答案编号与类别对应表:

标签课程
0飞机
1汽车
2
3
4鹿
5
6青蛙
7
8船舶
9卡车

让我们看看图片的尺寸:

images.shape

输出:torch.Size([64, 3, 32, 32])

这里64是批量大小,3是颜色通道数(因为图片是彩色的,是RGB)32和32是图片的宽度和高度。

事实证明,每张图片由 32 * 32 * 3 = 3072 个值表示。网络第一层应该有3072个神经元。

建立模型

你的任务是建立一个模型,然后训练它。请不要构建过于复杂的网络,不要使其深度超过四层(更少是可能的)。你的主要任务是训练模型并在测试样本上获得良好的质量。

您可以使用专栏里的课程3中的模型代码作为基础。
不要忘记,第一层的神经元数量应该不同。

你可以尝试什么来提高模型的质量:

  • 添加更多隐藏层;
  • 分层制造更多神经元;
  • 添加批量规范层。

批处理层是 BatchNorm1d(在下一个单元中导入)。该层应用在全连接层之后。例子:

def __init__(self):
        ...
        self.fc = nn.Linear(500, 100)
        self.bn = BatchNorm1d(100)
        ...

def forward(self, x):
        ...
        x = F.relu(self.fc(x))
        x = self.bn(x)
        ...

尝试在每个网络层之后插入一个 BatchNorm 层(最后一个网络层除外)。

为了成功通过任务,实现一个具有三层的网络和它们之间的 BatchNorm 就足够了。

这里我构建3072->128->64->10的网络:

# 导入 BatchNorm
from torch.nn.modules.batchnorm import BatchNorm1d

# 实现模型

class Model(nn.Module):
    def __init__(self):
      super(Model, self).__init__()
      # CIFAR - 10 图像尺寸为 3x32x32,展平后为 3072
      self.fc1 = nn.Linear(3 * 32 * 32, 128)
      self.bn1 = BatchNorm1d(128)
      self.fc2 = nn.Linear(128, 64)
      self.bn2 = BatchNorm1d(64)
      self.fc3 = nn.Linear(64, 10)

    def forward(self, x):
      # 展平输入
      x = x.view(-1, 3 * 32 * 32)
      x = F.relu(self.bn1(self.fc1(x)))
      x = F.relu(self.bn2(self.fc2(x)))
      x = self.fc3(x)
      return x

使用CPU/GPU操作:

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
device

输出:device(type=‘cpu’)

这里我用的是cpu

# 声明模型并将其传输到CPU/GPU
model = Model().to(device)

下面的单元格包含用于检查您的模型的测试。如果单元格没有返回错误,则模型运行正常。

assert model is not None, '模型变量为空。那么你的模型在哪里?'

try:
    x = images.reshape(-1, 3072).to(device)
    y = labels

    # 给定输入计算输出,两者都是变量
    y_predicted = model(x)
except Exception as e:
    print('该模型有问题')
    raise e


assert y_predicted.shape[-1] == 10, '模型的最后一层的神经元数量错误'

模型训练

现在我们需要训练模型。让我们使用课程3的用于评估模型质量的代码(评估函数)已经实现。

from sklearn.metrics import accuracy_score

def evaluate(model, dataloader, loss_fn):

    y_pred_list = []
    y_true_list = []
    losses = []

    # 我们浏览数据加载器批次
    for i, batch in enumerate(tqdm(dataloader)):

        # 这就是我们得到当前批次的方法
        X_batch, y_batch = batch

        # 关闭任何梯度的计算
        with torch.no_grad():

            # 我们收到该批次的网络响应
            logits = model(X_batch.to(device))

            # 我们计算批次上的损失函数值
            loss = loss_fn(logits, y_batch.to(device))
            loss = loss.item()

            # 将当前批次的损失保存到数组中
            losses.append(loss)

            # 对于我们理解的批次中的每个元素,
            # 网络将它分配到 0 到 9 中的哪个类别
            y_pred = torch.argmax(logits, dim=1)

        # 我们将当前批次的正确答案保存到数组中
        # 以及对当前批次的网络响应
        y_pred_list.extend(y_pred.cpu().numpy())
        y_true_list.extend(y_batch.numpy())

    # 我们计算网络响应和正确答案之间的准确率
    accuracy = accuracy_score(y_pred_list, y_true_list)

    return accuracy, np.mean(losses)
def train(model, loss_fn, optimizer, n_epoch=6):

    model.train(True)

    data = {
        'acc_train': [],
        'loss_train': [],
        'acc_val': [],
        'loss_val': []
    }

    # 网络训练周期
    for epoch in tqdm(range(n_epoch)):

        for i, batch in enumerate(tqdm(train_loader)):

            # 这就是我们获得当前一批图片和对它们的回应的方式
            X_batch, y_batch = batch

            # 前向传递(接收一批图像的网络响应)
            logits = model(X_batch.to(device))

            # 根据网络给出的答案和批次的正确答案计算损失
            loss = loss_fn(logits, y_batch.to(device))

            optimizer.zero_grad() # 我们重置优化器梯度的值
            loss.backward() # 反向传播(梯度计算)
            optimizer.step() # 更新网络权重

        # 时代终结,模型验证
        print('On epoch end', epoch)

        acc_train_epoch, loss_train_epoch = evaluate(model, train_loader, loss_fn)
        print('Train acc:', acc_train_epoch, 'Train loss:', loss_train_epoch)

        acc_val_epoch, loss_val_epoch = evaluate(model, val_loader, loss_fn)
        print('Val acc:', acc_val_epoch, 'Val loss:', loss_val_epoch)


        data['acc_train'].append(acc_train_epoch)
        data['loss_train'].append(loss_train_epoch)
        data['acc_val'].append(acc_val_epoch)
        data['loss_val'].append(loss_val_epoch)

    return model, data
# 声明模型并将其传输到 CPU/GPU
model = Model().to(device)

# 损失函数
loss_fn = torch.nn.CrossEntropyLoss()

# 优化器
learning_rate = 1e-3
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
model, data = train(model, loss_fn, optimizer, n_epoch=10)

在这里插入图片描述

测试评估

让我们在测试样本上评估一下模型的质量:

test_acc, test_loss = evaluate(model, test_loader, loss_fn)
test_acc

输出:0.5214

满足我们的要求,我们进行模型保存,之后就可以直接调用了:

x = torch.randn((64, 32*32*3))
torch.jit.save(torch.jit.trace(model.cpu(), (x)), "model.pth")

http://www.kler.cn/a/578866.html

相关文章:

  • Codeforces Round 305 (Div. 1) C. Mike and Foam 容斥原理、质因数分解
  • ACE协议学习1
  • 【python爬虫】酷狗音乐爬取
  • JavaWeb后端基础(7)AOP
  • 用K8S部署Milvus服务
  • 2025-3-9 leetcode刷题情况(贪心算法--序列问题)
  • 【QT5 Widgets示例】记事本:(一)项目创建
  • 基于PyTorch的深度学习3——非标量反向传播
  • Linux下的shell指令(二)
  • 计算机三级网络技术知识点汇总【7】
  • 打破界限!家电行业3D数字化营销,线上线下无缝对接
  • 【计算机网络】确认家庭网络是千兆/百兆带宽并排查问题
  • 深度解析:视频软编码与硬编码的优劣对比
  • 第十五届蓝桥杯省赛电子类单片机学习过程记录(客观题)
  • 旋转位置编码 (2)
  • 利用PHP爬虫根据关键词获取17网(17zwd)商品列表:实战指南
  • ABeam 德硕 | 中国汽车市场(1)——正在推进电动化的中国汽车市场
  • Android View设置圆角方式大全
  • LDR6500:革新手机OTG充电体验的关键芯片
  • MySQL快速使用Windows压缩包创建测试数据库