以CIFAR-10数据集为例,训练自己搭建的神经网络模型架构
一、准备CIFAR-10数据集
CIFAR10官网使用文档
torchvision.datasets.CIFAR10(root="./CIFAR_10",train=True,download=True)
参数 | 描述 |
---|---|
root | 字符串,指明要下载到的位置,或已有数据集存放的位置 |
train | 若为True则下载训练集,若为False则下载册数集 |
transform | 一个函数/转换,它接收PIL图像并返回转换后的版本 |
target_transform | 接收目标并对其进行转换的函数/转换 |
download | 若为True则会从官网进行下载,若为False则不下载 |
详细的datasets使用可以参考该篇博文:五、torchvision
导包
import torchvision
from torch import nn
from torch.optim.lr_scheduler import ExponentialLR
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
from beyond_model import *
创建python文件beyond_train.py
# CIFAR10是PIL的图片,通过transform转换为tensor类型图片
train_datasets = torchvision.datasets.CIFAR10("CIFAR_10",train=True,transform=torchvision.transforms.ToTensor(),download=True)
test_datasets = torchvision.datasets.CIFAR10("CIFAR_10",train=False,transform=torchvision.transforms.ToTensor(),download=True)#通过len方法获取数据集的大小
train_data_size = len(train_data)
test_data_size = len(test_data)# pycharm中 Ctrl+D进行复制一行操作
print("训练数据集的长度为:{}".format(train_data_size))# train_dataset_size is 50000
print("测试数据集的长度为:{}".format(test_data_size))# test_datasets_size is 10000
二、利用DataLoader进行加载CIFAR-10数据集
DataLoader官网使用手册
详细DataLoader看参考该篇博文:六、DataLoader
# 利用DataLoader加载CIFAR-10数据集
train_dataloader = DataLoader(dataset=train_datasets,batch_size=64)
test_dataloader = DataLoader(dataset=test_datasets,batch_size=64)
三、搭建神经网络架构
因为CIFAR-10数据集是10分类的数据集,故需要搭建一个10分类的网络架构
神经网络架构搭建的详细步骤可以参看该篇博文:二、复现网络模型训练CIFAR-10数据集
一般而言,神经网络模型都会另放在一个文件下
创建python文件beyond_model.py
# 搭建神经网络架构
import torch
from torch import nnclass Beyond(nn.Module):def __init__(self):super(Beyond,self).__init__()self.model = nn.Sequential(nn.Conv2d(in_channels=3,out_channels=32,kernel_size=(5,5),stride=1,padding=2),nn.MaxPool2d(2),nn.Conv2d(in_channels=32,out_channels=32,kernel_size=(5,5),stride=1,padding=2),nn.MaxPool2d(2),nn.Conv2d(in_channels=32,out_channels=64,kernel_size=(5,5),stride=1,padding=2),nn.MaxPool2d(2),nn.Flatten(),nn.Linear(in_features=1024,out_features=64),nn.Linear(in_features=64,out_features=10))def forward(self,input):x = self.model(input)return xif __name__ == '__main__':beyond = Beyond()input = torch.zeros((64,3,32,32))#验证网络的正确性,输入一个(batchsize,channel,H,W)数据output = beyond(input)print(output.shape)#torch.Size([64, 10]) 可以看出输出结果为十类,符合要求
四、创建网络模型
在beyond_train.py文件中引入beyond_model.py中的模型
# 引用网络模型
beyond = Beyond()
五、创建损失函数
这里使用交叉熵损失函数,当然用其他的也都可以
损失函数的详细使用说明可以参考该篇博文:十三、Loss Functions
# 创建交叉熵损失函数
loss_fn = nn.CrossEntropyLoss()
六、定义优化器
这里使用随机梯度下降SGD优化器,设置自动学习速率,每轮的学习速率会乘以0.1,随着训练次数的增加,学习速率会变小
优化器的使用可以参考该篇博文:十四、OPTIM
# 创建随机梯度下降SGD优化器
learning_rate = 1e-1 #0.01
optimizer = torch.optim.SGD(params=beyond.parameters(),lr=learning_rate)
scheduler = ExponentialLR(optimizer=optimizer,gamma=0.1)#将学习率设置为自动优化
七、设置训练网络中的一下其他参数
# 设置训练网络中的其他参数
#训练次数
total_train_step = 0
#train_step_sum = 0
#测试次数
total_test_step = 0
#test_step_sum = 0
#要训练的轮数
epoch = 10# 添加tensorboard
writer = SummaryWriter("y_log")
八、开始训练、测试、保存模型
for i in range(epoch):print("-------------第{}轮训练开始-------------".format(i + 1))#训练步骤开始beyond.train()for data in train_dataloader:# 从train_dataloader中获取训练数据,图片和图片的真实标签imgs,targets = data# 将训练数据进行解析outputs = beyond(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:# 每训练100张输出一次即可,不需要训练一张输出一次print("训练次数:{},Loss:{}".format(total_train_step, loss.item()))writer.add_scalar(tag="train_loss",scalar_value=loss.item(),global_step=total_train_step)scheduler.step() # 这里就不能用优化器,而是使用自动学习速率的优化器# 测试步骤开始beyond.eval()total_test_loss = 0# 需要获取经过所有验证集之后的损失值进行累加即可total_accuracy = 0# 分类问题上常用准确率来进行衡量with torch.no_grad():#这里的代码都没有梯度,不需要调优for data in test_dataloader:imgs,targets = dataoutputs = beyond(imgs)loss = loss_fn(outputs,targets)total_test_loss = total_test_loss + loss.item()accuracy = (outputs.argmax(1) == targets).sum()total_accuracy = accuracy + total_accuracyprint("整体测试集上的Loss:{}".format(total_test_loss))print("整体测试集上的准确率:{}".format(total_accuracy/test_data_size))writer.add_scalar(tag="test_loss", scalar_value=total_test_loss, global_step=total_test_step)writer.add_scalar(tag="test_accuracy", scalar_value=(total_accuracy/test_data_size), global_step=total_test_step)total_test_step = total_test_step + 1# 每测试一次该变量加一torch.save(beyond,"./beyond/beyond_{}.pth".format(i))print("模型已保存")#torch.save(beyond.state_dict(),"./beyond/beyond_{}.pth".format(i))
writer.close()
九、完整代码(未使用GPU进行训练)
beyond_train.py
import torchvision
from torch import nn
from torch.optim.lr_scheduler import ExponentialLR
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
from beyond_model import *train_data = torchvision.datasets.CIFAR10("CIFAR_10",train=True,transform=torchvision.transforms.ToTensor(),download=True)
test_data = torchvision.datasets.CIFAR10("CIFAR_10",train=False,transform=torchvision.transforms.ToTensor(),download=True)#获取数据集的大小
train_data_size = len(train_data)
test_data_size = len(test_data)# pycharm中 Ctrl+D进行复制一行操作
print("训练数据集的长度为:{}".format(train_data_size))# train_dataset_size is 50000
print("测试数据集的长度为:{}".format(test_data_size))# test_datasets_size is 10000# 利用DataLoader加载CIFAR-10数据集
train_dataloader = DataLoader(dataset=train_data,batch_size=64)
test_dataloader = DataLoader(dataset=test_data,batch_size=64)# 引用网络模型
beyond = Beyond()# 创建交叉熵损失函数
loss_fn = nn.CrossEntropyLoss()# 创建随机梯度下降SGD优化器
learning_rate = 1e-1 #0.01
optimizer = torch.optim.SGD(params=beyond.parameters(),lr=learning_rate)
scheduler = ExponentialLR(optimizer=optimizer,gamma=0.1)#将学习率设置为自动优化# 设置训练网络中的其他参数
#训练次数
total_train_step = 0
#train_step_sum = 0
#测试次数
total_test_step = 0
#test_step_sum = 0
#要训练的轮数
epoch = 10# 添加tensorboard
writer = SummaryWriter("y_log")for i in range(epoch):print("-------------第{}轮训练开始-------------".format(i + 1))#训练步骤开始beyond.train()for data in train_dataloader:# 从train_dataloader中获取训练数据,图片和图片的真实标签imgs,targets = data# 将训练数据进行解析outputs = beyond(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:# 每训练100张输出一次即可,不需要训练一张输出一次print("训练次数:{},Loss:{}".format(total_train_step, loss.item()))writer.add_scalar(tag="train_loss",scalar_value=loss.item(),global_step=total_train_step)scheduler.step() # 这里就不能用优化器,而是使用自动学习速率的优化器# 测试步骤开始beyond.eval()total_test_loss = 0# 需要获取经过所有验证集之后的损失值进行累加即可total_accuracy = 0# 分类问题上常用准确率来进行衡量with torch.no_grad():#这里的代码都没有梯度,不需要调优for data in test_dataloader:imgs,targets = dataoutputs = beyond(imgs)loss = loss_fn(outputs,targets)total_test_loss = total_test_loss + loss.item()accuracy = (outputs.argmax(1) == targets).sum()total_accuracy = accuracy + total_accuracyprint("整体测试集上的Loss:{}".format(total_test_loss))print("整体测试集上的准确率:{}".format(total_accuracy/test_data_size))writer.add_scalar(tag="test_loss", scalar_value=total_test_loss, global_step=total_test_step)writer.add_scalar(tag="test_accuracy", scalar_value=(total_accuracy/test_data_size), global_step=total_test_step)total_test_step = total_test_step + 1# 每测试一次该变量加一torch.save(beyond,"./beyond/beyond_{}.pth".format(i))print("模型已保存")#torch.save(beyond.state_dict(),"./beyond/beyond_{}.pth".format(i))
writer.close()
beyond_model.py
# 搭建神经网络架构
import torch
from torch import nnclass Beyond(nn.Module):def __init__(self):super(Beyond,self).__init__()self.model = nn.Sequential(nn.Conv2d(in_channels=3,out_channels=32,kernel_size=(5,5),stride=1,padding=2),nn.MaxPool2d(2),nn.Conv2d(in_channels=32,out_channels=32,kernel_size=(5,5),stride=1,padding=2),nn.MaxPool2d(2),nn.Conv2d(in_channels=32,out_channels=64,kernel_size=(5,5),stride=1,padding=2),nn.MaxPool2d(2),nn.Flatten(),nn.Linear(in_features=1024,out_features=64),nn.Linear(in_features=64,out_features=10))def forward(self,input):x = self.model(input)return xif __name__ == '__main__':beyond = Beyond()input = torch.zeros((64,3,32,32))#输入64张图片,3通道,大小为(32,32)output = beyond(input)print(output.shape)#torch.Size([64, 10]) 返回64张照片,每个图片中有10个数据代表这十分类任务的概率值
在Terminal下运行tensorboard --logdir=y_log --port=7870
,logdir为打开事件文件的路径,port为指定端口打开;
通过指定端口2312进行打开tensorboard,若不设置port参数,默认通过6006端口进行打开。
十、使用GPU训练网络
方法一:cuda()
在网络模型、损失函数、训练数据、测试数据
调用cuda方法
①网络模型
# 引用网络模型
beyond = Beyond()
if torch.cuda.is_available():beyond = beyond.cuda()
②损失函数
# 创建交叉熵损失函数
loss_fn = nn.CrossEntropyLoss()
if torch.cuda.is_available():loss_fn = loss_fn.cuda()
③训练数据
for data in train_dataloader:# 从train_dataloader中获取训练数据,图片和图片的真实标签imgs,targets = data# 将训练数据进行解析if torch.cuda.is_available():imgs = imgs.cuda()targets = targets.cuda()
④测试数据
with torch.no_grad():#这里的代码都没有梯度,不需要调优for data in test_dataloader:imgs,targets = dataif torch.cuda.is_available():imgs = imgs.cuda()targets = targets.cuda()
完整代码如下:
import torch
import torchvision
from torch import nn
from torch.optim.lr_scheduler import ExponentialLR
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
import timeclass Beyond(nn.Module):def __init__(self):super(Beyond,self).__init__()self.model = nn.Sequential(nn.Conv2d(in_channels=3,out_channels=32,kernel_size=(5,5),stride=1,padding=2),nn.MaxPool2d(2),nn.Conv2d(in_channels=32,out_channels=32,kernel_size=(5,5),stride=1,padding=2),nn.MaxPool2d(2),nn.Conv2d(in_channels=32,out_channels=64,kernel_size=(5,5),stride=1,padding=2),nn.MaxPool2d(2),nn.Flatten(),nn.Linear(in_features=1024,out_features=64),nn.Linear(in_features=64,out_features=10))def forward(self,input):x = self.model(input)return xtrain_data = torchvision.datasets.CIFAR10("CIFAR_10",train=True,transform=torchvision.transforms.ToTensor(),download=True)
test_data = torchvision.datasets.CIFAR10("CIFAR_10",train=False,transform=torchvision.transforms.ToTensor(),download=True)#获取数据集的大小
train_data_size = len(train_data)
test_data_size = len(test_data)# pycharm中 Ctrl+D进行复制一行操作
print("训练数据集的长度为:{}".format(train_data_size))# train_dataset_size is 50000
print("测试数据集的长度为:{}".format(test_data_size))# test_datasets_size is 10000# 利用DataLoader加载CIFAR-10数据集
train_dataloader = DataLoader(dataset=train_data,batch_size=64)
test_dataloader = DataLoader(dataset=test_data,batch_size=64)# 引用网络模型
beyond = Beyond()
if torch.cuda.is_available():beyond = beyond.cuda()
# 创建交叉熵损失函数
loss_fn = nn.CrossEntropyLoss()
if torch.cuda.is_available():loss_fn = loss_fn.cuda()# 创建随机梯度下降SGD优化器
learning_rate = 1e-1 #0.01
optimizer = torch.optim.SGD(params=beyond.parameters(),lr=learning_rate)
scheduler = ExponentialLR(optimizer=optimizer,gamma=0.1)#将学习率设置为自动优化# 设置训练网络中的其他参数
#训练次数
total_train_step = 0
#train_step_sum = 0
#测试次数
total_test_step = 0
#test_step_sum = 0
#要训练的轮数
epoch = 10# 添加tensorboard
writer = SummaryWriter("y_log")start_time = time.time()#记录训练开始时的时间
for i in range(epoch):print("-------------第{}轮训练开始-------------".format(i + 1))#训练步骤开始beyond.train()for data in train_dataloader:# 从train_dataloader中获取训练数据,图片和图片的真实标签imgs,targets = data# 将训练数据进行解析if torch.cuda.is_available():imgs = imgs.cuda()targets = targets.cuda()outputs = beyond(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:# 每训练100张输出一次即可,不需要训练一张输出一次end_tiem = time.time()#记录训练100次所使用的时间print("训练100次所使用的时间为:{}".format(end_tiem-start_time))#看下训练100次所用时间为多少print("训练次数:{},Loss:{}".format(total_train_step, loss.item()))writer.add_scalar(tag="train_loss",scalar_value=loss.item(),global_step=total_train_step)scheduler.step() # 这里就不能用优化器,而是使用自动学习速率的优化器# 测试步骤开始beyond.eval()total_test_loss = 0# 需要获取经过所有验证集之后的损失值进行累加即可total_accuracy = 0# 分类问题上常用准确率来进行衡量with torch.no_grad():#这里的代码都没有梯度,不需要调优for data in test_dataloader:imgs,targets = dataif torch.cuda.is_available():imgs = imgs.cuda()targets = targets.cuda()outputs = beyond(imgs)loss = loss_fn(outputs,targets)total_test_loss = total_test_loss + loss.item()accuracy = (outputs.argmax(1) == targets).sum()total_accuracy = accuracy + total_accuracyprint("整体测试集上的Loss:{}".format(total_test_loss))print("整体测试集上的准确率:{}".format(total_accuracy/test_data_size))writer.add_scalar(tag="test_loss", scalar_value=total_test_loss, global_step=total_test_step)writer.add_scalar(tag="test_accuracy", scalar_value=(total_accuracy/test_data_size), global_step=total_test_step)total_test_step = total_test_step + 1# 每测试一次该变量加一torch.save(beyond,"./beyond/beyond_{}.pth".format(i))print("模型已保存")#torch.save(beyond.state_dict(),"./beyond/beyond_{}.pth".format(i))
writer.close()
方法二:to()
定义训练的设备
,在网络模型、损失函数、训练数据、测试数据
调用即可
①定义训练设备
#定义设备
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
#device = torch.device("cpu")#CPU
#device = torch.device("cuda")#GPU
#device = torch.device("cuda:0")#GPU 指定GPU训练 与上面是等价的
②网络模型
# 引用网络模型
beyond = Beyond()
beyond = beyond.to(device)
③损失函数
# 创建交叉熵损失函数
loss_fn = nn.CrossEntropyLoss()
loss_fn = loss_fn.to(device)
④训练数据
for data in train_dataloader:# 从train_dataloader中获取训练数据,图片和图片的真实标签imgs,targets = data# 将训练数据进行解析imgs = imgs.to(device)targets = targets.to(device)
⑤测试数据
with torch.no_grad():#这里的代码都没有梯度,不需要调优for data in test_dataloader:imgs,targets = dataimgs = imgs.to(device)targets = targets.to(device)
补充
①item()
item()就是只获取数值,不获取该变量的类型
import torcha = torch.tensor(7870)
print(a)#tensor(7870)
print(a.item())#7870
②argmax(dim=Optional[int])
在分类问题上常用准确率来进行衡量
因为是有监督学习的十分类任务模型,最后的预测输出是十个值,且这十个值代表十个类别,且这些值的大小代表所对应的类别的可能性,而argmax方法则可以求出十个类别中可能性最大的那个类别对应的下标
output.argmax(dim=1)
,参数为1代表横向为一组求最大值;反之dim=0,则表示纵向为一组求最大值
import torchoutput = torch.tensor([[0.1,0.5,0.8],[0.5,0.1,0.4],[0.6,0.9,0.1]])out_x = output.argmax(dim=1)
print(out_x)#tensor([2, 0, 1])
# out_y = output.argmax(dim=0)
# print(out_y)#tensor([2, 2, 0])#假设这里以x为例
predicate = out_xtarget = torch.tensor([2,1,1])print(predicate == target)#tensor([ True, False, True])print((predicate == target).sum())#tensor(2) 对应位置相等的个数为2个
接下来解释下代码含义