Stanford CS231n 课程关于卷积神经网络(CNN)的经典讲义。CNN 在 2012 年用 AlexNet 引爆了深度学习革命,统治计算机视觉将近十年。这篇讲义从最朴素的问题开始——"为什么普通神经网络扛不住图像?"——一路讲到 ResNet 的残差连接,把三种核心层(卷积、池化、全连接)的细节、参数共享的妙处、感受野的几何、以及 LeNet → AlexNet → VGGNet → GoogLeNet → ResNet 五大经典架构的设计哲学一次讲透。本文是该讲义的中文精校版。
普通神经网络(FC)层与层之间全连接——对图像这种高维输入来说,参数量会爆炸。一张 $200 \times 200 \times 3$ 的图就要 12 万权重,根本不可行。CNN 的核心动机:把"输入是图像"这一假设显式编进网络结构,用局部连接和参数共享换取效率与泛化。
CNN 跟普通神经网络其实非常像——都由可学习权重的神经元构成,每个神经元做点积加非线性,整个网络仍然是一个从图像像素到类别得分的可微函数。最后一层仍然是 SVM 或 Softmax 损失,普通神经网络里的训练技巧也都适用。
那 CNN 改了什么?CNN 显式地假设"输入是图像"。基于这个假设,我们可以把某些性质硬编码进架构,让前向传播更高效,也大幅减少参数。
问题来自规模。在 CIFAR-10 上,图像大小只是 $32 \times 32 \times 3$,所以第一隐层一个全连接神经元已经有 $32 \cdot 32 \cdot 3 = 3072$ 个权重。这还算能管。但一张更现实的 $200 \times 200 \times 3$ 图像,一个神经元就要 12 万权重。而我们当然要好多个这样的神经元——参数量瞬间爆炸,必然过拟合。
CNN 用三个关键设计来解决这个问题——3D 体积排布、局部连接、参数共享。后面会一一展开。
构建 ConvNet 用三种主要层:卷积层(CONV)、池化层(POOL)、全连接层(FC)。每一层都把一个 3D 输入"体积"(width × height × depth)变换成一个 3D 输出体积。CONV/FC 含可学习参数;POOL/ReLU 不含。
一个简单的 CNN 就是一串层的序列,每一层都把一个激活体积通过一个可微函数变成另一个。一个用于 CIFAR-10 分类的 ConvNet 可能长这样:INPUT → CONV → ReLU → POOL → FC。
具体每一层做什么:
· INPUT $[32 \times 32 \times 3]$ 保存原始像素值(宽 32、高 32、3 个颜色通道)
· CONV 层计算神经元的输出——每个神经元只连接到输入体积里的一个局部区域,做权重和输入的点积。如果用 12 个滤波器,输出体积可能是 $[32 \times 32 \times 12]$
· ReLU 层逐元素做 $\max(0, x)$,保持体积大小不变
· POOL 层在空间维度(宽、高)做下采样,输出可能是 $[16 \times 16 \times 12]$
· FC 层计算最终的类别得分,输出 $[1 \times 1 \times 10]$(CIFAR-10 的 10 类)
整个网络层层把图像从原始像素变换到最终类别得分。有的层含参数,有的不含——CONV 和 FC 含权重和偏置(要训练),ReLU 和 POOL 实现固定函数(不含参数)。
CNN 的每一层都是一个 API:
输入一个 3D 体积,输出一个 3D 体积,
变换通过一个可微函数完成。
卷积层的参数是一组可学习的滤波器。每个滤波器空间上很小(如 $5 \times 5$),但延伸到输入的全部深度。前向传播时,把每个滤波器在输入上"滑动"(卷积),对每个位置计算点积,得到一张 2D 激活图。多个滤波器的激活图堆叠起来,就是输出体积。
卷积层是 CNN 的核心,做了大部分计算重活。先抛开"神经元"的类比,直接讲它在算什么。
卷积层的参数是一组可学习的滤波器。每个滤波器空间上很小——比如一个典型的第一层滤波器可能是 $5 \times 5 \times 3$(5 像素宽、5 像素高,3 是因为图像有 3 个颜色通道)。关键是"延伸到全部深度"——空间维度可以小,但必须覆盖输入的所有通道。
前向传播时,我们把每个滤波器在输入体积的宽和高上滑动(卷积),在每个位置计算滤波器条目和输入对应位置的点积。滑过整个宽高,就得到一张 2D 的激活图——这张图告诉我们这个滤波器在每个空间位置的响应强度。
直觉上,网络会学到这样的滤波器:
· 第一层的滤波器学会响应低层特征——某个方向的边缘、某种颜色的斑块
· 中层的滤波器响应纹理、形状部件——比如蜂窝状结构、轮辐
· 高层的滤波器响应语义对象的部件——眼睛、车轮、文字
每个 CONV 层会有一组滤波器(比如 12 个),每个产生一张独立的 2D 激活图。把这些激活图沿深度方向堆叠,就形成了输出体积。
设计一个卷积层需要决定 4 个超参数:滤波器数量 K、空间大小 F(如 3、5、7)、步长 S(滑动的步幅)、零填充 P(边缘补几圈零)。输出体积大小由公式 $W_2 = (W_1 - F + 2P) / S + 1$ 决定(高度同理)。
一个常见配置是 $F = 3, S = 1, P = 1$——这样卷积不改变空间大小,所有下采样交给池化层做。
CNN 的参数效率来自两个关键设计:局部连接(每个神经元只看输入的一个局部区域,叫感受野)和参数共享(同一深度切片上的所有神经元用同一组权重)。AlexNet 第一层因此把 1.05 亿参数压到了 3.5 万——压缩 3000 倍。
处理高维输入时,把神经元连到上一体积的所有神经元是不切实际的。CNN 让每个神经元只连接到输入体积的一个局部区域——这个区域的空间大小是一个超参数,叫感受野(receptive field),其实就是滤波器大小。
关键是要强调这种空间与深度的不对称:连接在 2D 空间上是局部的(沿宽和高),但在深度上始终是完整的(始终覆盖输入的所有通道)。
连接在空间上是局部的(沿宽和高),
但在深度上始终是完整的。
讲讲 AlexNet 的例子。它的输入是 $227 \times 227 \times 3$,第一层用感受野 $11 \times 11$、步长 4、无填充的神经元,输出是 $55 \times 55 \times 96$。这意味着 $55 \cdot 55 \cdot 96 = 290{,}400$ 个神经元,每个有 $11 \cdot 11 \cdot 3 = 363$ 个权重 + 1 个偏置——加起来一亿零五十七万零六百个参数,只在第一层!显然过多。
解决办法是参数共享。基于一个很合理的假设:如果一个特征在某个位置有用,那它在另一个位置也应该有用——这正是图像平移等变性的体现。
具体做法:把同一个深度切片上的所有神经元约束为用同一组权重和偏置。一个深度切片就是 $[55 \times 55]$ 的一张激活图(共 96 张)。这样 AlexNet 第一层就只有 96 套权重(每个深度切片一套),共 $96 \cdot 11 \cdot 11 \cdot 3 = 34{,}848$ 个权重 + 96 个偏置 = 34,944 个参数。
从一亿到三万——压缩比超过 3000 倍,而且性能更好(因为正则化作用更强)。
这就是"卷积"这个名字的来历——当一个深度切片上的所有神经元共享权重时,前向传播在每个切片上就是滤波器和输入的卷积运算。我们把这套共享权重叫做一个 filter(滤波器)或 kernel(核)。
当输入图像有特定居中结构时,参数共享可能不合理。比如,如果输入都是已经对齐到画面中心的人脸——你可能希望网络在不同空间位置学到不同的特征(眼睛在上方区域、嘴在下方区域)。这种情况下常常放松参数共享,称为 Locally-Connected Layer。
池化层周期性地插在 CONV 层之间,逐步缩小空间表示的大小——减少参数和计算量,同时控制过拟合。最常见是 $2 \times 2$、步长 2 的最大池化,每次丢弃 75% 激活值。深度方向不变。无参数。
池化层一般周期性地插在卷积层之间。它的作用是逐步缩小空间表示的大小,从而减少参数和计算量,并在一定程度上控制过拟合。
池化层独立操作每个深度切片,用 MAX 运算重置空间大小。最常见的形式是 $2 \times 2$ 滤波器、步长 2——在每个深度切片上,沿宽和高各下采样 2 倍,丢弃 75% 的激活值。每个 MAX 操作在 $2 \times 2$ 的小区域里取最大值。
注意几个细节:
· 深度维度保持不变——只缩小空间,不动通道
· 没有参数——池化是固定函数
· 一般不使用零填充
· 除了 max 池化,理论上还有 average 池化、L2 池化等。但实践证明 max 池化效果更好,average 池化逐渐被淘汰
实践中只有两种常见配置:$F = 3, S = 2$(重叠池化)和更常见的 $F = 2, S = 2$。更大的感受野太具破坏性,会丢太多信息。
常用的 CNN 架构模式是:INPUT → [[CONV → ReLU]*N → POOL]*M → [FC → ReLU]*K → FC。一个关键经验法则:用一堆小滤波器(3×3)的堆叠,胜过单个大滤波器(7×7)——非线性更多、参数更少。
常见的 ConvNet 架构模式可以写成:
INPUT → [[CONV → ReLU]*N → POOL?]*M → [FC → ReLU]*K → FC
其中 $N \geq 0$(通常 $N \leq 3$),$M \geq 0$,$K \geq 0$(通常 $K < 3$)。比如:
· INPUT → FC ——简单线性分类器
· INPUT → CONV → ReLU → FC ——最简单的 CNN
· INPUT → [CONV → ReLU → POOL]*2 → FC → ReLU → FC
· INPUT → [CONV → ReLU → CONV → ReLU → POOL]*3 → [FC → ReLU]*2 → FC——每个 POOL 前堆两个 CONV,更深的网络常用这种
更深、更小、更多 —
用一堆 3×3 替代单个 7×7。
非线性更丰富、参数更少。
这是 VGG 论文的核心洞察。假设你堆三个 $3 \times 3$ CONV 层。第一层的神经元在输入上看到 $3 \times 3$ 视野;第二层在第一层基础上又看 $3 \times 3$,相当于在输入上看 $5 \times 5$;第三层就是 $7 \times 7$。有效感受野和单个 $7 \times 7$ 卷积一样大。
但堆三个 $3 \times 3$ 有两大好处:
第一,非线性更多——三个 CONV 中间有两次非线性激活,特征更丰富。单个 $7 \times 7$ 只算一个线性变换。
第二,参数更少。假设所有体积都是 $C$ 通道:
· 单个 $7 \times 7$ CONV:$C \cdot (7 \cdot 7 \cdot C) = 49 C^2$ 参数
· 三个 $3 \times 3$ CONV:$3 \cdot (C \cdot (3 \cdot 3 \cdot C)) = 27 C^2$ 参数
"堆叠小滤波器"比"单个大滤波器"用更少的参数表达更强的特征。这是过去十年所有现代 CNN 设计的指导原则。
讲义作者 Andrej Karpathy 的原话:"如果你在设计架构上感到疲惫,那好消息是——90% 以上的应用,你不需要操心这个。我喜欢把这点总结成『不要逞英雄』:与其自己设计架构,不如去看现在 ImageNet 上跑得最好的是什么,下载预训练模型,在你的数据上微调。"
CNN 历史就是几个里程碑架构的演化:LeNet (1998) 开创范式;AlexNet (2012) 引爆深度学习;ZFNet (2013) 调参改进;GoogLeNet (2014) 引入 Inception 模块;VGGNet (2014) 证明深度的价值;ResNet (2015) 用残差连接打破深度上限。
CNN 的历史就是几个有名字的架构的演化史。讲义给了一份简明的家谱。
LeNet (1998, Yann LeCun)。卷积网络第一个成功应用,用来识别邮编、数字。架构很简单,几个 CONV + POOL + FC。奠定了整个范式。
AlexNet (2012, Krizhevsky / Sutskever / Hinton)。让 CNN 在计算机视觉里彻底走红的工作。在 ImageNet ILSVRC 2012 上,Top-5 错误率 16%,第二名 26%——这种差距前所未有。架构和 LeNet 类似但更深、更大,开始把多个 CONV 层堆在一起(之前的惯例是每个 CONV 立刻跟一个 POOL)。这是深度学习革命的起点。
ZF Net (2013, Zeiler & Fergus)。ILSVRC 2013 冠军。在 AlexNet 基础上微调超参——扩大中间卷积层、减小第一层步长和滤波器大小。
GoogLeNet (2014, Szegedy et al.)。ILSVRC 2014 冠军。最大贡献是 Inception 模块——大幅减少参数(只有 4M,对比 AlexNet 60M)。还用 Average Pooling 替代最后的 FC 层,再省一大笔参数。
VGGNet (2014, Simonyan & Zisserman)。ILSVRC 2014 亚军。最大贡献是证明了深度是关键。最佳网络有 16 个 CONV/FC 层,整个架构极其同质——只用 $3 \times 3$ 卷积和 $2 \times 2$ 池化,从头到尾。缺点是参数太多(140M),主要集中在第一个 FC 层。
ResNet (2015, Kaiming He et al.)。ILSVRC 2015 冠军,至今仍是最常用的视觉 backbone。最大创新是残差连接(skip connections)——让网络可以训到上百层不出梯度问题。重度使用 Batch Normalization,并去掉了末端的 FC 层。是当前的事实之王。
讲义把 VGG-16 的内存和参数算了一遍——非常有教育意义。一张 $224 \times 224 \times 3$ 图前向传一次:
· 大部分激活内存都在前几层(CONV3-64 占 3.2M 激活)
· 大部分参数都在最后的 FC 层(第一个 FC 层有 1.02 亿权重,占总 138M 的 73%)
· 总内存约 93 MB / 图(仅前向),反向再翻倍
这两个观察催生了后来的设计:用全局平均池化替代 FC(GoogLeNet 开始),用 1×1 卷积压通道。
CNN 的核心三招——局部连接、参数共享、池化下采样——把"图像是二维空间结构"这一归纳偏置烧进了网络结构。这种内置先验在过去十年统治了视觉,直到 ViT 证明:在足够大的数据上,模型可以不需要这种先验,自己学到。
从 1998 年 LeNet 到 2015 年 ResNet,CNN 统治计算机视觉将近 20 年。它的设计核心其实就三招——
第一招,局部连接。每个神经元只看输入的一个局部窗口(感受野)。这个假设来自图像的本质——像素的语义由它周围的邻居决定,不需要跨过半张图来理解。
第二招,参数共享。同一个滤波器在所有空间位置共享权重。这个假设来自图像的平移等变性——一个能在左上角检测边缘的滤波器,在右下角同样有用。
第三招,池化下采样。逐层缩小空间分辨率,保留深度。这建立了层次化的特征表示——浅层学边缘和纹理,深层学对象部件和语义。
这三招的共同之处是——它们把"图像是二维空间结构"这一归纳偏置显式烧进了网络结构。这种先验大大降低了数据需求和过拟合风险。在数据相对稀缺的时代(ImageNet 1M 张),这种偏置是无价的。
CNN 的伟大,
在于把人类对图像的认知
翻译成了可微的运算结构。
从此机器开始"看见"了世界。
但 2020 年 ViT 出现后,情况发生了戏剧性变化——在 JFT-300M 这种规模的数据上,纯 Transformer 不带任何 CNN 归纳偏置,反而超过了 ResNet。这告诉我们两件事:
第一,归纳偏置在数据稀缺时是无价的——这正是 CNN 在过去十年统治视觉的原因。
第二,在数据足够大时,强归纳偏置反而成为束缚——让模型自己从数据里学规律,往往比手工注入的先验更好。
今天看,CNN 和 Transformer 不是替代关系,而是数据规模函数下的不同最优解。小数据用 CNN,大数据用 ViT;移动端用轻量 CNN(MobileNet),云端大模型用 ViT 或 hybrid。理解 CNN 的设计哲学,依然是理解所有现代视觉模型的起点。