从0搭建卷积神经网络(CNN)--详细教学

目录

一、卷积神经网络介绍

1、简介

经典CNN架构

2、与传统神经网络区别

3、卷积神经网络的结构

(1) 卷积层(Convolutional Layer)

(2) 激活函数(Activation Function)

(3) 池化层(Pooling Layer)

(4) 全连接层(Fully Connected Layer)

二、卷积神经网络的原理

1、卷积层(Convolutional Layer)

2、激活函数层(Activation Function Layer)

3、池化层(Pooling Layer)

4、全连接层(Fully Connected Layer)

5、反向传播(Backpropagation)

三、卷积神经网络的搭建过程

1、卷积层的构建方法

2、激活层的构建方法

3、池化层的构建方法

4、全连接层的构建方法 

四、卷积神经网络代码实践

1、导入相应的库

2、数据集加载

3、选择训练工具(这里是GPU)

4、构建卷积神经网络

5、将模型传入GPU、打印检查是否有误

6、构建优化器和损失函数

7、定义训练和测试函数

 8、调用训练和测试函数

9、完整代码展示

 10、结果展示


一、卷积神经网络介绍

1、简介

卷积神经网络(CNN)是一种专门用于处理网格状数据(如图像、视频、音频)的深度学习模型。其核心思想是通过卷积操作自动提取数据的空间或时序特征,广泛应用于计算机视觉、自然语言处理等领域。

经典CNN架构
模型提出时间主要贡献应用场景
LeNet-51998首个成功的手写数字识别CNNMNIST 分类
AlexNet2012引入ReLU、Dropout,赢得ImageNet竞赛图像分类
VGGNet2014深层的3x3卷积堆叠,结构简洁通用视觉任务
ResNet2015残差连接解决深层网络梯度消失问题图像分类/检测
YOLO2016单阶段目标检测,实时性高目标检测

2、与传统神经网络区别

  • 传统神经网络:传统神经网络对输入数据的处理是基于全连接的方式,神经元与输入数据的每个元素都有连接。这意味着输入数据中目标的位置发生变化时,网络需要重新学习该目标的特征。因为对于传统神经网络而言,不同位置的相同特征在输入层对应的神经元是不同的,所以不具备画面不变性。

  • 卷积神经网络:卷积神经网络通过卷积层中的卷积核在输入图像上滑动进行卷积操作,提取特征。由于卷积核的参数共享机制,无论目标在图像中的哪个位置,只要其特征模式与卷积核匹配,就能够被检测到。因此,卷积神经网络天然具有画面不变性。

3、卷积神经网络的结构

(1) 卷积层(Convolutional Layer)
  • 功能:通过滑动窗口(卷积核)在输入数据上提取局部特征。

  • 关键参数

    • 卷积核(Filter):权重矩阵,用于捕捉特征(如边缘、纹理)。

    • 步长(Stride):卷积核每次滑动的距离。

    • 填充(Padding):在输入边缘补零,控制输出尺寸。

  • 输出:生成特征图(Feature Map)

(2) 激活函数(Activation Function)
  • 作用:引入非线性,增强模型表达能力。

  • 常用函数:ReLU(修正线性单元)、Sigmoid、Leaky ReLU。

(3) 池化层(Pooling Layer)
  • 功能:降低特征图的空间维度,减少计算量并增强平移不变性。一种降采样,减小数据的空间大小,因此参数的数量和计算量也会下降,这在一定程度上也控制了过拟合。

  • 类型

    • 最大池化(Max Pooling):取窗口内最大值。

    • 平均池化(Average Pooling):取窗口内平均值。

(4) 全连接层(Fully Connected Layer)
  • 功能:将提取的特征映射到最终输出(如分类结果)。

  • 位置:通常位于网络末端。

二、卷积神经网络的原理

1、卷积层(Convolutional Layer)

  • 卷积操作:这是 CNN 的核心操作。卷积层通过卷积核(也叫滤波器)在输入数据(如图像)上滑动,对每个位置进行局部的加权求和运算。例如,对于一个二维图像,卷积核是一个小的二维矩阵,在图像上按照一定的步长(stride)滑动,每次滑动时,卷积核与图像上对应的局部区域进行元素相乘并求和,得到一个输出值。

  • 特征提取:不同的卷积核可以提取不同的特征。例如,一些卷积核可能提取图像中的边缘信息,另一些可能提取纹理信息。通过多个不同的卷积核,可以从输入数据中提取丰富多样的特征。

  • 参数共享:卷积核在滑动过程中,其参数是固定不变的。这意味着无论卷积核在图像的哪个位置,它对局部区域的处理方式都是相同的。这种参数共享机制大大减少了网络的参数数量,降低了计算复杂度,同时也使得网络能够更有效地学习到图像的平移不变性特征。

2、激活函数层(Activation Function Layer)

  • 常见的激活函数有 ReLU(Rectified Linear Unit,修正线性单元)、Sigmoid、Tanh 等。激活函数的作用是为神经网络引入非线性因素。因为如果没有激活函数,神经网络只是线性的组合,其表达能力有限,只能处理线性可分的问题。而引入激活函数后,神经网络可以学习和表示更复杂的非线性关系。例如,ReLU 函数在输入大于 0 时直接输出输入值,在输入小于 0 时输出 0,它能够有效地解决梯度消失问题,并且计算速度快,在 CNN 中被广泛使用。

3、池化层(Pooling Layer)

  • 下采样操作:池化层主要用于对卷积层输出的特征图进行下采样,降低特征图的尺寸。常见的池化方法有最大池化(Max Pooling)和平均池化(Average Pooling)。最大池化是在每个池化窗口中取最大值作为输出,平均池化则是计算池化窗口内的平均值作为输出。

  • 作用:通过池化操作,一方面可以减少网络的计算量和参数数量,提高计算效率;另一方面可以在一定程度上增强网络对输入数据的平移、旋转和尺度变化的鲁棒性,使网络学习到更具代表性的特征。

4、全连接层(Fully Connected Layer)

  • 经过多层卷积和池化操作后,将提取到的特征图展平成一维向量,然后输入到全连接层。全连接层中每个神经元与上一层的所有神经元都有连接,其作用是对前面提取到的特征进行综合和分类。例如,在图像分类任务中,全连接层可以根据前面提取的特征判断输入图像属于哪个类别。

  • 通常,全连接层的最后一层会使用合适的激活函数(如 Softmax 用于多分类问题)来输出分类结果,Softmax 函数可以将输出值转换为概率分布,每个值表示输入数据属于相应类别的概率。

5、反向传播(Backpropagation)

  • 在训练 CNN 时,使用反向传播算法来更新网络的参数(卷积核的权重和偏置等)。首先,根据网络的预测结果和真实标签计算损失函数(如交叉熵损失函数),衡量预测结果与真实值之间的差异。然后,通过反向传播算法,从输出层开始,将损失函数关于每个参数的梯度逐层反向传播到网络的输入层。最后,根据计算得到的梯度,使用优化算法(如随机梯度下降、Adam 等)更新网络的参数,使得损失函数逐渐减小,从而提高网络的性能。

三、卷积神经网络的搭建过程

在搭建网络只之前要先设计和模型的形状结构,多少层网络、使用什么激活函数、在哪里添加池化层等。

1、卷积层的构建方法

nn.Conv2d(in_channels=1, # 输入图片的通道数
out_channels=32, # 卷积核的个数
kernel_size=5, # 卷积核的大小
stride=1, # 移动步长
padding=2) # 边缘填充层数

2、激活层的构建方法

nn.ReLU()

3、池化层的构建方法

nn.MaxPool2d(2)

4、全连接层的构建方法 

nn.Linear(64*7*7,out_features=10)

四、卷积神经网络代码实践

举例描述:以手写数字数据集作为例子,用卷积神经网络进行训练。

1、导入相应的库

import  torch
print(torch.__version__)
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets
from torchvision.transforms import ToTensor

2、数据集加载

# 训练集
training_data = datasets.MNIST(root='data', # 路径train=True, # True为训练集False为测试集download=True, # 下载后就不重复下载transform=ToTensor() # 转换为张量
)# 测试集
test_data = datasets.MNIST(root='data',train=False,download=True,transform=ToTensor()
)
print(len(training_data))train_dataloader = DataLoader(training_data, batch_size=32)
test_dataloader = DataLoader(test_data, batch_size=32)
for X, y in test_dataloader:print(f'Shape of X [N,C,H,W]:{X.shape}')print(f'Shape of y:{y.shape},{y.dtype}')break

3、选择训练工具(这里是GPU)

device = "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu"
print(f"Using {device} device")

4、构建卷积神经网络

class CNN(nn.Module):def __init__(self):super(CNN,self).__init__()self.conv1 = nn.Sequential(nn.Conv2d(in_channels=1,out_channels=32,kernel_size=5,stride=1,padding=2),nn.ReLU(),nn.Conv2d(32,16,5,1,2),nn.ReLU(),nn.MaxPool2d(2) # 14*14)self.conv2 = nn.Sequential(nn.Conv2d(16,32,5,1,2),nn.ReLU())self.conv3 = nn.Sequential(nn.Conv2d(32,16,5,1,2),nn.ReLU(),nn.Conv2d(16,28,5,1,2),nn.ReLU(),)self.conv4 = nn.Sequential(nn.Conv2d(28,64,5,1,2),nn.ReLU(),nn.MaxPool2d(2)  # 7*7)self.out = nn.Linear(64*7*7,out_features=10)def forward(self,x):x = self.conv1(x)x = self.conv2(x)x = self.conv3(x)x = self.conv4(x)x = x.view(x.size(0),-1)output = self.out(x)return output

5、将模型传入GPU、打印检查是否有误

model = CNN().to(device)
print(model)

6、构建优化器和损失函数

loss_fn = nn.CrossEntropyLoss()  # 交叉熵损失函数
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)  # 优化器,lr为步长学习率

7、定义训练和测试函数

# 训练
def train(dataloader, model, loss_fn, optimizer):model.train()  # 开始训练,w可以改变,与测试中的model.eval()相对应batch_size_num = 1for X, y in dataloader:X, y = X.to(device), y.to(device)  # 将数据传入Gpupred = model.forward(X)  # 前向传输,model的数据来自模型的outloss = loss_fn(pred, y)  # 通过交叉熵损失函数计算loss,pred为预测值,y为真实值optimizer.zero_grad()  # 优化,梯度值清零loss.backward()  # 反向传播计算每个参数的梯度值Woptimizer.step()  # 根据梯度更新Wloss_value = loss.item()  # 从tensor数据中提取数据出来,转换成对应的整数或者浮点数if batch_size_num % 200 == 0:print(f"loss: {loss_value:>7f} [number:{batch_size_num}]")batch_size_num += 1# 测试集
def test(dataloader, model, loss_fn):size = len(dataloader.dataset)num_batches = len(dataloader)model.eval()  # 测试,w不可更新test_loss, correct = 0, 0  # 初始化损失值以及正确率with torch.no_grad():  # 一个上下文管理器,关闭梯度计算for X, y in dataloader:  # 提取测试集的数据X, y = X.to(device), y.to(device)pred = model.forward(X)  # 预测结果test_loss += loss_fn(pred, y).item()  # test_loss会自动累加每一批次的损失值correct += (pred.argmax(1) == y).type(torch.float).sum().item()  # pred.argmax(1)返回每一行中最大值对应的索引号a = (pred.argmax(1) == y)  # 比较预测值与正确标签是否相同,返回True或者Falseb = (pred.argmax(1) == y).type(torch.float)  # 将True-->1,False-->0,便于统计正确率test_loss /= num_batchescorrect /= sizeprint(f"Test result: \n Accuracy: {(100 * correct)}%,Avg loss:{test_loss}")

 8、调用训练和测试函数

这里训练10轮测试一次

epoch = 10
for i in range(epoch):print('第{}轮训练'.format(i))train(train_dataloader, model, loss_fn, optimizer)
test(test_dataloader, model, loss_fn)

9、完整代码展示

import  torch
print(torch.__version__)
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets
from torchvision.transforms import ToTensor# 训练集
training_data = datasets.MNIST(root='data', # 路径train=True, # True为训练集False为测试集download=True, # 下载后就不重复下载transform=ToTensor() # 转换为张量
)# 测试集
test_data = datasets.MNIST(root='data',train=False,download=True,transform=ToTensor()
)
print(len(training_data))train_dataloader = DataLoader(training_data, batch_size=32)
test_dataloader = DataLoader(test_data, batch_size=32)
for X, y in test_dataloader:print(f'Shape of X [N,C,H,W]:{X.shape}')print(f'Shape of y:{y.shape},{y.dtype}')break
device = "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu"
print(f"Using {device} device")class CNN(nn.Module):def __init__(self):super(CNN,self).__init__()self.conv1 = nn.Sequential(nn.Conv2d(in_channels=1,out_channels=32,kernel_size=5,stride=1,padding=2),nn.ReLU(),nn.Conv2d(32,16,5,1,2),nn.ReLU(),nn.MaxPool2d(2) # 14*14)self.conv2 = nn.Sequential(nn.Conv2d(16,32,5,1,2),nn.ReLU())self.conv3 = nn.Sequential(nn.Conv2d(32,16,5,1,2),nn.ReLU(),nn.Conv2d(16,28,5,1,2),nn.ReLU(),)self.conv4 = nn.Sequential(nn.Conv2d(28,64,5,1,2),nn.ReLU(),nn.MaxPool2d(2)  # 7*7)self.out = nn.Linear(64*7*7,out_features=10)def forward(self,x):x = self.conv1(x)x = self.conv2(x)x = self.conv3(x)x = self.conv4(x)x = x.view(x.size(0),-1)output = self.out(x)return outputmodel = CNN().to(device)
print(model)loss_fn = nn.CrossEntropyLoss()  # 交叉熵损失函数
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)  # 优化器,lr为步长学习率# 训练
def train(dataloader, model, loss_fn, optimizer):model.train()  # 开始训练,w可以改变,与测试中的model.eval()相对应batch_size_num = 1for X, y in dataloader:X, y = X.to(device), y.to(device)  # 将数据传入Gpupred = model.forward(X)  # 前向传输,model的数据来自模型的outloss = loss_fn(pred, y)  # 通过交叉熵损失函数计算loss,pred为预测值,y为真实值optimizer.zero_grad()  # 优化,梯度值清零loss.backward()  # 反向传播计算每个参数的梯度值Woptimizer.step()  # 根据梯度更新Wloss_value = loss.item()  # 从tensor数据中提取数据出来,转换成对应的整数或者浮点数if batch_size_num % 200 == 0:print(f"loss: {loss_value:>7f} [number:{batch_size_num}]")batch_size_num += 1# 测试集
def test(dataloader, model, loss_fn):size = len(dataloader.dataset)num_batches = len(dataloader)model.eval()  # 测试,w不可更新test_loss, correct = 0, 0  # 初始化损失值以及正确率with torch.no_grad():  # 一个上下文管理器,关闭梯度计算for X, y in dataloader:  # 提取测试集的数据X, y = X.to(device), y.to(device)pred = model.forward(X)  # 预测结果test_loss += loss_fn(pred, y).item()  # test_loss会自动累加每一批次的损失值correct += (pred.argmax(1) == y).type(torch.float).sum().item()  # pred.argmax(1)返回每一行中最大值对应的索引号a = (pred.argmax(1) == y)  # 比较预测值与正确标签是否相同,返回True或者Falseb = (pred.argmax(1) == y).type(torch.float)  # 将True-->1,False-->0,便于统计正确率test_loss /= num_batchescorrect /= sizeprint(f"Test result: \n Accuracy: {(100 * correct)}%,Avg loss:{test_loss}")epoch = 10
for i in range(epoch):print('第{}轮训练'.format(i))train(train_dataloader, model, loss_fn, optimizer)
test(test_dataloader, model, loss_fn)

 10、结果展示

正确率达到了99.21%,还是很可观的。

 

 

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

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

相关文章

Jmeter对图片验证码的处理

Jmeter对图片验证码的处理 在web端的登录接口经常会有图片验证码的输入,而且每次登录时图片验证码都是随机的;当通过jmeter做接口登录的时候要对图片验证码进行识别出图片中的字段,然后再登录接口中使用; 通过jmeter对图片验证码…

深入理解指针初阶:从概念到实践

一、引言 在 C 语言的学习旅程中,指针无疑是一座必须翻越的高峰。它强大而灵活,掌握指针,能让我们更高效地操作内存,编写出更优化的代码。但指针也常常让初学者望而生畏,觉得它复杂难懂。别担心,本文将用通…

【CubeMX-HAL库】STM32F407—无刷电机学习笔记

目录 简介: 学习资料: 跳转目录: 一、工程创建 二、板载LED 三、用户按键 四、蜂鸣器 1.完整IO控制代码 五、TFT彩屏驱动 六、ADC多通道 1.通道确认 2.CubeMX配置 ①开启对应的ADC通道 ②选择规则组通道 ③开启DMA ④开启ADC…

在 C# 中,处理 Excel 和 PDF 文件的库有很多。以下是一些比较常用的选择

读取 Excel 文件的库 NPOI 用途:可以读取和写入 .xls 和 .xlsx 文件。特点:无需安装 Microsoft Office,支持简单的 Excel 操作,如格式化、公式、图表等。 EPPlus 用途:主要用于 .xlsx 格式(Excel 2007 及以…

java配置api,vue网页调用api从oracle数据库读取数据

一、主入口文件 1:java后端端口号 2:数据库类型 和 数据库所在服务器ip地址 3:服务器用户名和密码 二、映射数据库表中的数据 resources/mapper/.xml文件 1:column后变量名是数据库中存储的变量名 property的值是column值的…

Python——批量图片转PDF(GUI版本)

目录 专栏导读1、背景介绍2、库的安装3、核心代码4、完整代码总结专栏导读 🌸 欢迎来到Python办公自动化专栏—Python处理办公问题,解放您的双手 🏳️‍🌈 博客主页:请点击——> 一晌小贪欢的博客主页求关注 👍 该系列文章专栏:请点击——>Python办公自动化专…

云原生周刊:DeepSeek 颠覆人工智能

开源项目推荐 Ollama Ollama 是一个开源的 AI 工具,旨在为用户提供简单而强大的本地部署语言模型解决方案。它支持直接在本地计算机上运行多个预训练的语言模型,能够提供与云端类似的体验,但无需依赖外部服务器或网络连接。 Ollama 的主要…

vue3获取页面跳转携带的参数

获取页面跳转携带的参数 在 Vue 3 中,使用 Vue Router 进行页面跳转并携带参数后,在目标页面获取这些参数的方式会因参数类型(路径参数、查询参数)而有所不同,以下为你详细介绍获取参数的方法。 前置准备 确保你已经…

Docker 部署 MongoDB | 国内阿里镜像

一、简易单机版 1、镜像拉取 docker pull registry.cn-hangzhou.aliyuncs.com/farerboy/mongo:8.0.5-rc1 2、运行镜像 docker run -it --name mongodb \ -e MONGO_INITDB_ROOT_USERNAMEmongoroot \ -e MONGO_INITDB_ROOT_PASSWORDmongoroot \ -v /wwwroot/opt/docker/mong…

守护进程(Background Process)详解

什么是守护进程? 守护进程(background process)是Linux系统中一种特殊的进程类型,它们在后台运行,不与主线程竞争资源,通常用于处理系统性的任务。守护进程运行在内核空间,可以在系统负载较重时…

在cursor/vscode中使用godot C#进行游戏开发

要在 Visual Studio Code(VS Code)中启动 C#Godot 项目,可以按照以下步骤进行配置: 1.安装必要的工具 • 安装 Visual Studio Code:确保你已经安装了最新版本的 VS Code。 • 安装.NET SDK:下载并安装.NET 7.x SDK(…

Photoshop自定义键盘快捷键

编辑 - 键盘快捷键 CtrlShiftAltK 把画笔工具改成Q , 橡皮擦改成W , 涂抹工具改成E , 增加和减小画笔大小A和S 偏好设置 - 透明度和色域 设置一样颜色 套索工具 可以自定义套选一片区域 Shiftf5 填充 CtrlU 可以改颜色/色相/饱和度 CtrlE 合并图层 CtrlShiftS 另存…

C++ 学习:深入理解 Linux 系统中的冯诺依曼架构

一、引言 冯诺依曼架构是现代计算机系统的基础,它的提出为计算机的发展奠定了理论基础。在学习 C 和 Linux 系统时,理解冯诺依曼架构有助于我们更好地理解程序是如何在计算机中运行的,包括程序的存储、执行和资源管理。这对于编写高效、可靠…

vue 主子表加校验问题

1.在table绑定的data中将数据源加上form&#xff0c;要将tabel包含在form表单中才行 <el-table :data"form.procurementPlanDevicesList" :row-class-name"rowProcurementPlanDevicesIndex"selection-change"handleProcurementPlanDevicesSelecti…

第四节 docker基础之---dockerfile部署JDK

本地宿主机配置jdk 创建test目录&#xff1a; [rootdocker ~]# mkdir test 压缩包tomcat和jdk上传到root/test目录下&#xff1a; 本机部署Jdk 解压jdk&#xff1a; [rootdocker test]# tar -xf jdk-8u211-linux-x64.tar.gz [rootdocker test]# tar -xf apache-tomcat-8.5.…

【Linux】深入理解linux权限

&#x1f31f;&#x1f31f;作者主页&#xff1a;ephemerals__ &#x1f31f;&#x1f31f;所属专栏&#xff1a;Linux 目录 前言 一、权限是什么 二、用户和身份角色 三、文件属性 1. 文件属性表示 2. 文件类型 3. 文件的权限属性 四、修改文件的权限属性和角色 1. …

ComfyUI 安装教程:macOS 和 Linux 统一步骤

本教程将详细介绍如何在 macOS 和 Linux 上安装 ComfyUI。我们将从 安装 Anaconda 开始&#xff0c;到安装 PyTorch 和 ComfyUI&#xff0c;最后提供一些常见问题的解决方法。 macOS和linux安装步骤很相似 可以按照1️⃣安装anaconda2️⃣安装python3️⃣torch4️⃣comfyui Co…

网络分析工具—WireShark的安装及使用

Wireshark 是一个广泛使用的网络协议分析工具&#xff0c;常被网络管理员、开发人员和安全专家用来捕获和分析网络数据包。它支持多种网络协议&#xff0c;能够帮助用户深入理解网络流量、诊断网络问题以及进行安全分析。 Wireshark 的主要功能 数据包捕获与分析&#xff1a; …

头条百度批量采集软件说明文档

旧版说明文档《头条号文章批量采集软件4.0版本说明文档&#xff01;头条/微头条文章批量采集》 头条的采集软件已经更新了好多个版本了&#xff0c;一直没有做详细的介绍文档&#xff0c;最近更新了一些功能进去&#xff0c;一块来写一下说明文档。 1、主界面 2、头条作者采集…

echarts 3d中国地图飞行线

一、3D中国地图 1. 一定要使用 echarts 5.0及以上的版本; 2. echarts 5.0没有内置中国地图了。点击下载 china.json&#xff1b; 3. 一共使用了四层地图。 &#xff08;1&#xff09;第一层是中国地图各省细边框和展示南海诸岛&#xff1b; &#xff08;2&#xff09;第二层是…