【深度学习】卷积神经网络(LeNet)

news2024/11/25 1:34:20

卷积神经网络 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个输出通道,卷积核大小为5x5
        self.pool = nn.MaxPool2d(2, 2)   # 最大池化层,2x2窗口
        self.conv2 = nn.Conv2d(6, 16, 5)  # 6个输入通道,16个输出通道,卷积核大小为5x5
        self.fc1 = nn.Linear(16*4*4, 120) # 全连接层1
        self.fc2 = nn.Linear(120, 84)     # 全连接层2
        self.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和相应的标签labels
        inputs, labels = data
        # zero_grad 方法将优化器中的梯度清零,计算新的梯度
        optimizer.zero_grad()
        # 将输入数据传递给神经网络 net 进行前向传播,计算模型的输出 outputs
        outputs = 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个输出通道,卷积核大小为5x5
        self.pool = nn.MaxPool2d(2, 2)   # 最大池化层,2x2窗口
        self.conv2 = nn.Conv2d(6, 16, 5)  # 6个输入通道,16个输出通道,卷积核大小为5x5
        self.fc1 = nn.Linear(16*4*4, 120) # 全连接层1
        self.fc2 = nn.Linear(120, 84)     # 全连接层2
        self.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.0
    for i, data in enumerate(trainloader, 0):
        inputs, labels = data
        optimizer.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.0

print('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.coloradmin.cn/o/1009689.html

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

相关文章

6种最流行的API架构风格

作为一名 Java程序员,编写业务 API是非常日常的开发工作,那么,如何选择合适的 API框架?今天我们就来一起聊聊当下最流行的 6种API架构风格。 一、SOAP 定义 SOAP,Simple Object Access Protocol,中文翻译…

Android端Base64解码表情emoj乱码

一、背景:H5端用户评论中包含表情包,通过JSBridge 传递给客户端,Android Base64解码之后,显示乱码(是菱形问号)。小程序和iOS可以正常解码出表情。用Base64在线编码解码(Base64 在线编码解码 | …

中项系统集成项目管理2023上半年真题及解析

中项系统集成项目管理2023上半年真题及解析 上午题1. 在 (1) 领域,我国还远未达到世界先进水平,需要发挥新型举国体制优势,集中政府和市场两方面的力量全力发展2. ChatGPT于 2022年 11 月 30 日发布,它是人工智能驱动的 (2) 工具3…

Pandas数据分析一览-短期内快速学会数据分析指南(文末送书)

前言 三年耕耘大厂数据分析师,有些工具是必须要掌握的,尤其是Python中的数据分析三剑客:Pandas,Numpy和Matplotlib。就以个人经验而已,Pandas是必须要掌握的,它提供了易于使用的数据结构和数据操作工具&am…

写作业用白光还是暖光?分享专业的读写台灯

现在学生的学习状态用四个字形容“学业繁重”,从上小学开始晚上完成功课到八九点都是再正常不过的事情了,因此学习时的光线环境就很重要,直接影响了视力健康,有一个好的台灯,能很好保护我们的眼睛,还能提高…

快速导入mysql较大的SQL文件

一般情况下,我们的网站或者小项目的数据库文件也就几十兆的大小,使用navicat等可视化工具快速就可以导入成功,但是当我们遇到几百兆或者更大的数据库文件时候,使用这些可视化工具去操作肯定是不可以的,亲测导入时间会特…

分享三款免费好用的远程控制软件!

一、AnyViewer远程桌面软件 AnyViewer是一款免费的远程桌面软件,您可以使用它在家远程控制公司电脑办公,同时您还可以使用它远程传输文件、远程游戏、远程关闭电脑等,并且AnyViewer还具有以下优点: 易于使用&#xf…

大数据安全 | 【实验】凯撒加密与解密

文章目录 📚实验目的📚关于凯撒加密🔥输入任意明文和密钥K10,对其进行凯撒加密;🔥输入密文和密钥K10,对其进行凯撒解密。🔥(暴力)破译密文 📚分析…

GNSS(二):融合策略

文章目录 一、背景二、松耦合融合策略1. 信息有效性判断2. 坐标系对齐3. 观测方程a.杆臂补偿b.速度融合c.位置融合1) 置信度设置 d. 航向yaw融合 4.观测性分析1)状态表示在VIO坐标系下的观测性分析2)状态表示在GPS ENU坐标系下的观测性分析 三、紧耦合融…

linux log日志文件切割 提取时间段 某天 日志

# 将service-23082202.log文件中 2023-09-05 08:00:00 到 2023-09-05 10:00:00 时段内的日志内容提取到20230905.log文件中 sed -n /2023-09-05 08:00:00/,/2023-09-05 10:00:00/p service-23082202.log >> 20230905.log

盘点中国光博会CIOE2023上的国货

一、中国光博会历史地位 CIOE中国光博会首次举办于1999年,经历24年在行业的深耕及拓展,是全球极具规模及影响力的综合型展会,见证了中国光电行业的变化及蓬勃发展。无论是超高清视频领域还是AI应用领域,均属于近年来的热门赛道&a…

软件设计师-UML基础教程

场景 针对UML1.5各种模型图的构成和功能进行说明。 UML概述 UML简介 UML (Unified Modeling Language)为面向对象软件设计提供统一的、标准的、可视化的建模语言。 适用于描述以用例为驱动,以体系结构为中心的软件设计的全过程。 UML的定义包括UML语义和UML表…

C++(day2)

封装一个结构体,结构体中包含一个私有数组,用来存放学生的成绩,包含一个私有变量,用来记录学生个数, 提供一个公有成员函数,void setNum(int num)用于设置学生个数 提供一个公有成员函数:void…

【PHP】麻醉临床信息系统

麻醉临床信息系统以服务围术期临床业务工作的开展为核心,为医护人员、业务管理人员、院级领导提供流程化、信息化、自动化、智能化的临床业务综合管理平台。 麻醉信息系统处理的数据包含病人的手术信息、麻醉信息、病人手术过程中从监护仪上采集到的数据和病人情况等…

互联网医院系统|互联网医院探索未来医疗的新蓝海

随着互联网技术的飞速发展,互联网医院应运而生,为人们带来全新的医疗体验。本文将深入探讨互联网医院的开发流程、系统优势以及未来发展方向,带您领略医疗领域的新蓝海。互联网医院的开发流程是一个结合技术、医疗和用户需求的复杂过程。首先…

python可视化记录训练过程

可视化训练曲线 wandb基本流程离线运行wandb保存最佳结果及模型界面 tensorboard基本流程SummaryWriter 所提供的其他方法 wandb 基本流程 安装wandb pip install wandb注册wandb账号 然后在wandb官网注册一个账号,然后获取该账号的私钥。然后在命令行执行&#xf…

无涯教程-JavaScript - AND函数

描述 如果AND函数的所有参数都为TRUE,则返回TRUE;如果一个或多个参数为FALSE,则返回FALSE。 AND功能的一种常见用法是扩展执行逻辑测试的其他功能的用途。如,IF函数执行逻辑测试,如果测试判断为TRUE,则返回一个值,如果测试判断为FALSE,则返回另一个值。通过将AND函…

SkyWalking安装部署

一、概念 1、什么是 APM 系统? APM(Application Performance Management)即应用性能管理系统,是对企业系统即时监控以实现对应用程序性能管理和故障管理的系统化的解决方案。应用性能管理,主要指对企业的关键业务应用…

网络安全宣传周|这些网络安全知识赶紧get起来~

2023年9月11日至17日是第十个国家网络安全宣传周。今年的国家网络安全宣传周主题是“网络安全为人民,网络安全靠人民”。 网络安全是国家安全的重要组成部分,没有网络安全就没有国家安全,就没有经济社会稳定运行,广大人民群众利益…

工欲善其事,必先利其器,这5款利器推荐你

​ 工欲善其事,必先利其器。要想提升工作效率,除了提升自己的能力以外,好的工具也是必不可少的一环,今天给大家推荐5款办公必备的神器。 1.鼠标手势增强——MouseInc ​ MouseInc 是一款由知名的浏览器优化大神开发的系统全局鼠…