十七、完整神经网络模型训练步骤

以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 nn


class 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 x

if __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 = data
            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_accuracy
    print("整体测试集上的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 = data
            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_accuracy
    print("整体测试集上的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 nn

class 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 x

if __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 = data
            if 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 time

class 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 x

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()
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 = data
            if 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_accuracy
    print("整体测试集上的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 = data
            imgs = imgs.to(device)
            targets = targets.to(device)

补充

①item()

item()就是只获取数值,不获取该变量的类型

import torch

a = torch.tensor(7870)
print(a)#tensor(7870)
print(a.item())#7870

②argmax(dim=Optional[int])

在分类问题上常用准确率来进行衡量
因为是有监督学习的十分类任务模型,最后的预测输出是十个值,且这十个值代表十个类别,且这些值的大小代表所对应的类别的可能性,而argmax方法则可以求出十个类别中可能性最大的那个类别对应的下标
output.argmax(dim=1),参数为1代表横向为一组求最大值;反之dim=0,则表示纵向为一组求最大值

import torch

output = 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_x

target = torch.tensor([2,1,1])

print(predicate == target)#tensor([ True, False,  True])

print((predicate == target).sum())#tensor(2)  对应位置相等的个数为2个

接下来解释下代码含义
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_41264055/article/details/126479650
今日推荐