1.训练集和测试集引入
# 训练集和测试集引入
train_data = torchvision.datasets.CIFAR10(root = "E:\\PyCharm_Project\\Pytorch_2.3.1\\ALL_Datasets\\CIFAR10" , train = True , transform = torchvision.transforms.ToTensor() , download = True)
test_data = torchvision.datasets.CIFAR10(root = "E:\\PyCharm_Project\\Pytorch_2.3.1\\ALL_Datasets\\CIFAR10" , train = False , transform = torchvision.transforms.ToTensor() , download = True)
# 打印测试集长度
print("训练集长度为{}".format(len(train_data)))
print("训练集长度为{}".format(len(test_data)))
2.DataLoader
# dataloader
dataloader = DataLoader(dataset = train_data , batch_size = 64 , shuffle = False)
dataloader_test = DataLoader(dataset = test_data , batch_size = 64 , shuffle = False)
3.定义损失函数
# loss
loss = nn.CrossEntropyLoss()
4.优化器
# adam,可以自适应,无需加入lr
learning_rate = 1e-3
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
5.设置记录参数和tensorboard
# 记录数据
total_train_step = 0
total_test_step = 0
# 训练轮数
epoch = 10
# 可视化tensorboard
writer = SummaryWriter('./logs')
6.将模型单独写在一个文件里
import torch
from torch import nn
class Zilliax(nn.Module):
def __init__(self):
super(Zilliax,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
model = Zilliax()
# main里面的内容只会在当前文件运行时进入运行
if __name__ == '__main__':
print(model)
test = torch.ones((64 ,3 , 32 , 32))
result = model(test)
print(result.shape)
7.训练测试并进行操作
for i in range(epoch):
print("第{}轮训练".format(i+1))
for data in dataloader:
imgs , labels = data
outputs = model(imgs)
loss_train = loss(outputs , labels)
optimizer.zero_grad()
loss_train.backward()
optimizer.step()
total_train_step += 1
# 加上.item()就不会打印出tensor(x),而是直接打印出x
if total_train_step % 100 == 0:
print("训练次数:{} , loss:{}".format(total_train_step,loss_train.item()))
writer.add_scalar('train_loss',loss_train.item(),total_train_step)
# 测试步骤
total_test_loss = 0
total_accuracy = 0
with torch.no_grad():
for data in dataloader_test:
imgs , labels = data
outputs = model(imgs)
loss_test = loss(outputs , labels)
total_test_loss += loss_test.item()
"""
# argmax():处理output里的tensor值,(1)代表横着数据一行为一组,(0)代表竖着数据一列为一组,输出每一组最大值的下标
outputs 的形状是 (64, 10),对应于一个批次的 64 张图像,每张图像都有 10 个类别的预测分数:
假设outputs = torch.tensor([
[1.2, -0.5, 3.0, 0.1, 2.3, -1.0, 0.7, 0.5, 1.1, -0.2], # 第1个图像
[0.3, 2.2, -0.4, 1.9, -0.3, 2.7, -1.1, 0.4, 0.2, 1.5], # 第2个图像
......其他62张图像
则在这个例子中,outputs 的第一行对应第一个图像:
模型预测它最有可能属于第三个类别(分数是 3.0),其次是第五个类别(分数是 2.3)。
argmax(1) 会选择最大值的索引,即 2,表示预测的类别是第3类。
类似地,outputs 的第二行对应第二个图像:
最大值是 2.7,对应第六个类别。
argmax(1) 会返回 5,表示预测的类别是第6类。
于是outputs.argmax(1)就会返回一个tensor([2,5,.......])
并与label[4,5........]进行对比,对不上为false,对的上为true
再用.sum()将所有的true = 1, false = 0相加,得到这一组64个图片的正确率
然后用total_acc加上存储,最终得到50000个01相加之和,除以50000
outputs 是 logits(未归一化的实数),而不是概率,
Logits 是模型最后一层的输出,它们表示模型对各类别的信心值。由于这些值未归一化,因此它们可以是正数、负数或零。
概率 是通过对 logits 进行归一化(通常使用 Softmax 函数)后得到的值。
Softmax 函数将 logits 转换为 [0, 1] 范围内的值,所有类别的概率之和为 1。
但是在计算准确率时,只关心模型认为哪个类别的得分(logit)最高。
具体地说,我们使用 argmax 函数找到 logit 值最大的那个类别,认为这是模型的预测。
在分类任务中,计算正确率时,只需找到得分最高的类别,无需关心这些得分是否经过归一化。
因此,直接使用 logits 计算准确率是常见且有效的方法。
"""
acc = (outputs.argmax(1) == labels).sum()
total_accuracy += acc
print("第{}轮测试的整体loss集为:{}".format(total_test_step,total_test_loss))
print("第{}轮测试的整体正确率为:{}".format(total_test_step,total_accuracy/len(test_data)))
writer.add_scalar('test_loss',total_test_loss,total_test_step)
writer.add_scalar('test_accuracy',total_accuracy/len(test_data),total_test_step)
total_test_step += 1
# 保存每一轮训练的模型
torch.save(model,"Zilliax_{}.pth".format(i))
print("save over")
writer.close()
整体代码和可视化结果
Model.py
import torch
from torch import nn
class Zilliax(nn.Module):
def __init__(self):
super(Zilliax,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
model = Zilliax()
if __name__ == '__main__':
print(model)
test = torch.ones((64 ,3 , 32 , 32))
result = model(test)
print(result.shape)
Train.py
import torch
import torchvision
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
from model import *
# 训练集和测试集引入
train_data = torchvision.datasets.CIFAR10(root = "E:\\PyCharm_Project\\Pytorch_2.3.1\\ALL_Datasets\\CIFAR10" , train = True , transform = torchvision.transforms.ToTensor() , download = True)
test_data = torchvision.datasets.CIFAR10(root = "E:\\PyCharm_Project\\Pytorch_2.3.1\\ALL_Datasets\\CIFAR10" , train = False , transform = torchvision.transforms.ToTensor() , download = True)
# 打印测试集长度
print("训练集长度为{}".format(len(train_data)))
print("训练集长度为{}".format(len(test_data)))
# dataloader
dataloader = DataLoader(dataset = train_data , batch_size = 64 , shuffle = False)
dataloader_test = DataLoader(dataset = test_data , batch_size = 64 , shuffle = False)
# loss
loss = nn.CrossEntropyLoss()
# adam,可以自适应,无需加入lr
learning_rate = 1e-3
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
# 记录数据
total_train_step = 0
total_test_step = 0
# 训练轮数
epoch = 10
# 可视化tensorboard
writer = SummaryWriter('./logs')
for i in range(epoch):
print("第{}轮训练".format(i+1))
for data in dataloader:
imgs , labels = data
outputs = model(imgs)
loss_train = loss(outputs , labels)
optimizer.zero_grad()
loss_train.backward()
optimizer.step()
total_train_step += 1
# 加上.item()就不会打印出tensor(x),而是直接打印出x
if total_train_step % 100 == 0:
print("训练次数:{} , loss:{}".format(total_train_step,loss_train.item()))
writer.add_scalar('train_loss',loss_train.item(),total_train_step)
# 测试步骤
total_test_loss = 0
total_accuracy = 0
with torch.no_grad():
for data in dataloader_test:
imgs , labels = data
outputs = model(imgs)
loss_test = loss(outputs , labels)
total_test_loss += loss_test.item()
"""
# argmax():处理output里的tensor值,(1)代表横着数据一行为一组,(0)代表竖着数据一列为一组,输出每一组最大值的下标
outputs 的形状是 (64, 10),对应于一个批次的 64 张图像,每张图像都有 10 个类别的预测分数:
假设outputs = torch.tensor([
[1.2, -0.5, 3.0, 0.1, 2.3, -1.0, 0.7, 0.5, 1.1, -0.2], # 第1个图像
[0.3, 2.2, -0.4, 1.9, -0.3, 2.7, -1.1, 0.4, 0.2, 1.5], # 第2个图像
......其他62张图像
则在这个例子中,outputs 的第一行对应第一个图像:
模型预测它最有可能属于第三个类别(分数是 3.0),其次是第五个类别(分数是 2.3)。
argmax(1) 会选择最大值的索引,即 2,表示预测的类别是第3类。
类似地,outputs 的第二行对应第二个图像:
最大值是 2.7,对应第六个类别。
argmax(1) 会返回 5,表示预测的类别是第6类。
于是outputs.argmax(1)就会返回一个tensor([2,5,.......])
并与label[4,5........]进行对比,对不上为false,对的上为true
再用.sum()将所有的true = 1, false = 0相加,得到这一组64个图片的正确率
然后用total_acc加上存储,最终得到50000个01相加之和,除以50000
outputs 是 logits(未归一化的实数),而不是概率,
Logits 是模型最后一层的输出,它们表示模型对各类别的信心值。由于这些值未归一化,因此它们可以是正数、负数或零。
概率 是通过对 logits 进行归一化(通常使用 Softmax 函数)后得到的值。
Softmax 函数将 logits 转换为 [0, 1] 范围内的值,所有类别的概率之和为 1。
但是在计算准确率时,只关心模型认为哪个类别的得分(logit)最高。
具体地说,我们使用 argmax 函数找到 logit 值最大的那个类别,认为这是模型的预测。
在分类任务中,计算正确率时,只需找到得分最高的类别,无需关心这些得分是否经过归一化。
因此,直接使用 logits 计算准确率是常见且有效的方法。
"""
acc = (outputs.argmax(1) == labels).sum()
total_accuracy += acc
print("第{}轮测试的整体loss集为:{}".format(total_test_step,total_test_loss))
print("第{}轮测试的整体正确率为:{}".format(total_test_step,total_accuracy/len(test_data)))
writer.add_scalar('test_loss',total_test_loss,total_test_step)
writer.add_scalar('test_accuracy',total_accuracy/len(test_data),total_test_step)
total_test_step += 1
# 保存每一轮训练的模型
torch.save(model,"Zilliax_{}.pth".format(i))
print("save over")
writer.close()