CIFAR10数据集完整使用教程

分类器任务和数据介绍

  • 构建一个将不同图像进行分类的神经网络分类器,对输入的图片进行判别并完成分类
  • 案例采用CIFAR10数据集作为原始图片数据

  • CIFAR10数据集介绍:数据集中每张图片的尺寸是3*32*32,代表彩色3通道
  • CIFAR10数据集总共有10种不同的分类,分别是"airplane",“automobile”,“bird”,“car”,“deer”,“dog”,“frog”,“house”,“ship”,“truck”

  • CIFAR10数据集的样例如下图:

训练分类器步骤

  • 使用torchvision下载CIFAR10数据集
  • 定义卷积神经网络
  • 定义损失函数
  • 在训练集上训练模型
  • 在测试集上测试模型

1使用torchvision下载CIFAR10数据集

  • 导入torchvision包来辅助下载数据集
    import torch
    import torchvision
    import torchvision.transforms as transformas
    
  • 下载数据集并对图片进行调整,因为torchvision数据集的输出是PILImage格式,数据域在[0,1],需要将其转换为标准数据域[-1,1]的张量格式
    # 定义数据变换
    transform = transforms.Compose(
        [transforms.ToTensor(),  # 将图片转换为Tensor
         transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])  # 归一化
    # 下载CIFAR10数据集
    # #训练集
    trainset=torchvision.datasets.CIFAR10(root='F:\人工智能\自然语言模型处理\data',train=True,download=True,transform=transform)
    # 测试集
    testset=torchvision.datasets.CIFAR10(root='F:\人工智能\自然语言模型处理\data',train=False,download=True,transform=transform)
    
    
    • 结果
      Downloading https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz to F:\人工智能\自然语言模型处理\data\cifar-10-python.tar.gz
      Extracting F:\人工智能\自然语言模型处理\data\cifar-10-python.tar.gz to F:\人工智能\自然语言模型处理\data
      Files already downloaded and verified
      
      
  • 注意:
    • 如果是在Windows系统下载运行代码,并且报错信息为"BrokenPipeError",可以尝试将torch.utils.data.DataLoader()中的num_workers设置为0

2 展示若干训练集的图片

 # 定义batch_size和num_workers
batch_size = 4
num_workers = 0  # Windows系统不支持多进程,所以num_workers应设为0
#练习集 封装成DataLoader的形式 batch_size 按照批次传 shuffle 将数据打散 num_workers 线程
# 创建DataLoader对象
trainloader=torch.utils.data.DataLoader(trainset,batch_size=batch_size,shuffle=True,num_workers=num_workers)
testloader=torch.utils.data.DataLoader(testset,batch_size=batch_size,shuffle=False,num_workers=num_workers)

# 定义类别名称
classes = ('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')

展示图片的方式

  • 方式一
import matplotlib.pyplot as plt
import numpy as np

# 获取一些随机训练图像
dataiter = iter(trainloader)
images, labels = next(dataiter) #注意点,由于版本不同,应该使用next()来迭代dataiter对象

# 展示图像和标签
#ncols 生成图片数量
fig, axes = plt.subplots(figsize=(10, 5), ncols=4)
for i in range(4):
    ax = axes[i]
    ax.imshow(np.transpose(images[i], (1, 2, 0)))
    ax.set_title(classes[labels[i]])# 设置图片的标签
    ax.axis('off')
plt.show()

# 打印标签label
print(' '.join('%10s'% classes[labels[i]]for i in range(4)))

  • 方法二
# 构建展示图片的函数
def imshow(img):
    img=img/2+0.5
    # 将tensor转化成numpy格式的数据
    npimg=img.numpy()
    # 生成一张图片 位于trainset第一张图片
    # img = torchvision.utils.make_grid(trainset[1][0]).numpy()
#     #维度转换
    plt.imshow(np.transpose(npimg,(1,2,0)))
    plt.show()

# 展示图片
imshow(torchvision.utils.make_grid(images))

# 打印标签label
print(' '.join('%10s'% classes[labels[i]]for i in range(4)))

出现 DLL load failed 错误## 标题

  • 问题(Windows环境+pycharm+jupyter notebook)

    libiomp5md.dll文件存在多个

    向系统申请允许在多个进程中加载同一个动态链接库,从而避免出现“DLL load failed”等错误。

    方式一:删除或者修改以下文件的名字(任一环境中)

    方式二:输入以下命令,在系统调用绘图库时,允许同时加载库

    import os
    os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"
    
  • 结果

3 定义卷积神经网络

  • 仿照2.1节中的类来构造此处的类,唯一的区别是采用3个通道3-channel
    import torch.nn as nn
    import torch.nn.functional as F
    
    
    class Net(nn.Module):
        def __init__(self):
            super(Net, self).__init__()
            # 定义2个卷积层
            self.conv1 = nn.Conv2d(3, 6, 5)
            # 卷积层
            self.conv2 = nn.Conv2d(6, 16, 5)
            # 池化层
            self.pool = nn.MaxPool2d(2, 2)
            # 全连接层
            self.fc1 = nn.Linear(16 * 5 * 5, 120)
            self.fc2 = nn.Linear(120, 84)
            self.fc3 = nn.Linear(84, 10)
    
        def forward(self, x):
            # 激活
            x = self.pool(F.relu(self.conv1(x)))
            x = self.pool(F.relu(self.conv2(x)))
            # 变换x的形状以适配全连接层的输入
            x = x.view(-1, 16 * 5 * 5)
            x = F.relu(self.fc1(x))
            x = F.relu(self.fc2(x))
            x = self.fc3(x)
            return x
    
    
    net = Net()
    
  • 结果
    Net(
      (conv1): Conv2d(3, 6, kernel_size=(5, 5), stride=(1, 1))
      (pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
      (conv2): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1))
      (fc1): Linear(in_features=400, out_features=120, bias=True)
      (fc2): Linear(in_features=120, out_features=84, bias=True)
      (fc3): Linear(in_features=84, out_features=10, bias=True)
    )
    

4 定义损失函数

  • 采用交叉熵损失函数和随机梯度下降优化器
    import torch.optim as optim
    # 定义损失函数,选用交叉熵损失函数
    criterion = nn.CrossEntropyLoss()
    # 定义优化器,选用随机梯度下降优化器
    # parameters 网络里面所有可训练的参数
    # lr 学习率
    optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
    
    • 结果
      SGD (
      Parameter Group 0
          dampening: 0
          differentiable: False
          foreach: None
          lr: 0.001
          maximize: False
          momentum: 0.9
          nesterov: False
          weight_decay: 0
      )
      

5 在GPU上训练模型

  • 为了真正利用Pytorch中Tensor的优秀属性, 加速模型的训练, 我们可以将训练过程转移到GPU上进行
    #  在GPU上训练模型
    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
    print(device)
    
    
  • 首先要定义设备, 如果CUDA是可用的则被定义成GPU, 否则被定义成CPU
    # 将模型转移到GPU上
    net.to(device)
    
    # 将损失函数转移到GPU上
    criterion.to(device)
    
    # 将输入的图片张量和标签张量转移到GPU上
    # inputs, labels = data[0].to(device), data[1].to(device)
    
    

6 在训练集上训练模型

  • 采用基于梯度下降的优化算法, 都需要很多个轮次的迭代训练
    # import sys
    # # 将 sys.stdout 重定向到 sys.__stdout__
    # sys.stdout = sys.__stdout__
    
    # 整个训练集 遍历两轮
    for epoch in range(2):  # loop over the dataset multiple times
        # 记录损失
        running_loss = 0.0
    
        # # 记录批次数
        # batch_count = 0
    
        # 每一个批次取数据进行训练
        for i, data in enumerate(trainloader, 0):
            # data中包含输入图像张量inputs, 标签张量labels
            # inputs, labels = data
            # 将输入的图片张量和标签张量转移到GPU上
            inputs, labels = data[0].to(device), data[1].to(device)
            # 首先将优化器梯度归零
            optimizer.zero_grad()
    
            # 输入图像张量进网络, 得到输出张量outputs
            outputs = net(inputs)
    
            # 利用网络的输出outputs和标签labels计算损失值
            loss = criterion(outputs, labels)
    
            # 反向传播+参数更新, 是标准代码的标准流程
            loss.backward()
            optimizer.step()
    
            # 打印轮次和损失值
            running_loss += loss.item()
            # batch_count += 1
            if (i+1) % 2000 == 0:
                print('[%d, %5d] loss: %.3f' %
                      (epoch + 1, i+1, running_loss / 2000))
                running_loss = 0.0
                # sys.stdout.flush()  # 刷新输出缓冲区
        print('Number of batches:', len(trainloader))
    
        # 在每个epoch结束后打印损失值
        # print('[%d] loss: %.3f' % (epoch + 1, running_loss / len(trainloader)))
        running_loss = 0.0
        # sys.stdout.flush()  # 刷新输出缓冲区
    
    print('Finished Training')
    
    • 结果
      [1,  2000] loss: 1.252
      [1,  4000] loss: 1.245
      [1,  6000] loss: 1.230
      [1,  8000] loss: 1.234
      [1, 10000] loss: 1.204
      [1, 12000] loss: 1.221
      Number of batches: 12500
      [2,  2000] loss: 1.134
      [2,  4000] loss: 1.139
      [2,  6000] loss: 1.158
      [2,  8000] loss: 1.121
      [2, 10000] loss: 1.135
      [2, 12000] loss: 1.139
      Number of batches: 12500
      Finished Training
      

7 保存模型

# 首先设定模型的保存路径
PATH = './cifar_net.pth'
# 保存模型的状态字典
torch.save(net.state_dict(), PATH)

8 在测试集上测试模型

  • 第一步, 展示测试集中的若干图片
    dataiter = iter(testloader)
    images, labels = next(dataiter)
    
    # 打印原始图片
    imshow(torchvision.utils.make_grid(images))
    # 打印真实的标签
    print('GroundTruth: ', ' '.join('%5s' % classes[labels[j]] for j in range(4)))
    
    • 结果

      GroundTruth: cat ship ship plane

  • 第二步, 加载模型并对测试图片进行预测
    # 加载模型参数,在测试阶段
    # 首先实例化模型的类对象
    net = Net()
    # 加载训练阶段保存好的模型的状态字典
    net.load_state_dict(torch.load(PATH)) #重要
    
    # 利用模型对图片进行预测
    outputs = net(images)
    
    # 模型共有10个类别的输出, 选取模型中概率最大的那个类别作为预测值
    _, predicted = torch.max(outputs, 1) #贪心算法
    
    # 打印预测标签的结果
    print('Predicted: ', ' '.join('%5s' % classes[predicted[j]] for j in range(4)))
    
    • 结果
      Predicted:    cat   car   car plane
      
  • 接下来看一下在全部测试集上的表现
    # 在整个测试集上测试模型的准确率
    correct = 0
    total = 0
    with torch.no_grad():
        for data in testloader:
            images, labels = data
            outputs = net(images)
            _, predicted = torch.max(outputs.data, 1)
            # +4
            total += labels.size(0)
            # 真 1 错 0
            correct += (predicted == labels).sum().item()
    
    print('Accuracy of the network on the 10000 test images: %d %%' % (100 * correct / total))
    
    • 结果
    Accuracy of the network on the 10000 test images: 53 %
    

📌分析结果: 对于拥有10个类别的数据集, 随机猜测的准确率是10%, 模型达到了53%, 说明模型学到了真实的东西

9 准确率计算

  • 为了更加细致的看一下模型在哪些类别上表现更好, 在哪些类别上表现更差, 我们分类别的进行准确率计算
    # 分别测试不同类别的模型准确率
    class_correct = list(0. for i in range(10))
    class_total = list(0. for i in range(10))
    # 不调整参数模型
    with torch.no_grad():
        for data in testloader:
            images, labels = data
            outputs = net(images)
            _, predicted = torch.max(outputs, 1)
            # squeeze() 把多余的维度进行清理
            c = (predicted == labels).squeeze()
            for i in range(4):
                label = labels[i]
                # 真实的数据添加到预测正确地列表内
                class_correct[label] += c[i].item()
                class_total[label] += 1
    # 打印不同类别的准确率
    for i in range(10):
        print('Accuracy of %5s : %2d %%' % (
            classes[i], 100 * class_correct[i] / class_total[i]))
    
    • 结果
      Accuracy of plane : 52 %
      Accuracy of   car : 86 %
      Accuracy of  bird : 49 %
      Accuracy of   cat : 22 %
      Accuracy of  deer : 39 %
      Accuracy of   dog : 48 %
      Accuracy of  frog : 44 %
      Accuracy of horse : 76 %
      Accuracy of  ship : 69 %
      Accuracy of truck : 47 %
      
  • 6
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值