深度学习-LeNet(第一个卷积神经网络)

news2024/11/24 13:55:04

文章目录

  • 简介
  • 数据集
  • 模型搭建
  • 模型训练
  • 模型测试

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。

简介


LeNet模型是在1998年提出的一种图像分类模型,应用于支票或邮件编码上的手写数字的识别,也被认为是最早的卷积神经网络(CNN),为后续CNN的发展奠定了基础,作者LeCun Y也被誉为卷积神经网络之父。LeNet之后一直直到2012年的AlexNet模型在ImageNet比赛上表现优秀,使得沉寂了14年的卷积神经网络再次成为研究热点。

LeCun Y, Bottou L, Bengio Y, et al. Gradient-based learning applied to document recognition[J]. Proceedings of the IEEE, 1998, 86(11): 2278-2324.

LeNet模型结构如下:
在这里插入图片描述

  • INPUT(输入层)
    输入图像的尺寸为32X32,是单通道的灰色图像。
  • C1(卷积层)
    使用了6个大小为5×5的卷积核,步长为1,卷积后得到6张28×28的特征图。
  • S2(池化层)
    使用了6个2×2 的平均池化,步长为2,池化后得到6张14×14的特征图。
  • C3(卷积层)
    使用了16个大小为5×5的卷积核,步长为1,得到 16 张10×10的特征图。
    由于是多个卷积核对应多个输入,论文中采用了如下组合方式:
    在这里插入图片描述
  • S4(池化层)
    使用16个2×2的平均池化,步长为2,池化后得到16张5×5 的特征图。
  • C5(卷积层)
    使用120个大小为5×5的卷积核,步长为1,卷积后得到120张1×1的特征图。
  • F6(全连接层)
    输入维度120,输出维度是84(对应7x12 的比特图)。
  • OUTPUT(输出层)
    使用高斯核函数,输入维度84,输出维度是10(对应数字 0 到 9)。

数据集


使用torchversion内置的MNIST数据集,训练集大小60000,测试集大小10000,图像大小是1×28×28,包括数字0~9共10个类。官网:http://yann.lecun.com/exdb/mnist/

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

mnist_train = torchvision.datasets.MNIST(root='./datasets/',
                                         train=True, download=True, transform=transforms.ToTensor())
mnist_test = torchvision.datasets.MNIST(root='./datasets/',
                                        train=False, download=True, transform=transforms.ToTensor())
print(len(mnist_train), len(mnist_test))  # 打印训练/测试集大小
feature, label = mnist_train[0]
print(feature.shape, label)  # 打印图像大小和标签
dataloader = DataLoader(mnist_test, batch_size=64, num_workers=0)  # 每次批量加载64张
step = 0
writer = SummaryWriter(log_dir='runs/mnist')  # 可视化
for data in dataloader:
    features, labels = data
    writer.add_images(tag='train', img_tensor=features, global_step=step)
    step += 1
writer.close()

在这里插入图片描述
在这里插入图片描述

可视化部分可参考我这篇博客:深度学习-Tensorboard可视化面板

此外,还可以使用torchversion内置的FashionMNIST数据集,包括衣服、包等10类图像,也是1×28×28,各60000、10000张。

模型搭建


使用Pytoch进行搭建和测试。

import torch
from torch import nn, optim


class LeNet(nn.Module):

    def __init__(self) -> None:
        super().__init__()
        self.model = nn.Sequential(  # (-1,1,28,28)
            nn.Conv2d(in_channels=1, out_channels=6, kernel_size=5, padding=2),  # (-1,6,28,28)
            nn.Sigmoid(),
            nn.AvgPool2d(kernel_size=2, stride=2),  # (-1,6,14,14)
            nn.Conv2d(in_channels=6, out_channels=16, kernel_size=5),  # (-1,16,10,10)
            nn.Sigmoid(),
            nn.AvgPool2d(kernel_size=2, stride=2),  # (-1,16,5,5)
            nn.Flatten(),
            nn.Linear(in_features=16 * 5 * 5, out_features=120),  # (-1,120)
            nn.Sigmoid(),
            nn.Linear(120, 84),  # (-1,84)
            nn.Sigmoid(),
            nn.Linear(in_features=84, out_features=10)  # (-1,10)
        )

    def forward(self, x):
        return self.model(x)


leNet = LeNet()
print(leNet)

在这里插入图片描述

模型训练


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


class LeNet(nn.Module):

    def __init__(self) -> None:
        super().__init__()
        self.model = nn.Sequential(  # (-1,1,28,28)
            nn.Conv2d(in_channels=1, out_channels=6, kernel_size=5, padding=2),  # (6,28,28)
            nn.Sigmoid(),
            nn.AvgPool2d(kernel_size=2, stride=2),  # (6,14,14)
            nn.Conv2d(in_channels=6, out_channels=16, kernel_size=5),  # (16,10,10)
            nn.Sigmoid(),
            nn.AvgPool2d(kernel_size=2, stride=2),  # (16,5,5)
            nn.Flatten(),
            nn.Linear(in_features=16 * 5 * 5, out_features=120),  # (-1,120)
            nn.Sigmoid(),
            nn.Linear(120, 84),  # (-1,84)
            nn.Sigmoid(),
            nn.Linear(in_features=84, out_features=10)  # (-1,10)
        )

    def forward(self, x):
        return self.model(x)


# 创建模型
leNet = LeNet()
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
leNet = leNet.to(device)  # 若支持GPU加速
# 损失函数
loss_fn = nn.CrossEntropyLoss()
loss_fn = loss_fn.to(device)
# 优化器
learning_rate = 1e-2
optimizer = torch.optim.Adam(leNet.parameters(), lr=learning_rate)
total_train_step = 0  # 总训练次数
total_test_step = 0  # 总测试次数
epoch = 10  # 训练轮数
writer = SummaryWriter(log_dir='runs/LeNet')  # 可视化
# 数据
mnist_train = torchvision.datasets.MNIST(root='./datasets/',
                                         train=True, download=True, transform=transforms.ToTensor())
mnist_test = torchvision.datasets.MNIST(root='./datasets/',
                                        train=False, download=True, transform=transforms.ToTensor())
dataloader_train = DataLoader(mnist_train, batch_size=256, num_workers=0)  # 每次批量加载256张
# 训练模型
for i in range(epoch):
    print("-----第{}轮训练开始-----".format(i + 1))
    leNet.train()  # 训练模式
    for data in dataloader_train:
        imgs, labels = data
        imgs = imgs.to(device)
        labels = labels.to(device)
        outputs = leNet(imgs)
        loss = loss_fn(outputs, labels)
        optimizer.zero_grad()  # 清空之前梯度
        loss.backward()  # 反向传播
        optimizer.step()  # 更新参数
        total_train_step += 1  # 更新步数
        print("训练次数:{}, Loss: {}".format(total_train_step, loss.item()))
        writer.add_scalar("train_loss", loss.item(), total_train_step)

writer.close()

插播反爬信息 )博主CSDN地址:https://wzlodq.blog.csdn.net/

在这里插入图片描述

由于打印了每轮各个批次64张图的损失,不同批次损失不同,所以上下震荡大,但总体仍是减少收敛的。

模型测试


	leNet.eval()  # 测试模式
    total_test_loss = 0  # 当前轮次模型测试所得损失
    total_accuracy = 0  # 当前轮次精确率
    with torch.no_grad():  # 关闭梯度反向传播
        for data in dataloader_test:
            imgs, targets = data
            imgs = imgs.to(device)
            targets = targets.to(device)
            outputs = leNet(imgs)
            loss = loss_fn(outputs, targets)
            total_test_loss = 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/len(mnist_test)))
    writer.add_scalar("test_loss", total_test_loss, total_test_step)
    writer.add_scalar("test_accuracy", total_accuracy/len(mnist_test), total_test_step)
    total_test_step = total_test_step + 1
    torch.save(leNet, "LeNet_{}.pth".format(i))  # 保存模型

在这里插入图片描述
随着训练轮数增加,对应模型测试的损失减少并收敛,最后有一点震荡向上,可能是过拟合了,问题不大。

在这里插入图片描述
精确率在5轮后就趋于98%以上,就是说感受到了来自98年的科技~

最后,附完整代码:

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


class LeNet(nn.Module):

    def __init__(self) -> None:
        super().__init__()
        self.model = nn.Sequential(  # (-1,1,28,28)
            nn.Conv2d(in_channels=1, out_channels=6, kernel_size=5, padding=2),  # (-1,6,28,28)
            nn.Sigmoid(),
            nn.AvgPool2d(kernel_size=2, stride=2),  # (-1,6,14,14)
            nn.Conv2d(in_channels=6, out_channels=16, kernel_size=5),  # (-1,16,10,10)
            nn.Sigmoid(),
            nn.AvgPool2d(kernel_size=2, stride=2),  # (-1,16,5,5)
            nn.Flatten(),
            nn.Linear(in_features=16 * 5 * 5, out_features=120),  # (-1,120)
            nn.Sigmoid(),
            nn.Linear(120, 84),  # (-1,84)
            nn.Sigmoid(),
            nn.Linear(in_features=84, out_features=10)  # (-1,10)
        )

    def forward(self, x):
        return self.model(x)


# 创建模型
leNet = LeNet()
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
leNet = leNet.to(device)  # 若支持GPU加速
# 损失函数
loss_fn = nn.CrossEntropyLoss()
loss_fn = loss_fn.to(device)
# 优化器
learning_rate = 1e-2
optimizer = torch.optim.Adam(leNet.parameters(), lr=learning_rate)
total_train_step = 0  # 总训练次数
total_test_step = 0  # 总测试次数
epoch = 10  # 训练轮数
writer = SummaryWriter(log_dir='runs/LeNet')  # 可视化
# 数据
mnist_train = torchvision.datasets.MNIST(root='./datasets/',
                                         train=True, download=True, transform=transforms.ToTensor())
mnist_test = torchvision.datasets.MNIST(root='./datasets/',
                                        train=False, download=True, transform=transforms.ToTensor())
dataloader_train = DataLoader(mnist_train, batch_size=64, num_workers=0)  # 每次批量加载64张
dataloader_test = DataLoader(mnist_test, batch_size=64, num_workers=0)  # 每次批量加载64张

for i in range(epoch):
    print("-----第{}轮训练开始-----".format(i + 1))
    leNet.train()  # 训练模式
    for data in dataloader_train:
        imgs, labels = data
        imgs = imgs.to(device)  # 适配GPU/CPU
        labels = labels.to(device)
        outputs = leNet(imgs)
        loss = loss_fn(outputs, labels)
        optimizer.zero_grad()  # 清空之前梯度
        loss.backward()  # 反向传播
        optimizer.step()  # 更新参数
        total_train_step += 1  # 更新步数
        if total_train_step % 100 ==0:  # 每100次可视化一下
            print("训练次数:{}, Loss: {}".format(total_train_step, loss.item()))
        writer.add_scalar("train_loss", loss.item(), total_train_step)

    leNet.eval()  # 测试模式
    total_test_loss = 0  # 当前轮次模型测试所得损失
    total_accuracy = 0  # 当前轮次精确率
    with torch.no_grad():  # 关闭梯度反向传播
        for data in dataloader_test:
            imgs, targets = data
            imgs = imgs.to(device)
            targets = targets.to(device)
            outputs = leNet(imgs)
            loss = loss_fn(outputs, targets)
            total_test_loss = 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/len(mnist_test)))
    writer.add_scalar("test_loss", total_test_loss, total_test_step)
    writer.add_scalar("test_accuracy", total_accuracy/len(mnist_test), total_test_step)
    total_test_step = total_test_step + 1
    torch.save(leNet, "LeNet_{}.pth".format(i))  # 保存模型
writer.close()

原创不易,请勿转载本不富裕的访问量雪上加霜
博主首页:https://wzlodq.blog.csdn.net/
来都来了,不评论两句吗👀
如果文章对你有帮助,记得一键三连❤

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

双模蓝牙MIDI模块BT401的功能简单描述和蓝牙MIDI协议

目录 一、蓝牙MIDI概念和功能简述 蓝牙MIDI,实际上是由苹果公司推广并且应用的,目的是借助于低功耗蓝牙来实现 主机和设备之间的无线连接 。协议的标准也是苹果定的。目前也充分的应用到安卓平台了 二、详细记录--功能说明 2.1 蓝牙MIDI的测试说明--m…

【笔记】计算机组成原理复习重点——篇三

计算机组成原理复习重点笔记 第二篇 计算机系统的硬件结构 第3章 系统总线第4章 存储器第5章 输入输出系统 第3章 系统总线 3.1 总线的基本概念 一、为什么要用总线 计算机的各个系统功能部件连在一起才能协同工作,部件之间不可能采用全互联形式&…

MATLB|基于复杂网络的配电系统微电网优化配置

目录 一、概述 二、系统研究 三、复杂网络框架 四、结果与讨论 五、Matlab代码实现 一、概述 多年来,各个领域的科学家开发了一套广泛的工具:数学、计算和统计,旨在分析、建模和理解网络。网络研究的基础可以追溯到图论的发展&#xff0…

第三方软件测试机构如何选择?

什么是软件产品检测报告? 软件测试机构根据委托方提供的测试需求,对软件进行功能性的检测,保证软件功能能正常运行。 软件产品登记测试也是申请软件产品登记的必要条件,对于买方来说,通过第三方检测机构出具的测试报告…

yolov5修改骨干网络-使用自己搭建的网络-以efficientnetv2为例

yolov5修改骨干网络–原网络说明 yolov5修改骨干网络-使用pytorch自带的网络-以Mobilenet和efficientnet为例 yolov5修改骨干网络-使用自己搭建的网络-以efficientnetv2为例 增加网络的深度depth能够得到更加丰富、复杂的特征并且能够很好的应用到其它任务中。但网络的深度过深…

全面适配 Android12

本文目录 背景技术分析实战总结与展望 背景 2021 年 10 月 5 日 Google 发布 Android12 操作系统,安全性和隐私性大幅提升,各手机厂家陆续更新 Android12 操作系统。 2022 年随着各大 APP 应用市场推动 Android12 适配工作,开发者积极响应…

应用性能监控管理工具

应用程序性能监控 Application Manager 的应用程序性能监控(APM Insight) 使应用程序开发人员和 DevOps 工程师能够了解应用程序性能,并帮助他们在问题影响最终用户之前对其进行故障排除。在应用程序性能问题影响收入之前监控、查明并解决它…

计算机毕设Python+Vue校园社团管理系统(程序+LW+部署)

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

PiL测试实战(下)| PiL阶段的闭环测试

前言 上篇我们介绍了单元级软件的PiL测试,对于集成级的PiL测试,其流程和单元阶段基本一致。然而,对于一些带有反馈控制逻辑的集成测试(如电机控制器MCU),PiL阶段会将控制算法(Controller Model…

HeidiSQL连接MySQL失败

HeidiSQL连接MySQL失败故障现象解决方案方案一方案二故障现象 在使用非本地盘的位置上的Heidi SQL工具,远程连接MySQL,发现连接失败,错误的原因是“plugin caching_sha2_password.dll could not be loaded”的解决办法。 解决方案 我们可…

Linux进度条小程序与git

gitLinux进度条小程序缓冲区问题回车换行倒计时小程序进度条程序git什么是gitgit的发展史git的基本操作创建仓库与本地仓库建立联系Linux中git提交代码的三板斧git基础指令Linux进度条小程序 缓冲区问题 编译运行后发现延迟了两秒才出现数字,我们都知道程序中的代码…

83-137-springcloud-stream-nacos-sentinel

83-137-springcloud-stream-nacos-sentinel: Stream 常见MQ(消息中间件):ActiveMQ,RabbitMQ,RocketMQ,Kafka Cloud Stream:屏蔽底层消息中间件的差异,降低切换成本,统一消息的编程…

WSL_02 WSL配置强大的 zsh

文章目录1 ZSH简介2 安装zsh2.1 准备阶段2 基础安装3 zsh更换主题3.1 使用vscode 打开 .zshrc4 自定义支持插件4.1 修改配置5 安装第三方插件autosuggestion5. 1 下载参考1 ZSH简介 zsh是Linux命令行界面,可以为帮助我们自定义配置命令行窗口,并且具有许…

vue引入iconfont/引入svg原理

前言 本文撰写的初衷是为了向组内成员推行使用svg sprites的方式管理项目的图标,由于实际工作中很多项目仍然采用font class的方式,这样不自觉带来一个痛点. 当项目一期开发完毕后,过段时间进入到项目二期。新增的开发需求不可避免的会增加新的图标,而font class需要全量打包…

Redis数据结构及命令详解

个人博客地址: http://xiaohe-blog.top/ 文章目录0. 简述1. 通用命令1.1 keys1.2 del1.3 type1.4 exists1.5 expire1.6 ttl2. string 类型2.1 set2.2 get2.3 mset2.4 mget2.5 setnx2.6 setex2.4 incr2.5 incrby2.6 incrbyfloat3. hash 类型3.1 hset3.2 hget3.3 hmse…

互联网时代,云计算的6大特征

1 云计算的定义 云计算是目前业内的热点概念,它以开放的标准和服务为基础,以互联网为中心,提供安全、快速、便捷的数据存储和网络计算服务,让互联网这片“云”上的各种计算机共同组成数个庞大的数据中心及计算中心。它可以被看成…

Observability:我们该选 Beats 还是 Elastic Agents 来采集数据?

除了 Logstash 之外,Elastic 提供了两种主要的方式来向 Elasticsearch 发送数据: 我们可以选择直接把数据从 Beats 发送至 Elasticsearch。当然我们也可以通过 Logstash 更进一步处理再发送至 Elasticsearch。 另外一种方式是使用 Elastic Agents 来发送…

[附源码]Nodejs计算机毕业设计基于的二手车交易平台Express(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程。欢迎交流 项目运行 环境配置: Node.js Vscode Mysql5.7 HBuilderXNavicat11VueExpress。 项目技术: Express框架 Node.js Vue 等等组成,B/S模式 Vscode管理前后端分…

[附源码]Python计算机毕业设计Django课室预约系统

项目运行 环境配置: Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术: django python Vue 等等组成,B/S模式 pychram管理等等。 环境需要 1.运行环境:最好是python3.7.7,…

Jmeter简单入门

背景 我们项目中一般测试接口都是用vscode中的REST Client插件(推荐好用)或者的话postman(适合写一些脚本和文件的上传) 但是他们都有一个不太行的功能,那就是多线程并发测试,其他市面上的什么apipost也都是不支持,网…