当前位置: 首页 > 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.lryc.cn/news/598483.html

相关文章:

  • 大疆无人机炸机后视频损坏的完美修复案例解析
  • C语言:详解文件操作
  • 双紫擒龙紫紫红黄安装使用攻略,2025通达信指标源码,擒龙追踪源码公式学习
  • 树莓派5与Zero 2 W全面解析:选型指南与入门攻略
  • IPv6网络优化
  • DeepSpeed-FastGen:通过 MII 和 DeepSpeed-Inference 实现大语言模型的高吞吐文本生成
  • Docker 打包Vue3项目镜像
  • 【数字IC验证学习------- SOC 验证 和 IP验证和形式验证的区别】
  • 旅行短视频模糊的常见原因及应对方法
  • C++常见面试题/笔试收录(一)
  • [202103][Docker 实战][第2版][耿苏宁][译]
  • Vue 3 项目性能优化指南
  • TCP 套接字--服务器相关
  • MCU(微控制器)中的高电平与低电平?
  • 使用 Vue 实现移动端视频录制与自动截图功能
  • 每日算法刷题Day52:7.24:leetcode 栈5道题,用时1h35min
  • linux权限续
  • 【从0开始学习Java | 第3篇】阶段综合练习 - 五子棋制作
  • 奇异值分解(Singular Value Decomposition, SVD)
  • 光通信从入门到精通:PDH→DWDM→OTN 的超详细演进笔记
  • day62-可观测性建设-全链路监控zabbix+grafana
  • 深度分析Java内存结构
  • 排序查找算法,Map集合,集合的嵌套,Collections工具类
  • SSM之表现层数据封装-统一响应格式全局异常处理
  • Spring AI 系列之二十四 - ModerationModel
  • 从0到1学习c++ 命名空间
  • 【Linux】linux基础开发工具(一) 软件包管理器yum、编辑器vim使用与相关命令
  • 【YOLOv8改进 - 特征融合】FCM:特征互补映射模块 ,通过融合丰富语义信息与精确空间位置信息,增强深度网络中小目标特征匹配能力
  • Springboot儿童医院问诊导诊系统aqy75(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
  • 免费生成文献综述的网站推荐,助力高效学术写作