🏠 总目录📚 本教程 12 · CNN 处理图像
📑 本页目录(点开跳转)

12 · CNN:处理图像

30 分钟 | ⭐ 核心


🎯 一句话

CNN 的全部智慧是两条归纳偏置「局部相关」(相邻像素才有关系)和 「平移不变」(猫在左上角还是右下角都是猫)。把这两条硬编码进网络结构,参数量降几个数量级。

输入同一个 3×3 的核,在整张图上滑过去→ 权重共享:参数量和图片大小无关×核输出特征图窗口里的 9 个数 → 输出 1 个数
同一个 3×3 的核在整张图上滑过去,每次把窗口里的 9 个数变成 1 个数。⭐ 关键是整张图共用这一个核 —— 所以参数量和图片多大无关,而且「边缘」这个概念在左上角和右下角是同一套。

💥 一、为什么图像不能直接用 MLP

   一张 224×224 的彩色图 = 224×224×3 = 150,528 个数
   接一个 1000 维的全连接层 → 1.5 亿个参数(就这一层!)

   ❌ 参数爆炸
   ❌ 完全没利用「相邻像素相关」这个先验
   ❌ 图片平移一个像素,所有权重都要重新学

🔲 二、卷积:一个小窗口滑过整张图

输入图像 卷积核 3×3 输出特征图

卷积:一个小窗口在图上滑,每次做一次逐元素相乘再求和输入(▓ = 有信号的像素)101010101卷积核(要找的图案)=输出(亮 = 这块像那个图案)核在输入上逐格滑动,每停一次算一个输出格;所以同一组权重被全图复用
⭐ 关键不是「怎么算」,是同一个核在整张图上重复使用 —— 这就是卷积比全连接省几个数量级参数的原因。

每个位置算一次

两个关键机制

机制 含义 好处
局部连接 每个输出只看输入的一个小窗口 参数从 1.5 亿降到 9 个
权重共享 同一个卷积核滑遍全图 平移不变性 + 参数再降

💡 人话:一个卷积核就是一个「特征探测器」(比如"检测竖直边缘"), 它滑遍整张图,在哪都用同一套标准。 这就是「平移不变」。

🧮 算一次参数量,感受一下差距

   任务:224×224×3 的图 → 64 个特征图

   MLP 做法:150,528 × 64            = 9,633,792 个参数
   卷积做法:3×3 × 3(输入通道) × 64  =     1,728 个参数 ⭐

   → 少了【5575 倍】
   → 而且卷积的每个参数被复用了 224×224 = 5 万次

🔑 这就是"归纳偏置很值钱"的最直观证据。 🔗 数学原理第 9 章 PAC 给了它的定量版: 限制假设空间能把样本需求降几个数量级。 CNN 不是"更聪明的 MLP",而是一个被"图像的结构"约束过的 MLP

🎨 多通道是怎么回事(最容易卡住的一点)

   输入:H × W × C_in      (比如 224×224×3,RGB 三通道)
   卷积核:k × k × C_in     ← ⭐ 卷积核【也是三维的】,深度必须等于输入通道数
   一个核 → 一张 H'×W'×1 的特征图

   要 C_out 个特征图?→ 用 C_out 个这样的核

   ⭐ 所以参数量 = k × k × C_in × C_out  (+ C_out 个 bias)

💡 一句话记住卷积核在空间上滑动,但在通道上是"一次吃掉全部"的。

这句话能不能落到代码里,是「懂了」和「以为懂了」的分界: 🔗 附录 C 第 7 题用 15 行 numpy 把 conv2d 写出来了(和 F.conv2d 误差 0.0)。 那一行 np.tensordot(patch, w, axes=([1,2,3],[1,2,3])) 就是「通道一次吃掉全部」的字面翻译。 顺便还有两个这一节没说的:输出尺寸公式 $\lfloor(H+2p-k)/s\rfloor+1$(记不住就用 padding = k//2stride=1,尺寸不变), 以及深度学习里的「卷积」严格说是互相关——数学上的卷积要先把核翻转 180°,框架都没翻。主动说出这条是加分项。


🎛️ 三、四个必须懂的超参

import torch.nn as nn
nn.Conv2d(in_channels=3, out_channels=64, kernel_size=3, stride=1, padding=1)
参数 含义 经验
kernel_size 窗口大小 3×3 是现代默认(两个 3×3 ≈ 一个 5×5 但参数更少、非线性更多)
stride 每次滑几格 1(保持尺寸)或 2(尺寸减半)
padding 边缘补零 padding=1kernel=3 可保持尺寸不变 ⭐
out_channels 用多少个不同的卷积核 越深越多:64→128→256→512

输出尺寸公式

$$H_{out} = \left\lfloor \frac{H_{in} + 2p - k}{s} \right\rfloor + 1$$

💡 记不住就用 padding = kernel_size // 2stride=1 时尺寸不变。


🏗️ 四、一个典型 CNN 的结构

空间 ↓ 通道 ↑ 图像 224×224×3 [Conv 3×3 + BN + ReLU] ×2 提取低级特征(边缘、颜色块) MaxPool 2×2 → 112×112 降采样,扩大感受野 [Conv + BN + ReLU] ×2 中级特征(纹理、部件) MaxPool → 56×56 ... 重复几次 ... 高级特征(眼睛、轮子) GlobalAvgPool → 512 维向量 ⭐ 现代做法,替代大全连接层 Linear(512, 类别数)
从上往下走一遍:空间尺寸一路变小、通道数一路变多(左边两小列就是这两个趋势)。⭐ 真正要记的是右边那列 —— 浅层学边缘和颜色,中层学纹理和部件,深层学物体概念,每一层都在上一层的基础上组合

🔑 层级抽象:浅层学边缘和颜色,中层学纹理和部件,深层学物体概念。 这是"深比宽好"最直观的证据(第 7 章)——每一层都在上一层的基础上组合。

池化 Pooling:取窗口内最大值(MaxPool)或平均值(AvgPool) - 作用:降尺寸、扩大感受野、提供一点平移容忍 - 现代趋势:有时用 stride=2 的卷积替代池化(可学习的降采样比固定规则更灵活)

👁️ 感受野:一个必须建立的直觉

   感受野 = 一个输出神经元"能看到"输入的多大区域

   1 层 3×3 卷积        → 感受野 3×3
   2 层 3×3 卷积        → 感受野 5×5
   3 层 3×3 卷积        → 感受野 7×7      (每加一层 +2)
   加一次 stride=2 池化 → 之后每层的感受野【翻倍增长】⭐

   ⭐ 所以池化不只是"省算力",它是【快速扩大感受野】的主要手段

💡 为什么两个 3×3 优于一个 5×5

一个 5×5 两个 3×3
感受野 5×5 5×5(一样)
参数量 25·C² 18·C²(少 28%)
非线性 1 次 ReLU 2 次 ReLU(表达力更强)

🔑 这就是 VGG 的核心发现,也是"3×3 成为现代默认"的原因。

⚠️ 感受野不够的症状:模型能识别小物体但对大物体/整体结构判断差。 解法:加深、加池化、或用空洞卷积(dilated conv)。

🕳️ 三个变体(知道存在即可)

变体 做什么 用在哪
1×1 卷积 不看空间,只在通道间做线性组合 降/升通道数(省算力)、跨通道信息融合 ⭐
深度可分离卷积 空间卷积和通道卷积拆开做 MobileNet,参数量降 8~9 倍
空洞卷积 卷积核中间"留空" 不降分辨率也能扩感受野(分割任务)

💡 1×1 卷积值得单独理解:它看起来什么都没做,但 它是所有"瓶颈结构"(bottleneck)的核心—— 先用 1×1 把 256 通道压到 64,做完 3×3 再用 1×1 升回 256, 算力降到 1/4 而表达力几乎不变。ResNet-50 及以上全靠它。


📜 五、架构演进(记思想,不必记细节)

架构 年份 关键贡献
LeNet 1998 第一个成功的 CNN
AlexNet 2012 ReLU + Dropout + GPU,深度学习引爆点
VGG 2014 全部用 3×3,证明「深度」的价值
ResNet 2015 残差连接,让上百层可训练
MobileNet 2017 深度可分离卷积,移动端
EfficientNet 2019 复合缩放(深度/宽度/分辨率一起调)
ConvNeXt 2022 借鉴 Transformer 设计的现代 CNN

⭐ 残差连接:最重要的那一个

恒等映射(捷径) ⭐ 反向传播时,梯度可以从这条捷径直接走回去 x [Conv-BN-ReLU] 主路:F(x) + 输出 = F(x) + x 两条路在这里相加
主路 [Conv-BN-ReLU] 照常算,另外拉一条什么都不做的捷径,把 x 原样送到加号那里。⭐ 关键就在那个 +:反向传播时梯度可以顺捷径原样穿回去,不必挤过中间每一层 —— 这就是上百层能训起来的原因。

为什么它能让网络变深: - 梯度高速公路:反向传播时梯度可以直接通过 + 走捷径,不用穿过所有层 → 缓解梯度消失(第 8 章) - 学残差比学映射容易:网络只需学"要改变多少",最差就是学成 0(恒等映射)

🔗 你在全景导论第 2 章看到 Transformer 每层都有残差连接——同一个思想,源头在 ResNet。


💡 六、实践:别从零训练

   ❌ 从随机初始化训练自己的 CNN
      → 需要大量数据和算力,效果还差

   ✅ 迁移学习(99% 的场景该这么做)⭐
      拿在 ImageNet 上预训练好的模型 → 换掉最后一层 → 在你的数据上微调
import torchvision.models as models
import torch.nn as nn

model = models.resnet18(weights="IMAGENET1K_V1")   # 预训练权重
model.fc = nn.Linear(model.fc.in_features, num_classes)   # 换分类头

# 数据少时:冻结主干,只训分类头
for p in model.parameters(): p.requires_grad = False
for p in model.fc.parameters(): p.requires_grad = True

策略选择

数据量 做法
< 1000 张 冻结主干,只训分类头
1000–1 万 微调最后几层,小 lr
> 1 万 全部微调,lr 比从零训小 10 倍

🔗 Kaggle CV 板块(09–12 章)全是这套流程的实战细节。


⚠️ 七、CNN 的假设什么时候会害你

   平移不变的代价:CNN【故意】丢掉了"物体在哪"这个信息

   ✅ 适合:图像分类(猫在哪都是猫)
   ❌ 不适合:位置本身携带关键信息的任务
              · 医学影像:"病灶在左肺还是右肺"
              · 文档理解:"这个数字在表格的哪一列"
              · 界面识别:"按钮在屏幕上部还是下部"

解法:把位置作为额外通道喂进去(CoordConv),或改用带位置编码的 Transformer。

🔗 这正是数学原理第 11 章说的 「算法的专长是守恒的」——CNN 在图像分类上的优势, 换个任务就变成了负担。归纳偏置永远是双刃剑。


🔗 和站内其他章的关系

相关的地方 这里的对应
第 7 章"深比宽好" 层级抽象是最直观的证据
第 8 章梯度消失 残差连接是解法
数学原理第 9 章 PAC 归纳偏置降低样本需求的定量版
数学原理第 11 章 NFL 为什么平移不变有时是负担
Kaggle 第 9–12 章 CV 竞赛 本章的实战版(检测/分割/框融合)
全景导论第 10 章的 ViT ViT 用 Transformer 替代了 CNN,但 patch 切分借鉴了卷积思想
全景导论第 2 章的残差连接 源头就是本章的 ResNet
推荐算法第 13 章的图像 Embedding 就是 CNN 倒数第二层的输出

✅ 检查点

  1. CNN 硬编码了哪两条归纳偏置?靠什么机制实现?
  2. 算一下:224×224×3 → 64 个特征图,MLP 和卷积的参数量差多少倍?
  3. 卷积核在通道维度上是怎么工作的?参数量公式是什么?
  4. padding 怎么设能保持尺寸不变?
  5. 感受野怎么增长?为什么两个 3×3 优于一个 5×5?
  6. 1×1 卷积在做什么?为什么它是"瓶颈结构"的核心?
  7. 残差连接为什么能让网络变深?(两个理由)
  8. CNN 的平移不变在什么任务上会变成负担?
  9. 数据只有 500 张图,该怎么做?
👀 答案
  1. 局部相关(相邻像素才有关系)和平移不变(物体在哪个位置都一样)。靠局部连接权重共享实现。
  2. MLP:150,528 × 64 ≈ 963 万;卷积:3×3×3×64 = 1,728。差约 5575 倍,而且每个卷积参数还被复用了 5 万次。
  3. 卷积核也是三维的,深度必须等于输入通道数,在通道上"一次吃掉全部",只在空间上滑动。参数量 = k × k × C_in × C_out(+ C_out 个 bias)。
  4. padding = kernel_size // 2,配合 stride=1
  5. 每加一层 3×3 感受野 +2;加一次 stride=2 池化后,之后每层的感受野翻倍增长。两个 3×3 与一个 5×5 感受野相同,但参数少 28%、多一次 ReLU(表达力更强)——这是 VGG 的核心发现。
  6. 不看空间,只在通道间做线性组合——用来降/升通道数和跨通道融合。瓶颈结构:先 1×1 把 256 压到 64,做 3×3,再 1×1 升回去,算力降到 1/4 而表达力几乎不变
  7. 梯度高速公路:反传时梯度可直接走捷径,不必穿过所有层,缓解梯度消失;②学残差比学完整映射容易,最差学成 0(恒等映射)就行。
  8. 位置本身携带关键信息的任务:医学影像(病灶在左肺还是右肺)、文档理解(数字在哪一列)、界面识别。解法:CoordConv 或带位置编码的 Transformer。
  9. 迁移学习:用 ImageNet 预训练模型,冻结主干只训分类头,配合强数据增强。绝不从零训练(第 17 章的实验:100 张图时从零只有 25%,冻结主干能到 65%)。

🛑 可以停在这里

走神救援

CNN两条归纳偏置:局部相关+平移不变,靠局部连接+权重共享实现——224×224×3→64通道时,MLP要963万参数,卷积只要1728个(差5575倍),这是"归纳偏置很值钱"最直观的证据。卷积核是三维的,通道上一次吃掉全部、只在空间滑动,参数量=k×k×C_in×C_out。超参:3×3是默认、stride、padding=k//2保持尺寸。结构=Conv+BN+ReLU+池化+GlobalAvgPool,层级抽象(边缘→纹理→物体)。感受野:每层3×3 +2,池化后翻倍增长两个3×3 = 一个5×5的感受野但参数少28%、多一次ReLU(VGG的核心发现)。1×1卷积=只在通道间线性组合,是瓶颈结构的核心(256→64→3×3→256,算力降到1/4)。演进关键是ResNet残差连接:梯度高速公路+学残差比学映射容易,Transformer也用它。⚠️ 平移不变的代价:故意丢掉了"在哪"——在"病灶在左肺还是右肺"这类任务上是负担(NFL:专长守恒)。实践永远用迁移学习,数据少就冻主干。

下一节 👉 13-RNN与序列建模.md

打卡记录保存在你的浏览器里,首页能看到总进度