sunpongber

完整的模型训练套路

PyTorch官网

完整的模型训练套路(以CIFAR10数据集)

完整的模型训练套路(一)

import torchvision
from torch import nn
from torch.utils.data import DataLoader
from model import *

# 准备数据集
train_data = torchvision.datasets.CIFAR10(root="P27_train/dataset", train=True, transform=torchvision.transforms.ToTensor(), download=True)

test_data = torchvision.datasets.CIFAR10(root="P27_train/dataset", train=False, transform=torchvision.transforms.ToTensor(), download=True)

# length 长度 查看数据集有多少
train_data.size = len(train_data)
test_data.size = len(test_data)
# 如果train_data.size=10训练数据集的长度为10
print("训练数据集的长度为:{}".format(train_data.size)) # 字符串格式化
print("测试数据集的长度为:{}".format(test_data.size)) # 字符串格式化

print("训练数据集的个数为%d,测试数据集的个数为%d" %(train_data.size, test_data.size))

# 利用Dataloader来加载数据集
train_dataLoader = DataLoader(train_data, batch_size=64)
test_dataloader = DataLoader(test_data, batch_size=64)

# # 搭建神经网络
# class Pongber(nn.Module):
#     def __init__(self):
#         super(Pongber, 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(1024, 64),
#             nn.Linear(64, 10)
#         )
#
#     def forward(self, x):
#         x = self.model(x)
#
#         return x

# 创建网络模型
pongber = Pongber()

# 损失函数
loss_fn = nn.CrossEntropyLoss()

# 优化器
learning_rate = 0.01
# 1e-2  1e-2 = 1×(10)^(-2) = 1/100 = 0.01
# learning_rate = 1e-2
optimizer = torch.optim.SGD(pongber.parameters(), lr=learning_rate)

# 设置训练网络的一些参数
# 记录训练的次数
total_train_step = 0
# 记录测试的次数
total_test_step = 0
# 训练的轮数
epoch = 10

# epoch = 10i 从0跑到9
for i in range(epoch):
    print("------第{}轮训练开始------".format(i+1))

    # 训练步骤开始
    for data in train_dataLoader:
        imgs, targets = data
        outputs = pongber(imgs)
        loss = loss_fn(outputs, targets)

        # 优化器优化模型
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        total_train_step = total_train_step + 1
        # print("训练次数:{}, Loss:{}".format(total_train_step, loss))
        print("训练次数:{}, Loss:{}".format(total_train_step, loss.item())) # 加上item就会把它转换成一个真实的数字

运行:

Files already downloaded and verified
Files already downloaded and verified
训练数据集的长度为50000
测试数据集的长度为10000
训练数据集的个数为50000测试数据集的个数为10000
------第1轮训练开始------
训练次数1 Loss2.3051769733428955
训练次数2 Loss2.294654607772827
训练次数3 Loss2.3009750843048096
...
训练次数782 Loss2.1695666313171387
------第2轮训练开始------
训练次数783 Loss2.0236775875091553
...
训练次数1564 Loss2.315021514892578
------第3轮训练开始------
训练次数1565 Loss1.912036657333374
...
...
...
训练次数7038 Loss1.5217787027359009
------第10轮训练开始------
训练次数7039 Loss1.224427580833435
...
训练次数7818 Loss0.9744108319282532
训练次数7819 Loss1.217579960823059
训练次数7820 Loss1.4052762985229492

完整的模型训练套路(二)

现在整个训练步骤写完了,那我们思考一个问题,我们模型训练的时候如何得知它有没有训练好,或者说有没有达到我们想要的一个需求?

所以当我们训练完一轮的时候,在每一次训练完一轮后,进行一个测试,让它在测试数据集上跑一遍,以测试数据集上的损失或者正确率来评估有没有训练好,需要注意在测试的过程中就不需要对模型进行调优了,我们就是想用一个现有的模型进行一个测试

添加测试;每100次打印,避免一些无用的信息;添加tensorboard...

import torch
import torchvision
from torch import nn
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter

from P22_nn_sequential import writer
from model import *

# 准备数据集
train_data = torchvision.datasets.CIFAR10(root="P27_train/dataset", train=True, transform=torchvision.transforms.ToTensor(), download=True)

test_data = torchvision.datasets.CIFAR10(root="P27_train/dataset", train=False, transform=torchvision.transforms.ToTensor(), download=True)

# length 长度 查看数据集有多少
train_data.size = len(train_data)
test_data.size = len(test_data)
# 如果train_data.size=10训练数据集的长度为10
print("训练数据集的长度为:{}".format(train_data.size)) # 字符串格式化
print("测试数据集的长度为:{}".format(test_data.size)) # 字符串格式化

print("训练数据集的个数为%d,测试数据集的个数为%d" %(train_data.size, test_data.size))

# 利用Dataloader来加载数据集
train_dataLoader = DataLoader(train_data, batch_size=64)
test_dataloader = DataLoader(test_data, batch_size=64)

# # 搭建神经网络
# class Pongber(nn.Module):
#     def __init__(self):
#         super(Pongber, 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(1024, 64),
#             nn.Linear(64, 10)
#         )
#
#     def forward(self, x):
#         x = self.model(x)
#
#         return x

# 创建网络模型
pongber = Pongber()

# 损失函数
loss_fn = nn.CrossEntropyLoss()

# 优化器
learning_rate = 0.01
# 1e-2  1e-2 = 1×(10)^(-2) = 1/100 = 0.01
# learning_rate = 1e-2
optimizer = torch.optim.SGD(pongber.parameters(), lr=learning_rate)

# 设置训练网络的一些参数
# 记录训练的次数
total_train_step = 0
# 记录测试的次数
total_test_step = 0
# 训练的轮数
epoch = 10

# 添加tensorboard
writer = SummaryWriter(log_dir="logs_train")

# epoch = 10i 从0跑到9
for i in range(epoch):
    print("------第{}轮训练开始------".format(i+1))

    # 训练步骤开始
    for data in train_dataLoader:
        imgs, targets = data
        outputs = pongber(imgs)
        loss = loss_fn(outputs, targets)

        # 优化器优化模型
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        total_train_step = total_train_step + 1
        # print("训练次数:{}, Loss:{}".format(total_train_step, loss))
        if total_train_step % 100 == 0: # 每100次打印记录避免一些无用的信息
            print("训练次数:{}, Loss:{}".format(total_train_step, loss.item())) # 加上item就会把它转换成一个真实的数字
            writer.add_scalar("train_loss", loss.item(), total_train_step)

    # 测试步骤开始
    total_test_loss = 0
    with torch.no_grad(): # 没有梯度保证不进行调优
        for data in test_dataloader:
            imgs, targets = data
            outputs = pongber(imgs)
            loss = loss_fn(outputs, targets)
            total_test_loss = total_test_loss + loss
    print("整体测试集上的Loss:{}".format(total_test_loss))
    writer.add_scalar("test_loss", total_test_loss, total_test_step)
    total_test_step = total_test_step + 1

writer.close()

我们想保存每一轮训练的模型

import torch
import torchvision
from torch import nn
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter

from P22_nn_sequential import writer
from model import *

# 准备数据集
train_data = torchvision.datasets.CIFAR10(root="P27_train/dataset", train=True, transform=torchvision.transforms.ToTensor(), download=True)

test_data = torchvision.datasets.CIFAR10(root="P27_train/dataset", train=False, transform=torchvision.transforms.ToTensor(), download=True)

# length 长度 查看数据集有多少
train_data.size = len(train_data)
test_data.size = len(test_data)
# 如果train_data.size=10训练数据集的长度为10
print("训练数据集的长度为:{}".format(train_data.size)) # 字符串格式化
print("测试数据集的长度为:{}".format(test_data.size)) # 字符串格式化

print("训练数据集的个数为%d,测试数据集的个数为%d" %(train_data.size, test_data.size))

# 利用Dataloader来加载数据集
train_dataLoader = DataLoader(train_data, batch_size=64)
test_dataloader = DataLoader(test_data, batch_size=64)

# # 搭建神经网络
# class Pongber(nn.Module):
#     def __init__(self):
#         super(Pongber, 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(1024, 64),
#             nn.Linear(64, 10)
#         )
#
#     def forward(self, x):
#         x = self.model(x)
#
#         return x

# 创建网络模型
pongber = Pongber()

# 损失函数
loss_fn = nn.CrossEntropyLoss()

# 优化器
learning_rate = 0.01
# 1e-2  1e-2 = 1×(10)^(-2) = 1/100 = 0.01
# learning_rate = 1e-2
optimizer = torch.optim.SGD(pongber.parameters(), lr=learning_rate)

# 设置训练网络的一些参数
# 记录训练的次数
total_train_step = 0
# 记录测试的次数
total_test_step = 0
# 训练的轮数
epoch = 10

# 添加tensorboard
writer = SummaryWriter(log_dir="logs_train")

# epoch = 10i 从0跑到9
for i in range(epoch):
    print("------第{}轮训练开始------".format(i+1))

    # 训练步骤开始
    for data in train_dataLoader:
        imgs, targets = data
        outputs = pongber(imgs)
        loss = loss_fn(outputs, targets)

        # 优化器优化模型
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        total_train_step = total_train_step + 1
        # print("训练次数:{}, Loss:{}".format(total_train_step, loss))
        if total_train_step % 100 == 0: # 每100次打印记录避免一些无用的信息
            print("训练次数:{}, Loss:{}".format(total_train_step, loss.item())) # 加上item就会把它转换成一个真实的数字
            writer.add_scalar("train_loss", loss.item(), total_train_step)

    # 测试步骤开始
    total_test_loss = 0
    with torch.no_grad(): # 没有梯度保证不进行调优
        for data in test_dataloader:
            imgs, targets = data
            outputs = pongber(imgs)
            loss = loss_fn(outputs, targets)
            total_test_loss = total_test_loss + loss
    print("整体测试集上的Loss:{}".format(total_test_loss))
    writer.add_scalar("test_loss", total_test_loss, total_test_step)
    total_test_step = total_test_step + 1

    torch.save(pongber, "pongber_{}.pth".format(i+1))
    print("第{}轮训练模型已经保存".format(i+1))

writer.close()

其实还有一部分优化,就是我们发现即便我们得到整体测试集上的Loss,它好像也不能很好的说明我们在测试集上表现得效果,其实在分类问题中,我们可以用正确率来表示

这部分内容稍微也许会有点小困难,可以简单了解一下,因为这是分类问题中的常用的一种方式,如果说是普通的目标检测或者说是语义分割的时候,最简单的方法就是将输出直接在tensorboard中显示,所以我们可以在tensorboard中看到测试的结果

所以正确率其实是分类问题中比较特有的衡量指标

'''
2 × input

Model(2分类)

outputs =
[0.1, 0.2] # 代码中得到的output是这种形式
[0.3, 0.4]

0    1 # 实际的类

argmax # PyTorch给我们提供了这个方法,它能求出横向的最大值所在的位置

preds = [1] # 如何将以上形式转换为这个形式呢?argmax
        [1]

inputs target = [0] [1] # 与preds对比,看正确率

preds == inputs target

[false, true].sum()=1 # 0与1比false,1与1比true,算出来了对应位置相等(正确)的个数有多少,然后再除以总的个数就可以算出正确率
'''

P27_test

import torch

outputs = torch.tensor([[0.1, 0.2],
                        [0.3, 0.4]])

print(outputs.argmax(1)) # 填0或11的时候横向看

# 返回tensor([1, 1])横向看0.2大于0.10.4大于0.3位置是[1, 1]

preds = outputs.argmax(1)
targets = torch.tensor([0, 1])
print(preds == targets) # 返回tensor([False,  True])
print((preds == targets).sum()) # 返回tensor(1)记录对应位置相等的个数

经过验证,可以继续对代码进行优化,想办法计算出整体的一个正确率

import torch
import torchvision
from numpy.ma.core import argmax
from torch import nn
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter

from P22_nn_sequential import writer
from model import *

# 准备数据集
train_data = torchvision.datasets.CIFAR10(root="P27_train/dataset", train=True, transform=torchvision.transforms.ToTensor(), download=True)

test_data = torchvision.datasets.CIFAR10(root="P27_train/dataset", train=False, transform=torchvision.transforms.ToTensor(), download=True)

# length 长度 查看数据集有多少
train_data_size = len(train_data)
test_data_size = len(test_data)
# 如果train_data.size=10训练数据集的长度为10
print("训练数据集的长度为:{}".format(train_data_size)) # 字符串格式化
print("测试数据集的长度为:{}".format(test_data_size)) # 字符串格式化

print("训练数据集的个数为%d,测试数据集的个数为%d" %(train_data_size, test_data_size))

# 利用Dataloader来加载数据集
train_dataLoader = DataLoader(train_data, batch_size=64)
test_dataloader = DataLoader(test_data, batch_size=64)

# # 搭建神经网络
# class Pongber(nn.Module):
#     def __init__(self):
#         super(Pongber, 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(1024, 64),
#             nn.Linear(64, 10)
#         )
#
#     def forward(self, x):
#         x = self.model(x)
#
#         return x

# 创建网络模型
pongber = Pongber()

# 损失函数
loss_fn = nn.CrossEntropyLoss()

# 优化器
learning_rate = 0.01
# 1e-2  1e-2 = 1×(10)^(-2) = 1/100 = 0.01
# learning_rate = 1e-2
optimizer = torch.optim.SGD(pongber.parameters(), lr=learning_rate)

# 设置训练网络的一些参数
# 记录训练的次数
total_train_step = 0
# 记录测试的次数
total_test_step = 0
# 训练的轮数
epoch = 10

# 添加tensorboard
writer = SummaryWriter(log_dir="logs_train")

# epoch = 10i 从0跑到9
for i in range(epoch):
    print("------第{}轮训练开始------".format(i+1))

    # 训练步骤开始
    for data in train_dataLoader:
        imgs, targets = data
        outputs = pongber(imgs)
        loss = loss_fn(outputs, targets)

        # 优化器优化模型
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        total_train_step = total_train_step + 1
        # print("训练次数:{}, Loss:{}".format(total_train_step, loss))
        if total_train_step % 100 == 0: # 每100次打印记录避免一些无用的信息
            print("训练次数:{}, Loss:{}".format(total_train_step, loss.item())) # 加上item就会把它转换成一个真实的数字
            writer.add_scalar("train_loss", loss.item(), total_train_step)

    # 测试步骤开始
    total_test_loss = 0
    total_accuracy = 0
    with torch.no_grad(): # 没有梯度保证不进行调优
        for data in test_dataloader:
            imgs, targets = data
            outputs = pongber(imgs)
            loss = loss_fn(outputs, targets)
            total_test_loss = total_test_loss + loss
            accuracy = (outputs.argmax(1) == targets).sum()
            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_accuracy", total_accuracy/test_data_size, total_test_step)
    total_test_step = total_test_step + 1

    torch.save(pongber, "pongber_{}.pth".format(i+1))
    print("第{}轮训练模型已经保存".format(i+1))

writer.close()

'''
2 × input

Model(2分类)

outputs =
[0.1, 0.2] # 代码中得到的output是这种形式
[0.3, 0.4]

0    1 # 实际的类

argmax # PyTorch给我们提供了这个方法,它能求出横向的最大值所在的位置

preds = [1] # 如何将以上形式转换为这个形式呢?argmax
        [1]

inputs target = [0] [1] # 与preds对比,看正确率

preds == inputs target

[false, true].sum()=1 # 0与1比false,1与1比true,算出来了对应位置相等(正确)的个数有多少,然后再除以总的个数就可以算出正确率
'''

完整的模型训练套路(三)

注意一些细节

训练步骤开始前,pongber.train()并不是说要把这个写成训练模式它才开始训练,之前并没有写pongber.train()它也能开始训练
测试步骤开始前,pongber.eval()并不是说要把这个写成评估模式它才开始测试,之前并没有写pongber.eval()它也能开始测试
那它们有什么作用呢?

PyTorch官网

因为神经网络继承Module,所以看这个Module

train(mode=True)
将模块设置为训练模式。
这只会影响某些特定的模块。请参阅各个模块的文档,了解它们在训练模式和评估模式下的具体行为是否会受到影响,例如 Dropout、BatchNorm 等模块。

eval()
将模块设置为评估模式。
这只会影响某些特定的模块。请参阅各个模块的文档,了解它们在训练模式和评估模式下的具体行为是否会受到影响,例如 Dropout、BatchNorm 等模块。
该方法等价于 self.train(False)。
关于 .eval() 与其他可能被混淆的类似机制(如“局部禁用梯度计算”)之间的区别,请参见“Locally disabling gradient computation”部分的说明。

以后在写代码的时候,可以关注网络层有没有这些特殊的层,当然没有的话调用也是没有问题的

添加pongber.train(mode=True)pongber.eval()

import torch
import torchvision
from numpy.ma.core import argmax
from torch import nn
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter

from P22_nn_sequential import writer
from model import *

# 准备数据集
train_data = torchvision.datasets.CIFAR10(root="P27_train/dataset", train=True, transform=torchvision.transforms.ToTensor(), download=True)

test_data = torchvision.datasets.CIFAR10(root="P27_train/dataset", train=False, transform=torchvision.transforms.ToTensor(), download=True)

# length 长度 查看数据集有多少
train_data_size = len(train_data)
test_data_size = len(test_data)
# 如果train_data.size=10训练数据集的长度为10
print("训练数据集的长度为:{}".format(train_data_size)) # 字符串格式化
print("测试数据集的长度为:{}".format(test_data_size)) # 字符串格式化

print("训练数据集的个数为%d,测试数据集的个数为%d" %(train_data_size, test_data_size))

# 利用Dataloader来加载数据集
train_dataLoader = DataLoader(train_data, batch_size=64)
test_dataloader = DataLoader(test_data, batch_size=64)

# # 搭建神经网络
# class Pongber(nn.Module):
#     def __init__(self):
#         super(Pongber, 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(1024, 64),
#             nn.Linear(64, 10)
#         )
#
#     def forward(self, x):
#         x = self.model(x)
#
#         return x

# 创建网络模型
pongber = Pongber()

# 损失函数
loss_fn = nn.CrossEntropyLoss()

# 优化器
learning_rate = 0.01
# 1e-2  1e-2 = 1×(10)^(-2) = 1/100 = 0.01
# learning_rate = 1e-2
optimizer = torch.optim.SGD(pongber.parameters(), lr=learning_rate)

# 设置训练网络的一些参数
# 记录训练的次数
total_train_step = 0
# 记录测试的次数
total_test_step = 0
# 训练的轮数
epoch = 10

# 添加tensorboard
writer = SummaryWriter(log_dir="logs_train")

# epoch = 10i 从0跑到9
for i in range(epoch):
    print("------第{}轮训练开始------".format(i+1))

    # 训练步骤开始
    pongber.train(mode=True)
    for data in train_dataLoader:
        imgs, targets = data
        outputs = pongber(imgs)
        loss = loss_fn(outputs, targets)

        # 优化器优化模型
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        total_train_step = total_train_step + 1
        # print("训练次数:{}, Loss:{}".format(total_train_step, loss))
        if total_train_step % 100 == 0: # 每100次打印记录避免一些无用的信息
            print("训练次数:{}, Loss:{}".format(total_train_step, loss.item())) # 加上item就会把它转换成一个真实的数字
            writer.add_scalar("train_loss", loss.item(), total_train_step)

    # 测试步骤开始
    pongber.eval()
    total_test_loss = 0
    total_accuracy = 0
    with torch.no_grad(): # 没有梯度保证不进行调优
        for data in test_dataloader:
            imgs, targets = data
            outputs = pongber(imgs)
            loss = loss_fn(outputs, targets)
            total_test_loss = total_test_loss + loss
            accuracy = (outputs.argmax(1) == targets).sum()
            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_accuracy", total_accuracy/test_data_size, total_test_step)
    total_test_step = total_test_step + 1

    torch.save(pongber, "pongber_{}.pth".format(i+1))
    # torch.save(pongber.state_dict(), "pongber_{}.pth".format(i+1))
    print("第{}轮训练模型已经保存".format(i+1))

writer.close()

'''
2 × input

Model(2分类)

outputs =
[0.1, 0.2] # 代码中得到的output是这种形式
[0.3, 0.4]

0    1 # 实际的类

argmax # PyTorch给我们提供了这个方法,它能求出横向的最大值所在的位置

preds = [1] # 如何将以上形式转换为这个形式呢?argmax
        [1]

inputs target = [0] [1] # 与preds对比,看正确率

preds == inputs target

[false, true].sum()=1 # 0与1比false,1与1比true,算出来了对应位置相等(正确)的个数有多少,然后再除以总的个数就可以算出正确率
'''

首先准备数据集

然后利用Dataloader来加载数据集

创建网络模型(一般在另一个文件里创建类,调用)

创建损失函数

创建优化器

设置训练网络的一些参数(训练的轮数、训练的次数)

pongber.train(mode=True)进入训练状态
从train_dataLoader取数据
计算误差
放入优化器中优化
采用特定方式展示输出

在一轮训练结束后或者特定的步数之后pongber.eval()进入测试状态
with torch.no_grad():没有梯度,保证不进行调优
从test_dataloader取数据
计算误差
构建一些特殊的指标显示出来

最后通过一些方式展示一下我们训练的网络在测试集上的效果

最后可以某一轮或特定的步数保存这个模型(这里使用的是方式1,方式2是官方推荐的)
torch.save(pongber.state_dict(), "pongber_{}.pth".format(i+1))

原始资料地址:
完整的模型训练套路(一)
完整的模型训练套路(二)
完整的模型训练套路(三)
如有侵权联系删除 仅供学习交流使用