一、前情提要

        在深度学习专栏之前的部分中,介绍了什么是深度学习、梯度下降算法等知识点,主要掌握了第一把“神器”----全连接(nn.Linear)。全连接的作用是将矩阵从A维度转化到B维度,比如回归任务输入有4个变量, 需要输出1个值, 可以使用使用: nn.linear(4, 1) ;这样便让一个(16,4) 的矩阵经过nn.linear(4, 1) 转化为 (16,1)。如果中间要多算几次加强网络效果,可用nn.linear(4, 64)->nn.linear(64, 1)。

        代码里需要看懂数据集如何读取、模型写法以及训练流程。

        接下来向大家介绍深度学习的第二把“神器”----卷积。

二、情景导入:输入图片与分类输出

        现实中有很多问题并不是回归预测问题,比如:根据一封邮件的内容判断它是否是垃圾邮件;根据两个人的样貌判断是否为直系亲属;判断一个图片里的动物是鸟还是人,还是猫,狗等等

1、输入图片

        日常我们看到的彩色图片一般为三通道(RGB),可以将其信息转化为三维矩阵(张量),直接作为 CNN 的输入;在经过卷积层提取特征后,再将特征图拉直为一维向量,作为后续全连接层的输入。

2、分类输出

        将刚刚得到特征图展平为一维向量后再经过一层全连接训练,CNN的最终输出是一个类别得分向量。

        向量中每个数值对应模型判断图片属于该类别的预测得分(未归一化)或概率(实战中会通过Softmax 函数将得分归一化到0~1 之间,归一化后的值就是类别概率,所有类别的概率和为1)。

        但特征图展平的一维向量参数实在是太多了,这时就需要采用卷积神经网络减少参数量。

三、卷积神经网络

1、核心原理

(1) 准备输入和卷积核

假设:

        a、输入:一张 5×5 的单通道灰度图(数值 0-9)

        b、卷积核:一个 3×3 的小窗口(权重随机初始化),定义尺寸小于输入数据的小型权重矩阵

输入 (5x5):          卷积核 (3x3):
1 0 1 0 1           1  0 -1
0 1 0 1 0           0  1  0
1 0 1 0 1          -1  0  1
0 1 0 1 0
1 0 1 0 1

(2)滑动窗口(核心操作)

        把卷积核像滑动窗口一样,从输入的左上角开始,逐行逐列滑动,每次滑动,卷积核会覆盖输入上的一个 3×3 小区域。

(3)计算点积(Element-wise Multiply + Sum)

        这是卷积最核心的数学计算:对于卷积核覆盖的每一个小区域:

                a、对应位置相乘:卷积核的权重 × 输入的像素值

                b、全部加起来:把相乘后的 9 个结果求和

                c、填入输出:这个和就是输出特征图上的一个像素值

举个例子(计算第一个输出像素):

输入区域:          卷积核:        相乘后:
1 0 1              1  0 -1       1*1  0*0  1*(-1)  =  1  0 -1
0 1 0        ×     0  1  0   =   0*0  1*1  0*0     =  0  1  0
1 0 1             -1  0  1       1*(-1) 0*0  1*1   = -1  0  1

求和:1 + 0 -1 + 0 + 1 + 0 -1 + 0 + 1 = 1

        所以,输出特征图的第一个像素值 = 1。

(4)重复滑动,直到覆盖整张图

        按照同样的方法,把卷积核向右滑动(假设Stride=1),计算第二个像素;滑到最右边后,向下滑动一行,继续从左往右算;直到卷积核覆盖完输入的所有位置。

最终,我们得到一张 3×3 的输出特征图:

输出特征图 (3x3):
1 0 1
0 1 0
1 0 1

        加入卷积后的图像分类核心流程:

层类型 对应你之前的知识点 在流程里的位置
输入层 三通道 RGB 图片转成[B, C, H, W]张量 流程起点,接收原始图片,做归一化等预处理
卷积层 卷积核滑动提取特征、局部连接 + 权重共享大幅减少参数量 核心特征提取环节,替代了 “直接把整张图展平” 的操作,只提取图像的有效特征
激活层 给线性的卷积结果引入非线性,让网络能学习复杂特征 紧跟在每一次卷积之后,增强特征表达能力
池化层 特征降维、压缩计算量、保留关键特征 通常和「卷积 + 激活」组成一个卷积块,重复堆叠多次,实现从底层边缘到高层语义的层级化特征提取
全连接层 特征图展平为一维向量,整合高层特征 卷积 + 池化的输出是三维特征图,在这里先展平成一维向量,再送入全连接层,为最终分类做计算
输出层 Softmax 归一化,输出每个类别的概率 流程终点,把全连接层的原始分数,转成 0-1 之间、总和为 1 的类别概率,取最大值就是最终分类结果

        接下来让深入学习这些核心流程。

2、卷积计算

        即刚刚的点积计算,这里再举一个例子加深理解;设F (1)  =  红,F(-1)=  黑,从大图中找小图。

        得到的特征图中每个元素的位置都代表了大图中与小图面积重叠的一部分,可以从特征图上各个元素的数值判断大图中是否存在小图。

        在具体应用中也是如此,可以见微知著,从局部特征来进行图像分类。

        因此,我们的目标是通过合适的卷积核,最终得到一个有意义的特征图。

3、卷积核

        那么什么是卷积核呢?卷积核(也叫滤波器 / Filter)是卷积神经网络(CNN)的核心可学习单元,本质是一个固定尺寸的权重数值矩阵,是 CNN 实现图像特征提取的核心载体,也是 CNN 区别于传统全连接网络、能大幅压缩参数量的关键设计。

(1)本质与基础工作逻辑

(3*3*3的卷积核,有3个通道,长、宽均为3)

        a、物理本质:卷积核是一个 N 行 N 列的数值矩阵(深度学习最常用 3×3 尺寸,也有 5×5、1×1 等规格),矩阵里的每一个数值,都是模型可以通过训练迭代更新的权重参数。

        b、核心工作方式:卷积核会以设定的步长(Stride,常用步长 = 1),在输入的图像数字矩阵上逐行、逐列滑动;每次滑动到一个位置,就会和覆盖的图像局部区域做“对应位置相乘、全部结果求和”的点积运算,这个计算结果,就是输出特征图上的一个像素值。

        c、输出规律:1 个卷积核对输入图像完成完整的滑动卷积后,会输出 1 张对应的特征图;一层卷积层设置多少个卷积核,就会输出多少通道的特征图。

(2)核心特质

        模型训练开始前,卷积核里的权重是随机初始化的,此时它没有任何特征提取能力;训练过程中,卷积核会通过反向传播 + 梯度下降算法,不断自动调整内部的权重数值;

        训练完成后,每个卷积核都会收敛为一个专用的特征探测器:它会对自己负责捕捉的特征产生强烈响应(输出高数值),对无关特征则无响应(输出低数值);比如,有的卷积核专门捕捉竖边、有的专门捕捉横边、有的专门捕捉拐角。

(3)递进式的特征提取

        CNN 的卷积层是分层堆叠的,不同层的卷积核,会遵循从简单到复杂、从局部到整体的规律,提取不同层级的图像特征,这也是 CNN 能完成高精度图像分类的核心逻辑:

        a、浅层卷积核(第 1-2 层卷积层):只提取基础低维特征,比如各种方向的边缘(横、竖、斜)、纹理、明暗变化,这些是所有图像的通用基础特征;

        b、中层卷积核(第 3-5 层卷积层):将浅层提取的基础特征做融合,提取更复杂的中层形状特征,比如拐角、线条组合、物体的小部件(比如眼睛的轮廓、车轮的圆形);

        c、高层卷积核(最后几层卷积层):进一步融合中层的形状特征,提取高层语义特征,比如人脸、汽车、猫的整体轮廓或核心部件组合 —— 这是能直接区分图像类别的关键特征。

4、卷积存在的问题

        卷积能够减少参数,解决了原始特征图参数爆炸的问题,但每次卷积都减小了特征图尺寸,最后卷没了怎么办,如何保持特征图尺寸不变?

(1)如何保持特征图尺寸不变

        可以使用Padding(填充)抵消卷积操作带来的尺寸变化

        Padding 是在输入图像 / 特征图的边缘区域,填充固定数值的像素,从而调整输入的尺寸,抵消卷积操作带来的尺寸变化。深度学习中 99% 的场景使用Zero Padding(零填充),也就是在边缘填充数值为 0 的像素,也是我们日常所说的 Padding 的默认形式。

*手算神经网络

        需要理解模型每个步骤的参数变化,才能更好掌握训练过程,下面是练习时间~

(卷积核大小为 2,默认就是指2×2 尺寸的正方形卷积核)

(2)怎么让特征图变小

        如果依靠卷积每次减小2个单位,速度太慢,所以要依靠“扩大步长”和“池化”。

a、扩大步长

        扩大步长的原理就是下采样。

        下采样(Downsampling) 就是对特征图做尺寸缩小、分辨率降低的操作,核心目的是减少特征图的宽 / 高维度(通道数通常不变 / 增加),从而降低计算量、减少参数、抑制过拟合,同时还能提升特征的感受野,是 CNN 中实现特征降维与层级抽象的关键手段。

        简单理解,下采样就是把特征图 “压缩”,比如从 224×224 的特征图变成 112×112,保留核心特征的同时精简数据,和我们把高清图片缩成小图的逻辑类似:图片像素适当降低并不影响人眼识别。

        可以得到卷积尺寸计算公式:

        但官方一般不采用此种方法,会丢失信息,且引入计算。

b、池化(Pooling)

        池化也叫下采样 / 汇聚,是对卷积输出的特征图进行局部区域聚合、降采样的操作:用一个固定尺寸的滑动窗口(池化核)在特征图上滑动,用窗口内像素的统计值替代整个窗口区域的所有像素,从而在保留核心特征的前提下,压缩特征图的宽高尺寸。

常见的局部池化有两种:

        a、最大池化(Max Pooling):取局部区域的最大值,能更好保留边缘、纹理等强特征,是图像任务的首选
        b、平均池化(Average Pooling):取局部区域的平均值,能保留更平滑的全局特征,多用于分类层前的特征整合。

常见的全局池化有两种:

        a、全局平均池化(GAP):聚合通道的全局平均特征,能保留更多全局信息,泛化能力更强,是分类任务的绝对主流
        b、全局最大池化(GMP):只保留通道的局部最大值特征,易丢失全局信息,适合目标检测等需要局部特征的任务,分类中极少用。

        最大池化用在CNN 中间的特征提取层,目标是保留局部强特征、做下采样;全局平均池化用在CNN 最后一层的特征聚合阶段,目标是整合全局通道信息、输出分类特征,二者的设计初衷和适用场景根本不重叠

        简单来说:中间层用 Max Pooling 是为了「选优」,挑出局部最强特征做深层提取;最后层用 GAP 是为了「求和」,整合全图通道特征做分类判断

*手搓神经网络

● 一张图片通常被转换为3*224*224,你能将其变为1024*7*7么?

        采用卷积+下采样(池化)的方法:卷积核用1024*3*3,padding=1,stride=1,卷积1次变为1024*224*224,224 缩至 7 需要5 次 2 倍下采样(池化),即相当于224 / 32 = 7。

● 你用了多少次卷积?

        仅用了1次卷积。

● 你觉得一次好吗? 多少次好一点?

       一次卷积不好,因为无法实现分层特征提取,感受野太小,模型难以训练;一般需要 5 次左右卷积(配合下采样),才能有效提取从底层到高层的完整特征。

要把 3×224×224 变成 1024×7×7,应该遵循 CNN 的 “多次卷积堆叠 + 逐步下采样 + 逐步升通道” 的逻辑,比如:

        第 1 阶段:3×224×224 → 卷积(64 个 3×3 核)→ 64×224×224 → 池化 → 64×112×112

        第 2 阶段:64×112×112 → 卷积(128 个 3×3 核)→ 128×112×112 → 池化 → 128×56×56

        第 3 阶段:128×56×56 → 卷积(256 个 3×3 核)→ 256×56×56 → 池化 → 256×28×28

        第 4 阶段:256×28×28 → 卷积(512 个 3×3 核)→ 512×28×28 → 池化 → 512×14×14

        第 5 阶段:512×14×14 → 卷积(1024 个 3×3 核)→ 1024×14×14 → 池化 → 1024×7×7

        (有多少个卷积核,新的特征图深度就有多深)

        这样既完成了维度转换,又实现了分层特征提取,梯度传播也稳定,模型才能真正训得动、效果好。

四、卷卷卷, 怎么卷出来一个类别呢?

 CNN分类完整流程:输入预处理 -> 卷积提特征 -> 聚合展平 -> 类别输出 ->Loss 计算 -> 反向传播梯度求解 -> 参数更新 -> 迭代收敛

        CNN 分类的本质:流程分为分为两段----前半段“卷卷卷”:通过“卷积→激活→池化”堆叠,把原始图片转换为高维、抽象的特征张量(如刚才事例中的1024×7×7),完成特征提取;后半段:把特征张量的空间信息(7×7)和通道信息(1024)做聚合,映射到“类别数”维度,输出每个类别的概率,取最大值为预测类别。

1、“卷积提特征+池化聚合+全连接分类”的经典方法

         这是 VGG等经典 CNN 的分类逻辑,最易理解和实现,也是手搓 CNN 的入门标配,核心 为4 步,全程 “卷到底 + 最后映射”:

        (1)卷积层:通过 N 次 3×3 卷积堆叠,提取从低维到高维的分层特征,可通过 padding 和 stride 灵活控制特征图尺寸;
        (2)全局池化层:通过全局平均 / 最大池化,将三维特征张量聚合为一维向量,彻底丢掉空间维度,避免全连接层参数爆炸;
        (3)全连接层:将聚合后的特征向量映射到类别数维度,可选加 Dropout 抑制过拟合;
        (4)输出层:多分类用 Softmax、二分类用 Sigmoid 输出类别概率,或直接输出用原始值做交叉熵损失高效训练。

三种常见的 “卷积到全连接” 方式(以 1024×7×7 为例):

(1)直接展平(最基础)

把 1024×7×7 直接展平成 1024 × 7 × 7 = 50176 维的向量。然后用 Linear(50176, 3) 直接输出 3 个类别的得分。

缺点:参数量巨大(50176×3),容易过拟合。

(2)先降维再全连接(更常用)

先加一层全连接:Linear(50176, 1024),把 5 万维降到 1024 维。再用 Linear(1024, 3) 输出最终分类。

优点:减少参数量,防止过拟合。

(3)全局池化(更高级)

用 MaxPooling(7) 或 AvgPooling(7),把 7×7 的区域池化成 1×1。特征图就从 1024×7×7 变成了 1024×1×1,相当于每个通道只保留一个全局特征值。再用 Linear(1024, 1024) → Linear(1024, 3)。

优点:极大减少了参数量,同时保留了全局信息,是现在很多网络(如 ResNet)的常用做法。

2、全程无连接(现代CNN主流)

        ResNet /GoogLeNet/DenseNet 的设计逻辑便是这样,全程只用卷积层,没有任何全连接层,更简洁、更适合深层网络,其核心是用 1×1 卷积替代全连接层,步骤比经典法更简洁:

        (1)前端卷积层:通过 N 次卷积堆叠,提取从低维到高维的分层特征;
        (2)全局池化层:通过全局平均池化,将三维特征张量聚合为 C×1×1,彻底丢掉空间维度;
        (3)1×1 卷积层:用 N 个 1×1 卷积核(N 为类别数),将 C×1×1 直接卷积为 N×1×1,数学上等价于全连接层的线性映射,但全程保持张量结构,无需展平;(若原始图为1024*224*224,用10*1*1的卷积核卷积,点积加和则每层都是与卷积和相同位置点积,然后把所有结果叠加)
        (4)输出层:展平后通过 Softmax/Sigmoid 输出类别概率。

        纯卷积法结构更简洁,天然保留空间位置信息,更适配深层网络与迁移学习。

*注意

(1)全局池化为什么用「平均」不用「最大」?

全局平均池化(GAP):聚合通道的全局平均特征,能保留更多全局信息,泛化能力更强,是分类任务的绝对主流;
全局最大池化(GMP):只保留通道的局部最大值特征,易丢失全局信息,适合目标检测等需要局部特征的任务,分类中极少用。
(2)Softmax 什么时候加?

训练时:如果用 PyTorch 的nn.CrossEntropyLoss损失函数,不要加 Softmax—— 这个损失函数内置了 Softmax 和 LogLoss,加了会导致计算冗余、梯度异常;
推理时:需要输出类别概率时,一定要加 Softmax,把原始输出值转成 0~1 的概率,方便看预测置信度。

(3)怎么改「卷卷卷」的层数?

        前端卷积层可以随便加、随便减、随便改参数(比如加更多下采样、扩增通道数到 1024),只要最后把feature_channels(经典法)或1×1卷积的输入通道(纯卷积法)改成最终特征图的通道数,不管前端卷积层怎么设计,最后都能通过全连接层 / 1×1 卷积层,强制映射到任务要求的类别数,网络结构完整兼容、能正常跑通训练、能正常输出预测结果,这就是 CNN 的灵活性 ——“卷特征” 和 “分类” 解耦,随便怎么卷都能映射到类别。

3、怎么求Loss

(1)前置步骤:Softmax转换

        模型全连接层输出的是原始得分(如猫的得分 23、狗 11.7、树 20),这些数值还没有与概率建立起联系,需通过Softmax转为 0-1 的概率分布,满足 “所有类别概率和为 1”。

      

        猫的得分 23 最大,经 Softmax 后概率为 0.953(占比最高),狗 0、树 0.047,将 “得分大小” 转化为 “类别归属的置信度”,为后续损失计算提供基础。

        真实标签采用 One-Hot 编码(独热编码),如猫的标签为[0,1,0],仅正确类别位置为 1,其余为 0。

Softmax 函数的 PyTorch 实现如下:

import torch
import torch.nn as nn
 
# 1. 定义模型输出的原始得分(Logits):对应狗:11.3, 猫:23, 树:20
y = torch.tensor([11.3, 23, 20], dtype=torch.float32)
 
# 2. 创建Softmax层:dim=-1表示在最后一个维度(类别维度)计算概率
soft = nn.Softmax(dim=-1)
 
# 3. 计算概率分布并打印
y_prob = soft(y)
print("原始得分(Logits):", y)
print("Softmax后的概率分布:", y_prob)
print("概率总和:", torch.sum(y_prob))  # 验证概率和为1
 
'''
输出结果:
原始得分(Logits): tensor([11.3000, 23.0000, 20.0000])
Softmax后的概率分布: tensor([1.1431e-05, 9.5299e-01, 4.6998e-02])
概率总和: tensor(1.0000)
'''

(2)交叉熵损失

        分类任务不能使用回归的 MAE/MSE(无法有效惩罚错误分类),核心采用交叉熵损失(CrossEntropy Loss),分为二分类与多分类两种形式。

        二分类任务里,每个样本要么是正类,要么是负类,只能是1或0。两种情况代入公式:

        多分类任务里,有多个预测结果:预测越准确,正确类别概率越接近 1,log(1)≈0,损失值越小;预测越错误,正确类别概率越接近 0,log(0)→−∞,损失值急剧增大(有效惩罚错误)。

*交叉熵损失的补充:

a、预测的分布(Predicted Distribution)

        就是模型经过 Softmax 输出的每个类别的概率,比如 [0.0, 0.953, 0.047]。它代表了模型对 “这张图属于每个类别的置信度”。

b、真实值的下标(Target Indices)

        就是真实标签的类别编号,比如 “猫” 对应的下标是 1(假设类别顺序是狗:0, 猫:1, 树:2)。(注意:在 PyTorch 等框架中,交叉熵损失函数直接接受类别下标(如 1),而不是 One-Hot 向量,内部会自动处理。)

关于交叉熵的更多内容,请见李老师这篇文章:https://blog.csdn.net/YI_SHU_JIA/article/details/121610828?spm=1001.2014.3001.5502

五、完整的图像分类任务流程

1、前向传播(forward):从图片到预测结果,分为三个阶段:

(1)卷积 + 池化层

        a、卷积:用多个卷积核在图片上滑动,提取局部特征(如鸟的喙、羽毛纹理),生成多张特征图。

        b、非线性激活(如引入ReLU函数):给卷积结果加上非线性变换,让模型能学习更复杂的模式。

        c、池化(Max Pooling):对特征图进行下采样,缩小尺寸,保留最显著的特征,同时减少计算量。

        结果:得到一个 “又深又小” 的特征图(如 1024×7×7)。

(2)全连接层

        a、展平:把多维的特征图 “拉直” 成一维向量,让全连接层能处理。

        b、全连接计算:将一维向量输入全连接层,把提取到的特征组合起来,输出每个类别的原始得分。

(3)分类输出

        c、Softmax:将原始得分转换为每个类别的概率分布(如 [0, 0.953, 0.047]),表示模型对 “这张图属于每个类别的置信度”。

        d、预测:概率最高的类别就是模型的预测结果(如 95.3% 是猫)。

2、反向传播(backward):从损失到学习
这是模型 “从错误中学习” 的过程:

1)计算损失(Loss)

用真实标签(One-Hot 编码,如 [0, 1, 0])和模型预测的概率分布,计算交叉熵损失;损失值越大,说明模型预测得越错。

2)梯度下降(Gradient Descent)

从损失值出发,反向计算每个参数(卷积核权重、全连接层权重)的梯度;根据梯度更新参数,让下一次预测的损失值更小。

3、总结

前向传播:输入图片 → 卷积提取特征 → 全连接组合特征 → Softmax 输出概率。

反向传播:计算损失 → 反向求梯度 → 更新参数。

目标:通过不断迭代,让模型的预测概率分布越来越接近真实标签的分布,从而提高分类准确率。

六、大量带标签的数据

        图像分类任务,必须依赖大量带标签的图片来训练模型。没有高质量、大规模的带标签数据,再先进的模型也无法发挥作用。比如,猫狗分类需要大量标注了 “猫”“狗” 的图片,人脸识别需要大量标注了对应身份的人脸图片。

        数据集与模型相互促进,更大的数据集催生了更强大的模型,而更强大的模型又推动了对更大、更复杂数据集的需求。经典图片数据集:

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐