【深度学习】卷积神经网络(LeNet)【文章重新修改中】

卷积神经网络 LeNet

  • 前言
  • LeNet 模型
  • 代码实现
    • MINST
      • 代码分块解析
        • 1 构建 LeNet 网络结构
        • 2 加载数据集
        • 3 初始化模型和优化器
        • 4 训练模型
        • 5 训练完成
      • 完整代码
    • Fashion-MINST
      • 代码分块解析
        • 1 构建 LeNet 网络结构
        • 2 初始化模型参数
        • 3 加载数据集
        • 4 定义损失函数和优化器
        • 5 训练模型
      • 完整代码
  • 参考与更多阅读材料

前言

全连接神经网络,也称多层感知机, M L P MLP MLP,是深度学习最基本的神经网络之一。它包含输入层,多个隐藏层和输出层,每一层都与前一层的每个神经元相连接。尽管全连接神经网络具有一定的表达能力,其并不是解决所有问题的最佳工具。

e . g . e.g. e.g. 假设我们有一张 1000 ∗ 1000 1000 * 1000 10001000 像素的彩色照片,假设全连接层输出个数为 256 256 256,那么该层权重参数的形状是 3000000 ∗ 256 3 000 000 * 256 3000000256,即会占用 3 G B 3GB 3GB 的内存或显存。会导致复杂的模型与过高的存储开销。

在这里插入图片描述

卷积层试图解决这个问题。卷积层通过滑动窗口将同一卷积核与不同位置的输入重复计算,从而避免参数尺寸过大。而卷积神经网络,就是包含卷积层的网络。

LeNet 作为早期用来识别手写数字图像的卷积神经网络,名称来源于 Yann LeCun。其展示了通过梯度下降训练卷积神经网络可以达到手写数字识别在当时最先进的结果。


LeNet 模型

在这里插入图片描述

LeNet 模型分为卷积层块和全连接层块两个部分;

卷积层块里的基本单位是卷积层后接最大池化层:卷积层用来识别图像里的空间模式,如线条和物体局部,之后的最大池化层则是用来降低卷积层对位置的敏感性。卷积层,由这两个基本单位重复堆叠构成。

在这里插入图片描述

具体来说,在每个卷积层块中,每个卷积层都使用 5 ∗ 5 5*5 55 的窗口,并在输出上使用 s i g m o i d sigmoid sigmoid 激活函数;第一个卷积层输出通道数为 6 6 6,第二个卷积层输出通道数增加到 16 16 16。卷积层块的两个最大池化层的窗口形状均为 2 ∗ 2 2*2 22,且步幅为 2 2 2


代码实现

MINST

在这里插入图片描述

代码分块解析

1 构建 LeNet 网络结构
class LeNet(nn.Module):def __init__(self):super(LeNet, self).__init__()self.conv1 = nn.Conv2d(1, 6, 5)   # 1个输入通道,6个输出通道,卷积核大小为5x5self.pool = nn.MaxPool2d(2, 2)   # 最大池化层,2x2窗口self.conv2 = nn.Conv2d(6, 16, 5)  # 6个输入通道,16个输出通道,卷积核大小为5x5self.fc1 = nn.Linear(16*4*4, 120) # 全连接层1self.fc2 = nn.Linear(120, 84)     # 全连接层2self.fc3 = nn.Linear(84, 10)      # 输出层,10个类别def forward(self, x):x = self.pool(torch.relu(self.conv1(x)))x = self.pool(torch.relu(self.conv2(x)))x = x.view(-1, 16*4*4)x = torch.relu(self.fc1(x))x = torch.relu(self.fc2(x))x = self.fc3(x)x = torch.softmax(x, dim=1)return x

- 代码解释
super(LeNet, self).__init__() 是 python 中用于调用父类(或超类)的构造函数的一种方式。在上述定义中,用于在子类 LeNet 的构造函数中调用父类 nn.model 的构造函数。

具体来说:

  1. super(LeNet, self) 使用了 super() 函数创建了一个与子类 LeNet 相关联的 super 对象。这个 super 对象可以用来访问父类的方法和属性。
  2. .__init__() 调用 super 对象的构造函数,即调用父类 nn.model 的构造函数。确保子类 super 继承父类 nn.model 的所有属性和方法。

总之,super(LeNet, self).__init__() 目的是在子类 LeNet 的构造函数中初始化父类 nn.model。这是面向对象编程中用于构建继承层次结构中的子类。

- 代码解释
forward(self, x) 是神经网络中定义前向传播的方法。这个方法定义了一个张量 x,按照 LeNet 网络的结构将其传递给不同层,最终计算出网络的输出。

具体来说:

  1. x = self.pool(torch.relu(self.conv1(x))) 首先,输入 x 经过第一个卷积层 self.conv1(x),然后使用 ReLU 激活函数进行激活,接着使用 self.pool 进行最大池化操作;
  2. x = self.pool(torch.relu(self.conv2(x))) 然后,将前一步的输出再次经过第二个卷积层 self.conv2,然后使用 ReLU 激活函数进行激活,接着使用 self.pool 进行最大池化操作;
  3. x = x.view(-1, 16*5*5) 在进入到全连接层前,需要将池化层的输出展平为一维向量,通过 view 函数实现方法:
    e . g . e.g. e.g. 如果 x 的形状是 [ 64 , 16 , 5 , 5 ] [64, 16, 5, 5] [64,16,5,5](其中 batch_size 是 64,num_channels 是16,height 和 width 都是 5 ),那么 x.view(-1, 16 * 5 * 5) 将会将 x 的形状调整为 [ 64 , 16 ∗ 5 ∗ 5 ] [64, 16 * 5 * 5] [64,1655],也就是 [ 64 , 400 ] [64, 400] [64,400],作为全连接层的输入。
  4. x = torch.relu(self.fc1(x)) 将展平后的数据传递给第一个全连接层 self.fc1,然后使用 ReLU 函数进行激活;
  5. x = torch.relu(self.fc2(x)) 将第一个全连接层的输出传递给第二个全连接层 self.fc2,然后使用 ReLU 函数进行激活;
  6. x = self.fc3(x) x = torch.softmax(x, dim=1) 最后将第二个全连接层的输出传递给输出层 self.fc3,使用 softmax 获得概率分布;Softmax 将网络的原始输出值转化为 0 到 1 之间的概率值,以表示每个类别的预测概率。

2 加载数据集
# 数据标准化处理
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,))])
# 加载数据集
trainset = torchvision.datasets.MNIST(root='./data', train=True, download=True, transform=transform)
# 创建数据加载器 Loader
trainloader = torch.utils.data.DataLoader(trainset, batch_size=64, shuffle=True)

- 代码解释
transforms.ToTensor() 将图像从 PIL 图像对象转换为 PyTorch 张量,深度学习模型使用张量作为输入;

- 代码解释
transforms.Normalize((0.5,), (0.5,)) 对图像进行归一化操作。
参数 (0.5,)(0.5,) 表示均值和标准差,将图像像素值从 0 到 255 缩放到 -1 到 1 之间,以加速模型的训练过程。对于 MINST 数据集来说,因为只有一个通道(灰度图像),因此只有一个均值和一个标准差。


3 初始化模型和优化器
# 实例化网络对象
net = LeNet()
# 损失函数使用交叉熵损失函数
criterion = nn.CrossEntropyLoss()
# 优化器,使用随机梯度下降
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)

- 代码解释
CrossEntropyLoss() 交叉熵损失函数:通常用于多类别分类任务,例如图像分类。

- 代码解释
optim.SGD 即使用随机梯度下降作为优化器,SGD(Stochastic Gradient Descend)
net.parameters() 代表优化器会将神经网络中所有可学习参数不断更新权重;
lr 即 learning rate 学习率,控制优化器每次权重更新的步长;
momentum=0.9 动量,关于动量的概念将在后期单独出一期博文解析,读者在这里可以得知的是动量是一种加速优化过程的技巧,有助于跳出局部最小值。


4 训练模型
for epoch in range(10):  	# 遍历数据集 10 次running_loss = 0.0		# 损失值for i, data in enumerate(trainloader, 0):# 每个批次中,数据data包含了输入inputs和相应的标签labelsinputs, labels = data# zero_grad 方法将优化器中的梯度清零,计算新的梯度optimizer.zero_grad()# 将输入数据传递给神经网络 net 进行前向传播,计算模型的输出 outputsoutputs = net(inputs)# 计算模型的输出与真实标签之间的损失loss = criterion(outputs, labels)# 根据损失值计算梯度,使用反向传播算法loss.backward()# 使用优化器 optimizer 更新网络的参数,减小损失值optimizer.step()# 将损失值累积到 running_loss 中running_loss += loss.item()if i % 200 == 199:  # 每 200 批次打印一次损失# {i + 1:5d} 是一种字符串格式化的语法,用于将整数 i + 1 格式化为宽度为5的右对齐整数。print(f'[{epoch + 1}, {i + 1:5d}] loss: {running_loss / 200:.3f}')running_loss = 0.0

5 训练完成
print('Finished Training')

完整代码

import torch
import torch.nn as nn
import torch.optim as optim
import torchvision
import torchvision.transforms as transforms# 定义LeNet模型
class LeNet(nn.Module):def __init__(self):super(LeNet, self).__init__()self.conv1 = nn.Conv2d(1, 6, 5)   # 1个输入通道,6个输出通道,卷积核大小为5x5self.pool = nn.MaxPool2d(2, 2)   # 最大池化层,2x2窗口self.conv2 = nn.Conv2d(6, 16, 5)  # 6个输入通道,16个输出通道,卷积核大小为5x5self.fc1 = nn.Linear(16*4*4, 120) # 全连接层1self.fc2 = nn.Linear(120, 84)     # 全连接层2self.fc3 = nn.Linear(84, 10)      # 输出层,10个类别def forward(self, x):x = self.pool(torch.relu(self.conv1(x)))x = self.pool(torch.relu(self.conv2(x)))x = x.view(-1, 16*4*4)x = torch.relu(self.fc1(x))x = torch.relu(self.fc2(x))x = self.fc3(x)x = torch.softmax(x, dim=1)return x# 加载数据集
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,))])
trainset = torchvision.datasets.MNIST(root='./data', train=True, download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=64, shuffle=True)# 初始化模型和优化器
net = LeNet()
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)# 训练模型
for epoch in range(10):  # 遍历数据集10次running_loss = 0.0for i, data in enumerate(trainloader, 0):inputs, labels = dataoptimizer.zero_grad()outputs = net(inputs)loss = criterion(outputs, labels)loss.backward()optimizer.step()running_loss += loss.item()if i % 200 == 199:  # 每200批次打印一次损失print(f'[{epoch + 1}, {i + 1:5d}] loss: {running_loss / 200:.3f}')running_loss = 0.0print('Finished Training')

Fashion-MINST

在这里插入图片描述

代码分块解析

1 构建 LeNet 网络结构
net = nn.Sequential()
net.add(nn.Conv2D(channels=6, kernel_size=5, activation='sigmoid'),nn.MaxPool2D(pool_size=2, strides=2),nn.Conv2D(channels=16, kernel_size=5, activation='sigmoid'),nn.MaxPool2D(pool_size=2, strides=2),nn.Dense(120, activation='sigmoid'),nn.Dense(84, activation='sigmoid'),nn.Dense(10)
)

使用 nn.Sequential() 创建 LeNet 模型,包括卷积层、池化层和全连接层,其中激活函数为 sigmoid。


2 初始化模型参数
ctx = d2l.try_gpu()
# force_reinit在初始化之前强制重新初始化模型参数
# init.Xavier有助于避免梯度消失和梯度爆炸,提高模型的收敛速度
net.initialize(force_reinit=True, ctx=ctx, init=init.Xavier())

3 加载数据集
# 加载Fashion-MNIST数据集
batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size=batch_size, resize=96)

4 定义损失函数和优化器
# 定义损失函数和优化器
loss = gloss.SoftmaxCrossEntropyLoss()
trainer = gluon.Trainer(net.collect_params(), 'sgd', {'learning_rate': 0.9})

使用交叉熵损失函数来计算损失,使用梯度随机下降优化器 sgd 进行模型参数的优化。


5 训练模型
# 训练模型
num_epochs = 10
d2l.train_ch5(net, train_iter, test_iter, batch_size, trainer, ctx, num_epochs)

完整代码

import d2lzh as d2l
from mxnet import autograd, gluon, init, nd
from mxnet.gluon import loss as gloss, nn# 定义LeNet模型
net = nn.Sequential()
net.add(nn.Conv2D(channels=6, kernel_size=5, activation='sigmoid'),nn.MaxPool2D(pool_size=2, strides=2),nn.Conv2D(channels=16, kernel_size=5, activation='sigmoid'),nn.MaxPool2D(pool_size=2, strides=2),nn.Dense(120, activation='sigmoid'),nn.Dense(84, activation='sigmoid'),nn.Dense(10)
)# 初始化模型参数
ctx = d2l.try_gpu()
net.initialize(force_reinit=True, ctx=ctx, init=init.Xavier())# 加载Fashion-MNIST数据集
batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size=batch_size, resize=96)# 定义损失函数和优化器
loss = gloss.SoftmaxCrossEntropyLoss()
trainer = gluon.Trainer(net.collect_params(), 'sgd', {'learning_rate': 0.9})# 训练模型
num_epochs = 10
d2l.train_ch5(net, train_iter, test_iter, batch_size, trainer, ctx, num_epochs)

参考与更多阅读材料

  • https://www.analyticsvidhya.com/blog/2021/03/the-architecture-of-lenet-5/
  • https://zhuanlan.zhihu.com/p/459616884

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

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

相关文章

云服务器ECS_云主机_服务器托管_计算-阿里云

阿里云服务器是什么?云服务器ECS是一种安全可靠、弹性可伸缩的云计算服务,云服务器可以降低IT成本提升运维效率,免去企业或个人前期采购IT硬件的成本,阿里云服务器让用户像使用水、电、天然气等公共资源一样便捷、高效地使用服务器…

新手怎样快速上手接口测试?掌握这几个知识点直接起飞!

接口测试是测试系统组件间接口的一种方式,接口测试主要用于检测外部系统与系统之间以及内部各个子系统之间的交互点。测试的重点是检查数据的增删改查操作,以及系统之间的逻辑关系等 接口的几种类型 接口的类型包括:post ,get&am…

沉积物微体古生物鉴定

声明 本文是学习GB-T 42629.4-2023 国际海底区域和公海环境调查规程 第4部分:海洋沉积物物理特性调查. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 本文件规定了国际海底区域和公海环境调查中的沉积物组成、物理力学性质、生物…

【C++】unordered_map与unorder_set的封装(哈希桶)

文章目录 前言一、模板参数的改造二、模板的特例化操作三、仿函数的妙用四、unordered迭代器基本操作1.const迭代器注意:2.HashTable与HTIterator的冲突 五、迭代器的构造问题六、完整代码1.hash_bucket.h2.unordered_set.h3.unordered_map.h 前言 我们开辟一个指针…

使用LDA(线性判别公式)进行iris鸢尾花的分类

线性判别分析((Linear Discriminant Analysis ,简称 LDA)是一种经典的线性学习方法,在二分类问题上因为最早由 [Fisher,1936] 提出,亦称 ”Fisher 判别分析“。并且LDA也是一种监督学习的降维技术,也就是说它的数据集的每个样本都…

驱动开发--汇总

一,【驱动相关概念】 1,什么是驱动 能够驱使硬件实现特定功能的软件代码 根据驱动程序是否依赖于系统内核将驱动分为裸机驱动和系统驱动 2,逻辑驱动和系统驱动的区别 裸机驱动:编写的驱动代码中没有进行任何内核相关API的调用…

Flutter插件的制作和发布

Flutter制作插件有两种方式(以下以android和ios为例): 目录 1.直接在主工程下的android和ios项目内写插件代码:2.创建独立Flutter Plugin项目,制作各端插件后,再引入项目:1. 创建Flutter Plugin…

Webpack打包CSS文件,解决You may need an appropriate loader to handle this file type报错

在项目文件夹下创建webpack.config.js文件,该文件就是Webpack的配置文件 注意:该文件中遵循Node.js的代码格式规范 ,需要对导出配置文件中的内容 Webpack在默认情况下只能打包js文件,如果我们希望他能够打包其他类型的文件&#…

物联网安全优秀实践:2023年设备保护指南

物联网的发展可谓是革命性的,数十亿台设备实时互连、通信和共享数据。因此,考虑物联网安全的最佳实践至关重要。 物联网的重要性日益上升 在数字时代,物联网(IoT)已成为一股革命力量,重塑了企业运营和个人生活方式。从调节家庭温…

堆的OJ题

🔥🔥 欢迎来到小林的博客!!       🛰️博客主页:✈️林 子       🛰️博客专栏:✈️ 小林的算法笔记       🛰️社区 :✈️ 进步学堂       &am…

中国数据库走向国际的门槛: 15分钟准则

在十五分钟之内跑通第一条SQL 笔者曾经负责国内某Top云厂商的数据库的海外业务和产品设计。简单的说包括TP,AP,NoSQL和Utility的所有数据库相关产品,负责除中国大陆以外所有的业务和客户。三年时间撞墙的教训实在不少。 在官方宣传上&#…

Scala 高阶:Scala中的模式匹配

一、概述 Scala中的模式匹配(case)类似于Java中的switch...case,但是Scala的模式匹配功能更为强大。通过模式匹配,可以匹配更复杂的条件和数据结构,包括常量、类型、集合、元组等。而 Java 的 switch 语句只能用于匹配…

算法分析与设计编程题 贪心算法

活动安排问题 题目描述 解题代码 vector<bool> greedySelector(vector<vector<int>>& intervals) {int n intervals.size();// 将活动区间按结束时间的从小到大排序auto cmp [](vector<int>& interval1, vector<int>& interval2…

YOLOv5,YOLOv8添加ASFF(自适应空间特征融合)

ASFF&#xff1a;Adaptively Spatial Feature Fusion (自适应空间特征融合) 论文来源&#xff1a;Learning Spatial Fusion for Single-Shot Object Detection 代码地址&#xff1a;ASFF 1.背景 不同特征尺度之间的不一致性是基于特征金字塔的单阶段检测器的主要缺陷。 本文…

【VastbaseG100】 FATAL: The account has been locked.

使用VastbaseG100 数据库&#xff0c;查询数据报错。 org.postgresql.util.PSQLException: FATAL: The account has been locked. 帐户已被锁定。 解锁账户呗 ALTER ROLE doc ACCOUNT UNLOCK;ALTER ROLE 用户名 ACCOUNT UNLOCK; 修改密码 ALTER ROLE doc IDENTIFIED BY ZhangS…

Git小乌龟不弹add push commit的方法

1.关于使用Git小乌龟无法弹出Add菜单的问题 第一次使用小乌龟软件&#xff0c;发现可以正常将程序从Gitee仓库中克隆到本地&#xff0c;但是在将本地的程序上传到Gitee仓库中时&#xff0c;TortoiseGit无法弹出Add那一系列菜单&#xff0c;如下图所示&#xff1a; 2.解决方法 …

开源日报 0821:帮你修复老旧照片

这篇文章总结了几个开源项目的特点和优势。其中包括了 Python 资源列表、金融研究工具、动画精灵程序、游戏和旧照片修复项目等。这些项目提供了丰富的功能和技术支持&#xff0c;用户可以根据自己的需求进行定制和改进。总的来说&#xff0c;这些开源项目为开发者和用户提供了…

安防视频/视频汇聚平台EasyCVR使用onvif探测添加设备通道详细步骤来啦!

视频云存储/安防监控EasyCVR视频汇聚平台基于云边端智能协同&#xff0c;支持海量视频的轻量化接入与汇聚、转码与处理、全网智能分发、视频集中存储等。音视频流媒体视频平台EasyCVR拓展性强&#xff0c;视频能力丰富&#xff0c;具体可实现视频监控直播、视频轮播、视频录像、…

大数据学习1.1-Centos8虚拟机安装

1.创建新的虚拟机 2.选择稍后安装OS 3.选择Linux的CentOS8 4.选择安装路径 5.分配20g存储空间 6.自定义硬件 7.分配2g内存 8.分配2核处理器 9.选择镜像位置 10.开启虚拟机安装 推荐密码设置为root

WebGL 用鼠标控制物体旋转

目录 鼠标控制物体旋转 如何实现物体旋转 示例程序&#xff08;RotateObject.js&#xff09; 代码详解 示例效果 鼠标控制物体旋转 有时候&#xff0c;WebGL程序需要让用户通过鼠标操作三维物体。这一节来分析示例程序RotateObject&#xff0c;该程序允许用户通过拖动&…