思路步骤:
第一步准备数据集:(训练集,测试集)
import torchvision
Train_dataset = torchvision.datasets.CIFAR10("./data",True,transform=torchvision.transforms.ToTensor())
Test_Dataset =torchvision.datasets.CIFAR10("./data",False,transform=torchvision.transforms.ToTensor())
transform=torchvision.transforms.ToTensor() 将数据集图片转换为Tensor数据类型
第二步查询数据集长度:(len)
###第二步查询数据集长度
Train_length = len(Train_dataset)
Test_length = len(Test_Dataset)
print(f"训练集长度为{Train_length}")
print((f"测试集长度为{Test_length}"))
第三步加载数据集(DataLoader)
##第三步加载数据集
Train_load = DataLoader(Train_dataset,64,True)
Test_load = DataLoader(Test_Dataset,64,True)
第四步搭建神经网络,将神经网络放入单独的一个python文件中,测试网络正确性
class Tudui(nn.Module):
nn.Module
是所有神经网络模块的基类,用于创建自定义网络。
通过继承nn.Module,模型可以使用PyTorch提供的各种功能和方法,如参数管理、设备移动等。
遵循这种结构的模型可以轻松地与PyTorch的其他组件(如优化器、损失函数等)集成
class Tudui(nn.Module):
def __init__(self):
super(Tudui,self).__init__()
super()
主要用于调用父类(超类)的方法。
nn.Conv2d(3,32,padding=2,stride=1)
输入通道为3,输出通道为32,高宽不变padding = [(卷积核数-1 )/2]
对应神经网络部分:
self.model = nn.Sequential(
nn.Conv2d(3,32,padding=2,stride=1,kernel_size=5),
nn.MaxPool2d(2),
nn.Conv2d(32,32,padding=2,stride=1,kernel_size=5),
nn.MaxPool2d(2),
nn.Conv2d(32,64,padding=2,stride=1,kernel_size=5),
nn.MaxPool2d(2),
nn.Flatten(),
nn.Linear(64*4*4,64),
nn.Linear(64,10),
)
具体搞清楚python中 self.model写法 不能用self 直接替代的原因
###第四步搭建神经网络
class Tudui(nn.Module):
def __init__(self):
super(Tudui,self).__init__()
self.model = nn.Sequential(
nn.Conv2d(3,32,padding=2,stride=1,kernel_size=5),
nn.MaxPool2d(2),
nn.Conv2d(32,32,padding=2,stride=1,kernel_size=5),
nn.MaxPool2d(2),
nn.Conv2d(32,64,padding=2,stride=1,kernel_size=5),
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 = torch.ones(64,3,32,32)
创建一个四维张量,表示一批图像数据 ,参数batch_size,channels,H,W
if __name__ == '__main__':
tudui = Tudui()
input = torch.ones(64,3,32,32)
output = tudui(input)
print(output.shape)
结果:
第五步创建网络模型
###创建网络模型 tudui = Tudui()
第六步创建损失函数:
loss_fn = nn.CrossEntropyLoss()
第七步创建优化器:
##创建优化器
learning_rate =0.01
optimize = torch.optim.SGD(tudui.parameters(),lr=learning_rate)
第八步设置训练参数,开始训练:
起始参数设置:
train_step = 0###起始训练次数
test_step = 0###起始测试次数
epoch = 10 ####训练十轮
训练开始 :从train_load读取训练集
for data in Train_load:####训练开始
imgs,targets = data
将图片输入至模型中得到输出 ,并利用损失函数计算Loss
output = tudui(imgs)
loss = loss_fn(output,targets)
优化器梯度清零:
-
防止梯度累积:
- PyTorch 默认累积梯度。不清理会导致梯度在多个批次间累加。
-
确保每批次独立:
每个批次的梯度应该只反映当前批次的计算结果。
optimize.zero_grad()
loss.backward()
optimize.step()
train_step+=1
print(f"训练次数为{train_step},loss值{loss}")
测试开始:从test_load读取测试集
test_loss = 0
with torch.no_grad():
for data in Test_load:
imgs,targets = data
outputs = tudui(imgs)
loss = loss_fn(outputs,targets)
test_loss = test_loss+loss
print(f"整体测试集上的loss为{test_loss}")
注意写法 test_loss是普通数据类型,而loss为tensor数据类型,loss.item()
返回一个Python标量(如float),而不是PyTorch张量.
test_loss = test_loss+loss.item()
添加Tensorboard:
生成日志路径:
writer =SummaryWriter("./logs_train")
在训练集后添加相关数据
writer.add_scalar("训练loss",loss,train_step)
在测试集添加相关数据
writer.add_scalar("测试loss", test_loss, test_step)
训练集50000 测试集10000。每一个epoch,batch_size= 64 ,需要训练781次
生成模型的保存:
torch.save(tudui.state_dict(), f"tudui_model_epoch_{i + 1}.pth")
print(f"第{i + 1}轮模型已保存到 tudui_model_epoch_{i + 1}.pth")
argmax()的使用 :
import torch
outputs =torch.tensor([[0.1,0.2],
[0.5,0.3]])
print(outputs.argmax(1))
print(outputs.argmax(0))
argmax(1)
返回每行的最大值索引。argmax(0)
返回每列的最大值索引。
计算预测值与目标值相等的个数
outputs =torch.tensor([[0.1,0.2], [0.5,0.3]])
preds = outputs.argmax(1)
targets = torch.tensor([1,0])##[0,1],[1,1],[1,0]
print((preds==targets).sum())
输出个数为2
通过argmax()进行代码优化 计算出整体ACC(正确率) :
accuracy =((outputs.argmax(1) == targets).sum())
outputs.argmax(1)
找出每个样本预测概率最高的类别。(outputs.argmax(1) == targets)
比较预测类别和真实标签,得到一个布尔张量。.sum()
计算这个布尔张量的总和,即正确预测的数量。total_accuracy = total_accuracy + accuracy
累加每个批次的正确预测数。-
最后,用
total_accuracy / Test_length
计算整体准确率。
tudui.train() 和tudui.eval()作用解析
tudui.train()在训练部分:
tudui.train(true) 这只对某些模块有影响。如果它们受到影响,请参阅特定模块的文档,了解它们在培训/评估模式下的行为细节,例如Dropout、BatchNorm等。
tudui.eval()在测试部分同理
使用GPU训练:
GPU训练 只需要在原始CPU代码中 对:网络模型,数据(输入,标注),损失函数调用cuda
就可以使用CPU训练
问题:网络模型和损失函数调用cuda 不需要赋值回去
而数据需要赋值回去
imgs = imgs.cuda()
targets = targets.cuda()
优化写法一:GPU 与CPU 可以同时运行
if torch.cuda.is_available():
loss_fn.cuda()
优化写法二:定义训练的设备
device = torch.device("cuda")
imgs = imgs.to(device)
targets = targets.to(device)
优化写法:
device = torch.device("cuda"if torch.cuda.is_available()else"cpu")
GPU训练测试代码:
###第一步
import torch
import torchvision
from torch import nn
from torch.utils.tensorboard import SummaryWriter
from model import *
from torch.utils.data import DataLoader
writer =SummaryWriter("./logs_train")
Train_dataset = torchvision.datasets.CIFAR10("./data",True,transform=torchvision.transforms.ToTensor(),download=True)
Test_Dataset =torchvision.datasets.CIFAR10("./data",False,transform=torchvision.transforms.ToTensor(),download=True)
###定义训练的设备
device = torch.device("cuda"if torch.cuda.is_available()else"cpu")
###第二步查询数据集长度
Train_length = len(Train_dataset)
Test_length = len(Test_Dataset)
print(f"训练集长度为{Train_length}")
print((f"测试集长度为{Test_length}"))
##第三步加载数据集
Train_load = DataLoader(Train_dataset,64,True)
Test_load = DataLoader(Test_Dataset,64,True)
###第四步已保存
###创建网络模型
class Tudui(nn.Module):
def __init__(self):
super(Tudui,self).__init__()
self.model = nn.Sequential(
nn.Conv2d(3,32,padding=2,stride=1,kernel_size=5),
nn.MaxPool2d(2),
nn.Conv2d(32,32,padding=2,stride=1,kernel_size=5),
nn.MaxPool2d(2),
nn.Conv2d(32,64,padding=2,stride=1,kernel_size=5),
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
tudui = Tudui()
tudui.to(device)
###创建损失函数
loss_fn = nn.CrossEntropyLoss()
loss_fn.to(device)
##创建优化器
learning_rate =0.01
optimize = torch.optim.SGD(tudui.parameters(),lr=learning_rate)
###设置参数
train_step = 0###起始训练次数
test_step = 0###起始测试次数
epoch = 30 ####训练十轮
for i in range(epoch):
print(f"-------目前是第{i+1}轮训练-----------")
for data in Train_load:####训练开始
imgs,targets = data
imgs = imgs.to(device)
targets = targets.to(device)
outputs = tudui(imgs)
loss = loss_fn(outputs,targets)
###优化器优化模型
optimize.zero_grad()
loss.backward()
optimize.step()
train_step+=1
if train_step%100 ==0:
print(f"训练次数为{train_step},loss值{loss}")
writer.add_scalar("训练loss",loss,train_step)
####测试步骤
total_accuracy = 0 ###整体准确率为0
test_loss = 0
with torch.no_grad():
for data in Test_load:
imgs,targets = data
imgs = imgs.to(device)
targets = targets.to(device)
outputs = tudui(imgs)
loss = loss_fn(outputs,targets)
test_loss = test_loss+loss.item()
accuracy =((outputs.argmax(1) == targets).sum())
total_accuracy = total_accuracy+accuracy
print(f"整体测试集上的loss为{test_loss}")
print((f"整体测试集上的准确率为{total_accuracy/Test_length}"))
writer.add_scalar("测试loss", test_loss, test_step)
test_step+=1
###模型保存
torch.save(tudui, f"tudui_model_epoch_{i + 1}.pth")
print(f"第{i + 1}轮模型已保存到 tudui_model_epoch_{i + 1}.pth")
writer.close()
利用训练的好的模型进行验证:
import torch
import torchvision
from PIL import Image
from torch import nn
###定义训练的设备
device = torch.device("cuda"if torch.cuda.is_available()else"cpu")
print(f"当前使用设备为: {device}")
image_path = "./imgs/horse.jpg."
image = Image.open(image_path)
print(image)
image =image.convert('RGB')
transform = torchvision.transforms.Compose([torchvision.transforms.Resize((32,32)),
torchvision.transforms.ToTensor()])
image = transform(image)
print(image.shape)
class Tudui(nn.Module):
def __init__(self):
super(Tudui,self).__init__()
self.model = nn.Sequential(
nn.Conv2d(3,32,padding=2,stride=1,kernel_size=5),
nn.MaxPool2d(2),
nn.Conv2d(32,32,padding=2,stride=1,kernel_size=5),
nn.MaxPool2d(2),
nn.Conv2d(32,64,padding=2,stride=1,kernel_size=5),
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
model = torch.load("tudui_model_epoch_10.pth")
model = model.to(device)
image = image.to(device)
print(model)
image = torch.reshape(image,(1,3,32,32))
model.eval()
with torch.no_grad():
output = model(image)
print(output)
print(output.argmax(1))
验证成功为一匹马:
要注意输入图片与训练好的模型 在CPU与GPU上的部署,及时调整代码