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

重生学AI第二十集(大结局):完善模型以及学习总结

1.代码优化

这是我们学习容器的时候写的代码

import torch.optim
import torchvision
from torch import nn
from torch.utils.data import DataLoader# CIFAR-10 数据集加载
datasets = torchvision.datasets.CIFAR10(root='../dataset', train=False, download=True,transform=torchvision.transforms.ToTensor())
my_dl = DataLoader(datasets, batch_size=64)# 自定义神经网络模型
class MyModel(nn.Module):def __init__(self):super(MyModel, self).__init__()self.model = nn.Sequential(# 三层卷积和池化nn.Conv2d(3,32,5,padding=2),nn.MaxPool2d(2),nn.Conv2d(32,32,5,padding=2),nn.MaxPool2d(2),nn.Conv2d(32,64,5,padding=2),nn.MaxPool2d(2),# 展平层nn.Flatten(),# 线性层nn.Linear(1024, 64),nn.Linear(64, 10))def forward(self, x):x = self.model(x)return x# 模型实例化
model = MyModel()# 实例化损失函数(交叉熵损失函数)
loss1 = nn.CrossEntropyLoss()# 实例化优化器
my_optimizer = torch.optim.SGD(model.parameters(), lr=0.01)for epoch in range(20):total_loss = 0.0for data in my_dl:imgs, targets = data# 通过模型 计算类别得分outputs = model(imgs)#损失函数将类别得分转换为概率,并与实际结果进行对比,计算损失值loss_result = loss1(outputs, targets)#将梯度清零 以免被上一次的梯度影响到my_optimizer.zero_grad()#反向传播 计算梯度loss_result.backward()#调用优化器 根据梯度更新参数my_optimizer.step()total_loss += loss_resultprint(total_loss)

1.1 修改数据集

一个完整的模型是需要测试数据集和训练数据集的,训练数据集是用来训练模型的,测试数据集是测试模型学习成果,就像我们现实生活中的考试一样

# CIFAR-10 数据集加载
train_datasets = torchvision.datasets.CIFAR10(root='../dataset', train=True, download=True,transform=torchvision.transforms.ToTensor())
test_datasets = torchvision.datasets.CIFAR10(root='../dataset', train=False, download=True,transform=torchvision.transforms.ToTensor())#dataloader
train_dataloader = DataLoader(train_datasets, batch_size=64)
test_dataloader = DataLoader(test_datasets, batch_size=64)

1.2 修改训练步骤

把原来的训练过程修改了一下,并新增了两个变量用来记录训练步数,并且为了方便运行,暂时把运行轮次改为了1

#初始化两个步数
total_train_step = 0
total_test_step = 0# 训练过程
for epoch in range(1):# 开始训练model.train()for data in train_dataloader:imgs, targets = data# 通过模型 计算类别得分outputs = model(imgs)#损失函数将类别得分转换为概率,并与实际结果进行对比,计算损失值loss_result = loss1(outputs, targets)#优化模型my_optimizer.zero_grad()loss_result.backward()my_optimizer.step()# 每次训练完毕 步数加1total_train_step += 1# 每训练100次打印步数和loss值if total_train_step % 100 == 0:print("训练次数:{},loss:{}".format(total_train_step, loss_result.item()))

运行一下看看效果

1.3 增加测试代码

接下来就要增加测试过程,测试过程和训练过程都在训练轮次的循环内,每一轮训练完成后就测试一下这个模型在测试集的表现

# 训练过程
for epoch in range(1):# 开始训练model.train()for data in train_dataloader:imgs, targets = data# 通过模型 计算类别得分outputs = model(imgs)#损失函数将类别得分转换为概率,并与实际结果进行对比,计算损失值loss_result = loss1(outputs, targets)#优化模型my_optimizer.zero_grad()loss_result.backward()my_optimizer.step()# 每次训练完毕 步数加1total_train_step += 1# 每训练100次打印步数和loss值if total_train_step % 100 == 0:print("训练次数:{},loss:{}".format(total_train_step, loss_result.item()))# 开始测试model.eval()total_test_loss = 0with torch.no_grad():for data in test_dataloader:imgs, targets = dataoutputs = model(imgs)loss_result = loss1(outputs, targets)total_test_loss += loss_result.item()print("测试集的整体损失值:{}".format(total_test_loss))total_test_step += 1

运行代码

1.4 可视化

接下来,我们加入可视化,让他在tensorboard上显示出来

...
# 初始化写入器
writer = SummaryWriter("../logs")
...print("训练次数:{},loss:{}".format(total_train_step, loss_result.item()))writer.add_scalar("train_loss", loss_result.item(), total_train_step)...print("测试集的整体损失值:{}".format(total_test_loss))writer.add_scalar("test_loss", total_test_loss, total_test_step)total_test_step += 1
...
writer.close()

再次运行代码,然后打开终端输入指令

打开网址后是这样的

1.5 统计正确率

正确率要用到torch.argmax(input, dim)这个函数,他的作用是从一个向量或多维张量中选择最大值所在的索引。

我们通过代码 outputs = model(imgs) 得到的是一个这样的数据

那么,argmax返回的就是【2,2,2】,因为

  • 3是列表1中最大的,下标为2;
  • 6是列表2中最大的,下标为2;
  • 9是列表3中最大的,下标为2;

我们可以测试一下

import torchoutputs = torch.tensor([[1,2,3],[4,5,6],[7,8,9]])preds = outputs.argmax(1)
print(preds)

运行结果:

假设列表1、列表2、列表3代表三张图片对于三个分类的预测结果,那么2,2,2就是最终的预测值,代表预测第一张图片是2,第二张图片也是2,第三张也是2,如果这三张图片的真实结果是2,2,1,那么我们就可以求出他们正确的个数,像这样

import torchoutputs = torch.tensor([[1,2,3],[4,5,6],[7,8,9]])preds = outputs.argmax(1)
print(preds)targets = torch.tensor([2,2,1])
print(preds == targets)
print((preds == targets).sum())

运行结果:

代入到我们的训练模型代码中就是这样的

# 开始测试model.eval()total_test_loss = 0total_correct = 0with torch.no_grad():for data in test_dataloader:imgs, targets = dataoutputs = model(imgs)loss_result = loss1(outputs, targets)total_test_loss += loss_result.item()#统计正确的个数preds = outputs.argmax(1)correct = (preds==targets).sum()total_correct += correct.item()# 计算测试集的准确率total_accuracy = total_correct/len(test_datasets)print("测试集的整体损失值:{}".format(total_test_loss))print("测试集的整体正确率:{}".format(total_accuracy))writer.add_scalar("test_loss", total_test_loss, total_test_step)writer.add_scalar("test_accuracy", total_accuracy, total_test_step)total_test_step += 1

1.6 保存模型

加入保存模型的代码,让它每训练一轮就保存下来

#保存模型torch.save(model,"model_{}.pt".format(epoch))

运行看看效果,之前一轮看着效果不太好,我改成3轮了

唔。。。这个test_loss看起来很奇怪,于是我把日志文件清空,又重新运行了代码,重启了tensorboard,现在看起来好多了

并且模型文件也成功被保存到了项目文件夹中

1.7 GPU加速

GPU加速就是对网络模型、数据、损失函数的计算从CPU转移到GPU上面,因为GPU要比CPU快很多,.to()就是将数据进行设备转移的一个函数。

首先,定义一个device,如果有GPU的话就用GPU,没有就用CPU

...
# 定义设备
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
...

cuda:0的意思是:如果有多个显卡的话,用第一个GPU,只有一个的话,可以省略掉后面的:0,像这样:device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

然后将模型、数据、损失函数进行设备转移

...
# 模型实例化
model = MyModel()
model = model.to(device)# 实例化损失函数(交叉熵损失函数)
loss1 = nn.CrossEntropyLoss()
loss1 = loss1.to(device)
...
imgs, targets = data
imgs, targets = imgs.to(device), targets.to(device)
...

最后我们还可以加上时间,来看一下他们的差距

# 训练过程
for epoch in range(3):# 开始训练model.train()start_time = time.time()for data in train_dataloader:imgs, targets = dataimgs, targets = imgs.to(device), targets.to(device)# 通过模型 计算类别得分outputs = model(imgs)#损失函数将类别得分转换为概率,并与实际结果进行对比,计算损失值loss_result = loss1(outputs, targets)#优化模型my_optimizer.zero_grad()loss_result.backward()my_optimizer.step()# 每次训练完毕 步数加1total_train_step += 1# 每训练100次打印步数和loss值if total_train_step % 100 == 0:print("训练次数:{},loss:{}".format(total_train_step, loss_result.item()))writer.add_scalar("train_loss", loss_result.item(), total_train_step)end_time = time.time()print("训练一轮花费时长:{}".format(end_time - start_time))

直接运行看GPU版本的时长,直接看第一个就好了

然后把设备那里改成CPU再运行,像这样

# 定义设备
device = torch.device("cpu")

运行结果:

差距就出来了

1.8 完整代码

最后附上完整代码

import timeimport torch.optim
import torchvision
from torch import nn
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter# CIFAR-10 数据集加载
train_datasets = torchvision.datasets.CIFAR10(root='../dataset', train=True, download=True,transform=torchvision.transforms.ToTensor())
test_datasets = torchvision.datasets.CIFAR10(root='../dataset', train=False, download=True,transform=torchvision.transforms.ToTensor())#dataloader
train_dataloader = DataLoader(train_datasets, batch_size=64)
test_dataloader = DataLoader(test_datasets, batch_size=64)
# 初始化写入器
writer = SummaryWriter("../logs")
# 定义设备
device = torch.device("cpu")
# device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")# 自定义神经网络模型
class MyModel(nn.Module):def __init__(self):super(MyModel, self).__init__()self.model = nn.Sequential(# 三层卷积和池化nn.Conv2d(3,32,5,padding=2),nn.MaxPool2d(2),nn.Conv2d(32,32,5,padding=2),nn.MaxPool2d(2),nn.Conv2d(32,64,5,padding=2),nn.MaxPool2d(2),# 展平层nn.Flatten(),# 线性层nn.Linear(1024, 64),nn.Linear(64, 10))def forward(self, x):x = self.model(x)return x# 模型实例化
model = MyModel()
model = model.to(device)# 实例化损失函数(交叉熵损失函数)
loss1 = nn.CrossEntropyLoss()
loss1 = loss1.to(device)# 实例化优化器
my_optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
#初始化两个步数
total_train_step = 0
total_test_step = 0# 训练过程
for epoch in range(3):# 开始训练model.train()start_time = time.time()for data in train_dataloader:imgs, targets = dataimgs, targets = imgs.to(device), targets.to(device)# 通过模型 计算类别得分outputs = model(imgs)#损失函数将类别得分转换为概率,并与实际结果进行对比,计算损失值loss_result = loss1(outputs, targets)#优化模型my_optimizer.zero_grad()loss_result.backward()my_optimizer.step()# 每次训练完毕 步数加1total_train_step += 1# 每训练100次打印步数和loss值if total_train_step % 100 == 0:print("训练次数:{},loss:{}".format(total_train_step, loss_result.item()))writer.add_scalar("train_loss", loss_result.item(), total_train_step)end_time = time.time()print("训练一轮花费时长:{}".format(end_time - start_time))# 开始测试model.eval()total_test_loss = 0total_correct = 0with torch.no_grad():for data in test_dataloader:imgs, targets = dataimgs, targets = imgs.to(device), targets.to(device)outputs = model(imgs)loss_result = loss1(outputs, targets)total_test_loss += loss_result.item()#统计正确的个数preds = outputs.argmax(1)correct = (preds==targets).sum()total_correct += correct.item()# 计算测试集的准确率total_accuracy = total_correct/len(test_datasets)print("测试集的整体损失值:{}".format(total_test_loss))print("测试集的整体正确率:{}".format(total_accuracy))writer.add_scalar("test_loss", total_test_loss, total_test_step)writer.add_scalar("test_accuracy", total_accuracy, total_test_step)total_test_step += 1#保存模型torch.save(model,"model_{}.pt".format(epoch))
writer.close()

2. 学习总结

至此,对于人工神经网络的学习可以初步画个句号了,通过这些天的学习,我们学会了

  1. Conda安装Pytorch 以及环境配置(第一集、第二集)
  2. Pycharm和Jupyter的安装配置(第三集、第四集、第五集)
  3. 实现Dataset类来自定义数据集(第六集)
  4. 使用add_scalar()和add_image()将数据和图片添加到tensorboard中进行可视化(第七集、第八集)
  5. 通过transforms将图片进行处理的多种方式(第九集、第十集、第十一集)
    1. 转为张量数据:totensor()
    2. 归一化:Normalize()
    3. 修改尺寸(Resize)
    4. 随机裁剪(RandomCrop)
    5. 打包的容器(Compose)
  6. 内置数据集(CIFAR10)以及数据加载器DataLoader(第十二集)
  7. 如何搭建神经网络以及卷积层Conv2d(第十三集)
  8. 最大池化层、非线性激活函数、全连接层(线性层)(第十四集、第十五集、第十六集)
  9. 损失函数、反向传播和优化器(第十七集、第十八集)
  10. VGG16模型的认识和学习、模型的保存与加载(第十九集)
  11. 最后对整个模型进行优化和完善(本集)

最后总结一下人工神经网络的实现步骤:

  1. 准备数据集和数据加载器
  2. 搭建人工神经网络
  3. 定义各种网络层并实现前向传播forward()对数据进行处理
  4. 实例化模型、损失函数和优化器
  5. 定义训练的轮数,然后再分别定义训练过程和测试过程
  6. 对代码进行优化,如:进行GPU加速、保存模型等
  7. 将需要的信息进行输出或者可视化(损失值、正确率等)

学海无涯,前路漫漫,以后学习新知识还会继续分享的,再见

http://www.dtcms.com/a/296145.html

相关文章:

  • 【STM32】FreeRTOS 任务的删除(三)
  • NX804NX810美光固态闪存NX815NX839
  • 人形机器人双足行走动力学:K-V模型其肌腱特性拟合中的应用
  • Baumer工业相机堡盟工业相机如何通过YoloV8深度学习模型通过YoloV8深度学习模型实现工人安全装备(安全帽、手套、马甲等)检测识别 (C#)
  • C++高效实现轨迹规划、自动泊车、RTS游戏、战术迂回包抄、空中轨迹、手术机器人、KD树
  • 408——数据结构(第二章 线性表)
  • IPSec VPN -- 野蛮模式
  • windows11新建文件夹重命名时总是出现加载界面卡死状态
  • javaweb面试
  • 数据结构实验-查找与排序算法
  • 游戏开发Unity/ ShaderLab学习路径
  • 【独立工具】小红书图片采集软件
  • ExoCode.ino - OpenExo
  • Lua(文件I/O)
  • Claude4、GPT4、Kimi K2、Gemini2.5、DeepSeek R1、Code Llama等2025主流AI编程大模型多维度对比分析报告
  • PHP 与 Vue.js 结合的前后端分离架构
  • 虚拟机导入导出ova文件
  • Nginx 运维实战:动静分离,加速静态资源访问!
  • vue3:十八、内容管理-搜索栏的完善
  • C++之Stack和Queue的常用函数+习题
  • 若依框架在 IDEA 中运行的前置软件环境配置指南
  • XORM完全指南:Go语言数据库操作从入门到进阶
  • DS18B20扩展:在数码管上显示温度时包含小数部分
  • 黑马点评系列问题之p44实战篇商户查询缓存 jmeter如何整
  • 【基础】go基础学习笔记
  • OpenCV —— 绘制图形
  • 实验研究 | VR虚拟现实环境中植物景观偏好与生理恢复性效益研究
  • linux端 RAGflow超详细小白教程(一)安装及环境搭建
  • Linux系统编程——网络
  • 河南萌新联赛2025第(二)场:河南农业大学(整除分块,二进制,树的搜索)