PyTorch进行CIFAR-10图像分类

news2024/11/23 22:33:36

本节将通过一个实战案例来详细介绍如何使用PyTorch进行深度学习模型的开发。我们将使用CIFAR-10图像数据集来训练一个卷积神经网络。

神经网络训练的一般步骤如图5-3所示。

(1)加载数据集,并做预处理。

(2)预处理后的数据分为Feature和Label两部分,Feature 送到模型里面,Label被当作ground-truth。

(3)Model接收Feature作为Input,并通过一系列运算,向外输出 predict。

(4)建立一个损失函数 Loss,Loss 的函数值是为了表示 predict 与 ground-truth 之间的差距。

(5)建立 Optimizer 优化器,优化的目标就是 Loss 函数,让它的取值尽可能最小,Loss越小代表 Model 预测的准确率越高。

(6)Optimizer 优化过程中,Model 根据规则改变自身参数的权重,这是一个反复循环和持续的过程,直到Loss值趋于稳定,不能再取得更小的值。

数据集的加载可以自行编写代码,但如果是基于学习目的的话,那么把精力放在编写这个步骤的代码上面会让人十分无聊,好在PyTorch 提供了非常方便的包torchvision。torchvison提供了dataloader来加载常见的MNIST、CIFAR-10、ImageNet 等数据集,也提供了transform对图像进行变换、正则化和可视化。

在本项目中,我们的目的是用 PyTorch 创建基于 CIFAR-10 数据集的图像分类器。CIFAR-10图像数据集共有60 000幅彩色图像,这些图像是32×32的,分为10个类,分别是airplane、automobile、bird、cat等,每类6 000幅图,如图5-4所示。这里面有50 000幅训练图像,10 000幅测试图像。

首先,加载数据并进行预处理。我们将使用torchvision包来下载CIFAR-10数据集,并使用transforms模块对数据进行预处理。主要用来进行数据增强,为了防止训练出现过拟合,通常在小型数据集上,通过随机翻转图片、随机调整图片的亮度来增加训练时数据集的容量。但是,测试的时候,并不需要对数据进行增强。运行代码后,会自动下载数据集。

接下来,定义卷积神经网络模型。在这个网络模型中,我们使用nn.Module来定义网络模型,然后在__init__方法中定义网络的层,最后在forward方法中定义网络的前向传播过程。在PyTorch中可以通过继承nn.Module来自定义神经网络,在init()中设定结构,在forward()中设定前向传播的流程。因为PyTorch可以自动计算梯度,所以不需要特别定义反向传播。

定义好神经网络模型后,还需要定义损失函数(Loss)和优化器(Optimizer)。在这里采用 cross-entropy-loss函数作为损失函数,采用 Adam 作为优化器,当然SGD也可以。

一切准备就绪后,开始训练网络,这里训练10次(可以增加训练次数,提高准确率)。在训练过程中,首先通过网络进行前向传播得到输出,然后计算输出与真实标签的损失,接着通过后向传播计算梯度,最后使用优化器更新模型参数。训练完成后,我们需要在测试集上测试网络的性能。这可以让我们了解模型在未见过的数据上的表现如何,以评估其泛化能力。

完整代码如下:

#############cifar-10-pytorch.py####################
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.autograd import Variable
import torch
import torchvision
import torchvision.transforms as transforms
import torch.optim as optim

# torchvision输出的是PILImage,值的范围是[0, 1]
# 我们将其转换为张量数据,并归一化为[-1, 1]
transform = transforms.Compose([transforms.ToTensor(),
                                transforms.Normalize(mean=(0.5, 0.5, 0.5),
                                                     std=(0.5, 0.5, 0.5)),
                                ])

# 训练集,将相对目录./data下的cifar-10-batches-py文件夹中的全部数据
# (50 000幅图片作为训练数据)加载到内存中
# 若download为True,则自动从网上下载数据并解压
trainset = torchvision.datasets.CIFAR10(root='./data', train=True,
                                        download=True, transform=transform)

# 将训练集的50 000幅图片划分成12 500份,每份4幅图,用于mini-batch输入
# shffule=True在表示不同批次的数据遍历时,打乱顺序。num_workers=2表示使用两个子进程来加载数据
trainloader = torch.utils.data.DataLoader(trainset, batch_size=4,
                                          shuffle=False, num_workers=2)

classes = ('plane', 'car', 'bird', 'cat',
           'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
# 下面的代码只是为了给小伙伴们展示一个图片例子,让大家有个直观感受
# functions to show an image
import matplotlib.pyplot as plt
import numpy as np

# matplotlib inline
def imshow(img):
    img = img / 2 + 0.5  # unnormalize
    npimg = img.numpy()
    plt.imshow(np.transpose(npimg, (1, 2, 0)))
    plt.show()
class Net(nn.Module):
    # 定义Net的初始化函数,这个函数定义了该神经网络的基本结构
    def __init__(self):
        super(Net, self).__init__()
        # 复制并使用Net的父类的初始化方法,即先运行nn.Module的初始化函数
        self.conv1 = nn.Conv2d(3, 6, 5)
        # 定义conv1函数是图像卷积函数:输入为3张特征图
        # 输出为 6幅特征图, 卷积核为5×5的正方形
        self.conv2 = nn.Conv2d(6, 16, 5)
        # 定义conv2函数的是图像卷积函数:输入为6幅特征图,输出为16幅特征图
        # 卷积核为5×5的正方形
        self.fc1 = nn.Linear(16 * 5 * 5, 120)
        # 定义fc1(fullconnect)全连接函数1为线性函数:y = Wx + b
        # 并将16×5×5个节点连接到120个节点上
        self.fc2 = nn.Linear(120, 84)
        # 定义fc2(fullconnect)全连接函数2为线性函数:y = Wx + b
        # 并将120个节点连接到84个节点上
        self.fc3 = nn.Linear(84, 10)
        # 定义fc3(fullconnect)全连接函数3为线性函数:y = Wx + b
        # 并将84个节点连接到10个节点上

    # 定义该神经网络的向前传播函数,该函数必须定义
    # 一旦定义成功,向后传播函数也会自动生成(autograd)
    def forward(self, x):
        x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))
        # 输入x经过卷积conv1之后,经过激活函数ReLU
        # 使用2×2的窗口进行最大池化,然后更新到x
        x = F.max_pool2d(F.relu(self.conv2(x)), 2)
        # 输入x经过卷积conv2之后,经过激活函数ReLU
        # 使用2×2的窗口进行最大池化,然后更新到x
        x = x.view(-1, self.num_flat_features(x))
        # view函数将张量x变形成一维的向量形式
        # 总特征数并不改变,为接下来的全连接作准备
        x = F.relu(self.fc1(x))
        # 输入x经过全连接1,再经过ReLU激活函数,然后更新x
        x = F.relu(self.fc2(x))
        # 输入x经过全连接2,再经过ReLU激活函数,然后更新x
        x = self.fc3(x)
        # 输入x经过全连接3,然后更新x
        return x

    # 使用num_flat_features函数计算张量x的总特征量
    # 把每个数字都作一个特征,即特征总量
    # 比如x是4×2×2的张量,那么它的特征总量就是16
    def num_flat_features(self, x):
        size = x.size()[1:]
        # 这里为什么要使用[1:],是因为PyTorch只接受批输入
        # 也就是说一次性输入好几幅图片,那么输入数据张量的维度自然上升到了4维
        # 【1:】让我们把注意力放在后3维上面
        # x.size() 会 return [nSamples, nChannels, Height, Width]。
        # 只需要展开后三项成为一个一维的张量
        num_features = 1
        for s in size:
            num_features *= s
        return num_features
net = Net()
criterion = nn.CrossEntropyLoss()  # 交叉熵损失函数
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
# 使用SGD(随机梯度下降)优化,学习率为0.001,动量为0.9
if __name__ == '__main__':
    for epoch in range(10):
        running_loss = 0.0
        # enumerate(sequence, [start=0]),i是序号,data是数据
        for i, data in enumerate(trainloader, 0):
            inputs, labels = data
            # data的结构是:[4×3×32×32的张量,长度为4的张量]
            inputs, labels = Variable(inputs), Variable(labels)
            # 把input数据从tensor转为variable

            optimizer.zero_grad()
            # 将参数的grad值初始化为0
            # forward + backward + optimize
            outputs = net(inputs)
            loss = criterion(outputs, labels)
            # 将output和labels使用交叉熵计算损失
            loss.backward()  # 反向传播
            optimizer.step()  # 用SGD更新参数

            # 每2000批数据打印一次平均loss值
            running_loss += loss.item()
            # loss本身为Variable类型
            # 要使用data获取其张量,因为其为标量,所以取0 或使用loss.item()
            if i % 2000 == 1999:  # 每2000批打印一次
                print('[%d, %5d] loss: %.3f' % (epoch + 1, i + 1, running_loss / 2000))
                running_loss = 0.0

    print('Finished Training')
    # 测试集,将相对目录./data下的cifar-10-batches-py文件夹中的全部数据
    # (10 000幅图片作为测试数据)加载到内存中
    # 若download为True,则自动从网上下载数据并解压
    testset = torchvision.datasets.CIFAR10(root='./data', train=False,
                                           download=True, transform=transform)

    # 将测试集的10 000幅图片划分成2500份,每份4幅图,用于mini-batch输入
    testloader = torch.utils.data.DataLoader(testset, batch_size=4,
                                             shuffle=False, num_workers=2)
    correct = 0
    total = 0
    with torch.no_grad():
        for data in testloader:
            images, labels = data
            outputs = net(Variable(images))
            # print outputs.data
            # print(outputs.data)
            # print(labels)
            value, predicted = torch.max(outputs.data,
                                         1)
            # outputs.data是一个4x10张量
            # 将每一行的最大的那一列的值和序号各自组成一个一维张量返回
            # 第一个是值的张量,第二个是序号的张量
            # label.size(0) 是一个数
            total += labels.size(0)
            correct += (predicted == labels).sum()
            # 两个一维张量逐行对比,相同的行记为1,不同的行记为0
            # 再利用sum()求总和,得到相同的个数

    print('Accuracy of the network on the 10000 test images: %d %%' % (100 * correct / total))

    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)
            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]))

运行结果如下:

Files already downloaded and verified
Files already downloaded and verified
Files already downloaded and verified
[1,  2000] loss: 2.165
[1,  4000] loss: 1.834
[1,  6000] loss: 1.667
[1,  8000] loss: 1.566
[1, 10000] loss: 1.532
[1, 12000] loss: 1.462
Files already downloaded and verified
Files already downloaded and verified
[2,  2000] loss: 1.403
[2,  4000] loss: 1.380
[2,  6000] loss: 1.325
[2,  8000] loss: 1.281
[2, 10000] loss: 1.304
[2, 12000] loss: 1.262
Files already downloaded and verified
Files already downloaded and verified
[3,  2000] loss: 1.230
[3,  4000] loss: 1.221
[3,  6000] loss: 1.181
[3,  8000] loss: 1.147
[3, 10000] loss: 1.175
[3, 12000] loss: 1.147
Files already downloaded and verified
Files already downloaded and verified
[4,  2000] loss: 1.120
[4,  4000] loss: 1.110
[4,  6000] loss: 1.079
[4,  8000] loss: 1.064
[4, 10000] loss: 1.090
[4, 12000] loss: 1.068
Files already downloaded and verified
Files already downloaded and verified
[5,  2000] loss: 1.039
[5,  4000] loss: 1.030
[5,  6000] loss: 1.009
[5,  8000] loss: 0.990
[5, 10000] loss: 1.021
[5, 12000] loss: 1.007
Files already downloaded and verified
Files already downloaded and verified
[6,  2000] loss: 0.975
[6,  4000] loss: 0.971
[6,  6000] loss: 0.947
[6,  8000] loss: 0.937
[6, 10000] loss: 0.963
[6, 12000] loss: 0.953
Files already downloaded and verified
Files already downloaded and verified
[7,  2000] loss: 0.930
[7,  4000] loss: 0.923
[7,  6000] loss: 0.902
[7,  8000] loss: 0.891
[7, 10000] loss: 0.928
[7, 12000] loss: 0.911
Files already downloaded and verified
Files already downloaded and verified
[8,  2000] loss: 0.881
[8,  4000] loss: 0.890
[8,  6000] loss: 0.864
[8,  8000] loss: 0.868
[8, 10000] loss: 0.896
[8, 12000] loss: 0.875
Files already downloaded and verified
Files already downloaded and verified
[9,  2000] loss: 0.846
[9,  4000] loss: 0.870
[9,  6000] loss: 0.836
[9,  8000] loss: 0.834
[9, 10000] loss: 0.851
[9, 12000] loss: 0.847
Files already downloaded and verified
Files already downloaded and verified
[10,  2000] loss: 0.816
[10,  4000] loss: 0.835
[10,  6000] loss: 0.797
[10,  8000] loss: 0.805
[10, 10000] loss: 0.841
[10, 12000] loss: 0.809
Finished Training
Files already downloaded and verified
Files already downloaded and verified
Files already downloaded and verified
Accuracy of the network on the 10000 test images: 61 %
Files already downloaded and verified
Files already downloaded and verified
Accuracy of plane : 58 %
Accuracy of   car : 72 %
Accuracy of  bird : 41 %
Accuracy of   cat : 51 %
Accuracy of  deer : 55 %
Accuracy of   dog : 44 %
Accuracy of  frog : 66 %
Accuracy of horse : 72 %
Accuracy of  ship : 80 %
Accuracy of truck : 69 %

在这段代码中,我们在整个测试集上测试网络,并打印出网络在测试集上的准确率。通过这种详细且实践性的方式介绍了PyTorch的使用,包括张量操作、自动求导机制、神经网络创建、数据处理、模型训练和测试。我们利用PyTorch从头到尾完成了一个完整的神经网络训练流程,并在 CIFAR-10数据集上测试了网络的性能。在这个过程中,我们深入了解了PyTorch提供的强大功能。

本文节选自《PyTorch深度学习与企业级项目实战》,获出版社和作者授权发布。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1673197.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用PageHelper分页插件,发现获取到的total总记录数量不对,无法获取到正确的total数量

目录 1.1、错误描述 1.2、解决方案 1.1、错误描述 周一在工作中,写了一个列表分页的接口,其中使用的是PageHelper分页依赖,原本想着挺简单的,也就是使用PageHelper.startPage(pageNum, pageSize);方法就可以了,代码…

讨论:WGS84与CGCS2000的坐标系怎么互转

前言: 今天我们要讨论一个问题:WGS84与CGCS2000的坐标系怎么互转? 对于有一定基础的朋友应该知道,WGS84和CGCS2000属于不同的椭球,如果进行严密的数学转换,是需要建立参数模型之后,再进行转换&…

视频素材哪里找?7个无版权视频素材网站

这篇文章为那些正在学习视频剪辑的新手提供了一份宝贵的资源清单,介绍了7个可以找到高质量且免费可商用的视频素材网站。每个网站都有其独特的资源库,可以帮助用户找到适合各种项目的视频素材,从生活vlog到专业旅行记录,都可以在这…

STM32存储左右互搏 USB接口FATS文件读写U盘

STM32存储左右互搏 USB接口FATS文件读写U盘 STM32的USB接口可以例化为Host主机从而对U盘进行操作。SD卡/MicroSD/TF卡也可以通过读卡器转换成U盘使用。这里介绍STM32CUBEIDE开发平台HAL库实现U盘FATS文件访问的例程。 USB接口介绍 常见的USB接口电路部分相似而有不同的连接器…

数据分离和混淆矩阵的学习

1.明确意义 通过训练集建立模型的意义是对新的数据进行准确的预测(测试集的准度高才代表good fit); 2.评估流程 3.单单利用准确率accuracy进行模型评估的局限性 模型一:一共1000个数据(分别为900个1和100个0&#x…

网站服务器备案及域名购买配置教程

一、阿里云服务备案准备工作 1.什么是备案? 备案是指向相关部门提交网站信息,以便监管和管理互联网信息服务,未经备案的网站可能面临罚款甚至被关闭的风险。备案主要看您的网站或App等互联网信息服务解析到的服务器是否在中国内地(大陆),如果服务器在中国内地(大陆),…

Postman基础功能-Collection集合和批量运行

一、Collection(集合)介绍 当我们对一个或多个系统中的很多接口用例进行维护时,首先想到的就是对接口用例进行分类管理,同时还希望对这批接口用例做回归测试。 在 Postman 中也提供了这样一个功能,就是 Collec…

Aim Web API 远程代码执行

摘要 漏洞类型:远程代码执行(RCE)产品:目标版本:> 3.0.0(afaik)受影响的端点: /api/runs/search/run/严重性:临界 描述 在aim项目中发现了一个关键的远程代码执行漏…

设计模式 六大原则之里氏替换原则

文章目录 概念替换逻辑行为不变 拆解小结 概念 子类对象能够替换程序中父类对象出现的任何地方,并且保证原来程序的逻辑行为不变及正确性不被破坏。 替换 替换的前提是面向对象语言所支持的多态特性,同一个行为具有多个不同表现形式或形态的能力。 逻…

js基础-数组-事件对象-日期-本地存储

一、大纲 一、获取元素位置 在JavaScript中,获取一个元素在页面上的位置可以通过多种方法实现。以下是一些常见的方法: getBoundingClientRect() getBoundingClientRect() 方法返回元素的大小及其相对于视口的位置。它提供了元素的left、top、right和bo…

Tkinter组件:Text-显示和处理多行文本

Tkinter组件:Text Text(文本)组件用于显示和处理多行文本。在 Tkinter 的所有组件中,Text 组件显得异常强大和灵活,适用于多种任务。虽然该组件的主要目的是显示多行文本,但它常常也被用于作为简单的文本编…

【单片机调试】mcu调试bug记录

【单片机调试】mcu调试bug记录 2023.5-2023.11待输入 2023.12-2023.22024.3-至今1.spi通信问题 2023.5-2023.11 待输入 2023.12-2023.2 辞职阶段:【STM32调试】寄存器调试不良问题记录持续版 2024.3-至今 1.spi通信问题 现象说明: mcu与afe芯片为spi通…

为什么使用AI 在游戏中不犯法

使用AI在游戏中本身并不违法,甚至在很多情况下,游戏公司自己也会在游戏中集成AI来提高游戏体验,例如通过AI驱动的非玩家角色(NPC)来增加游戏的互动性和挑战性。然而,使用AI是否违法取决于AI的使用方式和目的…

设计一个游戏的基本博弈框架

设计一个游戏的基本博弈框架,玩家通过操作改变某个数值,这个数值的变动会引发一系列实时变化,并且当这些数值累计到特定阈值时,会导致游戏中出现其他变化,可以分为以下几个步骤: 1. 确定游戏类型和主题 首…

邮件地址采集软件有哪些-邮箱地址采集软件

邮件地址采集软件是帮助用户收集、管理和使用邮件地址的工具,它们在商业营销、市场调研、网络爬虫等领域有着广泛的应用。以下是一些常见的邮件地址采集软件: 易邮件地址搜索大师:易邮件地址搜索大师是一款搜索邮件地址和手机号码的软件&…

一篇文章拿下Redis 通用命令

文章目录 Redis数据结构介绍Redis 通用命令命令演示KEYSDELEXISTSEXPIRE RedisTemplate 中的通用命令 本篇文章介绍 Redis 的通用命令, 通用命令在 Redis 的所有数据类型下都使用, 学好通用命令可以让我们更好的使用 Redis. Redis数据结构介绍 Redis 是一个key-value的数据库&…

如何进行免杀

0x03 免杀思路总结 环境准备: 火绒(静态)、360、windowsdef(动态) 免杀的最基本思路就是去除其特征,这个特征有可能是特征码,也有可能是行为特征,只要在不修改其 原有功能的情况下…

基于C#开发web网页管理系统模板流程-登录界面

前言,首先介绍一下本项目将要实现的功能 (一)登录界面 实现一个不算特别美观的登录窗口,当然这一步跟开发者本身的设计美学相关,像蒟蒻博主就没啥艺术细胞,勉强能用能看就行…… (二&#xff09…

极验3滑块逆向分析

1、底图还原 下 断点&#xff0c;可以分析底图还原逻辑 2、跟W值 var Str_Unicodefunction(str){var unid\\u00;for(let i0,lenstr.length;i<len;i){if(i<len-1){unidstr.charCodeAt(i).toString(16)\\u00;}else if(ilen-1){unidstr.charCodeAt(i).toString(16);}}re…

【数据结构】数组循环队列的实现

队列&#xff08;Queue&#xff09;是一种特殊的线性数据结构&#xff0c;它遵循FIFO&#xff08;First In First Out&#xff0c;先入先出&#xff09;的原则。队列只允许在表的前端&#xff08;front&#xff09;进行删除操作&#xff0c;而在表的后端&#xff08;rear&#…