卷积神经网络学习
卷积神经网络(CNN)专为处理网格结构数据(如图像、语音)设计的深度学习模型,其内部构造通过模拟人类视觉系统的层级特征提取机制,实现从低级到高级的特征学习。
CNN 的核心构造由多个功能模块有序组合而成,每个模块承担特定任务,共同完成 “特征提取→特征整合→决策输出” 的全过程。
为防止文字讲解过于抽象我们结合代码一起解释卷积神经网络
首先下面展示的是一段简单的CNN结构:
import torch
import torch.nn as nn
import torch.nn.functional as F
class SimpleCNN(nn.Module):
def __init__(self):
super(SimpleCNN, self).__init__()
self.conv1 = nn.Conv2d(1, 32, 3, 1)
self.conv2 = nn.Conv2d(32, 64, 3, 1)
self.fc1 = nn.Linear(64 * 12 * 12, 128)
self.fc2 = nn.Linear(128, 10)
self.max_pool = nn.MaxPool2d(2)
self.dropout = nn.Dropout(0.25)
def forward(self, x):
x = F.relu(self.conv1(x))
x = self.max_pool(F.relu(self.conv2(x)))
x = torch.flatten(x, 1)
x = F.relu(self.fc1(x))
x = self.dropout(x)
x = self.fc2(x)
return x
# 实例化模型
model = SimpleCNN()
print(model)
对于新手,我们可能只能看出来这段代码导入了torch包还构建了一个SimpleCNN的类,下面我将逐行解释这段代码的使用.
导入PyTorch的神经网络模块和函数式接口
import torch
import torch.nn as nn
import torch.nn.functional as F
定义名为 SimpleCNN 的神经网络类,继承自 PyTorch 的 nn.Module 基类
class SimpleCNN(nn.Module):
def __init__(self):
super(SimpleCNN, self).__init__()
这里或许会有一些疑问,为什么要继承nn.Module,或者会问这个是什么东西
你可以按住ctrl再将鼠标拖到这个Module处,可以看到这里可以点进去,如下图一般:

点进去后会有一段解释

我在这里大致解释说明一下,nn.Module
nn.Module是 PyTorch 所有神经网络模块的基类,它提供了构建和训练模型的核心功能框架:
-
参数管理:①自动跟踪所有定义在类中的nn.Parameter(如卷积核权重、全连接层权重),可通过module.parameters
()统一访问。②支持参数初始化、梯度计算、权重更新等操作(如优化器直接作用于module.parameters())。 -
模块化设计:允许嵌套子模块(如将多个卷积层封装为一个特征提取器),形成树形结构,便于组织复杂网络。
-
前向传播定义:通过实现
forward()方法定义数据流向,使模型可像函数一样被调用(如output = model(input))。 -
状态管理:提供训练 / 评估模式切换(
model.train()/model.eval()),影响如 Dropout、BatchNorm 等层的行为。 -
序列化支持:支持模型保存 / 加载(
torch.save(model.state_dict(), path)),方便迁移学习和部署。
创建第一个卷积层(提取特征):
self.conv1 = nn.Conv2d(1, 32, 3, 1)
四个参数分别对应:输入通道数=1,输出通道数=32,卷积核大小=3×3,步长=1。
进一步解释一下,输入通道数为1的意思就是输入一张图像(灰色表示无颜色通道之分,故通道数=1),输出通道数为32表示使用了32个不同的卷积核,每个卷积核会生成一个独立的特征图(Feature Map),这些特征图的尺寸相同但是内容不同。
而这时的特征图尺寸是多少呢,我们可以来计算一下:
一般对于MNIST手写数字数据集(单通道灰度图),输入尺寸为28×28像素(关键基础,接下来每一层的特征图计算都会基于这个计算数字),输入层的输入尺寸:1×28×28(通道数×高度×宽度)
卷积层输出尺寸计算:
高度/宽度=(输入尺寸-卷积核+2×填充)/步长+1(此处的填充也就是Conv2d中的一个参数pedding)
=(28-3+0)/1+1=26
故输出尺寸:32×26×26
创建第二个卷积层(与第一个卷积层思路一样,这里就不过多赘述)
self.conv2 = nn.Conv2d(32, 64, 3, 1)
创建第一个全连接层(将前序层提取的局部特征整合为全局特征,最终用于分类、回归等任务)
self.fc1 = nn.Linear(64*12*12, 128)
全连接层的输入必须是一维向量,因此需先将前序层(如卷积层、池化层)输出的高维特征展平(Flatten)为一维向量,就是全连接层的输入特征数。
假设卷积层输出的特征图形状为(32,7,7)展平后的一维向量长度为:32×7×7=1568,则全连接层的输入特征数为1568
输入特征数=64×12×12(前序层输出的特征图展平后的大小)、
输出特征数=128
创建第二个全连接层
self.fc2 = nn.Linear(128, 10)
输入特征数=128
输出特征数=10(对应10个分类类别)
创建最大池化层(用于减少特征图的尺寸,降低计算复杂度,并在一定程度上防止过拟合)
self.max_pool = nn.MaxPool2d(2)
池化窗口大小=2×2,步长默认为2(与窗口大小相同),填充默认为0。
输出尺寸计算:
高度/宽度=输入尺寸/步长=24/2=12 (这里为什么是24呢我们后面会进行总体计算进行解释)
输出尺寸=64×12×12
创建Dropout层(防止模型过拟合,通过随机丢弃一部分神经元来增强模型的泛化能力)
self.dropout = nn.Dropout(0.25)
丢弃率=0.25(训练时随机忽略25%的神经元,防止过拟合)
定义前向传播过程
def forward(self, x):
x = F.relu(self.conv1(x))
x = self.max_pool(F.relu(self.conv2(x)))
x = torch.flatten(x, 1)
x = F.relu(self.fc1(x))
x = self.dropout(x)
x = self.fc2(x)
return x
输入X经过第一个卷积层,应用ReLU激活函数引入非线性;
输入X经过第二个卷积层,通过最大池化层进行降维;
将多维特征图展平为一维向量;
输入X经过第一个全连接层,应用ReLU激活函数;
应用Dropout正则化,训练时随机丢弃部分神经元;
输入X经过第二个全连接层,输出10维的原始得分,通常配合softmax进行分类。
以上就是SimpleCNN的总体框架,我们下面进行整体的计算(根据forward函数的流程):
输入层:灰色图像(1×28×28)
第一个卷积层(前面已经计算过了):32×26×26
第二个卷积层:高度/宽度=(26-3+0)/1+1=24,输出尺寸:64×24×24
最大池化层:高度/宽度=24/2=12,输出尺寸:64×12×12
展平操作:三维向量展平为一维向量:64×12×12=9216
第一个全连接层:将输入的9216维向量映射为128维向量,包含线性变化和ReLU激活:
线性变换:

对每个样本i的第j个神经元的计算:![]()
ReLU激活:![]()
对每个元素的计算:![]()
Dropout操作:

第二个全连接层计算:将128维向量映射到10维向量:
线性变换:
对每个样本i的第j个神经元的计算:![]()
最终结果如图所示:

以上就是今天学习的全部内容,主要是搞懂CNN中的简单架构,有利于我们接下来更深入的学习
更多推荐
所有评论(0)