基础 · 03

卷积神经网络

图像不是一维向量——卷积用局部连接和权重共享,让网络像人一样看到「局部模式」再拼成全局理解。

16 min read

卷积运算

一张 224×224224 \times 224 的 RGB 图片有 224×224×3=150528224 \times 224 \times 3 = 150528 个像素值。如果第一层全连接到 1000 个神经元,参数量就是 1.5 亿——还什么都没学呢。

卷积的核心洞察:图像的特征是局部的。一条边、一个角、一块纹理,只涉及一小片区域。不需要让每个神经元看整张图,只让它看一个小窗口就够了。

1D 与 2D 卷积

对一维信号 xx 和核 ww,卷积定义为:

(xw)[n]=kx[nk]w[k](x * w)[n] = \sum_{k} x[n-k] \cdot w[k]

对二维图像 II 和核 KK(大小 k×kk \times k),2D 卷积为:

(IK)[i,j]=m=0k1n=0k1I[im,jn]K[m,n](I * K)[i, j] = \sum_{m=0}^{k-1}\sum_{n=0}^{k-1} I[i-m, j-n] \cdot K[m, n]

实践中用的是互相关(cross-correlation)——区别仅在于核是否翻转。深度学习框架中的"卷积层"实际做的都是互相关,因为核的值是学出来的,翻不翻转无所谓。

输入 5×50121013431248421343101210卷积核 3×310-110-110-1输出 3×3?????????点击 Step 或 Play 开始
卷积运算:核在输入上滑动,逐元素相乘求和得到输出

填充与步幅

填充(padding):在输入边缘补零。用 pp 圈零填充后输出大小变为 (H+2pk+1)×(W+2pk+1)(H + 2p - k + 1) \times (W + 2p - k + 1)。当 p=k/2p = \lfloor k/2 \rfloor 时输出和输入同尺寸(same padding)。

步幅(stride):核每次移动的格数。步幅为 ss 时输出大小为 (H+2pk)/s+1\lfloor (H + 2p - k) / s + 1 \rfloor。步幅 > 1 直接起到降采样的作用。

卷积层

一个卷积层做三件事:局部连接权重共享多通道映射

局部连接 + 权重共享

每个输出位置只连接输入中一个 k×kk \times k 的局部区域(感受野)。更关键的是,同一个核在所有位置共享权重——不管边在图片左上角还是右下角,检测它的权重是同一组。

这两点让参数量急剧下降:一个 3×33 \times 3 的核只有 9 个参数,却能扫遍整张图。

多通道

输入有 CinC_{in} 个通道(RGB 图 Cin=3C_{in}=3),核的完整形状是 k×k×Cink \times k \times C_{in}——对每个通道有一组权重,结果相加得到一个输出通道。

要输出 CoutC_{out} 个通道,就需要 CoutC_{out} 个这样的核。每个核检测一种不同的模式(水平边、垂直边、色彩变化等)。

参数量

一个卷积层的参数量:

(k×k×Cin+1)×Cout(k \times k \times C_{in} + 1) \times C_{out}

+1+1 是偏置。对比全连接层:一层 3×33 \times 3 卷积、64 输入通道、128 输出通道只需 (9×64+1)×128=73856(9 \times 64 + 1) \times 128 = 73856 个参数。同样的输入输出维度用全连接需要几百万。

池化层

卷积提取特征后,我们希望:1)减小空间尺寸降低计算量;2)获得一定的平移不变性——图案微小移动不应改变判断。

最大池化(max pooling):在每个 2×22 \times 2 窗口内取最大值。空间尺寸减半,保留最强激活。

y[i,j]=max0m,n<2 x[2i+m,2j+n]y[i,j] = \max_{0 \le m,n < 2} \ x[2i+m, 2j+n]

平均池化(average pooling):取窗口均值,更平滑但信号弱化。

池化没有可学习参数。它的作用是让后续层的感受野更大——经过两次 2×22 \times 2 池化后,一个 3×33 \times 3 的核实际上"看到"了原始图像 12×1212 \times 12 的区域。

经典架构

LeNet-5(1998)

LeCun 等人为手写数字识别设计的开山之作。结构清晰地体现了 CNN 的核心范式:

输入ConvPoolConvPoolFCFC输出\text{输入} \to \text{Conv} \to \text{Pool} \to \text{Conv} \to \text{Pool} \to \text{FC} \to \text{FC} \to \text{输出}

具体配置:

  • 输入:32×3232 \times 32 灰度图
  • C1:6 个 5×55 \times 5 卷积核 → 28×28×628 \times 28 \times 6
  • S2:2×22 \times 2 平均池化 → 14×14×614 \times 14 \times 6
  • C3:16 个 5×55 \times 5 卷积核 → 10×10×1610 \times 10 \times 16
  • S4:2×22 \times 2 平均池化 → 5×5×165 \times 5 \times 16
  • 全连接层 → 10 类 softmax

总参数量只有约 6 万——放在今天微不足道,但当时在 MNIST 上达到了 99%+ 的准确率。这个「卷积→池化→卷积→池化→全连接」的模式成为后续十多年 CNN 架构的模板。

后续演进

从 LeNet 到 AlexNet(2012)再到 VGG(2014),核心思想没变——只是更深、更多通道、用 ReLU 代替 sigmoid。真正的范式突破来自 ResNet。

残差连接

2015 年,何恺明等人发现一个违反直觉的现象:把网络从 20 层加到 56 层,训练误差反而上升了。这不是过拟合(测试集也差),而是优化困难——太深的网络梯度消失,根本训不动。

残差连接的解法极其简单:

y=F(x)+x\mathbf{y} = F(\mathbf{x}) + \mathbf{x}

其中 F(x)F(\mathbf{x}) 是两层卷积的输出(残差),x\mathbf{x} 是直接跳过的恒等映射。网络只需要学输入和输出的差异(残差),而不是从头学完整映射。

为什么有效?看梯度:

yx=Fx+I\frac{\partial \mathbf{y}}{\partial \mathbf{x}} = \frac{\partial F}{\partial \mathbf{x}} + I

无论 Fx\frac{\partial F}{\partial \mathbf{x}} 多小,梯度至少有一个恒等项 II 能把信号直接传回去。这条「梯度高速公路」让 152 层的 ResNet 不仅能训练,还在 ImageNet 上首次超越了人类水平。

残差连接后来成为深度学习的通用基础设施——Transformer 的每个子层都包在 x+f(x)x + f(x) 里,本质相同。