0 引言
本人是参考B站UP主炮哥带你学的Pytorch框架与经典卷积神经网络与实战链接如下,可辅助食用:4.14、实战1--LeNet-5模型搭建_哔哩哔哩_bilibili
1 开始之前
1.1 pytorch的安装
可以参考一下该文【超详细教程】2024最新Pytorch安装教程(同时讲解安装CPU和GPU版本)-优快云博客
2 CNN卷积神经网络算法原理
2.1 全连接神经网络 FCN
全连接神经网络本质上是有由单位到整体的过程,而模型的运行则是输入x输出y的过程,也被称为前向传播,本质为模型的计算过程。
2.1.1 整体结构
整体结构分为三部分,分别为输入层,隐藏层,输出层。
输入层是指输入的数据,而输出层则为输出的数据,中间的所有神经元都属于隐藏层。
如下例代码:
model = nn.Sequential(
nn.Flatten(),
#Flatten 层将一个多维的层输出展平成一维数组。这个输出被称为特征向量,将连接到最终的分类层。
nn.Linear(input_size, 512), # Input
nn.ReLU(), # Activation for input
nn.Linear(512, 512), # Hidden
nn.ReLU(), # Activation for hidden
nn.Linear(512, n_classes) # Output
)
其中nn.Sequnetial为PyTorch的模型类.
P.S. model的使用方法为model(x),x为DataLoaders数据加载器。

图1.1
图1.2
2.1.2 结构单元
结构单元也就是上面提到的神经元,就是图1.2所表示的a11,a12,a13一样的节点。一般为多个输入在此结构单元经过数据处理产生多个输出。而多个结构单元经过一定的组合便成为了模型的整体结构。其中逻辑可简化为y=a(X1*W1+X2*W2+X3*W3+...+Xn*Wn+B),如图2.1。由此可知其中发挥重要作用的是参数W1,W2,W3...Wn,B,他们决定了模型的输出是否与预测的接近。

图2.1
而一层神经元输出结果即同一层内神经元输出结果形成的矩阵a也是下一层神经元的输入,即
,所以model的本质就是多个h(w*x+b)嵌套,其目的也转为找到一组最优的b和w使我们最后输出的y接近我们的真实值。也就是说对于
,其中的h(x)为激活函数,w,b为最佳参数。
2.1.2.1 激活函数(重中之重)
激活函数大多都是非线性函数,只有少部分是线性函数,在模型中起到特殊的功能。图2.2是对激活函数大多都是非线性函数的解释。

图2.2
2.1.2.1.1 Sigmoid函数
对于我们学习中遇到的函数,主要关注的点有两个:函数曲线与导数曲线,导数曲线用于求出在model已确定的情况下最合适的参数(w,b)。

图2.1.2.1.1 Sigmoid函数
对Sigmoid函数有其值域为(0,1)且越往两边越平缓的特性,导致其一般用于输出层中用于分类。
2.1.2.1.2 Tanh函数

图2.1.2.1.2 Tanh函数
其值域为(-1,1),我们可以发现Tanh函数与Sigmoid函数十分相似,但Tanh函数为奇函数,关于原点呈中心对称。
2.1.2.1.3 ReLU函数

图2.1.2.1.3 ReLU函数
ReLU函数在model中使用较多,其本质为分段函数。其特点是计算简单,能有效缓解梯度消失问题。训练时可能出现神经元死亡是因为在小于等于0的情况下, ReLU函数导数为0,导致w与b直接无法更新。使用方法为nn.ReLU()。
2.1.2.1.4 Leaky ReLU函数

图2.1.2.1.4 Leaky ReLU函数
Leaky ReLU函数为ReLU函数的改进版,通过设置不同的斜率解决了导数为0的问题。 但因为函数不对称导致无法为输入值提供一致的关系预测。
2.1.3 全连接神经网络前向传播
图2.1.3.1 前向传播计算过程

图2.1.3.2 具体计算过程
前向传播是神经网络中数据从输入层经过隐藏层传递到输出层的过程。每一层的神经元接收前一层输出的加权求和结果,通过激活函数处理并输出到下一层,最终得到预测值。本质为模型的计算过程。并且模型的训练,推理,验证,测试都需要前向传播的参与。在机器学习中,label指训练数据中的目标输出值。
2.1.4 损失函数(重点)

图 2.1.4 损失函数
损失函数(Loss Function)用于衡量模型预测值与真实值之间的差异,是机器学习和深度学习中优化模型的核心工具。通过最小化损失函数,模型逐步调整参数以提高预测准确性。
对于model的基本问题我们有三大基本模型,分别是回归,分类,聚类。
其中回归问题多用来预测一个具体的数值,如预测房价、未来的天气情况等等。例如我们根据一个地区的若干年的PM2.5数值变化来估计某一天该地区的PM2.5值大小,预测值与当天实际数值大小越接近,回归分析算法的可信度越高。由此我们可知回归问题的预测值是连续的。当然预测值与真实值的差值可能为负,为解决差值分别为-1,0,+1的损失函数计算为0(-1+0+1=0),我们需要给差值加绝对值或平方,于是得到适合回归问题的损失函数均方误差的损失函数如图2.1.4。对于图2.1.4中的1/2则为对函数导数化的方便计算,对函数本身并无影响。
而分类则是对事物进行分类,所以其预测值也就是离散的,如只有false和true。
2.1.5 反向传播与梯度下降法
2.1.5.1 反向传播
对于前向传播所经历的过程我们可以得到对应每一层的损失函数的结果loss值,那么花那么大力气求得的结果有什么用呢?这就要引出一个与前向传播相应的过程:反向传播。
反向传播(Backpropagation)是一种用于训练神经网络的算法,通过计算损失函数对网络参数的梯度,利用梯度下降法优化参数。核心思想是利用链式法则从输出层向输入层逐层传播误差,调整权重和偏置以减少预测误差。其本质就是根据前向传播的结果反作用于参数w,b的修改使loss值下降,从而使model效果更好。而反作用使loss值下降的方法就是梯度下降法。
2.1.5.2 梯度下降法(重点)

图 2.1.5.1 对w的梯度下降法(对b同理,只需换字符就行)
因为我们有损失函数,由此可反推在已知x,y的情况下w,b的值,即对损失函数求导算出最小值,但我们为什么不这么做呢?因为函数中的x往往为矩阵,通过求导求最小值会极为困难甚至可能无解。所以我们只能用参数更新的方式去逼近。其中a决定了单次梯度下降的倾斜程度,所以a不能太大也不能太小,避免一次就超过或效率过慢。

图 2.1.5.2 下降梯度法原理图示

图 2.1.5.3 对w,b的下降梯度法三维演示
2.1.5.2.1 举例计算(不在乎细节可跳)

图 2.1.5.2.1.1 案例

图 2.1.5.2.1.2 计算过程1
注意其中a21=relu(a11*w21+b2)

图 2.1.5.2.1.3 计算过程2

图 2.1.5.2.1.2 计算过程3

图 2.1.5.2.1.3 第二轮验证
2.1.6 存在的问题
对于全连接神经网络而言,其相对于CNN卷积神经网络在图像识别的问题在于其会破坏图像信息的空间结构。这是因为全连接层将输入图像的所有像素展开为一维向量,导致像素间的二维空间关系被破坏。例如,一张28x28x1(其中1表明图像为灰度图,RGB则为x3,意为有红黄绿三个维度)的图像会被展平为784维向量,相邻像素的行列位置信息完全丢失。这种扁平化处理忽略了图像的局部特征(如边缘、纹理)在空间上的相关性。但CNN卷积神经网络因卷积核仅连接输入图像的局部区域(如3x3窗口)从而可以保留空间拓扑结构。
2.2 卷积神经网络 CNN
卷积神经网络本质上是运用卷积运算搭建的神经网络。其核心在于利用卷积运算提取局部特征,并通过层级结构实现高效的特征学习和模式识别。
2.2.1 卷积层--卷积运算
卷积层通过滑动窗口(卷积核)在输入数据上执行局部加权求和,自动学习空间或时间上的局部模式。这种操作具有参数共享和稀疏连接的特性,显著减少了模型的参数量,同时保留了数据的平移不变性。

图2.2.1.1 卷积运算演示
在卷积运算中卷积核其实就相当于全连接神经网络中的w,但不同的是卷积核的大小(即权重)不会因输入数据的多少而发生变化(如图2.2.1.1中核的大小为2x2),全连接神经网络中的w个数与输入数据正相关。同时卷积神经网络中的偏置也可看作成b,即卷积神经网络可写成

图 2.2.1.2 卷积运算详细过程
那么如何进行卷积运算呢?由图 2.2.1.2我们不难发现卷积运算分为以下5步:
输入准备
卷积运算需要一个输入矩阵(如图像)和一个卷积核(或滤波器)。输入矩阵通常是一个二维数组,卷积核是一个更小的二维数组,其大小由设计者决定(如3x3、5x5等)。
滑动窗口操作
将卷积核从输入矩阵的左上角开始,每次滑动一个步长(stride),覆盖输入矩阵的一个局部区域。在每个位置上,卷积核与输入矩阵的对应元素进行逐元素相乘。如图2.2.1.2中顺序为左上右上左下右下。
逐元素相乘并求和
对于每个覆盖的局部区域,计算卷积核与输入矩阵对应元素的乘积,并将所有乘积结果相加,得到一个输出值。这个输出值成为输出矩阵(特征图)的一个元素。如图2.2.1.2中左上为0x0+1x1+3x2+4x3=19.
填充与步长的影响
填充(padding)可以在输入矩阵周围添加额外的行和列(通常用0填充),以控制输出矩阵的大小。步长(stride)决定了卷积核每次滑动的距离,较大的步长会减少输出矩阵的尺寸。如图2.2.1.1中19+偏置的值2=21及结果。
输出特征图生成
重复上述滑动和计算过程,直到卷积核覆盖整个输入矩阵,最终生成完整的输出特征图。
2.2.1.1 卷积层--步幅

图2.2.1.1.1 步幅S=2时卷积运算过程
卷积层的步幅(Stride)指卷积核在输入数据上滑动时的步长。步幅决定了卷积核每次移动的像素数量,直接影响输出特征图的尺寸。如图 2.2.1.2与图2.2.1.1.1对比可发现步幅S大时输出尺寸会相应减小。
2.2.1.2 卷积层--填充
填充(Padding)是在输入特征图周围添加额外像素(通常为0),以控制输出特征图的尺寸。主要作用包括:
- 保持空间维度:避免卷积操作导致特征图尺寸过快缩小,尤其在深层网络中。
因为图片在经过卷积操作后尺寸会变小,为了
- 利用边缘信息:防止输入边缘区域的信息因卷积核中心对齐而丢失。
2.2.1.3 卷积层--经过计算后的特征图大小(重要)
图2.2.1.3 特征图大小的计算公式(p为填充,S为步幅)
若计算结果为小数,一般向下取整,但也有向上取整的模型框架。
2.2.1.4 卷积层--多通道数据卷积运算

图2.2.1.4.1 多通道数据单卷积核卷积运算过程

图2.2.1.4.2 多通道数据多卷积核卷积运算过程
如图2.2.1.4所示根据2.2.1.3的计算公式有,所以输出的特征图的大小为2x2x1.至于深度为何为1是因为该运算的卷积核是深度为三的单个卷积核,所以我们可看出输出的特征图深度不由输入数据与卷积核的深度(通道数)决定,而是由卷积核的数量决定。如图2.2.1.4.2所示。在卷积神经网络(CNN)中,卷积核的数目与偏置(bias)的通道数相等,这是因为每个卷积核对应一个独立的偏置项。
2.2.1.5 卷积层—2D图像上的运用

其中还有IMG_CHS为图像通道数,灰度为1
2.2.2 池化层
池化层(Pooling Layer)是卷积神经网络(CNN)中的一种重要组件(实际上不算是一个神经网络层,因为它不带有参数,其本质是一种下采样操作),主要用于降低特征图的空间维度(宽度和高度)不改变深度,减少计算量并增强模型的平移不变性。通过聚合局部区域的信息,池化层能够保留主要特征,同时减少过拟合风险。
2.2.2.1 最大池化
图2.2.2.1 最大池化过程
顾名思义,就是取局部区域的最大值,保留最显著特征。通常在滑动窗口内操作,窗口大小(如 2×2)和步长(如 2)是常见参数。其运用如下:

使用方法为
MaxPool2d(2, stride=2)#2代表2*2窗口,stride=2代表步长为二
2.2.2.2 平均池化

图2.2.2.2.1 平均池化过程
其本质也就是输入特征图的局部区域取平均值来降低其空间维度。
平均池化与最大池化的对比
- 最大池化:保留局部最显著特征,适合纹理、边缘等高频信息。
- 平均池化:保留整体分布特性,适合平滑区域或背景主导的任务。
2 2.2.3 池化输出大小计算

图2.2.2.3 池化输出大小计算公式(其中FH,FW为自己设定的窗口大小和步长)
2.2.3 卷积神经网络整体结构
卷积神经网络(CNN)通常由输入层、卷积层、池化层、全连接层和输出层组成。输入层接收原始数据(如图像),卷积层提取局部特征,池化层降低空间维度,全连接层整合特征,输出层生成预测结果。

其中卷积层的功能为输出特征图,且特征图的通道数由卷积核的个数决定。而卷积层的各个卷积核都分别对不同部分做提取,所以到最后一层池化层时输出的数据已是被提取的数据,与原始输入无关,此时便不用担心全连接对数据的空间结构的破坏。输出层的结构取决于任务类型。
3.LeNet与AlexNet原理与实战
对于我们神经网络模型的搭建一般是先搭建模型(model.py),再搭建训练代码即送入并处理数据(train.py),之后再搭建测试代码即test.py。其中train.py与test.py大多相近,可重复套用模板。
3.1 LeNet
LeNet(LeNet-5)是由 Yann LeCun 等人在 1998 年提出的经典卷积神经网络(CNN)架构,主要用于手写数字识别(MNIST 数据集)。它是现代深度卷积神经网络的先驱,奠定了 CNN 的基础设计模式。
3.1.1 LeNet-5 网络结构

图3.1.1 LeNet网络结构
LeNet-5 由 7 层组成,包括卷积层、池化层和全连接层:
- 输入层:32×32 的灰度图像(MNIST 图像被填充到这一尺寸)。
- 卷积层 C1:6 个 5×5 的卷积核,输出 6 个 28×28 的特征图。
- 池化层 S2:2×2 的平均池化,输出 6 个 14×14 的特征图。
- 卷积层 C3:16 个 5×5 的卷积核,输出 16 个 10×10 的特征图。
- 池化层 S4:2×2 的平均池化,输出 16 个 5×5 的特征图。
- 全连接层 C5:120 个神经元,与 S4 层全连接。
- 全连接层 F6:84 个神经元。
- 输出层:10 个神经元(对应 0-9 的数字类别),使用 Softmax 激活函数。
其中因为池化层无参数并不算是神经网络层,所以该模型的神经网络层为5层(-5的由来)。同时LeNet也可视为由两部分组成:由两个卷积层和两个平均池化层组成的特征提取主干,由三个全连接层组成的任务层(如分类)。
3.1.2 LeNet-5网络参数详解

图3.1.2.1 LeNet-5网络结构参数

图3.1.2.2 LeNet-5网络参数细节
注意就可以一层层向下推,由此可以得到卷积是用来增多特征的,池化是用来修改特征表现的,如平滑或者突出。
3.1.3 LeNet-5总结

图3.1.3 LeNet-5总结
import torch.nn as nn
class LeNet5(nn.Module):
def __init__(self):
super(LeNet5, self).__init__()
self.conv1 = nn.Conv2d(1, 6, 5)
self.pool1 = nn.AvgPool2d(2, stride=2)
self.conv2 = nn.Conv2d(6, 16, 5)
self.pool2 = nn.AvgPool2d(2, stride=2)
self.fc1 = nn.Linear(16*5*5, 120)
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10)
def forward(self, x):
x = self.pool1(torch.tanh(self.conv1(x)))
x = self.pool2(torch.tanh(self.conv2(x)))
x = x.view(-1, 16*5*5)
x = torch.tanh(self.fc1(x))
x = torch.tanh(self.fc2(x))
x = self.fc3(x)
return x
3.2 AlexNet
AlexNet 是由 Alex Krizhevsky、Ilya Sutskever 和 Geoffrey Hinton 在 2012 年提出的深度卷积神经网络(CNN),在 ImageNet 竞赛中以显著优势获胜,推动了深度学习在计算机视觉领域的广泛应用。其核心创新包括 ReLU 激活函数、Dropout 正则化和 GPU 并行训练。
3.2.1 AlexNet网络结构

图3.2.1 AlexNet网络结构
3.2.2 AlexNet网络参数详解

图3.2.2 AlexNet网络参数详解
其中我们已知池化层主要用于降低特征图的空间维度(宽度和高度)不改变深度,卷积层使数据通道数变大,但在第九层我们发现通道数反而变小了,这是为什么呢?这里要引入过拟合的概念:过拟合是指机器学习模型在训练数据上表现优异,但在未见过的测试数据上表现较差的现象。这种现象通常由于模型过于复杂,过度拟合了训练数据中的噪声或无关特征,导致泛化能力下降。网络参数过多会导致模型在训练数据上表现极佳,但在未见过的测试数据上表现不佳。过拟合的根本原因是模型复杂度过高,记住了训练数据的噪声和细节,而非学习到数据的泛化规律。
3.3.3 Dropout操作
Dropout是一种常用的正则化技术,旨在防止神经网络过拟合。其核心思想是在训练过程中随机“丢弃”(即暂时移除)一部分神经元,从而减少神经元之间的复杂共适应关系,增强模型的泛化能力。
使用方法为
dropout = nn.Dropout(0.2) # 20%的神经元会被随机丢弃

图3.3.3 Dropout操作
Dropout 的核心思想是在训练过程中随机"丢弃"(即暂时移除)神经网络中的一部分神经元及其连接。具体来说:
-
在每次训练迭代中,每个神经元都有概率 p 被暂时丢弃(不参与前向传播和反向传播)
-
未被丢弃的神经元的输出会被缩放(通常乘以 1/(1-p))以保持总体激活值的期望不变
-
在测试/推理阶段,所有神经元都保持激活,但它们的输出要乘以 (1-p)
3.3.4 LRN正则化
LRN是一种在深度学习模型中常用的局部响应归一化技术,主要用于增强模型的泛化能力。它通过对局部神经元的活动进行归一化,模拟生物神经系统的侧抑制机制,使得响应较大的神经元变得相对更突出,同时抑制反馈较小的神经元。
其中我们看到公式可能会有点蒙,但听过我的解释一定能掌握:
- n指我们想要局部归一化的范围,即有多少个元素参与。
与
分别表示以
为中心两边元素的范围。
- k, α, β是超参数(通常k=2, α=10⁻⁴, β=0.75)而其中系数k则保证了分母不等于0同时提供基础偏移,避免极端情况下的数值不稳定。α 调节相邻通道的贡献权重。β 控制惩罚项的非线性变换强度。
-
通过调整这三个参数,可以平衡以下两种效应:
增强显著特征:抑制周围通道的弱激活,突出当前通道的强激活。防止过度抑制:避免所有激活值被压缩到过小的范围。

图3.3.4 LRN正则化简介
3.3.5 AlexNet总结

4.图像增强
4.1 水平翻转,随机裁剪
水平翻转和随机裁剪是图像数据增强的常用技术,能够提高模型的泛化能力。这样做可以有效扩增训练数据,使训练数据足够并且防止过拟合。
4.1.1 水平翻转
水平翻转是将图像沿垂直轴进行镜像翻转的操作。其改变了像素坐标,产生了新的数据。
使用方法如下
trans = transforms.Compose([
transforms.RandomHorizontalFlip(p=0.5)#p指概率
])
使用Python和OpenCV进行水平翻转
import cv2
# 读取图像
image = cv2.imread('input.jpg')
# 水平翻转
flipped_image = cv2.flip(image, 1)
# 保存结果
cv2.imwrite('flipped_output.jpg', flipped_image)
在机器学习数据增强中,水平翻转常用于增加训练数据多样性。但需要注意某些场景(如文字识别、非对称物体)可能不适合使用翻转增强。

图4.1.1 水平翻转
4.1.2 随机裁剪
随机裁剪是一种数据增强技术,常用于图像处理领域。通过在图像中随机选取一个区域并进行裁剪,可以增加数据的多样性,提升模型的泛化能力。随机裁剪的核心在于随机性,避免模型过度依赖特定区域的特征。使用方法如下
trans = transforms.Compose([
transforms.RandomResizedCrop((IMG_WIDTH, IMG_HEIGHT), scale=(.7, 1), ratio=(1, 1)),
])
#这个变换将根据 scale 随机调整输入图像的大小,然后将其裁剪(crop)到我们指定的大小。在本例中,我们
#将其裁剪到原始图像尺寸。为此,TorchVision 需要知道它所缩放图像的长宽比。由于这里的高度与宽度相同,#因此宽高比为 1:1。

图4.1.2 随机裁剪
4.2 图像增强-PCA
PCA(主成分分析)是一种降维技术,通过提取数据的主要特征成分来减少冗余信息。在图像增强中,PCA可用于去噪、特征提取和对比度提升。

4.2.1 改变图像的亮度、对比度、饱和度和色调
trans = transforms.Compose([
transforms.ColorJitter(
brightness=0, # 亮度调整范围
contrast=0, # 对比度调整范围
saturation=0, # 饱和度调整范围
hue=0, # 色调调整范围
)
])
4.2.2 图像增强整合
random_transforms = transforms.Compose([
transforms.RandomRotation(5),#旋转
transforms.RandomResizedCrop((IMG_WIDTH, IMG_HEIGHT), scale=(.9, 1), ratio=(1, 1)),
#裁剪
transforms.RandomHorizontalFlip(),#水平翻转
transforms.ColorJitter(brightness=.2, contrast=.5)#图像调节
])
以上代码的图片演示代码如下
row_0 = train_df.head(1)
y_0 = row_0.pop('label')
x_0 = row_0.values / 255
x_0 = x_0.reshape(IMG_CHS, IMG_WIDTH, IMG_HEIGHT)
x_0 = torch.tensor(x_0)
x_0.shape
image = F.to_pil_image(x_0)
plt.imshow(image, cmap='gray')
new_x_0 = trans(x_0)
image = F.to_pil_image(new_x_0)
plt.imshow(image, cmap='gray')

1229






