小土堆pytorch学习—P27👉P29-完整的模型训练套路
CIFAR数据集原始数据为PIL数据类型,在使用该数据集时,需要对其转换。
案例👇train.py
#引入模型
from model import *
#准备训练数据集
train_data = torchvision.datasets.CIFAR10(root = "../data", train = True ,transform = torchvision.transforms.ToTensor(), download = True )
#准备测试数据集
test_data = torchvision.datasets.CIFAR10(root = "../data" , train = False , transform = torchvision.transforms.ToTensor() , download = True )
#如果想要训练数据集有多少张图片,测试数据集有多少张图片,下面代码可以做到👇
train_data_length = len(train_data)
test_data_length = len(test_data)
#该写法于python中较为常见
print("训练数据集的长度为:{}".format(train_data_length))
print("测试数据集的长度为:{}".format(test_data_length))
#利用DataLoader加载数据集
train_dataloader = DataLoader(train_data , batch_size = 64)
test_dataloader = DataLoader(test_data , batch_size = 64)
#创建网络模型
tudui = Tudui()
#创建损失函数
#因为这个是分类问题,所以可以用交叉熵,参数暂时用不到
loss_fn = nn.CrossEntropyLoss()
#定义优化器,用随机梯度下降,parameters一定要填,学习速率也要填。
learning_rate = 1e-2#方便提取
optimizer = torch.optim.SGD(tudui.parameters() , lr =learning_rate)
#1e-2 = 0.01
#设置训练网络的一些参数
#记录训练的次数
total_train_step = 0
#记录测试的次数
total_test_step = 0
#训练的轮数
epoch = 10
for i in range(epoch):
print("--------第{}轮训练开始--------".format(i+1))
#训练步骤开始
for data in train_dataloader:
imgs , targets = data
#分别取得训练数据,并放入网络当中
outputs = tudui(imgs)
#这个输出结果是每一张图片对应的实际标签。而outputs是训练之后10分类对应的标签得分
#得到输出之后,要放入损失函数中,看与targets相差多少
loss = loss_fn(outputs , targets)
#优化器优化模型
#进行优化,要记住利用优化器对梯度清0
optimizer.zero_grad()
#清零之后,可以用损失所得值进行反向传播,得到每个参数之间的梯度
loss.backward()
#调用该方法,就可以对其中参数进行优化
optimizer.step()
#因为已经做了一次优化,所以可以对优化次数加1
total_train_step = total_train_step + 1
#这里的训练次数说的是对于数据集中所有的数据进行一次训练,所以每个损失都不一样。
print("训练次数:{} , loss:{}".format(total_train_step , loss.item()))
targets👇

一个batch_size =64,所以会有64个targets。
outputs👇

一张图片有可能被分为10类别中的一种,所以对应得分是10个。
为了规范,常把神经网络模型放入单独文件夹中,此时案例文件为model.py,代码如下👇
#搭建神经网络,因为CIFAR是10分类的数据集,所以该网络应该是10分类网络
class Tudui(nn.Module):
def __init__(self):
super(Tudui, self).__init__()
self.model = nn.Sequential(
nn.Conv2d(3, 32 , 5, 1, 2),
nn.MaxPool2d(2 ),
nn.Conv2d(32 , 32 , 5 ,1 2),
nn.MaxPool2d(2),
nn.Conv2d(32,64,5 , 1, 2),
nn.MaxPool2d(2),
nn.Flatten(),
nn.Linear(64*4*4,64),
nn.linear(64, 10)
)
def forward(self , x ):
x = self.model(x)
return x
#测试网络的正确性,一般是给定一个输入尺寸,输出尺寸是不是想要的,此时创建为input
if __name__ == '__main__':
tudui = Tudui()
input = torch.ones((batch_size = 64, channel = 3 , 32 , 32))
output = input(tudui)
print(output.shape)
但一定要注意,这两个文件要在同一文件夹下。
import torch
a = torch.tensor(5)
print(a)
print(a.item())
#如果只是打印a,那就会出现tensor(5)
#加上item(),则会转换为真是的数字5
训练步骤写完,但此时出现一个问题,怎么知道自己的模型有没有训练好?达到期望的需求?所以每一轮训练之后,会进行一个测试。让它再在测试数据集上跑一遍,以测试数据集的损失/正确率来评估模型有没有训练好。注意,在测试过程中,不需要对模型进行调优,因为想要利用现有的模型进行测试。
测试步骤代码及注释如下👇
#准备训练数据集
train_data = torchvision.datasets.CIFAR10(root = "../data", train = True ,transform = torchvision.transforms.ToTensor(), download = True )
#准备测试数据集
test_data = torchvision.datasets.CIFAR10(root = "../data" , train = False , transform = torchvision.transforms.ToTensor() , download = True )
#如果想要训练数据集有多少张图片,测试数据集有多少张图片,下面代码可以做到👇
train_data_length = len(train_data)
test_data_length = len(test_data)
#该写法于python中较为常见
print("训练数据集的长度为:{}".format(train_data_length))
print("测试数据集的长度为:{}".format(test_data_length))
#利用DataLoader加载数据集
train_dataloader = DataLoader(train_data , batch_size = 64)
test_dataloader = DataLoader(test_data , batch_size = 64)
#创建网络模型
tudui = Tudui()
#创建损失函数
#因为这个是分类问题,所以可以用交叉商,参数暂时用不到
loss_fn = nn.CrossEntropyLoss()
#定义优化器,用随机梯度下降,parameters一定要填,学习速率也要填。
learning_rate = 1e-2#方便提取
optimizer = torch.optim.SGD(tudui.parameters() , lr =learning_rate)
#1e-2 = 0.01
#设置训练网络的一些参数
#记录训练的次数
total_train_step = 0
#记录测试的次数
total_test_step = 0
#训练的轮数
epoch = 10
#添加tensorboard
writer = SummaryWriter("tb_logs")
for i in range(epoch):
print("--------第{}轮训练开始--------".format(i+1))
#训练步骤开始
for data in train_dataloader:
imgs , targets = data
#分别取得训练数据,并放入网络当中
outputs = tudui(imgs)
#得到输出之后,要放入损失函数中,看与targets相差多少
loss = loss_fn(outputs , targets)
#优化器优化模型
#进行优化,要记住利用优化器对梯度清0
optimizer.zero_grad()
#清零之后,可以用损失所得值进行反向传播,得到每个参数之间的梯度
loss.backward()
#调用该方法,就可以对其中参数进行优化
optimizer.step()
#因为已经做了一次优化,所以可以对优化次数加1
total_train_step + = 1
if total_train_step % 100 = 0 :
print("训练次数:{} , loss:{}".format(total_train_step , loss.item()))
#更方便查看训练次数
#可以把每一次的训练记录下来,逢百记录
writer.add_scalar("train_loss" , loss.item() , total_train_step )
#
total_test_loss = 0
#从名字看出来with里面的代码,没有梯度,这样就不能对其进行调优。
#测试步骤开始,for以及with属同一级。
total_accuracy = 0 #整体正确的个数
with torch.no_grad():
#从测试的dataloader中取测试的数据集
for data in test_dataloader:
#
imgs , targets = data
#把测试数据集中的数据放入网络中,得到一个输出
outputs = tudui(imgs)
#比较输出与真实的targets之间的误差
loss = loss_fn(outputs , targets)
#一般是在测试过程中看网络模型在整体数据集上的误差/正确率
#现在的loss只是一部分数据在网络模型上的损失,但目的是求整个数据集上的loss
total_test_loss = total_test_loss + loss
#这部分运行结束,就相当于把所有的损失加到一块
#添加每次一小部分数据,正确的个数有多少。就等于outputs最大的有多少,方向是横向的,所以是1,
#又要与真实的targets进行相比,得出true,false等于多少,接下来再求和。
accuracy = (outputs.argmax(1) == targets).sum()
#把每次求出来的正确的个数加到总的上面
total_accuracy = accuracy + total_accuracy
print("整体测试集上的Loss:{}".format(total_test_loss))
#正确率=总共预测对的个数,除以总共数据集上的个数
print("整体测试集上的正确率total_accuracy:{}".format(total_accuracy/test_data_length))
writer.add_scalar(tag = "test_loss" , scalar_value = total_test_loss ,global_step = total_test_step )
writer.add_scalar("test_accuracy" , scalar_value = total_accuracy/test_data_length , total_test_step)
total_test_step = total_test_step +1
#global_step 就是之前记录测试的次数,测试次数要+1
torch.save(tudui , "tudui_{}.pth".format(i))
print("模型已保存")
所以在此的一个问题是为什么它训练的数量是782个一轮?
训练集大小为50000,batch_size = 64,则50000/64 = 781.25,总共有781个含64个数据的集合,以及一个含16个数据的集合,合成782次训练。
如果想要保存每一轮训练的数据,那么应该加上一点东西。在最后的几行。
解决二分类问题
outputs = [0.1 , 0.2]
[0.3 , 0.4]
按照下标来标注,每个概率大的都是[1]。输出为:preds = [1]\n[1],找到的都是其位置(下标)。
inputs targets = [0] [1]
接着对照👉preds == inputs targets ,这里对照的都是它们的位置。inputs targets的0位置,并不是概率最大的,所以为0,对应的后者为1。
[false , true].sum() = 1 相加过程中会把前者为0,后者为1。通过“ = = ”知道两者是否相等,接着对比preds 和inputs targets 相应的元素相等有多少,再除以总个数,可算出正确率。一横零纵。
print('='*100)
print(F"outputs = {outputs}")
print(F"outputs.argmax(1) = {outputs.argmax(1)}")
#outputs是一个矩阵,每一行代表一个数据,每一列代表一个数据对应10个类别的得分
#argmax,参数为1时,计算每一行/每一个数据得分最高的数值在该行的索引值
#argmax,参数为0时,计算每一列/每个类别得分最高的数值的索引
print(F"outputs.argmax(0) = {outputs.argmax(0)}")
print("="*100)

细节
大多数训练模型在训练步骤开始时,会把网络模型设置为train,或者是在测试网络之前设置网络模型为eval(),这并不是说把网络设置为训练模式才能够开始训练,把网络设置为eval状态才开始测试。而是有一些层必须这样做。(神经网络都是继承Module)网站:https://pytorch.org/docs/stable/generated/torch.nn.Module.html#torch.nn.Module
可以看到它只对一部分的网络层有作用,比如说Dropout, BatchNorm。
同样,eval()层也只对特定层有作用。
捋一遍思路👇
首先准备数据集,准备对应的DataLoader,接着创建网络模型、损失函数、优化器,设置训练中的一些参数,接着设置训练中的轮数,以便能够进行多次训练。接着到55行进入训练的状态,不断从train_dataloader 中取数据,放入网络模型中,计算损失函数,放入优化器中,采用特定方式,展示输出。
特定步数之后,做测试,可以设置eval(),但是一定要设置with torch.no_grad(),让网络模型中的梯度都没有,不需要对梯度测试,也不需要优化。计算误差,构建特殊指标显示出来。最后可以在特定的步数保存模型。

浙公网安备 33010602011771号