适合入门深度学习的项目!!!搭建LeNet-5网络模型——2 训练模型搭建

上一节里,我们的网络模型放在一个名为net.py的文件里,这里我们调用它进行了模型的训练和测试,并将最优的模型保存在指定路径里。

详细注释的代码如下:

import torch
from torch import nn
from net import MyLeNet
from torch.optim import lr_scheduler  # 学习率经过多次会下降,使得学习率会变得更小
from torchvision import datasets, transforms
import os

# # 数据转换为tensor格式。数据刚拿到是矩阵(array)的格式,但神经网络里面需要张量(tensor)的格式
# data_transform = transforms.Compose(
#     [transforms.ToTensor]
# )
data_transform = transforms.ToTensor()

# 加载预训练的数据集
train_dataset = datasets.MNIST(root='./data',train=True,transform=data_transform,download=True)
train_dataloader = torch.utils.data.DataLoader(dataset = train_dataset,batch_size = 16, shuffle = True)

# 加载测集的数据
test_dataset = datasets.MNIST(root='./data',train=False,transform=data_transform,download=True)
test_dataloader = torch.utils.data.DataLoader(dataset = test_dataset,batch_size = 16, shuffle = True)

# 选择设备
# Get cpu, gpu or mps device for training.
device = (
    "cuda"
    if torch.cuda.is_available()
    else "mps"
    if torch.backends.mps.is_available()
    else "cpu"
)
print(f"Using {device} device")

# 调用net(1 网络模型的文件)里面定义的模型,将模型数据转到GPU
model = MyLeNet().to(device)

# 定义一个损失函数(交叉熵)
loss_fn = nn.CrossEntropyLoss()

# 定义一个优化器(随机梯度下降)

# SGD(需要反向传播的参数,学习率,momentum动量)
# momentum 动量是依据物理学的势能与动能之间能量转换原理提出来的。
# 当 momentum 动量越大时,其转换为势能的能量也就越大,就越有可能摆脱局部凹域的束缚,进入全局凹域。
# 大概意思就是:在随机梯度下降的过程中,一开始的幅度会很大,如果加上该动量
# 梯度下降的方向上会缓慢下降,容易找到我们需要的最低点,更好收敛
optimizer = torch.optim.SGD(model.parameters(), lr=1e-3, momentum=0.9)

# 当学习率(Learning Rate,lr)设置的过小时,收敛过程将变得十分缓慢;
# 而当lr设置的过大时,梯度可能会在最小值附近来回震荡,甚至可能无法收敛。
# 合理的lr调整可以在梯度下降过程防止抖动比较大,越往后面学,学习率越小越容易找到最小点,越好收敛
# 学习率调整有离散下降、指数减缓、分数减缓这三种常用方法。参考:http://t.csdn.cn/UkBFJ

# 这里我们采用离散下降:每过10轮,lr变为原来的0.1
lr_scheduler = lr_scheduler.StepLR(optimizer,step_size=10,gamma=0.1)

# 定义训练函数
def train(dataloader, model, loss_fn, optimizer):
    loss, correct, n = 0.0, 0.0, 0
    # 批次,数据(eg:图片,标签)
    for batch,(X,y) in enumerate(dataloader):
        # 1.前向传播

        # 先传入指定设备中
        X,y = X.to(device),y.to(device)
        output = model(X)

        # 损失函数——交叉熵,(输出值,真实的lable),用于反向传播
        cur_loss = loss_fn(output, y)

        # 用于后面计算loss值
        _, pred = torch.max(output, axis = 1)

        # 一组数据有16个批次——output.shape[0]
        # 其中准确的批次数——torch.sum(y == pred)
        cur_acc = torch.sum(y == pred)/output.shape[0]

        # 2.反向传播
        optimizer.zero_grad() # 梯度清零
        cur_loss.backward() # loss值越大反向传播力度越大,loss值越小说明效果越好
        optimizer.step() #梯度更新

        # 计算每一batch的loss
        # item():取出单元素张量的元素值并返回该值,保持原元素类型不变
        loss += cur_loss.item()
        correct +=  cur_acc.item()
        # 统计n,计算平均精确度
        n = n + 1
    loss /= n
    correct /= n
    print(f"Test Error: \n Train Accuracy: {(100 * correct):>0.1f}%, Train Avg_loss: {loss:>8f} \n")

# 定义测试函数
def val(dataloader, model, loss_fn):
    model.eval() # 验证模式
    loss, correct, n = 0.0, 0.0, 0
    # 模型不参与更新,用with torch.no_grad()
    # 验证集的时候,我们只是想看一下训练的效果,并不是想通过验证集来更新网络时
    # 使用该语句不会影响之前的量
    with torch.no_grad():
        for batch,(X,y) in enumerate(dataloader):
            # 1.前向传播(和train内容相似)
            X,y = X.to(device),y.to(device)
            output = model(X)
            cur_loss = loss_fn(output, y)
            _, pred = torch.max(output, axis = 1)
            cur_acc = torch.sum(y == pred)/output.shape[0]
            # 2.测试里没有反向传播去更新参数奥
            loss += cur_loss.item()
            correct +=  cur_acc.item()
            # 统计n,计算平均精确度
            n = n + 1
        loss /= n
        correct /= n
        print(f"Test Error: \n Val Accuracy: {(100 * correct):>0.1f}%, Val Avg_loss: {loss:>8f} \n")
        # 返回精确度,用以保存指定效果精确度的模型
        return correct
# 训练
epochs = 50
max_acc = 0
for t in range(epochs):
    print(f"Epoch {t + 1}\n-------------------------------")
    train(train_dataloader, model, loss_fn, optimizer)
    a = val(test_dataloader, model, loss_fn)
    # 保存最好的模型权重
    if a > max_acc:
        folder = 'save_model'
        if not os.path.exists(folder):
            os.mkdir('save_model')
        min_acc = a
        print('save best model')
        torch.save(model.state_dict(),'save_model/best.pth')
print("Done!")

经过50个epoch的训练,模型达到了98.2%的准确率:

 参考:B站视频 【从0开始撸代码--手把手教你搭建LeNet-5网络模型】

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
《零基础入门深度学习(5) - 循环神经网络.pdf》是一本介绍深度学习中的循环神经网络的学习指南。循环神经网络是一种能够处理时间序列数据的机器学习模型,广泛应用于语言处理、自然语言生成、图像处理等领域。 该书以零基础入门为出发点,逐步介绍了深度学习和循环神经网络的基本概念和原理,并通过实例演示了如何使用Python和常见的深度学习框架来构建和训练循环神经网络模型。 书中首先介绍了循环神经网络的基本结构和原理,包括循环单元的作用和实现方式。然后详细介绍了常见的循环神经网络模型,如LSTM和GRU,并解释了它们在处理长序列数据时的优势。 接下来,书中提供了大量的代码实例,帮助读者了解如何使用Python和深度学习框架来构建循环神经网络模型。这些实例包括文本情感分析、机器翻译、股票预测等应用场景,涵盖了循环神经网络在不同领域中的应用。 此外,该书还提供了一些常用的训练技巧和调参方法,帮助读者提高模型的性能和稳定性。最后,书中还介绍了一些最新的研究进展和发展趋势,帮助读者了解循环神经网络领域的最新动态。 总之,该书通过简单易懂的语言、清晰的实例和详细的代码解释,帮助读者快速入门深度学习中的循环神经网络。无论是初学者还是有一定基础的读者,都能从中获得实用的知识和技能,为在深度学习领域取得进一步的研究和实践打下坚实的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值