Press "Enter" to skip to content

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

本站内容均来自兴趣收集,如不慎侵害的您的相关权益,请留言告知,我们将尽快删除.谢谢.

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

 

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()

 

运行结果如下:

 

Be First to Comment

发表回复

您的电子邮箱地址不会被公开。