欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 健康 > 养生 > 深度学习之卷积神经网络入门

深度学习之卷积神经网络入门

2025/4/26 12:40:47 来源:https://blog.csdn.net/2201_75345884/article/details/147521379  浏览:    关键词:深度学习之卷积神经网络入门

一、引言

在深度学习蓬勃发展的今天,卷积神经网络(Convolutional Neural Network,简称 CNN)凭借其在图像识别、计算机视觉等领域的卓越表现,成为了人工智能领域的核心技术之一。从手写数字识别到复杂的医学影像分析,从自动驾驶中的目标检测到智能安防的人脸识别,CNN 无处不在,深刻改变着我们的生活与工作方式。本文将深入剖析 CNN 的原理、结构组成,并通过实际案例展示其强大的应用能力。

二、原理

1、CNN 的核心思想是利用卷积运算来提取图像的特征。与传统的全连接神经网络不同,CNN 通过卷积层、池化层和激活函数等组件,能够自动学习图像中的局部特征和空间层次结构,从而更有效地处理图像数据。 

2、卷积层是 CNN 的核心组成部分,负责对输入图像进行特征提取。它通过卷积核与输入图像进行卷积运算,将图像与卷积核对应位置的元素相乘并求和,得到卷积结果。例如,一个 3×3 的卷积核在 6×6 的图像上进行步长为 1 的卷积操作,会生成一个 4×4 的特征图。卷积层中的参数主要包括卷积核的数量、大小、步长和填充方式,这些参数的设置会直接影响特征图的尺寸和提取到的特征类型。 

 

 3、激活函数层:为了引入非线性因素,使网络能够学习到复杂的函数关系,在卷积层之后通常会连接激活函数层。常见的激活函数有 ReLU(Rectified Linear Unit)、Sigmoid、Tanh 等。以 ReLU 函数为例,其公式为 f (x) = max (0, x),它能够有效缓解梯度消失问题,加快网络的训练速度,并且计算简单,在现代 CNN 模型中被广泛应用。

4、池化层:池化层的主要作用是对特征图进行下采样,降低数据的维度,减少计算量,同时还能增强模型的鲁棒性。常见的池化操作有最大池化(Max Pooling)和平均池化(Average Pooling)。最大池化会选取池化窗口内的最大值作为输出,能够保留最显著的特征;平均池化则计算池化窗口内的平均值,对特征进行平滑处理。例如,在一个 2×2 的最大池化窗口下,4×4 的特征图会被下采样为 2×2 的特征图。

 

5、全连接层:经过多层卷积和池化操作后,网络提取到的特征被展平并输入到全连接层。全连接层中的每个神经元都与上一层的所有神经元相连,它将提取到的特征进行整合,并通过激活函数进行非线性变换,最终输出分类结果或回归值。在图像分类任务中,全连接层的输出节点数量通常等于类别数,例如在 MNIST 手写数字识别任务中,全连接层的输出节点数为 10,分别对应 0 - 9 这 10 个数字类别。 

 

6、输出层:输出层根据具体的任务类型进行设计。在分类任务中,通常使用 Softmax 函数作为激活函数,将全连接层的输出转换为每个类别的概率分布,概率最大的类别即为预测结果;在回归任务中,输出层直接输出连续的数值

三、案例实现 

1、环境准备与数据加载

在开始之前,我们需要安装 PyTorch 和 torchvision。PyTorch 是一个强大的深度学习框架,而 torchvision 提供了许多与图像相关的数据集和工具。

import torch
from torch import nn   #导入神经网络模块,
from torch.utils.data import DataLoader   #数据包管理工具,打包数据,
from torchvision import datasets    #封装了很多与图像相关的模型,数据集
from torchvision.transforms import ToTensor    #数据转换,张量,将其他类型的数据转换为tensor张量

 2、下载MNIST数据集

'''下载训练数据集(包含训练图片+标签)'''
training_data=datasets.MNIST(root='data',           #表示下载的手写数字 到哪个路径。60000train=True,            #读取下载后的数据 中的 训练集download=True,         #如果你之前已经下载过了,就不用再下载transform=ToTensor(),  #张量,图片是不能直接传入神经网络模型
)    #对于pytorch库能够识别的数据一般是tensor张量。'''下载测试数据集(包含训练图片+标签)'''
test_data=datasets.MNIST(root='data',           #表示下载的手写数字 到哪个路径。60000train=False,           #读取下载后的数据中的训练集download=True,         #如果你之前已经下载过了,就不用再下载transform=ToTensor(),  #Tensor是在深度学习中提出并广泛应用的数据类型
)    #NumPy数组只能在CPU上运行。Tensor可以在GPU上运行,这在深度学习应用中可以显著提高计算速度
print(len(training_data))

3、数据可视化 

'''展示手写字图片,把训练数据集中的前59000张图片展示一下'''
from matplotlib import pyplot as plt
figure = plt.figure()
for i in range(9):img,label=training_data[i+59000]#提取第59000张图片figure.add_subplot(3,3,i+1)#图像窗口中创建多个小窗口,小窗口用于显示图片plt.title(label)plt.axis("off") #  plt.show(I)#是示矢量,plt.imshow(img.squeeze(),cmap="gray") #plt.imshow()将Numpy数组data中的数据显示为图像,并在图形窗口中显贡a = img.squeeze()# img.squeeze()从张量img中去掉维度为1的。如果该维度的大小不为1则张量不会改变。#cmap="gray
plt.show()

4、创建数据加载器和配置设备 

"""创建数据DataLoader(数据加载器)
batch_size:将数据集分成多份,每一份为batch_size个数据
优点:可以减少内存的使用,提高训练速度。"""train_dataloader=DataLoader(training_data,batch_size=64)
test_dataloader=DataLoader(test_data,batch_size=64)for X, y in test_dataloader:#X时打包的的每一个数据包print("Shape of X [N, C, H, W]: {X.shape}")print(f"shape of y: {y.shape} {y.dtype}")break'''断当前设备是否支持GPU,其中mps是苹果m系列芯片的GPU。'''
device = "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu"
print(f"Using {device} device")  #字符串的格式化

 5、搭建神经网络模型 

'''定义神经网络 类的继承'''
class CNN(nn.Module):#类的名称def __init__ (self):   #python基础关于类,self类自已本身super(CNN,self).__init__()   #继承的父类初始化self.conv1 = nn.Sequential(    #将多个层组合成一起,创建了一个容器,将多个网络合在一起nn.Conv2d(       #2d一般用于图像,3d用于视频数据(多一个时间维度),1d一般用于结构化的序列数据in_channels=1,   #图像通道个数,1表示灰度图(确定了卷积核 组中的个数)out_channels=16,   # 要得到多少个特征图,卷积核的个数kernel_size=5,     # 卷积核大小,5*5stride=1,          # 步长padding=2,        #一般希望卷积核处理后的结果大小与处理前的数据大小相同,效果会比较好。那padding改如何),                     # 输出的特征图为(16,28,28)nn.ReLU(),            # 激活函数,relu层,不会改变特征图的大小(16,28,28)nn.MaxPool2d(kernel_size=2),        #池化层,进行池化操作(2x2 区域),输出结果为:(16,14,14))self.conv2 = nn.Sequential(   #输入(16, 14, 14)nn.Conv2d(16,32,5,1,2),   # 输出(32,14,14)nn.ReLU(),     # (32*14*14)#nn.Conv2d(32, 32, 5, 1, 2),  # 输出(32,14,14)nn.ReLU(),         #(32 14 14)nn.MaxPool2d(2),     #输出(32,7,7))self.conv3 = nn.Sequential(      #输入(32 7 7)nn.Conv2d(32,64,5,1,2),   #(64,7,7)nn.ReLU(),)self.out=nn.Linear(64*7*6,10)    #全连接层得到的结果def forward(self,x):    #这里必须要写 forward是来自于父类nn里面的函数 要继承父类的功能x=self.conv1(x)x=self.conv2(x)x=self.conv3(x)  #输出(64,64,7,7)x=x.view(x.size(0),-1)#把x的数据变成2维的output=self.out(x)return outputmodel = CNN().to(device)#类的初始化完成,就会创建一个对象,model
print(model)

    定义了一个继承自nn.Module的CNN类,用于构建卷积神经网络模型。模型包含多个卷积层、激活函数层和池化层:

    conv1层:首先通过nn.Conv2d进行卷积操作,将输入的 1 通道图像转换为 16 个特征图;然后使用nn.ReLU激活函数引入非线性;最后通过nn.MaxPool2d进行最大池化操作,降低数据维度。

    conv2层:包含两个卷积层和激活函数层,进一步提取图像特征,并通过池化操作降低维度。

    conv3层:进行卷积和激活操作,继续提取更高级的特征。

    out层:全连接层,将卷积层输出的特征图展平后映射到 10 个类别(对应 0 - 9 这 10 个数字)。

    .forward方法定义了数据在模型中的前向传播过程,确保数据按照正确的顺序通过各个层。

     6、模型训练与测试

    def train(dataloader,model,loss_fn,optimizer):model.train()   #告诉模型,现在要进入训练模式,模型中w进行随机化操作,已经更新w。在训练过程中,w会被修改的
    #pytorch提供2种方式来切换训练和测试的模式,分别是:model.train()和 model.eval()。
    #一般用法是:在训练开始之前写上model.trian(),在测试时写上 model.eval()batch_size_num=1for X,y in dataloader:       #其中batch为每一个数据的编号X,y=X.to(device),y.to(device)    #把训练数据集和标签传入cpu或GPUpred=model.forward(X)    #.forward可以被省略,父类中已经对次功能进行了设置。自动初始化loss=loss_fn(pred,y)     #通过交叉熵损失函数计算损失值loss# Backpropagation 进来一个batch的数据,计算一次梯度,更新一次网络optimizer.zero_grad()    #梯度值清零loss.backward()          #反向传播计算得到每个参数的梯度值woptimizer.step()         #根据梯度更新网络w参数loss_value=loss.item()   #从tensor数据中提取数据出来,tensor获取损失值if batch_size_num %100 ==0:print(f'loss:{loss_value:>7f} [number:{batch_size_num}]')batch_size_num+=1def test(dataloader,model,loss_fn):size=len(dataloader.dataset)num_batches=len(dataloader)  #打包的数量model.eval()  #测试,w就不能再更新。test_loss,correct=0,0with torch.no_grad():    #一个上下文管理器,关闭梯度计算。当你确认不会调用Tensor.backward()的时候。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()a=(pred.argmax(1)==y)   #dim=1表示每一行中的最大值对应的索引号,dim=0表示每一列中的最大值b=(pred.argmax(1)==y).type(torch.float)test_loss /=num_batchescorrect /=sizeprint(f'Test result: \n Accuracy: {(100*correct)}%, Avg loss: {test_loss}')

    7、定义损失函数和优化器 

    loss_fn=nn.CrossEntropyLoss()   #创建交叉熵损失函数对象,因为手写字识别中一共有10个数字,输出会有10个结果
    optimizer=torch.optim.Adam(model.parameters(),lr=0.01)   #创建一个优化器
    # #params:要训练的参数,一般我们传入的都是model.parameters()
    # lr:learning_rate学习率,也就是步长

    nn.CrossEntropyLoss是交叉熵损失函数,适用于多分类任务,用于计算模型预测结果与真实标签之间的差距。torch.optim.Adam是一种常用的优化器,用于更新模型的参数,以最小化损失函数。lr=0.01设置学习率,控制参数更新的步长。 

    6、模型训练与测试流程

    epoch=9
    for i in range(epoch):print(i+1)train(train_dataloader, model, loss_fn, optimizer)test(test_dataloader,model,loss_fn)

    通过循环进行多个 epoch 的训练,每个 epoch 都会调用train函数对模型进行训练,训练完成后调用test函数对模型在测试集上的性能进行评估。随着训练的进行,可以观察到损失值逐渐降低,准确率逐渐提高,最终得到一个在 MNIST 数据集上表现良好的手写数字识别模型。

    四、总结

    本文详细介绍了利用 PyTorch 构建卷积神经网络实现 MNIST 手写数字识别的全过程。从数据集的准备、模型的构建,到训练和测试的各个环节,都进行了深入的代码解析和原理讲解。通过实践,我们可以看到卷积神经网络在图像识别任务中的强大能力,同时也掌握了 PyTorch 框架的基本使用方法。希望本文能够帮助读者更好地理解和应用卷积神经网络,在深度学习领域不断探索前进。 

    版权声明:

    本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

    我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

    热搜词