一个完整的模型
不可能将数据一次性送入神经网络,一次送入batch_size。 将训练集和测试集的数据取完,一个epoch结束。 外层循环走一次,取50000张图片。内层循环走一次,取batch_size(100)张图片,内层循环共走50000/100=500次。所以一次epoch训练500次,一次训练batch_size100张图片(一次训练100张图片)。测试:
import torch
import torchvision
from torch import nn
from torch.utils.data import DataLoader
import time
from b_nn.P14_model import *
from torchvision.datasets import CIFAR10
'''1准备数据集'''
train_data=torchvision.datasets.CIFAR10("./dataset_CIFAR10",train=True,
transform=torchvision.transforms.ToTensor(),
download=True)
test_data=torchvision.datasets.CIFAR10("./dataset_CIFAR10",train=False,
transform=torchvision.transforms.ToTensor(),
download=True)
'''查看数据集的长度'''
train_data_size=len(train_data)
test_data_size=len(test_data)
print("训练数据集的长度:{}".format(train_data_size))
print("测试数据集的长度:{}".format(test_data_size))
'''2利用dataloader加载数据集'''
train_dataloader=DataLoader(train_data,batch_size=100)
test_dataloader=DataLoader(test_data,batch_size=100)
'''3创建网络模型'''
class CIFAR10(nn.Module):
def __init__(self) -> None:
super().__init__()
self.model=Sequential(
Conv2d(3,32,5,1,2,1),
MaxPool2d(2,),
Conv2d(32,32,5,1,2),
MaxPool2d(2,),
Conv2d(32,64,5,1,2,),
MaxPool2d(2,),
Flatten(),
Linear(64*4*4,64),
Linear(64,10)
)
def forward(self,x):
x=self.model(x)
return x
cifar10=CIFAR10()
'''4创建损失函数'''
loss_fn=nn.CrossEntropyLoss()
'''5优化器'''
learning_rate=1e-4#学习率1*10的-4次方
optimizer=torch.optim.SGD(cifar10.parameters(),learning_rate,)
'''6设置训练啊网络的一些参数'''
total_train_step=0#记录训练的次数
total_test_step=0#记录测试的次数
epoch=5#记录训练的轮数
start_time=time.time()
for i in range(epoch):
print("-----------------第{}轮训练开始:------------------".format(i))
'''训练步骤开始'''
cifar10.train()
batch_total_accuracy=0
train_total_loss=0
for data in train_dataloader:
imgs,targets=data #取数据
outputs=cifar10(imgs) #送入神经网络模型
loss=loss_fn(outputs,targets) #计算误差
'''训练一次:优化器优化模型'''
optimizer.zero_grad()#梯度清零
loss.backward()#反向传播 自动计算所有梯度
optimizer.step()#对参数进行优化
total_train_step=total_train_step+1
train_accuracy = (outputs.argmax(1) == targets).sum()
if total_train_step % 100==0:
print("训练集上这100个batch_size准确率:{}".format(train_accuracy / 100))
batch_total_accuracy=batch_total_accuracy+train_accuracy
if total_train_step % 100==0:
end_time = time.time()
print("训练时间:{}s".format(end_time - start_time))
print("在训练集上的训练次数:{},这100个batch_size上的loss:{}".format(total_train_step,loss.item()))#例如.item()可以把一个tensor数据类型转换成真实的数字
train_total_loss=train_total_loss+loss.item()
print("训练集上一个epoch的准确率:{}".format(batch_total_accuracy/train_data_size))
print("训练集上的总loss:{}".format(train_total_loss))
print('--------------------------------------------------------------------')
'''训练完一轮后,在测试数据集上进行测试,看是否需要终止训练'''
'''测试步骤'''
cifar10.eval()
total_test_loss=0
total_accuracy=0#整体正确的个数
#停止跟踪历史记录和使用内存,因为在评估阶段不需要梯度
with torch.no_grad():#没有梯度
for data in test_dataloader:
imgs,targets=data
outputs=cifar10(imgs)
loss=loss_fn(outputs,targets) #loss是一部分loss
total_test_loss=loss.item()+total_test_loss #整体loss
#指标
accuracy=(outputs.argmax(1)==targets).sum()#outputs.argmax(1)==targets 预测结果和标签值相同的求和
total_accuracy=total_accuracy+accuracy
print("整体测试集上的loss:{}".format(total_test_loss))
print("整体测试集上的正确率:{}".format(total_accuracy/test_data_size))
total_test_step=total_test_step+1
# '''保存模型'''
# torch.save(cifar10,"cifar_{}.pth".format(i)) #将每一轮训练的结果都保存一下
# print("模型已经保存")
结果:
问题:怎么计算正确率?
假如是一个二分类问题,利用argmax。概率最大的位置上返回0或1,target也设置为0,1。
多分类问题也可以使用argmax。将target设为0、1、2、3…
测试:
import torch
output=torch.tensor([
[0.1,0.2],
[0.05,0.4]
])
print(output.argmax(1)) #横向看,求出某一行的最大值对应的索引
print(output.argmax(0)) #纵向看,求出某一列的最大值对用的索引
preds=output.argmax(1)
targets=torch.tensor([0,1])
print(preds==targets)
print((preds==targets).sum())#相等的加起来
结果:
model.train()函数:
model.eval()函数:
训练阶段
- 准备数据集。并将其分为训练集和数据集。
- 利用dataloader加载训练集和测试集。dataloader将数据成批送入神经网络。
- 创建网络模型,可以直接写,也可以在另一个文件model.py写好,然后引用。
- 创建损失函数。
- 优化器:选择梯度下降法,使损失函数减少。
- 送入网络进行训练。将训练的模型保存下来。
- 用测试集进行测试。
model.py写网络模型
'''搭建神经网络:CIFAR10网络结构'''
import torch
from torch import nn
from torch.nn import Sequential, Conv2d, MaxPool2d, Flatten, Linear
class CIFAR10(nn.Module):
def __init__(self) -> None:
super().__init__()
self.model=Sequential(
Conv2d(3,32,5,1,2,1),
MaxPool2d(2,),
Conv2d(32,32,5,1,2),
MaxPool2d(2,),
Conv2d(32,64,5,1,2,),
MaxPool2d(2,),
Flatten(),
Linear(64*4*4,64),
Linear(64,10)
)
def forward(self,x):
x=self.model(x)
return x
if __name__ == '__main__':
cifar10=CIFAR10()
'''验证模型是否正确
给一个输入,看输出的结果
'''
input = torch.ones((64, 3, 32, 32))
output = cifar10(input)
print(output)
print(output.shape)
结果:
batch_size为64,一个图片有10个数字,分别是概率。
train.py进行训练,该文件直接把网络模型写进去了,推荐写外面,因为加载模型的时候,需要导入模型结构。
import torch
import torchvision
from torch import nn
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
import time
from model import *
from torchvision.datasets import CIFAR10
'''1准备数据集'''
train_data=torchvision.datasets.CIFAR10("./dataset_CIFAR10",train=True,
transform=torchvision.transforms.ToTensor(),
download=True)
test_data=torchvision.datasets.CIFAR10("./dataset_CIFAR10",train=False,
transform=torchvision.transforms.ToTensor(),
download=True)
'''查看数据集的长度'''
train_data_size=len(train_data)
test_data_size=len(test_data)
print("训练数据集的长度:{}".format(train_data_size))
print("测试数据集的长度:{}".format(test_data_size))
'''2利用dataloader加载数据集'''
train_dataloader=DataLoader(train_data,batch_size=100)
test_dataloader=DataLoader(test_data,batch_size=100)
'''3创建网络模型'''
class CIFAR10(nn.Module):
def __init__(self) -> None:
super().__init__()
self.model=Sequential(
Conv2d(3,32,5,1,2,1),
MaxPool2d(2,),
Conv2d(32,32,5,1,2),
MaxPool2d(2,),
Conv2d(32,64,5,1,2,),
MaxPool2d(2,),
Flatten(),
Linear(64*4*4,64),
Linear(64,10)
)
def forward(self,x):
x=self.model(x)
return x
cifar10=CIFAR10()
'''4创建损失函数'''
loss_fn=nn.CrossEntropyLoss()
'''5优化器'''
learning_rate=1e-4#学习率1*10的-4次方
optimizer=torch.optim.SGD(cifar10.parameters(),learning_rate,)
'''6设置训练啊网络的一些参数'''
total_train_step=0#记录训练的次数
total_test_step=0#记录测试的次数
epoch=5#记录训练的轮数
'''添加tensorboard'''
writer=SummaryWriter("../logs_train")
start_time=time.time()
for i in range(epoch):
print("-----------------第{}轮训练开始:------------------".format(i))
'''训练步骤开始'''
cifar10.train()
train_total_accuracy=0
for data in train_dataloader:
imgs,targets=data #取数据
outputs=cifar10(imgs) #送入神经网络模型
loss=loss_fn(outputs,targets) #计算误差
'''训练一次(取100张图):优化器优化模型'''
optimizer.zero_grad()#梯度清零
loss.backward()#反向传播 自动计算所有梯度
optimizer.step()#对参数进行优化
total_train_step=total_train_step+1
train_accuracy = (outputs.argmax(1) == targets).sum()
train_total_accuracy=train_total_accuracy+train_accuracy
if total_train_step % 100==0:
end_time = time.time()
print("训练时间:{}s".format(end_time - start_time))
print("---在训练集上的训练次数:{},训练一次的loss:{}---".format(total_train_step,loss.item()))#item()可以把一个tensor数据类型转换成真实的数字 tensor(5)=5
writer.add_scalar("训练集每训练100次的train_loss",loss.item(),total_train_step)
print("整体训练集上的准确率:{}".format(train_total_accuracy/train_data_size))
'''训练完一轮后,在测试数据集上进行测试,看是否需要终止训练'''
'''测试步骤'''
cifar10.eval()
total_test_loss=0
total_accuracy=0#整体正确的个数
#停止跟踪历史记录和使用内存,因为在评估阶段不需要梯度
with torch.no_grad():#没有梯度
for data in test_dataloader:
imgs,targets=data
outputs=cifar10(imgs)
loss=loss_fn(outputs,targets) #loss是一部分loss
total_test_loss=loss.item()+total_test_loss #整体loss
#指标
accuracy=(outputs.argmax(1)==targets).sum()#outputs.argmax(1)==targets 预测结果和标签值相同的求和
total_accuracy=total_accuracy+accuracy
print("整体测试集上的loss:{}".format(total_test_loss))
print("整体测试集上的正确率:{}".format(total_accuracy/test_data_size))
writer.add_scalar("整体测试集总test_loss",total_test_loss,total_test_step)
writer.add_scalar("整体测试集准确率test_acc",total_accuracy/test_data_size,total_test_step)
total_test_step=total_test_step+1
# '''保存模型'''
# torch.save(cifar10,"cifar_10{}.pth".format(i)) #将每一轮训练的结果都保存一下
# print("模型已经保存")
writer.close()
结果:
tensorboard里:
效果很犀利哈哈哈,因为网络太差了。。。。
使用resnet进行训练
目前为止写的最完善的一个网络
import torch
import torchvision
from torch import nn
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
'''1准备数据集'''
train_data = torchvision.datasets.CIFAR10("dataset_CIFAR10", train=True,
transform=torchvision.transforms.ToTensor(),
download=True)
test_data = torchvision.datasets.CIFAR10("dataset_CIFAR10", train=False,
transform=torchvision.transforms.ToTensor(),
download=True)
'''查看数据集的长度'''
train_data_size = len(train_data)
test_data_size = len(test_data)
print("训练数据集的长度:{}".format(train_data_size))
print("测试数据集的长度:{}".format(test_data_size))
'''2利用dataloader加载数据集'''
train_dataloader = DataLoader(train_data, batch_size=100,shuffle=True)
test_dataloader = DataLoader(test_data, batch_size=100,shuffle=True)
'''训练模型'''
resnet34=torchvision.models.resnet34(pretrained=True,progress=True)
resnet34.fc=nn.Sequential(
nn.Linear(resnet34.fc.in_features,resnet34.fc.out_features),
nn.ReLU(),
nn.Dropout(0.3),
nn.Linear(resnet34.fc.out_features,10)
)
resnet34.add_module("Softmax",nn.Softmax(dim=None))
resnet34=resnet34.cuda()
#print(resnet34)
'''4创建损失函数'''
loss_fn = nn.CrossEntropyLoss()
loss_fn=loss_fn.cuda()
'''5优化器'''
learning_rate = 1e-4 # 学习率
optimizer = torch.optim.Adam(resnet34.parameters(), learning_rate, )
'''6设置训练啊网络的一些参数'''
total_train_step = 0 # 记录训练的次数
total_test_step = 0 # 记录测试的次数
epoch = 30 # 记录训练的轮数
'''添加tensorboard'''
writer = SummaryWriter("../train_resnet34")
for i in range(epoch):
print("-----------------第{}轮训练开始:------------------".format(i))
'''训练步骤开始'''
resnet34.train()
total_train_loss=0
total_train_accuracy=0
for data in train_dataloader:
imgs, targets = data # 取数据
imgs=imgs.cuda()
targets=targets.cuda()
outputs = resnet34(imgs) # 送入神经网络模型
loss = loss_fn(outputs, targets) # 计算误差
'''训练一次:优化器优化模型'''
optimizer.zero_grad() # 梯度清零
loss.backward() # 反向传播
optimizer.step() # 对参数进行优化
total_train_step = total_train_step + 1
if total_train_step % 100 == 0:
print("在训练集上的训练次数:{},loss:{}".format(total_train_step, loss.item())) # 例如.item()可以把一个tensor数据类型转换成真实的数字
writer.add_scalar("训练集train_loss", loss.item(), total_train_step)
train_accuracy=(outputs.argmax(1)==targets).sum()
total_train_accuracy=total_train_accuracy+train_accuracy
total_train_loss=total_train_loss+loss.item()
print("整体训练集上的准确率:{}".format(total_train_accuracy/train_data_size))
print("整体训练集上的loss:{}".format(total_train_loss))
writer.add_scalar("训练集上的总loss",total_train_loss,total_train_step)
'''训练完一轮后,在测试数据集上进行测试,看是否需要终止训练'''
'''测试步骤'''
resnet34.eval()
total_test_loss = 0
total_accuracy = 0 # 整体正确的个数
with torch.no_grad(): # 没有梯度
for data in test_dataloader:
imgs, targets = data
imgs=imgs.cuda()
targets=targets.cuda()
outputs = resnet34(imgs)
loss = loss_fn(outputs, targets) # loss是一部分loss
total_test_loss = loss.item() + total_test_loss # 整体loss
# 指标
accuracy = (outputs.argmax(1) == targets).sum() # outputs.argmax(1)==targets 预测结果和标签值相同的求和
total_accuracy = total_accuracy + accuracy
print("整体测试集上的loss:{}".format(total_test_loss))
print("整体测试集上的正确率:{}".format(total_accuracy / test_data_size))
writer.add_scalar("整体测试集总test_loss", total_test_loss, total_test_step)
writer.add_scalar("test_acc", total_accuracy / test_data_size, total_test_step)
total_test_step = total_test_step + 1
'''保存模型'''
torch.save(resnet34, "resnet34_t_{}.pth".format(i)) # 将每一轮训练的结果都保存一下
print("模型已经保存")
writer.close()
在colab上进行训练:
结果:
在colab上使用tensoeboard:
结果:
训练集的loss不断下降,测试集的loss稳定上升,这个现象很常见,说明模型过拟合或者数据集分布不合理或训练集过小。不用太关注测试集的了loss,关注测试集的acc即可。
解决方式:
- 增加训练样本
- 增加正则项系数权重,减小过拟合
- 加入早停机制,ValLoss上升几个epoch直接停止
- 采用Focal Loss
- 加入Label Smoothing
添加GPU训练
两种训练方式
- .cuda()
#模型
cifar10 = CIFAR10()
cifar10=cifar10.cuda()
#损失函数
loss_fn = nn.CrossEntropyLoss()
loss_fn=loss_fn.cuda()
.cuda()提示的话就说明可以用。
推荐这种写法:
if torch.cuda.is_available():
cifar10=cifar10.cuda()
- device
#定义训练的设备
device=torch.device("cuda:0") #第一张显卡
cifar10 = CIFAR10()
cifar10=cifar10.to(device)
推荐写法:
device=torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
完整的模型验证(测试)套路
利用已经训练好的模型,然后给它提供输入。
- 在colab上训练网络,将效果最好的模型下载下来
- 将模型导入pycharm里,写测试文件
训练文件:
import torchvision
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
import time
from torch import nn
#定义训练的设备
#device=torch.device("cuda:0")
'''1准备数据集'''
train_data = torchvision.datasets.CIFAR10("dataset_CIFAR10", train=True,
transform=torchvision.transforms.ToTensor(),
download=True)
test_data = torchvision.datasets.CIFAR10("dataset_CIFAR10", train=False,
transform=torchvision.transforms.ToTensor(),
download=True)
'''查看数据集的长度'''
train_data_size = len(train_data)
test_data_size = len(test_data)
print("训练数据集的长度:{}".format(train_data_size))
print("测试数据集的长度:{}".format(test_data_size))
'''2利用dataloader加载数据集'''
train_dataloader = DataLoader(train_data, batch_size=64)
test_dataloader = DataLoader(test_data, batch_size=64)
'''3创建网络模型 vgg16_t'''
vgg16_t=torchvision.models.vgg16(pretrained=True,progress=True)
vgg16_t.classifier.add_module("7",nn.Linear(1000,10))
vgg16_t=vgg16_t.cuda()
'''4创建损失函数'''
loss_fn = nn.CrossEntropyLoss()
loss_fn=loss_fn.cuda()
'''5优化器'''
learning_rate = 1e-4 # 学习率
optimizer = torch.optim.Adam(vgg16_t.parameters(), learning_rate, )
'''6设置训练啊网络的一些参数'''
total_train_step = 0 # 记录训练的次数
total_test_step = 0 # 记录测试的次数
epoch = 30 # 记录训练的轮数
'''添加tensorboard'''
writer = SummaryWriter("../train_logs_vgg16")
start_time=time.time()
for i in range(epoch):
print("-----------------第{}轮训练开始:------------------".format(i + 1))
'''训练步骤开始'''
vgg16_t.train()
total_train_accuracy=0
for data in train_dataloader:
imgs, targets = data # 取数据
imgs=imgs.cuda()
targets=targets.cuda()
outputs = vgg16_t(imgs) # 送入神经网络模型
loss = loss_fn(outputs, targets) # 计算误差
'''训练一次:优化器优化模型'''
optimizer.zero_grad() # 梯度清零
loss.backward() # 反向传播
optimizer.step() # 对参数进行优化
total_train_step = total_train_step + 1
if total_train_step % 100 == 0:
end_time=time.time()
print("已经运行{}秒".format(end_time-start_time))
print("在训练集上的训练次数:{},loss:{}".format(total_train_step, loss.item())) # 例如.item()可以把一个tensor数据类型转换成真实的数字
writer.add_scalar("训练集train_loss", loss.item(), total_train_step)
train_accuracy=(outputs.argmax(1)==targets).sum()
total_train_accuracy=total_train_accuracy+train_accuracy
print("整体训练集上的准确率:{}".format(total_train_accuracy/train_data_size))
'''训练完一轮后,在测试数据集上进行测试,看是否需要终止训练'''
'''测试步骤'''
vgg16_t.eval()
total_test_loss = 0
total_accuracy = 0 # 整体正确的个数
with torch.no_grad(): # 没有梯度
for data in test_dataloader:
imgs, targets = data
imgs=imgs.cuda()
targets=targets.cuda()
outputs = vgg16_t(imgs)
loss = loss_fn(outputs, targets) # loss是一部分loss
total_test_loss = loss.item() + total_test_loss # 整体loss
# 指标
accuracy = (outputs.argmax(1) == targets).sum() # outputs.argmax(1)==targets 预测结果和标签值相同的求和
total_accuracy = total_accuracy + accuracy
print("整体测试集上的loss:{}".format(total_test_loss))
print("整体测试集上的正确率:{}".format(total_accuracy / test_data_size))
writer.add_scalar("整体测试集总test_loss", total_test_loss, total_test_step)
writer.add_scalar("test_acc", total_accuracy / test_data_size, total_test_step)
total_test_step = total_test_step + 1
'''保存模型'''
torch.save(vgg16_t, "vgg16_t_{}.pth".format(i)) # 将每一轮训练的结果都保存一下
print("模型已经保存")
writer.close()
结果:第24轮效果最好,将模型下载下来。
测试文件1:测试一张图片。
'''获取图片'''
img_path= "../img/img_3.png"
image=Image.open(img_path)
print(image)
image=image.convert('RGB') #PNG文件是4通道的,加上后保留三通道。
transform=torchvision.transforms.Compose([torchvision.transforms.Resize((224,224)),
torchvision.transforms.ToTensor()])
image=transform(image)
print(image.shape)
'''加载网络模型'''
model_vgg16_10=torch.load("vgg16_t_25.pth")
model_vgg16_10=model_vgg16_10.cuda()
print(model_vgg16_10)
#神经网络中训练的图片是四维的,在使用一张图片的时候不要忘了reshape,指定一个batch_size
image=torch.reshape(image,(1,3,224,224))
#注意:训练的时候使用gpu训练的,现在验证的时候要用gpu加速
image=image.cuda()
model_vgg16_10.eval()
with torch.no_grad():
output=model_vgg16_10(image)
print(output)
print(output.argmax(1))
结果:是飞机的概率最大,这张图确实也是飞机。
测试文件2:用保存的模型在训练集、测试集上测试一下。
import torch
import torchvision
from torch.utils.data import DataLoader
'''1准备数据集'''
train_data = torchvision.datasets.CIFAR10("dataset_CIFAR10", train=True,
transform=torchvision.transforms.ToTensor(),
download=True)
test_data = torchvision.datasets.CIFAR10("dataset_CIFAR10", train=False,
transform=torchvision.transforms.ToTensor(),
download=True)
'''查看数据集的长度'''
train_data_size = len(train_data)
test_data_size = len(test_data)
print("训练数据集的长度:{}".format(train_data_size))
print("测试数据集的长度:{}".format(test_data_size))
'''2利用dataloader加载数据集'''
train_dataloader = DataLoader(train_data, batch_size=100)
test_dataloader = DataLoader(test_data, batch_size=100)
'''3创建网络模型'''
'''直接加载训练好的模型'''
model_vgg16_10=torch.load("vgg16_t_25.pth")
model_vgg16_10=model_vgg16_10.cuda()
#就一轮测试一下
'''在训练集上试一下'''
total_accuracy=0
for data in train_dataloader:
imgs, targets = data # 取数据
imgs=imgs.cuda()
targets=targets.cuda()
outputs = model_vgg16_10(imgs) # 送入神经网络模型
accuracy = (outputs.argmax(1) == targets).sum()
print("训练集上每100个图片的正确率(一个batch_size):{}".format(accuracy / 100))
total_accuracy = total_accuracy + accuracy
print("总训练集上识别的正确率:{}".format(total_accuracy / train_data_size))
print("--------------------------------------------------------------------------------")
'''在测试集上试一下'''
total_accuracy_test=0
for data in test_dataloader:
imgs, targets = data # 取数据
imgs=imgs.cuda()
targets=targets.cuda()
outputs = model_vgg16_10(imgs) # 送入神经网络模型
accuracy = (outputs.argmax(1) == targets).sum()
print("测试集上每100个图片的正确率(一个batch_size):{}".format(accuracy / 100))
total_accuracy_test=total_accuracy_test+accuracy
print("总测试集上识别的正确率:{}".format(total_accuracy_test / test_data_size))
结果:
训练集上:
测试集上: