【深度学习】卷积神经网络(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 1000∗1000 像素的彩色照片,假设全连接层输出个数为 256 256 256,那么该层权重参数的形状是 3000000 ∗ 256 3 000 000 * 256 3000000∗256,即会占用 3 G B 3GB 3GB 的内存或显存。会导致复杂的模型与过高的存储开销。

卷积层试图解决这个问题。卷积层通过滑动窗口将同一卷积核与不同位置的输入重复计算,从而避免参数尺寸过大。而卷积神经网络,就是包含卷积层的网络。
LeNet 作为早期用来识别手写数字图像的卷积神经网络,名称来源于 Yann LeCun。其展示了通过梯度下降训练卷积神经网络可以达到手写数字识别在当时最先进的结果。
LeNet 模型

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

具体来说,在每个卷积层块中,每个卷积层都使用 5 ∗ 5 5*5 5∗5 的窗口,并在输出上使用 s i g m o i d sigmoid sigmoid 激活函数;第一个卷积层输出通道数为 6 6 6,第二个卷积层输出通道数增加到 16 16 16。卷积层块的两个最大池化层的窗口形状均为 2 ∗ 2 2*2 2∗2,且步幅为 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 的构造函数。
具体来说:
super(LeNet, self)使用了super()函数创建了一个与子类LeNet相关联的super对象。这个super对象可以用来访问父类的方法和属性。.__init__()调用super对象的构造函数,即调用父类nn.model的构造函数。确保子类super继承父类nn.model的所有属性和方法。
总之,super(LeNet, self).__init__() 目的是在子类 LeNet 的构造函数中初始化父类 nn.model。这是面向对象编程中用于构建继承层次结构中的子类。
- 代码解释
forward(self, x) 是神经网络中定义前向传播的方法。这个方法定义了一个张量 x,按照 LeNet 网络的结构将其传递给不同层,最终计算出网络的输出。
具体来说:
x = self.pool(torch.relu(self.conv1(x)))首先,输入x经过第一个卷积层self.conv1(x),然后使用 ReLU 激活函数进行激活,接着使用self.pool进行最大池化操作;x = self.pool(torch.relu(self.conv2(x)))然后,将前一步的输出再次经过第二个卷积层self.conv2,然后使用 ReLU 激活函数进行激活,接着使用self.pool进行最大池化操作;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,16∗5∗5],也就是 [ 64 , 400 ] [64, 400] [64,400],作为全连接层的输入。x = torch.relu(self.fc1(x))将展平后的数据传递给第一个全连接层self.fc1,然后使用 ReLU 函数进行激活;x = torch.relu(self.fc2(x))将第一个全连接层的输出传递给第二个全连接层self.fc2,然后使用 ReLU 函数进行激活;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
相关文章:
【深度学习】卷积神经网络(LeNet)
卷积神经网络 LeNet 前言LeNet 模型代码实现MINST代码分块解析1 构建 LeNet 网络结构2 加载数据集3 初始化模型和优化器4 训练模型5 训练完成 完整代码 Fashion-MINST代码分块解析1 构建 LeNet 网络结构2 初始化模型参数3 加载数据集4 定义损失函数和优化器5 训练模型 完整代码…...
什么是数据仓库,解释数据仓库的结构和ETL过程
1、什么是数据仓库,解释数据仓库的结构和ETL过程。 数据仓库是一种用于存储和管理数据的系统,它提供了一种统一的方式,将不同来源、不同格式和不同时间的数据集成在一起。数据仓库的结构如下: 主题域(Domain…...
无线通信网络
一、无线局域网 WLAN概念 WLAN(Wireless Local Area Network)无线局域网,目前大部分无线产品都是根据IEEE802.11标准开发。 IEEE802.11标准 名称发布时间工作频段调制技术数据速率802.111997年2.4GHz ISM频段DB/SK、DQPSK1Mbps、2Mbps802.11b1998年2.4GHz ISM频段CCK5.5Mbps…...
使用ElementPlus实现内嵌表格和内嵌分页
前言 有时遇到这样的需求,就是在表格里面嵌入一个表格,以及要求带有分页,这样在ElementPlus中很好实现。以下使用Vue2语法实现一个简单例子,毕竟Vue3兼容Vue2语法,若想要Vue3版本例子,简单改改就OK了。 一…...
flex弹性盒模型与阿里图标的使用
华子目录 flex布局flex布局原理flex使用三要素 阿里图标(字体) flex布局 相关学习网站:http://c.biancheng.net/css3/flex.html 1.flex是当前最主流的布局方式:用它布局起来更方便,取代了浮动的作用。 2.浮动布局有缺…...
linux 应用中offsetof ()是个啥?
#include <stdio.h> #include <stddef.h> // 需要包含 <stddef.h> 否则会有以下错误, 是因为找不到offsetof()而引起 // printf("age offset:%d\n",offsetof(Persion,age)); //main.cpp|11 col 43| error: expected primary-expression before …...
ununtu中vim的使用
插入命令 i:表示输入 退出命令 :w - 保存文件,不退出 vim :w file -将修改另外保存到 file 中,不退出 vim :w! -强制保存,不退出 vim :wq -保存文件,退出 vim :wq! -强制保存文件,退出 vim …...
SqlServer在尝试加载程序集 ID 65917 时 Microsoft .NET Framework 出错。服务器可能资源不足,或者不信任该程序集
问题:在尝试加载程序集 ID 65917 时 Microsoft .NET Framework 出错。服务器可能资源不足,或者不信任该程序集,因为它的 PERMISSION_SET 设置为 EXTERNAL_ACCESS 或 UNSAFE。 检查数据库属性:检查服务器是否信任该程序集 解决方法…...
Discourse 如何下载备份并恢复本地数据库
进入网站的备份界面,会看到当前所有的备份情况。 单击下载按钮。 需要注意的是,当你下载后,系统将会发送一个链接到你的邮箱地址中。 你可以使用邮箱地址中收到的链接进行数据下载。 下载链接 单击邮件中收到的下载链接地址进行下载。 下载…...
激光焊接汽车PP塑料配件透光率测试仪
随着汽车主机厂对车辆轻量化的需求越来越强烈,汽车零部件轻量化设计、制造也成为汽车零部件生产厂商的重要技术指标。零部件企业要实现产品的轻量化,在材料指定的情况下,要通过产品设计优化、产品壁厚减小和装配方式的优化来解决。使用PP材料…...
Android面试题汇总(二)
一、Java集合 1、谈谈 Java 中 List、Set 以及 Map 的区别? List:有序的,数据可以重复。。 Set:无序的,数据不能重复。 Map:键值对存储。键是唯一的,值不是唯一的。 2、谈谈 ArrayList 和 Link…...
最新模块化设计小程序系统源码完整版:开源可二开,支持DIY
随着互联网的快速发展,小程序已成为各行各业开展业务的重要工具。而模块化设计小程序系统源码完整版则是一种高效、灵活、易维护的解决方案。 分享一个最新的模块化设计小程序系统源码完整版,源码开源可二开,支持自由DIY设计,含完…...
edge扩展下载出现Download interrupted
一、Edge扩展下载失败无法下载网络问题完美解决方案 1.首先我们找到我的电脑双击我的电脑,找到C盘并打开C盘,并找到windows选项 双击打开windows并找到system32 2.双击打开system32并找到drivers 4.双击打开drivers找到etc选项 5.双击打开etc选项找到hos…...
Dokcer搭建Apache Guacamole堡垒机
一、什么是堡垒机 “堡垒机” 这个词通常指的是 “堡垒机器”(Bastion Host)的简称。堡垒机是一种计算机系统或网络设备,用于增强计算机网络的安全性。它在网络中充当一个重要的安全关口,通过限制对内部网络的访问,帮…...
【Spring Boot自动装配】
Spring Boot启动的时候会通过EnableAutoConfiguration注解找到META-INF/spring.factories配置文件中的所有自动配置类,并对其进行加载,而这些自动配置类都是以AutoConfiguration结尾来命名的,它实际上就是一个JavaConfig形式的Spring容器配置…...
windows彻底卸载unity
1.控制面板卸载 双击打开桌面的控制面板,选择卸载程序,选中Unity和UnityHub右击卸载。 2.清除unity的注册表 在运行中输入“regedit”双击打开注册表界面 删除 HKEY_CURRENT_USER\Software\Unity 下所有项 删除 HKEY_CURRENT_USER\Software\Unity Tec…...
Java项目-苍穹外卖-Day10-SpirngTask及WebSocket
文章目录 前言SpringTask介绍SpringTask_corn表达式Spring_Task入门案例 订单状态定时处理需求分析代码开发功能测试 WebScoket介绍入门案例 来单提醒需求分析代码开发功能测试 客户催单代码开发功能测试 前言 本章实现的业务功能 超时未支付订单自动取消,配送中订…...
Spring IOC 容器:掌握 Spring 的核心技术
Spring 是一个非常流行和强大的 Java 开发框架,它可以帮助我们简化和优化 Java 项目的开发过程。Spring 的核心技术之一就是 IOC(Inversion of Control,控制反转),它可以实现对象之间的解耦,让对象的创建和…...
python实现批量从excel列表显示图片网址中下载图片
遇到一个需求:给了一个excel表,里面有很多网址图片,要把图片下载到本地。手动操作的话就是在浏览器里输入网址,再图片另存为保存。这篇文章介绍一下使用python代码批量实现 第一步操作就是实现从网上下图片,这个用到了…...
java 单元测试Junit
所谓单元测试,就是针对最小的功能单元,编写测试代码对其进行正确性测试。为了测试更加方便,有一些第三方的公司或者组织提供了很好用的测试框架,给开发者使用。这里介绍一种Junit测试框架。Junit是第三方公司开源出来的࿰…...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...
java_网络服务相关_gateway_nacos_feign区别联系
1. spring-cloud-starter-gateway 作用:作为微服务架构的网关,统一入口,处理所有外部请求。 核心能力: 路由转发(基于路径、服务名等)过滤器(鉴权、限流、日志、Header 处理)支持负…...
Admin.Net中的消息通信SignalR解释
定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...
Python:操作 Excel 折叠
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...
java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别
UnsatisfiedLinkError 在对接硬件设备中,我们会遇到使用 java 调用 dll文件 的情况,此时大概率出现UnsatisfiedLinkError链接错误,原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用,结果 dll 未实现 JNI 协…...
家政维修平台实战20:权限设计
目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系,主要是分成几个表,用户表我们是记录用户的基础信息,包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题,不同的角色…...
python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...
第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明
AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...
分布式增量爬虫实现方案
之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面,避免重复抓取,以节省资源和时间。 在分布式环境下,增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路:将增量判…...
有限自动机到正规文法转换器v1.0
1 项目简介 这是一个功能强大的有限自动机(Finite Automaton, FA)到正规文法(Regular Grammar)转换器,它配备了一个直观且完整的图形用户界面,使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...
