从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…

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办公自动化专…

Photoshop自定义键盘快捷键

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

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

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

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

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

【Linux】深入理解linux权限

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

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

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

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

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

echarts 3d中国地图飞行线

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

Unity游戏(Assault空对地打击)开发(7) 爆炸效果

效果 准备 首先请手搓一个敌军基地。 然后添加一个火焰特效插件或者自建。 爆炸脚本编写 新建一个脚本命名为Explode。 无需挂载到对象上。 首先是全部代码。 using System.Collections; using System.Collections.Generic; using System.Linq; using TMPro; using UnityEngine…

NLP面试之-激活函数

一、动机篇 1.1 为什么要有激活函数? 数据角度:由于数据是线性不可分的,如果采用线性化,那么需要复杂的线性组合去逼近问题,因此需要非线性变换对数据分布进行重新映射;线性模型的表达力问题:由于线性模型…

windows server独立部署Qwen2.5-vl-7B

服务器配置信息 CPU:64G GPU:48G(RTX 4090) 一、使用conda下载模型 Qwen2.5-VL-7B-Instruct conda下载 conda create --name qwen python3.11 conda activate qwen 魔塔社区下载模型 pip install modelscope modelscope downl…

2025影视泛目录站群程序设计_源码二次开发新版本无缓存刷新不变实现原理

1. 引言 本设站群程序计书旨在详细阐述苹果CMS泛目录的创新设计与实现,介绍无缓存刷新技术、数据统一化、局部URL控制及性能优化等核心功能,以提升网站访问速度和用户体验。 2. 技术概述 2.1 无缓存刷新技术 功能特点: 内容不变性&#x…

在大型语言模型(LLM)框架内Transformer架构与混合专家(MoE)策略的概念整合

文章目录 传统的神经网络框架存在的问题一. Transformer架构综述1.1 transformer的输入1.1.1 词向量1.1.2 位置编码(Positional Encoding)1.1.3 编码器与解码器结构1.1.4 多头自注意力机制 二.Transformer分步详解2.1 传统词向量存在的问题2.2 详解编解码…

win10 llamafactory模型微调相关②

微调 使用微调神器LLaMA-Factory轻松改变大语言模型的自我认知_llamafactory 自我认知-CSDN博客 【大模型微调】使用Llama Factory实现中文llama3微调_哔哩哔哩_bilibili 样本数据集 (数据集管理脚本处需更改,见报错解决参考1) 自我认知微…

从基础到人脸识别与目标检测

前言 从本文开始,我们将开始学习ROS机器视觉处理,刚开始先学习一部分外围的知识,为后续的人脸识别、目标跟踪和YOLOV5目标检测做准备工作。我采用的笔记本是联想拯救者游戏本,系统采用Ubuntu20.04,ROS采用noetic。 颜…

06排序 + 查找(D2_查找(D2_刷题练习))

目录 1. 二分查找-I 1.1 题目描述 1.2 解题思路 方法:二分法(推荐使用) 2. 二维数组中的查找 2.1 题目描述 2.2 解题思路 方法一:二分查找(推荐使用) 3. 寻找峰值 3.1 题目描述 3.2 解题思路 方…