借LeNet简单的模型对深度学习训练过程中的注意事项进一步总结

本文是在卷积神经网络(LeNet)详解_欲游山河十万里的博客-CSDN博客博文的基础之上,对深度学习过程遇到的一些常见的问题进行总结。本文所总结的问题,不仅仅适用于这个简单的模型,更适用在其他的多个应用场景之下。

一、训练过程中模型的保存

我们在训练模型的时候经常出现各种问题导致训练中断,比方说断电,或者关机之类的导致电脑系统关闭,从而将模型训练中断,那么如何在模型中断后,能够保留之前的训练结果不被丢失,同时又可以继续之前的断点处继续训练?

首先在代码离需要保存模型,比方说我们模型设置训练5000轮,那么我们可以选择每100轮保存一次模型,这样的话,在训练的过程中就能保存下100,200,300.。。。等轮数时候的模型,那么当模型训练到400轮的时候突然训练中断,那么我们就可以通过加载400轮的参数来进行继续训练,其实这个过程就类似在预训练模型的基础上进行训练。下面简单粗暴上代码:

 checkpoint = {
                            'model': net.state_dict(),
                            'optimizer': optimizer.state_dict(),
                            "epoch": epoch,
                            "train_loss":train_loss,
                            "test_loss":test_loss,
                            "train_acc":train_acc,
                            "test_acc":test_acc,
                        }
                        torch.save(checkpoint, checkpoint_path)

假如此时模型训练中断了,我们得在代码里设置一个参数,这个参数用来查找确定当前路径下是否有已存在得模型。

 if os.path.exists(checkpoint_path):
        checkpoint=torch.load(checkpoint_path)
        net.load_state_dict(checkpoint['model'])
        optimizer.load_state_dict(checkpoint['optimizer'])
        start_epoch = checkpoint['epoch']
        train_loss = checkpoint['train_loss']
        train_acc = checkpoint['train_acc']
        test_loss = checkpoint['test_loss']
        test_acc = checkpoint['test_acc']
        test_loss.pop()
        test_acc.pop()
        train_loss.pop()
        train_acc.pop()
        print('加载 epoch {} 成功!'.format(start_epoch))
        #start_epoch=start_epoch+1#前面的那轮是保存成功的,所以从下一轮开始.比如保存了10轮,那么加1从第11轮开始训练
        start_train_and_test(start_epoch, epochs,train_loss=train_loss,train_acc=train_acc,test_loss=test_loss,test_acc=test_acc)
    else:
        print('没有保存的模型,从头开始训练!')
        start_epoch=0
        start_train_and_test(start_epoch,epochs,train_loss=train_loss,train_acc=train_acc,test_loss=test_loss,test_acc=test_acc)

完整的范例如下所示:

#对模型的训练过程进行代码注释
import torch
import torchvision
import torch.nn as nn
from model import LeNet, LeNetDemo1
import torch.optim as optim
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
import numpy as np
import time
import os
# Compose将多个步骤组合在一起
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Resize((28,28)),
    transforms.Normalize((0.1307), (0.3081))
])
# 导入60000张训练图片
train_set = torchvision.datasets.MNIST(root='./data', 	 # 数据集存放目录
										 train=True,		 # 表示是数据集中的训练集
                                        download=True,  	 # 第一次运行时为True,下载数据集,下载完成后改为False
                                        transform=transform) # 预处理过程
# 加载训练集,实际过程需要分批次(batch)训练
train_loader = torch.utils.data.DataLoader(train_set, 	  # 导入的训练集
										  batch_size=100, # 每批训练的样本数
                                          shuffle=False,  # 是否打乱训练集
                                          num_workers=0)  # 使用线程数,在windows下设置为0
# 10000张验证图片
# 第一次使用时要将download设置为True才会自动去下载数据集
val_set = torchvision.datasets.MNIST(root='./data', train=False,
                                       download=True, transform=transform)
val_loader = torch.utils.data.DataLoader(val_set, batch_size=1000,
                                         shuffle=False, num_workers=0)
val_data_iter = iter(val_loader)
val_image, val_label = next(val_data_iter)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(device)
net = LeNetDemo1()#导入模型网络
net.to(device) # 将网络分配到指定的device中
loss_function = nn.CrossEntropyLoss()#定义损失函数
optimizer = optim.Adam(net.parameters(), lr=0.001)#定义优化器,nets.parameters()是指网络中的参数,lr是学习率

checkpoint_path = './checkpoint/saved_lent.pth'  # 保存的模型

def start_train_and_test(start_epoch,epochs,train_loss=[],test_acc=[],train_acc=[],test_loss=[]):#开始模型的训练
    for epoch in range(start_epoch,epochs):#训练的轮数
        net.train()#训练模式
        running_loss = 0.0#训练集的损失
        time_start = time.perf_counter()#计时开始
        for step, data in enumerate(train_loader, start=0):#step是训练集的批次,data是训练集的数据
            inputs, labels = data#inputs是训练集的图片,labels是训练集的标签
            #print(f"labels.size(0)的值是{labels.size(0)}")
            #print(f"step的值是{step}")
            optimizer.zero_grad()#梯度清零
            outputs = net(inputs.to(device))				  # 将inputs分配到指定的device中
            loss = loss_function(outputs, labels.to(device))  # 将labels分配到指定的device中
            loss.backward()#反向传播
            optimizer.step()#更新参数
            running_loss += loss.item()#训练集的损失
            y_hat= net(inputs.to(device))
            train_accuary=(y_hat.argmax(dim=1) == labels.to(device)).sum().item()/labels.size(0)#训练集的准确率
            if step % 100 == 99:
                with torch.no_grad():#不计算梯度
                    net.eval()#验证模式
                    outputs = net(val_image.to(device)) # 将test_image分配到指定的device中
                    val_loss = loss_function(outputs, val_label.to(device))  # 将test_label分配到指定的device中
                    predict_y = torch.max(outputs, dim=1)[1]#取出最大值的索引
                    accuracy = (predict_y == val_label.to(device)).sum().item() / val_label.size(0) # 将test_label分配到指定的device中
                    print('[%d, %5d] train_loss: %.3f train_acc:%.3f test_accuracy: %.3f' %
                      (epoch, step + 1, running_loss/100,train_accuary, accuracy))
                    if step+1==600:
                        train_loss.append(running_loss/100)
                        test_acc.append(accuracy)
                        train_acc.append(train_accuary)#训练过程中的准确率
                        test_loss.append(val_loss.item())#测试过程中的损失
                    if epoch % 1 == 0 and step + 1 == 600:  # 实现了每1轮保存一次模型
                        if not os.path.isdir('./checkpoint'):
                            os.makedirs("./checkpoint")
                        checkpoint = {
                            'model': net.state_dict(),
                            'optimizer': optimizer.state_dict(),
                            "epoch": epoch,
                            "train_loss":train_loss,
                            "test_loss":test_loss,
                            "train_acc":train_acc,
                            "test_acc":test_acc,
                        }
                        torch.save(checkpoint, checkpoint_path)
                    print('%f s' % (time.perf_counter() - time_start))
                    running_loss = 0.0
    print('Finished Training')
    print(len(train_loss),len(test_acc),len(train_acc))
    save_path = f"./lennet+{epochs-1}+train_acc={train_acc[-1]}+test_acc={test_acc[-1]}.pt"
    torch.save(net.state_dict(), save_path)
    print(len(train_loss),len(test_acc),len(train_acc))
    #绘制图形
    index=[i for i in range(1,epochs+1)]
    print(train_loss)
    plt.plot(index,train_loss,'g',label="train_loss")
    plt.plot(index,train_acc,'b',label="train_acc")
    plt.plot(index,test_acc,'m',label="test_acc")
    plt.plot(index,test_loss,'r',label="test_loss")
    plt.xlabel("epoch")
    plt.legend()
    plt.pause(0.01)  # 暂停0.01秒

def main():
    # 画图用的变量
    train_loss = []  # 训练集的损失集合
    train_acc = []  # 训练集的准确率集合
    test_acc = []  # 测试集的准确率集合
    test_loss = []  # 测试集的损失集合
    epochs = 3
    start_epoch = -1
    # 如果有保存的模型,则加载模型,并在其基础上继续训练
    if os.path.exists(checkpoint_path):
        checkpoint=torch.load(checkpoint_path)
        net.load_state_dict(checkpoint['model'])
        optimizer.load_state_dict(checkpoint['optimizer'])
        start_epoch = checkpoint['epoch']
        train_loss = checkpoint['train_loss']
        train_acc = checkpoint['train_acc']
        test_loss = checkpoint['test_loss']
        test_acc = checkpoint['test_acc']
        test_loss.pop()
        test_acc.pop()
        train_loss.pop()
        train_acc.pop()
        print('加载 epoch {} 成功!'.format(start_epoch))
        #start_epoch=start_epoch+1#前面的那轮是保存成功的,所以从下一轮开始.比如保存了10轮,那么加1从第11轮开始训练
        start_train_and_test(start_epoch, epochs,train_loss=train_loss,train_acc=train_acc,test_loss=test_loss,test_acc=test_acc)
    else:
        print('没有保存的模型,从头开始训练!')
        start_epoch=0
        start_train_and_test(start_epoch,epochs,train_loss=train_loss,train_acc=train_acc,test_loss=test_loss,test_acc=test_acc)
if __name__ == '__main__':
    main()

写在最后

        我觉得参考文献的第一个大佬的代码格式是非常规整的,我认为应该把我的代码改成这种规整的代码,这样才能够更好,更方便的进行代码的维护操作。

参考文献 

Pytorch模型保存与加载,并在加载的模型基础上继续训练 - 简书

pytorch训练中断后,如何在之前的断点处继续训练_模型训练中途中断可以继续吗_程序小K的博客-CSDN博客

机器学习算法在训练过程中保存参数_Will_Ye的博客-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/4917.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

计算机网络名词解释和简答题总结

名词解释 CSMA/CD(载波监听多点接入/碰撞检测协议) CSMA/CD是一种基于冲突检测的载波监听多路访问技术。CSMA/CD协议要求站点在发送数据之前先监听信道。如果信道空闲,站点就可以发送数据;如果信道忙,则站点不能发送…

使用CookieJar提取cookie信息

首先,推荐几个帖子,大伙可以先看看。国内通过cookiejar主要获取cookie的方法,大致都是如此的。 http.cookiejar库之CookieJar_pigYanYan的博客-CSDN博客 Python编程:cookiejar的使用_彭世瑜的博客-CSDN博客 再推荐一个资料帖&a…

Linux权限

Linux下有两种用户:超级用户(root)、普通用户。超级用户(root):可以在linux系统下做任何事,不受限制,只有1个。普通用户:在linux系统下做有限的事,有N个。超级用户的提示符#;普通用户的提示符$切换用户的命令:su切换root时可以直接…

MQ之kafka

一 概念 Kafka是最初由Linkedin公司开发,是一个分布式、支持分区的(partition)、多副本的(replica),基于zookeeper协调的分布式消息系统,它的最大的特性就是可以实时的处理大量数据以满足各种需…

Visual Studio Code2023(VSCode2023)安装包下载及安装教程(最新版接入了chat GPT)

[软件名称]: Visual Studio Code2023 [软件大小]: 88.6 MB [安装环境]: Win11/Win10/Win7 [软件安装包下载]:https://pan.quark.cn/s/ee94a4aa2abc Visual Studio Code简称“VS Code”是Microsoft在2015年4月30日Build开发者大会上正式宣布一个运行于 Mac OS X、Windows和 Lin…

【Datawhale动手学深度学习笔记】多层感知机代码实践

多层感知机 激活函数 激活函数(activation function)通过计算加权和并加上偏置来确定神经元是否应该被激活, 它们将输入信号转换为输出的可微运算。 大多数激活函数都是非线性的。 由于激活函数是深度学习的基础,下面简要介绍一…

多线程进阶学习09------ThreadLocal详解

ThreadLocal:提供线程的局部变量,对于线程共享变量如果使用ThreadLocal则无需加锁,更省事省心。 ThreadLocal本地线程变量,线程自带的变量副本(实现了每一个线程副本都有一个专属的本地变量,主要解决的就是让每一个线程绑定自己的值,自己用自…

FastReport .NET 2023.2.4 Crack

FastReport .NET Reporting and documents creation library for .NET 7 FastReport .NET适用于 .NET 7、.NET Core、Blazor、ASP.NET、MVC 和 Windows Forms 的全功能报告库。它可以在微软视觉工作室 2022 和 JetBrains Rider 中使用。 利用 .NET 7、.NET Core、Blazor、ASP.N…

React:九、组件的生命周期

1.生命周期的理解 组件从创建到死亡它会经历一些特定的阶段。React组件中包含一系列勾子函数(生命周期回调函数), 会在特定的时刻调用。我们在定义组件时&#xff0c;会在特定的生命周期回调函数中&#xff0c;做特定的工作。2.生命周期小案例 <!DOCTYPE html> <html…

操作系统权限维持(十五)之Linux系统-inetd远程后门

系列文章 操作系统权限维持&#xff08;一&#xff09;之Windows系统-粘贴键后门 操作系统权限维持&#xff08;二&#xff09;之Windows系统-克隆账号维持后门 操作系统权限维持&#xff08;三&#xff09;之Windows系统-启动项维持后门 操作系统权限维持&#xff08;四&…

leaflet加载GPX文件,第2种图形显示方法(119)

第119个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+leaflet中加载GPX文件,将图形显示在地图上,这是另外一种方式,看前一种方式请从目录中查找。GPX文件是以GPS数据交换格式保存的GPS数据文件,是一种通用的地图信息文件,可以被众多GPS应用和Web服务更轻松地导入和…

Jenksin pipeline: 全局变量 和 input中的局部变量

在jenkins的流水线中全局变量的定义基本有两种实现方法&#xff1a;参数化构建过程中定义&#xff0c;流水线中直接定义 参数化构建过程中定义 流水线中直接定义(Jenkins 2.x支持代码及即服务) 可以用流水线生成 在配置parameters后&#xff0c;往往需要先构建一遍&#…

耗时 24 小时整理了网络安全学习路线,非常详细!

前言上次发的文章【都2023年了&#xff0c;还在问网络安全怎么入门】很多小伙伴在评论区回复不知道怎么学习&#xff0c;我也反思了一下&#xff0c;确实没写到学习方法和路线&#xff0c;所以这一期就出一一个怎么学习网络安全的学习路线和方法&#xff0c;觉得有用的话三连收…

软件测试入门简单么?入行后如何做职业规划

软件测试的确是入门相对简单的一个学科&#xff0c;他们不常写代码&#xff0c;主要去检查代码&#xff0c;是不是出现了漏洞、程序是否能运行下去&#xff1f;那这部分程序员就是做软件测试。 这个类别没有做Java难没有大数据那么复杂&#xff0c;但还可以拿到程序员的高薪。…

一招解决macOS12 CleanMyMac闪退

距全新的macOS 12 Monterey正式版发布已经过去了快6个月&#xff0c;macOS Monterey 12 新增了同播共享功能、 Apple Music 声控方案、“数字遗产”计划、“照片”中重新设计的“回忆”&#xff0c;以及针对 Mac 的其他功能和错误修复等大量更新和改进。 很多Mac用户也已经升级…

【模板】树状数组

目录&#xff1a; 单点修改&#xff0c;区间查询&#xff1a; 题目描述&#xff1a; lowbit()运算&#xff1a; 插入、修改单点数据&#xff1a; 计算前缀和&#xff1a; 完整代码&#xff1a; 区间修改&#xff0c;单点查询&#xff1a; 计算差分数组&#xff1a; 计算每个点的…

Node.js 入门

转载请注明出处&#xff0c;点击此处 查看更多精彩内容。 什么是 Node.js &#xff1f; Node.js 是一个基于 Chrome V8 引擎的开源的跨平台的 JavaScript 运行时环境。 Node.js 采用了基于事件的、单线程的异步 I/O 架构。 Node.js 的组成部分 V8引擎 V8 引擎就是 JavaScrip…

使用 React 和 GPT-4 技术构建智能语言翻译应用

Midjourney 创作&#xff0c;Language Translation in future在今天的互联世界中&#xff0c;语言翻译在弥合沟通差距和促进全球合作方面发挥着至关重要的作用。随着像 OpenAI 的 GPT-4 这样先进的 AI 模型的出现&#xff0c;我们现在有机会创建高度精确和上下文感知的翻译工具…

USB键盘实现——带指示灯的键盘(九)

文章目录带指示灯的键盘set_report 类特殊请求实现类特殊请求USB 控制端点收到的数据增加一个输出端点实现配置描述符集合输出端点收到的数据带指示灯的键盘 要实现带指示灯的键盘&#xff0c;有两种方式 除控制端点和输入端点外&#xff0c;不额外增加端点&#xff0c;根据 …

不完全微分算法(SCL+ST代码)

PID控制器的基本算法,可以参看专栏的系列文章,链接如下: 三菱FX3U PLC 位置式PID算法(ST语言)_fx3u pid_RXXW_Dor的博客-CSDN博客三菱PLC自带的PID不必多说,大家可以自行查看指令说明。关于FX3U 增量式PID可以参看专栏的另一篇博客三菱PLC增量式PID算法FB(带死区设置和外部…