Appearance
第4章 卷积神经网络 — 让网络"看见"图像
Chapter 4: Convolutional Neural Networks — Teaching Networks to "See" Images
卷积(convolution /ˌkɒnvəˈluːʃən/)神经网络(Convolutional Neural Network, CNN) 是深度学习在计算机视觉领域取得突破性进展的核(kernel /ˈkɜːrnl/)心引擎。从手写数字识别到自动驾驶,从医疗影像诊断到人脸识别,CNN 无处不在。本章将深入卷积操作的数学本质,理解 CNN 为何天生适合图像,并沿着经典架构的演进路线,一步步走向现代 CNN 设计思想。
时间线:
- 1989: LeCun 提出卷积神经网络(CNN)
- 1998: LeCun et al. 提出 LeNet-5
- 2012: AlexNet 赢得 ImageNet 竞赛,深度学习革命开始
- 2015: He et al. 提出 ResNet(残差网络)
CNNs are the engine behind deep learning's breakthrough in computer vision. From handwritten digit recognition to autonomous driving, from medical imaging to face recognition, CNNs are everywhere. This chapter dives into the mathematics of convolution, explains why CNNs are inherently suited for images, and traces the evolution from LeNet to modern ConvNeXt.
前置知识 (Prerequisites): 第3章(线性模型、神经网络基础),微积分(积分、偏导数),线性代数(矩阵运算) 依赖库 (Dependencies): torch>=2.1.0, torchvision>=0.16.0, matplotlib>=3.7.0, numpy>=1.24.0
Code companion: code/cnn_cifar10.py — 实际输出见文末附录
目录 (Table of Contents)
- 卷积运算的数学定义 📐 1.3 关键参数 (Key Parameters) 📐
- 为什么 CNN 适合图像
- 池化(pooling /ˈpuːlɪŋ/) (Pooling)
- 经典架构演进
- 小结 (Summary)
1. 卷积运算的数学定义 (Mathematical Definition of Convolution)
1.1 从连续到离散 (From Continuous to Discrete)
卷积(Convolution)是一个在数学、信号处理和深度学习中都极其重要的运算。它的核心思想是:用一个函数(核/滤波器)去"扫描"另一个函数,在每一点上计算加权和。
连续定义 (Continuous Definition):
两个连续函数
其中
离散定义 (Discrete Definition):
在计算机中,信号是离散的。对于一维离散信号
1.2 二维离散卷积 (2D Discrete Convolution)
在图像处理中,输入是二维矩阵
其中
💡 直观理解: 将
看作一个"窗口",它在 上逐像素滑动。在每个位置,窗口内的像素值与核的对应权重相乘后求和,得到一个输出值。这个输出值表示"核模板"在当前窗口位置的匹配程度。
1.3 关键参数 (Key Parameters)
| 参数(parameter /pəˈræmɪtər/) | 符号 | 含义 | 公式 |
|---|---|---|---|
| 核大小 | 卷积窗口的尺寸(如 | — | |
| 步长 | 核每次滑动的像素数 | — | |
| 填充 | 输入边缘补零的圈数 | — | |
| 扩张 | 核元素之间的间隔 | — |
输出尺寸公式:
给定输入尺寸
常见的填充模式:
- Valid 卷积 (无填充):
,输出尺寸减小 - Same 卷积:
( 为奇数),输出尺寸与输入相同 - Full 卷积:
,输出尺寸增大
💡 直觉: 可以把 kernel 想象成一个"特征探测器"。比如一个
的核,如果中间列全是正数、两边全是负数,它就会对垂直边缘有强烈响应。不同的核权重对应检测不同的特征——边缘、纹理、颜色变化等。
🔍 完整演算:输出尺寸公式验证 — 多参数组合手算
📐 公式
卷积输出尺寸的通用公式(包含扩张 dilation):
当扩张
📖 参数含义
| 符号 | 名称 | 含义 |
|---|---|---|
| 输入尺寸 (Input Size) | 输入特征图的宽度(或高度) | |
| 核尺寸 (Kernel Size) | 卷积核的宽度(假设正方形核) | |
| 步长 (Stride) | 核每次滑动的像素数 | |
| 填充 (Padding) | 输入边缘补零的圈数 | |
| 扩张 (Dilation) | 核元素之间的间隔, | |
| 向下取整 (Floor) | 结果必须是整数,不能有半个像素 |
📝 公式来源
公式的直观含义:计算核能在输入上滑动多少次。
核覆盖的有效宽度为
✏️ 手算演示
以下用
例 1: Valid 卷积(无填充)
参数:
输出
验证: 核在
例 2: 步长为 2 的下采样
参数:
输出
验证: 核以步长 2 滑动,起始位置为
例 3: Same 卷积(保持尺寸)
参数:
输出
验证: 填充 1 圈零后,输入变为
总结对比
| 例 | 效果 | |||||
|---|---|---|---|---|---|---|
| 1 | 28 | 3 | 1 | 0 | 26 | Valid 卷积,尺寸缩小 |
| 2 | 28 | 3 | 2 | 0 | 13 | 步长为 2,下采样至约一半 |
| 3 | 28 | 3 | 1 | 1 | 28 | Same 卷积,尺寸不变 |
🌍 实际意义
- 设计网络时,输出尺寸公式是 CNN 架构设计的基础工具。每一层的
决定了下一层的输入尺寸,影响着参数量和感受野的覆盖范围。 - 下采样策略:步长 2 的卷积(
)是现代 CNN 中替代池化层的常用下采样方式,如 ResNet、ConvNeXt 等架构均采用此设计。 - Same 卷积:通过
保持特征图尺寸不变,使得网络可以堆叠任意深度的卷积层。这是 VGG、ResNet 等架构大量使用 核加 的原因。 - 自动推导:理解公式后,给定任意参数组合都能快速算出输出尺寸,避免编码时的维度错误。
🔍 完整演算:卷积核手算 — 3×3 核在 5×5 输入上的滑动过程
📐 公式
二维离散卷积定义:
其中
📖 参数含义
| 符号 | 名称 | 含义 |
|---|---|---|
| 卷积核 / 滤波器 (Kernel/Filter) | 可学习的特征探测器,本例为 | |
| 输出特征图 (Output Feature Map) | 卷积操作后得到的二维激活图 | |
| 输入 (Input) | 待卷积的输入数据,本例为 | |
| stride | 步长 (Stride) | 核每次滑动的像素数,本例 |
| padding | 填充 (Padding) | 输入边缘补零的圈数,本例 |
📝 公式来源
二维离散卷积直接来自连续卷积的离散化。在信号处理中,卷积
本例中
✏️ 手算演示
给定
Step 1: 核在左上角
核覆盖的区域为
对应元素相乘:
Step 2: 核向右滑动一步
核覆盖
对应元素相乘:
Step 3: 核向下滑动一步
核覆盖
与 Step 2 相同的对称位置,结果也相同:
Step 4: 完整输出特征图
按此方式计算所有
输出尺寸为
🌍 实际意义
- 边缘检测:卷积核的权重模式决定了它检测的特征类型。本例中的拉普拉斯核对局部亮度变化敏感——当核覆盖区域中心与周围差异大时,输出值大;反之输出值接近 0。
- 从低级到高级:浅层卷积核检测边缘、纹理等低级特征;中层卷积核检测形状、部件;深层卷积核检测物体、场景等高级语义特征。
- 可学习性:在 CNN 训练中,卷积核的权重不是手工设计的,而是通过反向传播从数据中自动学习得到的,使网络能针对特定任务发现最优特征探测器。
- 参数共享优势:同一个
核(仅 9 个参数)扫描整个 输入,无论特征出现在哪个位置,都能被同一个探测器识别。
2. 为什么 CNN 适合图像 (Why CNNs are Suited for Images)
CNN 之所以在图像上取得巨大成功,源于三个关键设计原则。这些原则利用了自然图像的固有结构。
2.1 局部连接 (Local Connectivity)
在传统的全连接网络(Fully Connected Network)中,每个输出神经元与所有输入神经元相连。而在 CNN 中,每个输出神经元只连接到输入的一个局部区域(感受野, receptive field)。
直觉: 自然图像中,相邻像素之间的相关性远高于远距离像素。你不需要看整张图就能识别一个边缘或一个角点——局部信息就足够了。
参数量的对比:
- 全连接层:每个输出神经元有
个连接 - 卷积层:每个输出神经元有
个连接
对于一张
2.2 参数共享 (Parameter Sharing)
CNN 中,同一个核会在输入的所有位置上共享相同的权重。这意味着无论特征出现在图像的哪个位置,同一个探测器都能检测到它。
直觉: 一个垂直边缘检测器在图像左上角有用,在右下角也同样有用。我们不需要为每个位置学习独立的探测器。
参数量的巨大差异:
对于输入
- 全连接层:
个参数 - 卷积层:
个参数
对于
| 层类型 | 参数数量 | 比例 |
|---|---|---|
| 全连接层 | ||
| 卷积层 |
参数共享将参数量降低了约 5000 倍!
2.3 平移等变性 (Translation Equivariance)
如果输入图像平移了几个像素,特征图也会相应地平移几个像素。这一性质被称为平移等变性。
其中
直觉: 猫无论出现在图像的左上角还是右下角,CNN 都能检测到它。全连接网络需要从训练数据中"记住"猫在不同位置的特征,而 CNN 通过卷积操作天然获得了这一能力。
2.4 对比总结 (Summary Comparison)
| 性质 | 全连接层 | 卷积层 |
|---|---|---|
| 连接方式 | 全局连接 | 局部连接(感受野) |
| 参数共享 | ❌ 每个位置独立参数 | ✅ 全局共享 |
| 平移等变性 | ❌ 需要数据增强学习 | ✅ 天然具备 |
| 参数数量( | ||
| 对空间结构的利用 | ❌ 展平为向量 | ✅ 保持 2D 结构 |
3. 池化 (Pooling)
池化层是 CNN 中另一个核心组件,它通过下采样来降低特征图的空间维度。
3.1 最大池化 (Max Pooling)
在
输入特征图: 输出 (2×2 Max Pooling):
[1, 3, 2, 4] [3, 4]
[5, 6, 7, 8] → [6, 8]
[9, 1, 2, 3]
[4, 5, 6, 7]3.2 平均池化 (Average Pooling)
在
输入特征图: 输出 (2×2 Avg Pooling):
[1, 3, 2, 4] [3.75, 5.25]
[5, 6, 7, 8] → [4.75, 4.50]
[9, 1, 2, 3]
[4, 5, 6, 7]3.3 为什么需要池化?
1. 降低维度 (Dimensionality Reduction)
池化将特征图的宽高减半,参数量和计算量随之降低为原来的
2. 平移不变性 (Translation Invariance)
池化使得输出对微小平移不敏感。想象一个
💡 区分等变 vs. 不变: 卷积提供平移等变性(特征位置随输入变化),池化提供平移不变性(对微小平移不敏感)。等变性有助于定位,不变性有助于识别。
3. 增大感受野
每一步池化都让后续卷积层的感受野扩大一倍,使网络能捕捉更大范围的上下文信息。
3.4 池化 vs. 步长卷积
现代 CNN 设计中,池化层越来越多地被步长卷积(strided convolution)替代,因为:
- 步长卷积的参数是可学习的,而池化无参数
- 步长卷积可以与卷积层融合,减少层数
4. 经典架构演进 (Architecture Evolution)
CNN 从 1998 年的 LeNet 到今天的 ConvNeXt,经历了近 25 年的演进。理解这条演进路线,就是理解深度学习视觉领域的设计哲学演变。
mermaid
flowchart LR
LeNet[LeNet 1998] -->|"更大更深"| AlexNet[AlexNet 2012]
AlexNet -->|"更规整"| VGG[VGG 2014]
VGG -->|"残差连接"| ResNet[ResNet 2015]
ResNet -->|"复合缩放"| EfficientNet[EfficientNet 2019]
ResNet -->|"现代化改造"| ConvNeXt[ConvNeXt 2022]4.1 LeNet-5 (1998) — 开山之作
由 Yann LeCun 于 1998 年提出,用于手写数字识别(MNIST)。
结构: Conv(5×5) → Pool(2×2) → Conv(5×5) → Pool(2×2) → FC(120) → FC(84) → FC(10)
关键点:
- 确立了 CNN 的基本范式:卷积 → 池化 → 卷积 → 池化 → 全连接
- 输入
灰度图 - 使用
卷积核和 平均池化
4.2 AlexNet (2012) — 深度学习革命
由 Alex Krizhevsky 于 2012 年提出,在 ImageNet 上以巨大优势夺冠,标志着深度学习时代的到来。
关键创新:
- ReLU 激活函数:
,解决了饱和激活函数的梯度(gradient /ˈɡreɪdiənt/)消失问题 - Dropout(/ˈdrɒpaʊt/): 随机(stochastic /stəˈkæstɪk/)丢弃神经元,防止过拟合(overfitting /ˈoʊvərˈfɪtɪŋ/)
- 数据增强: 随机裁剪、水平翻转、颜色变换
- GPU 训练: 使用两块 GTX 580 GPU 并行训练
为什么 ReLU 比 Sigmoid(/ˈsɪɡmɔɪd/)/Tanh 好?
ReLU 在正半轴的梯度恒为 1,不会出现梯度消失。这使得训练更深的网络成为可能。
4.3 VGG (2014) — 简洁的力量
由牛津大学 Visual Geometry Group 提出,证明了深度而非单个层的复杂度更重要。
核心设计:
- 全部使用
卷积核 - 全部使用
最大池化 - 堆叠多个
卷积,替代更大的核
为什么堆叠
堆叠两个
- 参数量:
vs. - 更少的参数 + 更多的非线性(两次 ReLU)= 更强的表示能力
VGG 将网络深度推到了 16-19 层,但也暴露了一个问题:超过一定层数后,单纯的堆叠不再带来精度提升。
4.4 ResNet (2015) — 残差学习的革命
ResNet(Residual Network)由 Kaiming He 等人于 2015 年提出,是 CNN 发展史上最重要的里程碑之一。它解决了网络退化(Degradation) 问题,使得训练上百层的网络成为可能。
4.4.1 退化问题 (The Degradation Problem)
直觉告诉我们:更深的网络应该能取得更好的性能。但实验发现,当网络层数增加到一定程度后,训练误差反而上升。这不是过拟合(测试误差也上升),而是一个优化问题——深层网络更难优化。
4.4.2 残差连接 (Skip Connection)
ResNet 的核心思想:不再学习原始的映射

x
│
▼
┌─────────┐
│ Conv3×3 │
│ ReLU │
│ Conv3×3 │
└────┬────┘
│ F(x)
▼
┌─────────┐
│ + ◄───│──── x (identity shortcut)
└────┬────┘
▼
ReLU
│
▼
F(x) + x4.4.3 为什么残差连接有效?
视角 1: 梯度流动
在前向传播中,信息可以沿着恒等捷径(identity shortcut)直接流动。在反向传播(backpropagation /ˌbækprəpəˈɡeɪʃən/)中,梯度也可以直接流过捷径,到达前层:
梯度中有一个"1"项,确保梯度不会消失。即使
视角 2: 学习目标更简单
假设网络已经接近最优,
视角 3: 网络集成 (Ensemble)
ResNet 可以被解释为多个浅层网络的隐式集成。因为捷径的存在,网络中的路径可以被"跳过",形成一个指数级数量的浅层子网络集合。
4.4.4 ResNet 系列架构
| 变体 | 层数 | 结构特点 | 参数数量 |
|---|---|---|---|
| ResNet-18 | 18 | BasicBlock(2 层卷积) | 11M |
| ResNet-34 | 34 | BasicBlock(2 层卷积) | 22M |
| ResNet-50 | 50 | Bottleneck(1×1→3×3→1×1) | 26M |
| ResNet-101 | 101 | Bottleneck | 45M |
| ResNet-152 | 152 | Bottleneck | 60M |
Bottleneck 设计:
对于更深的 ResNet(50+),使用
4.5 现代演进 (Modern Evolution)
EfficientNet (2019)
提出了复合缩放(Compound Scaling) 策略:同时缩放网络的深度、宽度和分辨率。通过 Neural Architecture Search (NAS) 找到最优缩放系数:
其中
ConvNeXt (2022)
ConvNeXt 对 ResNet 进行"现代化改造",吸收了 Swin Transformer(/trænsˈfɔːrmər/) 的设计经验:
| 改造项 | ResNet | ConvNeXt | 效果 |
|---|---|---|---|
| 激活函数 | ReLU | GELU | 更平滑的梯度 |
| 归一化(normalization /ˌnɔːrmələˈzeɪʃən/) | BatchNorm | LayerNorm | 更好的稳定性 |
| 下采样 | MaxPool | 步长卷积 | 可学习下采样 |
| 核大小 | 更大感受野 | ||
| 阶段设计 | 堆叠 | 倒置瓶颈 | 更高效 |
ConvNeXt 证明:经过现代化改造的纯 CNN 架构,性能可以媲美 Vision Transformer。
本章演算盒索引
| 位置 | 演算盒 | 跳转 |
|---|---|---|
| §1 | 🔍 卷积核手算 — 3×3 核在 5×5 输入 | 跳转 |
| §1.3 | 🔍 输出尺寸公式验证 — 多参数组合 | 跳转 |
5. 小结 (Summary)
核心概念回顾
| 概念 | 要点 |
|---|---|
| 卷积运算 | |
| 局部连接 | 每个神经元只连接输入的局部区域,参数量从 |
| 参数共享 | 同一核滑动扫描全图,进一步降低参数量 |
| 平移等变性 | 输入平移 → 特征图同步平移 |
| 池化 | 最大池化/平均池化,降低维度,提供平移不变性 |
| 残差连接 |
架构演进速览
LeNet (1998) 5 层 手写数字识别
AlexNet (2012) 8 层 ReLU + Dropout + GPU
VGG (2014) 16-19 层 全部 3×3 卷积
ResNet (2015) 18-152 层 残差连接 → 核心思想沿用至今
EfficientNet 2019 复合缩放
ConvNeXt 2022 纯 CNN 现代化改造关键洞见
- CNN 的设计哲学是归纳偏置(inductive bias):利用图像的结构化特性(局部性、平移不变性、层次性),将这些先验知识编码到网络架构中。
- 残差连接是 CNN 最重要的贡献——它使训练极深网络成为可能,其思想(短路连接/捷径)后来被 Transformer 等架构广泛采用。
- CNN 在与 Transformer 的竞争中并未过时:ConvNeXt 等现代化 CNN 证明,经过合理改造的纯卷积架构仍然具有竞争力。
下一步: 运行代码实战 CNN on CIFAR-10,从零实现 ResNet 并在 CIFAR-10 上训练验证残差连接的效果。
附录: 实际运行输出 (Actual Runtime Output)
以下是在 CPU 上运行 cnn_cifar10.py --epochs 3 的实际控制台输出,展示了 ResNet-20 在 CIFAR-10 上的逐 epoch 训练过程:
$ .venv/bin/python ai/04-neural-networks/code/cnn_cifar10.py --epochs 3
Using device: cpu
============================================================
ResNet on CIFAR-10 -- Training Starting
============================================================
Device: cpu
Epochs: 3
Batch size: 128
Learning rate: 0.1
Weight decay: 0.0005
Momentum: 0.9
[1/4] Loading data...
Train samples: 50000
Test samples: 10000
Batches per epoch (train): 391
[2/4] Building ResNet-20 model...
Total parameters: 272,474
Trainable parameters: 272,474
Model architecture:
ResNet(
(conv1): Conv2d(3, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn1): BatchNorm2d(16, ...)
(layer1): Sequential((0-2): 3× ResidualBlock(16→16, stride=1))
(layer2): Sequential(
(0): ResidualBlock(16→32, stride=2) ← shortcut uses 1×1 conv
(1-2): 2× ResidualBlock(32→32, stride=1)
)
(layer3): Sequential(
(0): ResidualBlock(32→64, stride=2) ← shortcut uses 1×1 conv
(1-2): 2× ResidualBlock(64→64, stride=1)
)
(avg_pool): AdaptiveAvgPool2d((1, 1))
(fc): Linear(64 → 10)
)
[3/4] Starting training...
--------------------------------------------------------------------------------
Epoch | Train Loss | Train Acc | Test Loss | Test Acc | Time
--------------------------------------------------------------------------------
1 | 1.5459 | 42.11% | 1.4651 | 49.97% | 103.4s
→ Best model saved! (test_acc=49.97%)
2 | 1.0691 | 61.60% | 0.9676 | 66.60% | 104.9s
→ Best model saved! (test_acc=66.60%)
3 | 0.8730 | 69.18% | 0.8365 | 70.96% | 102.4s
→ Best model saved! (test_acc=70.96%)
--------------------------------------------------------------------------------
Training completed! Best test accuracy: 70.96%
[4/4] Plotting training curve...
Training curve saved to: output/training_curve.png
Final model saved to: output/resnet20_cifar10_final.pth
Done!分析 (Analysis):
| Epoch | Train Acc | Test Acc | 观察 |
|---|---|---|---|
| 1 | 42.11% | 49.97% | 模型快速收敛,从随机初始化迅速学习基本特征 |
| 2 | 61.60% | 66.60% | 准确率跃升~17%,残差连接使梯度高效传播 |
| 3 | 69.18% | 70.96% | 训练与测试差距缩小(仅差 1.78pp),模型泛化能力良好 |
关键观察 (Key Observations):
- 快速收敛: 仅 3 个 epoch,测试准确率就达到了 70.96%。如果使用 GPU 训练更多 epoch(如 50-100),配合学习率衰减,ResNet-20 在 CIFAR-10 上可以轻松达到 91-93% 的测试准确率。
- 残差连接的有效性: ResNet-20 只有 272K 参数(约 0.27M),远小于 VGG-16 的 138M 参数,但性能相当。这说明残差连接显著提升了参数效率和梯度流动。
- 梯度流动顺畅: 与不包含残差连接的普通网络相比,ResNet 在训练初期就能快速降低损失(从 1.5459→0.8730),梯度可以高效地通过捷径传播到网络的前层。
- 训练/测试差距很小: 第 3 个 epoch 时,训练和测试准确率相差不到 2 个百分点,说明模型没有过拟合,仍有进一步提升空间。
参考文献 (References)
- LeCun, Y. et al. (1998). Gradient-based learning applied to document recognition. Proc. IEEE, 86(11), 2278–2324.
- Krizhevsky, A., Sutskever, I. & Hinton, G. E. (2012). ImageNet classification(/ˌklæsɪfɪˈkeɪʃən/) with deep convolutional neural networks. NeurIPS.
- He, K. et al. (2016). Deep residual learning for image recognition. CVPR.