尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

【深度学习入门系列 06】CNN 完整结构解析:一张图片如何从输入变成分类结果

【深度学习入门系列 06】CNN 完整结构解析:一张图片如何从输入变成分类结果 在前面的文章中我们已经分别学习了 CNN 的几个核心组件卷积Convolution、步幅Stride、填充Padding、多通道卷积和池化Pooling。但只理解单个模块还不够。真正搭建网络时我们更需要回答下面这些问题一张图片进入 CNN 后数据形状会怎样变化卷积层为什么能提取特征全连接层、Softmax 和损失函数分别做什么模型训练与实际预测有什么区别本文将把这些知识串成一条完整的数据流并通过一个可运行的 PyTorch 示例演示图片从输入到分类输出的全过程。一、先看全局CNN 到底在做什么一个经典的图像分类 CNN 可以概括为输入图像 ↓ [卷积 → 激活 → 下采样] × N ↓ 分类头 ↓ Logits ↓ 类别概率 / 预测结果从功能上看它包含两部分特征提取器卷积层逐步学习边缘、纹理、局部形状等视觉模式并扩大有效感受野。分类头将提取到的特征映射为各个类别的分数。需要注意的是“卷积负责特征提取、全连接负责分类”只是便于入门的经典说法。现代 CNN 常用全局平均池化Global Average PoolingGAP 线性层代替大规模全连接层CNN 也不仅能做分类还可用于目标检测、图像分割、姿态估计等任务。二、输入层CNN 看到的不是图片而是张量计算机中的图像会被表示成数值张量。灰度图28 × 28 × 1高度为 28宽度为 28通道数为 1。RGB 彩色图224 × 224 × 3包含 R、G、B 三个颜色通道。模型通常一次处理多张图片因此还需要加入批次维度N。不同框架常见的数据排列方式不同TensorFlow 常用N × H × W × CPyTorch 常用N × C × H × W例如PyTorch 中一批 32 张 RGB 图片的形状可能是[32, 3, 224, 224]送入网络之前通常还会把像素值缩放到[0, 1]并按通道进行标准化。标准化不会改变张量形状但能让优化过程更稳定。三、卷积层提取局部特征卷积层使用一组可学习的卷积核在输入上滑动对局部区域执行加权求和从而生成新的特征图Feature Map。假设输入为32 × 32 × 3卷积层配置为卷积核大小 K 3 × 3 卷积核数量 C_out 16 步幅 S 1 填充 P 1输出为32 × 32 × 16空间尺寸保持不变是因为3 × 3卷积使用了padding 1输出通道数变为 16是因为该层包含 16 个卷积核每个卷积核产生一张特征图。1. 卷积输出尺寸公式不考虑空洞卷积时单个空间维度的输出尺寸为H_out floor((H_in 2P - K) / S) 1宽度同理。代入上面的例子H_out (32 2 × 1 - 3) / 1 1 322. 卷积层参数量带偏置项时卷积层的参数量为参数量 (K_h × K_w × C_in 1) × C_out因此上述卷积层共有(3 × 3 × 3 1) × 16 448个可学习参数。这里的1表示每个输出通道对应一个偏置项。这也说明了卷积的一个关键优势卷积核在整张图像上共享参数参数量不会随着图像空间位置的增加而成倍增长。四、激活函数为网络引入非线性卷积和全连接本质上都是线性变换。如果网络只叠加线性层无论叠多少层整体仍然等价于一次线性变换无法拟合复杂模式。因此每次卷积后通常会加入非线性激活函数。最常用的入门选择是 ReLUReLU(x) max(0, x)也就是负数 → 0 正数 → 保持不变ReLU 计算简单、训练速度快并能在一定程度上缓解 Sigmoid、Tanh 等激活函数在深层网络中的梯度消失问题。但它也可能出现“神经元死亡”因此工程中还会见到 Leaky ReLU、GELU、SiLU 等变体。激活函数不会改变特征图的形状。例如32 × 32 × 16 → ReLU → 32 × 32 × 16五、池化层压缩特征图池化层用于降低特征图的空间尺寸从而减少后续计算量和显存占用。经典 CNN 中最常见的是最大池化Max Pooling。例如对4 × 4特征图使用2 × 2池化窗口和stride 24 × 4 → 2 × 2最大池化会在每个局部窗口中保留最大值。它没有可学习参数通常也不会改变通道数32 × 32 × 16 → MaxPool(2 × 2, stride2) → 16 × 16 × 16下采样可以提升模型对小范围位置变化的鲁棒性但也会损失空间细节。因此池化并不是越多越好。现代网络也经常用步幅卷积代替池化完成下采样。六、卷积块网络如何从像素逐步形成高级特征经典 CNN 往往重复堆叠下面的结构Conv → ReLU → Pool更常见的工程结构还会加入批归一化Conv → BatchNorm → ReLU → Pool随着网络加深常见变化趋势是特征图的高度和宽度逐渐减小通道数逐渐增加单个神经元对应的有效感受野逐渐扩大特征表示通常从局部边缘、纹理逐步过渡到更复杂的结构和语义模式。例如32 × 32 × 3 ↓ Conv(3×3, 16) 32 × 32 × 16 ↓ MaxPool(2×2) 16 × 16 × 16 ↓ Conv(3×3, 32) 16 × 16 × 32 ↓ MaxPool(2×2) 8 × 8 × 32“浅层学边缘、深层学物体”是帮助理解的概括并不是每个神经元都严格遵循固定分工。具体学到什么仍由数据、任务和训练过程共同决定。七、分类头Flatten 与全局平均池化经过多层卷积后我们得到一组高层特征图。要把它们转换成类别分数常见做法有两种。1. 经典做法Flatten 全连接层若特征图形状为8 × 8 × 32Flatten 会将其展开为8 × 8 × 32 2048然后送入全连接层2048 → 128 → 10这种方式表达能力强但参数量较大。仅2048 → 128这一层就有2048 × 128 128 262272个参数容易增加过拟合风险。2. 现代常用做法GAP 线性层全局平均池化会对每个通道的所有空间位置求平均8 × 8 × 32 → GAP → 1 × 1 × 32 → 32再接一个32 → 10的线性层即可完成十分类。该线性层只有32 × 10 10 330个参数。GAP 能显著减少参数量也能自然适配不同输入尺寸因此在 ResNet 等现代 CNN 中非常常见。八、输出层Logits、Softmax 与损失函数分类头最后输出的原始分数称为Logits。假设是三分类网络可能输出[2.1, 0.8, -0.4]这些数不是概率不要求位于[0, 1]总和也不必等于 1。单标签多分类任务中可以使用 Softmax 将它们转换为概率p_i exp(z_i) / Σ_j exp(z_j)例如猫0.75 狗0.20 鸟0.05预测类别通常取概率最大的类别即argmax的结果。这里有一个很容易踩坑的细节训练时PyTorch 的CrossEntropyLoss直接接收 Logits不需要先手动执行 Softmax。该损失函数内部已经完成了数值更稳定的LogSoftmax NLLLoss。另外Softmax 适合“每张图片只属于一个类别”的互斥分类问题如果一张图片可以同时拥有多个标签应使用 Sigmoid并搭配二元交叉熵损失。九、完整示例逐层追踪形状与参数量下面设计一个十分类 CNN输入为32 × 32 × 3层配置输出形状可学习参数量输入RGB 图像32 × 32 × 30Conv13×3, 3→16, S1, P132 × 32 × 16448ReLU激活函数32 × 32 × 160MaxPool2×2, S216 × 16 × 160Conv23×3, 16→32, S1, P116 × 16 × 324,640ReLU激活函数16 × 16 × 320MaxPool2×2, S28 × 8 × 320GAP自适应平均池化1 × 1 × 320Linear32→1010330可以看到整条数据流的本质是空间尺寸逐步减小 通道数逐步增加 局部像素逐步转换为可分类的特征表示十、PyTorch 实现下面的代码与上一节的结构一一对应import torch import torch.nn as nn class SimpleCNN(nn.Module): def __init__(self, num_classes10): super().__init__() self.features nn.Sequential( nn.Conv2d(3, 16, kernel_size3, stride1, padding1), nn.ReLU(inplaceTrue), nn.MaxPool2d(kernel_size2, stride2), nn.Conv2d(16, 32, kernel_size3, stride1, padding1), nn.ReLU(inplaceTrue), nn.MaxPool2d(kernel_size2, stride2), ) self.classifier nn.Sequential( nn.AdaptiveAvgPool2d((1, 1)), nn.Flatten(), nn.Linear(32, num_classes), ) def forward(self, x): x self.features(x) logits self.classifier(x) return logits model SimpleCNN(num_classes10) x torch.randn(4, 3, 32, 32) # 4 张 RGB 图片 logits model(x) print(logits.shape) # torch.Size([4, 10]) print(logits.softmax(dim1)[0]) # 查看第 1 张图片的类别概率训练时的核心步骤为criterion nn.CrossEntropyLoss() optimizer torch.optim.Adam(model.parameters(), lr1e-3) labels torch.tensor([1, 3, 2, 0]) optimizer.zero_grad() logits model(x) loss criterion(logits, labels) # 直接传入 Logits loss.backward() optimizer.step()这几行代码对应完整训练闭环前向传播 → 计算损失 → 反向传播 → 更新参数实际预测时则不需要反向传播model.eval() with torch.no_grad(): logits model(x) predictions logits.argmax(dim1)十一、CNN 为什么适合图像任务CNN 的优势主要来自三个重要的归纳偏置。1. 局部连接卷积核只观察局部区域符合图像中相邻像素通常具有较强关联的特点。2. 权值共享同一个卷积核会在整张图像上重复使用大幅减少参数量并让模型能够在不同位置识别相似模式。3. 平移等变性与位置鲁棒性当输入中的目标发生平移时卷积特征也会相应平移这称为平移等变性。池化、步幅卷积和全局平均池化可以进一步增强模型对小范围位置变化的鲁棒性但不能简单地理解为“完全不受位置影响”。CNN 也存在局限连续下采样可能丢失细粒度空间信息要建模长距离关系往往需要更深的网络或更大的卷积核模型效果仍高度依赖数据质量、网络设计和训练策略。十二、经典 CNN 与现代 CNN 的区别学习 CNN 时我们通常从Conv → ReLU → Pool → Flatten → FC开始因为它直观、容易理解。实际工程中的现代 CNN 还常见以下设计用 BatchNorm 或其他归一化层稳定训练用残差连接缓解深层网络的优化困难用步幅卷积完成下采样用 GAP 替代大规模 Flatten 全连接层在分类头中按需加入 Dropout 抑制过拟合使用数据增强、学习率调度和权重衰减提升泛化能力。这些改进没有改变 CNN 的核心逻辑通过可学习的局部运算逐层构建特征表示再根据任务输出预测结果。十三、总结一张图片在 CNN 中的完整旅程可以概括为图像张量 ↓ 卷积提取局部模式 ↓ 激活函数引入非线性 ↓ 池化或步幅卷积完成下采样 ↓ 多层堆叠形成更高层特征 ↓ Flatten 或 GAP 汇总特征 ↓ 线性层输出 Logits ↓ Softmax / Argmax 得到分类结果如果只记住一句话可以这样理解CNN 利用局部连接和权值共享逐层学习图像特征并将最终的特征表示映射为任务所需的预测结果。至此我们已经把卷积、步幅、填充、多通道、池化和完整网络结构连成了一条完整主线。下一步可以尝试在 CIFAR-10 数据集上训练本文的SimpleCNN观察训练损失、验证准确率以及不同网络结构对结果的影响。
返回列表