深度学习(pytorch)——神经网络完整模型训练套路及其注意事项

本文介绍了PyTorch中如何测试神经网络模型的正确性,包括输入数据的规格和输出形状。此外,讨论了训练过程中的损失值打印策略,并解释了为何在损失值上使用`item()`。还详细阐述了`model.train()`和`model.eval()`在训练和验证阶段的作用,以及`torch.no_grad()`的用途。案例中展示了CIFAR10数据集上的网络结构及训练流程,包括模型保存和验证精度计算。
摘要由CSDN通过智能技术生成

一、写好网络后如何测试网络的正确性?程序如下:

if __name__ == '__main__':
    # 通过以下代码测试模型的正确性
    tudui = Tudui()
    input = torch.ones((64,3,32,32))
    output = tudui(input)
    print(output.shape)

torch.ones((64,3,32,32))表示batch_size=64,channel=3,高H=32,宽W=32,cifar10的图片就是3通道,宽高就是32的 

二、为了减少打印输出太多的冗余信息,通常每几百次训练打印一次损失,下面程序是每训练100次,打印一次损失值,具体程序如下:

       if total_train_step % 100 ==0:
            print("训练次数 : {},Loss : {}".format(total_train_step,loss.item()))
            writer.add_scalar("train_loss",loss.item(),total_train_step)

为什么loss要加一个item(),使其变成loss.item(),因为原本的loss是tensor类型,加了item后就变成了数值型,防止构建计算图,具体案例如下:

 

运行结果如下:

三、加入tensorboard,具体程序如下:

在terminal中输入tensorboard --logdir=logs --port=6007得到下图

 

四、模型的保存程序如下:

五、在分类问题当中,通常需要有正确率作为分类评判的标准。

argmax(1)时,是横向查找比较数据的大小索引,取出最大值所在的位置

也就是说,如果是为1,则返回每一最大值的索引

argmax(0)时,是纵向查找比较数据的大小索引,取出最大值所在的位置 

也就是说,如果是为0,则返回每一最大值的索引

 

 

源程序计算准确率的代码如下:

六、model.train()的用法

model.train()的作用是启用 Batch Normalization 和 Dropout。

如果模型中有BN层(Batch Normalization)和Dropout,需要在训练时添加model.train()。model.train()是保证BN层能够用到每一批数据的均值和方差。对于Dropout,model.train()是随机取一部分网络连接来训练更新参数。

七、model.eval()的用法

model.eval()的作用是不启用 Batch Normalization 和 Dropout。

如果模型中有BN层(Batch Normalization)和Dropout,在测试时添加model.eval()。model.eval()是保证BN层能够用全部训练数据的均值和方差,即测试过程中要保证BN层的均值和方差不变。对于Dropout,model.eval()是利用到了所有网络连接,即不进行随机舍弃神经元。

训练完train样本后,生成的模型model要用来测试样本。在model(test)之前,需要加上model.eval(),否则的话,有输入数据,即使不训练,它也会改变权值。这是model中含有BN层和Dropout所带来的的性质。

在做one classification的时候,训练集和测试集的样本分布是不一样的,尤其需要注意这一点。

八、model.eval()和torch.no_grad()的区别

在PyTorch中进行validation/test时,会使用model.eval()切换到测试模式,在该模式下:

1. 主要用于通知dropout层和BN层在train和validation/test模式间切换:

  • 在train模式下,dropout网络层会按照设定的参数p设置保留激活单元的概率(保留概率=p); BN层会继续计算数据的mean和var等参数并更新。

  • 在eval模式下,dropout层会让所有的激活单元都通过,而BN层会停止计算和更新mean和var,直接使用在训练阶段已经学出的mean和var值。

2. 该模式不会影响各层的gradient计算行为,即gradient计算和存储与training模式一样,只是不进行反向传播(back probagation)。

而with torch.no_grad()则主要是用于停止autograd模块的工作,以起到加速和节省显存的作用。它的作用是将该with语句包裹起来的部分停止梯度的更新,从而节省了GPU算力和显存,但是并不会影响dropout和BN层的行为。

如果不在意显存大小和计算时间的话,仅仅使用model.eval()已足够得到正确的validation/test的结果;而with torch.no_grad()则是更进一步加速和节省gpu空间(因为不用计算和存储梯度),从而可以更快计算,也可以跑更大的batch来测试。

九、案例、实现下图的神经网络结构

 完整程序如下:

model.py文件

import torch
from torch import nn

class Tudui(nn.Module):
    def __init__(self):
        super(Tudui, self).__init__()
        self.model1 = nn.Sequential(
            nn.Conv2d(3, 32, 5, padding=2, stride=1),
            nn.MaxPool2d(2),
            nn.Conv2d(32, 32, 5, padding=2, stride=1),
            nn.MaxPool2d(2),
            nn.Conv2d(32, 64, 5, padding=2, stride=1),
            nn.MaxPool2d(2),
            nn.Flatten(),
            nn.Linear(1024, 64),
            nn.Linear(64, 10)
        )

    def forward(self, x):
        x = self.model1(x)
        return x

if __name__ == '__main__':
    # 通过以下代码测试模型的正确性
    tudui = Tudui()
    input = torch.ones((64,3,32,32))
    output = tudui(input)
    print(output.shape)

train.py文件

import torchvision
from torch import nn
from torch.nn import Conv2d, MaxPool2d, Flatten
from torch.utils.tensorboard import SummaryWriter

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

train_data = torchvision.datasets.CIFAR10(root='./data_CIFAR10',train=True,
                                          transform=torchvision.transforms.ToTensor(),download=True)

test_data = torchvision.datasets.CIFAR10(root='./data_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))

train_dataloader = DataLoader(train_data,batch_size=64)
test_dataloader = DataLoader(test_data,batch_size=64)

#搭建神经网络

tudui = Tudui()
#损失函数
loss_fn = nn.CrossEntropyLoss()
#优化器
optimizer = torch.optim.SGD(tudui.parameters(),lr=0.01)

#设置训练网络的一些参数
total_train_step = 0
total_test_step = 0
epoch = 10

writer = SummaryWriter('./logs_train')


for i in range(epoch):
    print("------------第 {} 轮训练开始--------------".format(i+1))

    tudui.eval()
    for data in train_dataloader:
        imgs,targets = data
        outputs = tudui(imgs)
        loss = loss_fn(outputs,targets)

        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        total_train_step +=1
        if total_train_step % 100 ==0:
            print("训练次数 : {},Loss : {}".format(total_train_step,loss.item()))
            writer.add_scalar("train_loss",loss.item(),total_train_step)

    tudui.eval()
    total_test_loss = 0
    total_accuracy = 0
    with torch.no_grad():
        for data in test_dataloader:
            imgs,targets = data
            outputs = tudui(imgs)
            loss = loss_fn(outputs,targets)
            total_test_loss += loss.item()
            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 += 1

    torch.save(tudui, 'tudui_{}.pth'.format(i))
    print("模型已保存")
writer.close()

运行结果如下:

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值