§ 5.3 · Section

CNN · 卷积网络

Convolutional Neural Networks

卷积神经网络(CNN)是深度学习"看得懂图片"的头号功臣。从 2012 年 AlexNet 一战成名,到今天的人脸识别、医疗影像、自动驾驶——凡是"识图"任务,几乎都绕不开 CNN。它的秘诀,是模仿人眼一小块一小块看世界的方式。

生活场景
🎬 你在人群里认出老朋友

你在拥挤的地铁站里,一眼看到十米外一位老朋友的背影——你其实并没有把整个地铁站"逐像素"扫描一遍。你的眼睛是这样工作的:
先扫到"一头熟悉的卷发"(局部特征)——你顺着往下看,发现"熟悉的红外套 + 熟悉的走路姿势"——把这几个局部拼起来,脑子里蹦出"是她!"
你识别一个人,靠的是几个具有代表性的"局部特征",而不是记全身每个像素。CNN 抄的就是你这套"看局部、再组合"的策略。

先算一道算术:为什么全连接层碰上图片就爆炸

要理解 CNN 存在的意义,得先看看不用 CNN 会有多惨。所谓全连接层(Fully Connected Layer),说白了就是"下一层每个神经元都要跟上一层的每一个数字连一根线"——一个不漏,全都连上。这就像开一场会,让每位到场的人都必须跟每位其他人握一遍手:五个人还好,五百个人就得握十二万多次。

现在把一张普通照片喂给它。手机随手一拍就是 1000×1000 像素,彩色照片每个像素有红绿蓝三个数字,所以这张图一共有 1000 × 1000 × 3 = 300 万个数字。假设第一层隐藏层放 1000 个神经元(这在深度学习里算很小的规模)。那么需要多少根线(也就是多少个参数)?

【全连接的算术】

  输入数字个数 = 1000 × 1000 × 3 = 3,000,000
  第一层神经元数 = 1,000
  需要的权重 = 3,000,000 × 1,000 = 30 亿个

  只是第一层!后面还有几十层。

【这 30 亿个参数有多大】
  每个参数用 float32 存,占 4 字节
  30 亿 × 4 字节 = 120 亿字节 = 约 11.2 GB

  你的显卡显存装不下第一层的权重表。
  换个感受:一部高清电影约 2 GB,
  这一层权重相当于 5 部半电影的体积 ——
  而它只是用来"看第一眼"的那一层。

【换成 CNN 的算术】
  一个 3×3 的卷积核,作用在 3 个颜色通道上:
    3 × 3 × 3 = 27 个权重 + 1 个偏置 = 28 个参数
  一层放 64 个不同的卷积核(业界常规配置):
    28 × 64 = 1,792 个参数

  30 亿 vs 1792 —— 相差约 167 万倍。

  换个感受:如果全连接的参数量是一座
  30 亿人口的超级城市,CNN 只用了
  一个 1792 人的小村子,干的还是同一件活。

这个数量级差距不是"优化一下"的问题,是可行与不可行的区别。而且参数太多还有第二重灾难:参数越多,模型越容易"死记硬背"训练数据。30 亿个参数用来学几万张图片,等于给一个学生 30 亿页的笔记本去抄 5 万道题——他会一字不落地把答案背下来,而不是理解解题方法。考试换一道题,立刻交白卷。这个现象在深度学习里叫过拟合(overfitting),说白了就是背题背过了头,不会举一反三

还有第三个问题,也是最根本的:全连接层完全不懂"图片是有空间结构的"。它把 300 万个像素当成 300 万个互不相干的数字,一字排开地喂进去——相当于你把一幅拼图全部拆散,装在一个袋子里摇一摇,然后要求别人从袋子里看出画的是什么。像素之间的上下左右关系,这个最重要的信息,在第一步就被扔掉了。CNN 的全部设计,都是为了把这个信息保住。

卷积核:一块能滑动的小放大镜

CNN 里最关键的零件叫卷积核(Kernel / Filter),通俗理解就是一块很小的"侦探放大镜"——比如 3×3 或 5×5 那么大。这个小放大镜在整张图片上从左到右、从上到下慢慢滑,每滑一步就把当前覆盖的一小块像素做一次加权求和,输出一个数字。
滑完整张图,就得到一张新的"特征图"(feature map)——这张图告诉你:"在原图的每一个位置,是不是含有我这块放大镜想找的那种花纹?"
同一块卷积核,走遍整张图——这个"共享"是 CNN 相比全连接网络的一大杀器:全连接每个像素都独立学一套权重,CNN 只用一小组权重扫全图,参数量少上百倍还学得更快。

Analogy · 老师在批卷子上盖印章

卷积操作就像老师用同一个印章去批全班的卷子:印章上刻着"正确"、"错误"或者"漂亮的一个字"。老师在每份卷子上都盖一遍,看哪里最匹配。CNN 的卷积核也一样——同一个"花纹探测器"在整张图上到处扫,扫到匹配处就在特征图上打个高分。这就是所谓的"参数共享"

手算一次卷积:这个动作真的只有加法和乘法

"卷积"(convolution)这个词是数学界翻译过来的,听着像什么高深的积分运算。其实在 CNN 里,它就是"对应位置相乘,然后全部加起来"——学名叫"点积",说白了就是超市结账:单价 × 数量,一项一项算,最后加个总数。我们真的算一遍。

【原图】一张 5×5 的灰度小图(数字越大越亮)
  这张图的内容是"一条竖着的亮线在中间"

    0   0  100  0   0
    0   0  100  0   0
    0   0  100  0   0
    0   0  100  0   0
    0   0  100  0   0

【卷积核】一个 3×3 的"竖线探测器"
  设计思路:中间列给正分,两侧列给负分
  ——如果中间亮、两侧暗,就得高分

   -1   2  -1
   -1   2  -1
   -1   2  -1

【第一步:把核放在左上角,覆盖这 9 个像素】
   覆盖的区域:
     0   0  100
     0   0  100
     0   0  100

   对应位置相乘再求和:
     (0×-1) + (0×2) + (100×-1)   = -100
   + (0×-1) + (0×2) + (100×-1)   = -100
   + (0×-1) + (0×2) + (100×-1)   = -100
   ────────────────────────────────
   总和 = -300   → 这个位置得分很低(不像竖线)

【第二步:核向右滑一格,覆盖中间三列】
   覆盖的区域:
     0  100  0
     0  100  0
     0  100  0

     (0×-1) + (100×2) + (0×-1)   = +200
   + (0×-1) + (100×2) + (0×-1)   = +200
   + (0×-1) + (100×2) + (0×-1)   = +200
   ────────────────────────────────
   总和 = +600   → 这个位置得分极高!找到竖线了

【第三步:核再向右滑一格】
     100  0  0
     100  0  0
     100  0  0
     总和 = -300   → 又变低了

【滑完全图,得到一张 3×3 的特征图】
   -300  +600  -300
   -300  +600  -300
   -300  +600  -300

读法:这张"特征图"(feature map)在告诉你——
     原图的正中间那一竖列有一条竖线,
     其它地方没有。

看清楚了吗?整个卷积运算,从头到尾只有 9 次乘法和 8 次加法。所谓"卷积神经网络",就是把这个动作在整张图上重复几百万次、用几百种不同的核、堆几十层。最先进的视觉 AI,底层动作就是这个小学生能做的算术

还有一件更妙的事:这个"竖线探测器"的九个数字(-1, 2, -1, -1, 2, -1, -1, 2, -1)不是人设计的。在真实的 CNN 里,它们一开始是随机数,然后靠反向传播一点点被训练出来。网络自己发现"哦,如果我把中间列调成正数、两侧调成负数,我就能探测竖线,这对识别猫的胡须很有用"——于是它就把这九个数字调成了这个样子。人类做的唯一一件事,是给了它 3×3 这个"看多大一块"的框架,剩下的全是数据教出来的。

顺便解释一个业内的小科普:CNN 里的这个运算严格来说不叫"卷积",而叫"互相关"(cross-correlation)——真正的数学卷积还要把核先翻转 180 度。但因为核是训练出来的,翻不翻转对结果毫无影响,所以整个行业就懒得纠正这个叫法了。你在论文里看到的 convolution,实际做的就是上面这套"对齐相乘再加起来",不用担心翻转的事。

三个关键设计:局部连接、权值共享、平移不变性

CNN 之所以能把参数量从 30 亿压到 1792,靠的是三个设计原则。这三个词在任何一本教材里都会出现,我们用三个生活场景把它们各自钉死。

第一,局部连接(Local Connectivity),说白了就是每个神经元只看图片的一小块,不看全图。为什么这样合理?因为你判断一个像素是不是"眼角的一部分",只需要看它周围几个像素长什么样,跟图片右下角那个像素完全没关系。
生活场景:安检。机场安检员检查一个箱子时,是把箱子分成一格一格地看 X 光图,重点检查每一小块区域里有没有可疑形状。他不需要同时对比"这个箱子左上角"和"隔壁那个箱子右下角"的关系——那样做既没意义又累死人。

第二,权值共享(Weight Sharing),说白了就是同一块放大镜要走遍全图,不给每个位置单独配一块。这是省参数的最大功臣:一个"竖线探测器"只要 9 个数字,无论图片是 100×100 还是 4000×4000,都还是这 9 个数字。
生活场景:流水线上的检验员拿着同一把卡尺。工厂质检时,检验员用同一把卡尺去量每一个零件——不会给第一个零件配一把卡尺、给第二个零件再买一把新的。卡尺的刻度(也就是权重)是通用的,因为"什么算合格尺寸"这个标准,跟零件排在流水线上的第几位毫无关系。同理,"什么算一条边缘"这个标准,跟这条边缘出现在图片的哪个位置毫无关系

第三,平移不变性(Translation Invariance),说白了就是东西挪了位置,还是同一个东西。猫在照片正中央是猫,挪到左上角还是猫;这件事对人来说理所当然,对全连接网络来说却完全不成立——全连接网络会认为"左上角有毛"和"正中央有毛"是两组彻底无关的信号,得分别学一遍。
生活场景:你认得自家钥匙。钥匙扔在桌上、掉在地上、塞在口袋里,你都一眼认得出,因为你识别的是它的形状特征,不是它的坐标。而且注意:平移不变性是权值共享的自然结果——因为同一块放大镜扫过了每个位置,所以不管特征躲在哪里,都会被同一块放大镜逮到。这两个性质是同一件事的两个说法。

这三条合起来,在机器学习里有一个专门的说法叫归纳偏置(inductive bias,归纳偏置——人类事先塞给模型的"关于这个世界的假设")。说白了就是不让模型从零开始瞎摸,先给它划几条明显正确的规矩。这就像教小孩认字:你不会让他自己从一堆墨点里悟出汉字的规律,你会先告诉他"汉字是由笔画组成的,笔画有横竖撇折"——这几句话就是你给他的归纳偏置,能省下他几年的摸索。CNN 的三条偏置正是关于图片世界的真理,所以它学得又快又省。

再补一句为什么"局部"就够用。识别一只猫,你不需要知道图片左上角和右下角像素的关系——你只要能识别出"耳朵"、"胡须"、"眼睛"这些局部特征,再判断它们的空间关系就够了。CNN 假设"近的像素之间关系强、远的关系弱"——所以每个卷积核只看一小块局部。
这个假设在图像上惊人地好用,因为图片本身就是"空间局部相关"的:一只眼睛的所有像素通常聚在一小块区域。语言、声音也有类似的"局部相关性",所以卷积后来也被用到 NLP 和音频。

padding 与 stride:卷积的两个基本旋钮

刚才手算的例子里,5×5 的图被 3×3 的核扫完,出来的特征图变成了 3×3——缩小了。为什么?因为核的中心不能放在最边上的那一圈像素上,否则核会伸出图外没东西可乘。这个"每卷一次就缩一圈"的副作用,堆到几十层就麻烦了:一张 224×224 的图,用 3×3 核卷 50 层,只剩 124×124,而且图片边缘的像素被扫到的次数远少于中心像素,等于边角的信息被系统性歧视了

padding(填充)就是解决这个问题的办法,说白了就是在图片四周镶一圈 0,把图片"框大一号",让核的中心能站到原来的最边上去。生活场景:贴瓷砖留边。师傅贴墙砖时,会在墙的四周留出一圈过渡区,这样中间的砖才能整整齐齐对齐、不会因为墙不方正而歪掉。padding 干的就是这个活。给 5×5 的图镶一圈 0,变成 7×7,再用 3×3 核扫,出来还是 5×5——尺寸一分不差。这种配置在框架里叫 padding='same',是绝大多数现代 CNN 的默认选择。

stride(步长)说白了就是放大镜每次滑几格。stride=1 是"挨着一格一格滑",扫得最细,输出的特征图跟原图差不多大。stride=2 是"隔一格跳一步",扫的位置只有一半,输出的特征图立刻缩小到原来的一半。生活场景:扫地。stride=1 像用小扫帚仔仔细细一寸寸扫,不放过任何角落;stride=2 像拿个大拖把大步流星拖过去,速度快四倍但会漏一些细节。工程上 stride=2 常被用来替代池化层做降采样——既缩小了图,又顺手多学了一层特征,一举两得。

【输出尺寸的通用公式】

  输出边长 = (输入边长 + 2×padding − 核边长) ÷ stride + 1

【几个例子,直接代进去验证】

  ① 输入 5×5,核 3×3,padding=0,stride=1
     (5 + 0 − 3) ÷ 1 + 1 = 3    → 输出 3×3   ✓(跟手算一致)

  ② 输入 5×5,核 3×3,padding=1,stride=1
     (5 + 2 − 3) ÷ 1 + 1 = 5    → 输出 5×5   (尺寸保持)

  ③ 输入 224×224,核 3×3,padding=1,stride=2
     (224 + 2 − 3) ÷ 2 + 1 = 112  → 输出 112×112(对折)

  ④ 输入 224×224,核 7×7,padding=3,stride=2
     (224 + 6 − 7) ÷ 2 + 1 = 112  → ResNet 的第一层就长这样

记住一句口诀:padding 管"要不要缩",stride 管"缩多快"。

还有一个必须解释的词:通道(channel),说白了就是每个像素位置上叠了几层数字。灰度图 1 个通道(只有明暗),彩色图 3 个通道(红、绿、蓝各一层)。经过一层有 64 个卷积核的卷积之后,输出就变成 64 个通道——每个通道是一张特征图,各自记录"我这块放大镜在图上各处找到了多少匹配"。生活场景:一沓透明胶片。你把 64 张同样大小的透明胶片摞在一起,第 1 张上画的是"图里所有的横线",第 2 张是"所有的竖线",第 3 张是"所有 45 度斜线"……摞起来这一沓,就是这一层的输出。CNN 越往深走,图的长宽越小、通道数越多——空间信息在被压缩,语义信息在被堆厚

池化:把细节压缩,让特征稳定

卷积核算完之后,图像通常会加一层池化(Pooling)——最常见的是"最大池化"(Max Pooling),从 2×2 的小窗里挑最大的那个数字留下。池化干两件事:缩小图像尺寸、让识别对位置变化不敏感
你的猫在图片正中央和往左偏 5 像素,都应该被认成同一只猫——这就是"位置无关性"(平移不变性)。池化通过粗粒化,把"这个位置附近有耳朵"变成"这块区域里有耳朵",识别就更皮实。

Analogy · 微信里那张压缩过的缩略图

你要理解池化层,看看微信朋友圈里那张缩略图就够了。你拍了一张 4000×3000 的高清照片,发朋友圈时微信只显示一张几百像素的小图。这张小图丢掉了什么?丢掉了睫毛上的水珠、衣服布料的纹路、背景里远处的车牌号——所有细枝末节。但它保住了什么?保住了"这是海边、有个穿红裙子的人在跳、天是蓝的"这些大意。你朋友刷朋友圈时,一眼就知道你去海边玩了,完全不需要看清睫毛。
最大池化干的活儿就是这个,只不过更粗暴:从每 2×2 的四个数字里只挑最大的那一个留下,其余三个直接扔掉。为什么挑最大的?因为在特征图里,数字越大代表"这里越像我要找的那个特征"。挑最大的,就是在说"这一小块区域里最强的那个信号是多少"——我只关心这块区域有没有耳朵,不关心耳朵精确在这块区域的第几个像素上
这一挑,三个好处一起到手。第一,图小了四倍,后面所有层的计算量都省了四分之三。第二,对位置变化免疫了——猫往右挪一个像素,那个最大值还在同一个 2×2 格子里,池化输出一模一样。第三,抗噪——某个像素被相机噪点污染了,只要它不是那格里最大的,就直接被扔掉,噪声消失。
但代价也很实在:丢掉的信息是永久性的、找不回来的。所以在需要精细定位的任务里(比如医学影像要标出结节的准确边界、自动驾驶要知道行人到底在哪个像素),池化就成了拖累——这也是为什么近年来越来越多的网络改用 stride=2 的卷积来降采样:至少那样"丢什么"是学出来的,不是硬性规定的。

感受野:一层层看得越来越宽

感受野(Receptive Field)这个词听着专业,说白了就是"深层的某个神经元,追根溯源能看到原图上多大一块地方"。这是理解 CNN 为什么"越深越懂语义"的关键。

生活场景:一家公司的汇报链条。基层员工每人只盯自己那一小摊事(一个 3×3 的小块)。主管手下有 9 个员工,他汇总 9 份报告,等于间接看到了 9 个小块合起来的范围。部门总监手下有 9 个主管,他看到的范围又扩大了 9 倍。总经理再往上一层,视野已经覆盖整个公司。每一级都只跟直接下属对话,从没人跟全公司每个人挨个谈,但最上面那个人确实"看到了全局"。CNN 的感受野就是这个逐级扩大的过程。

【感受野的逐层增长】假设每层都是 3×3 卷积、stride=1

  第 1 层的一个神经元:看到原图 3×3    =  9 个像素
  第 2 层:              5×5           = 25 个像素
  第 3 层:              7×7           = 49 个像素
  第 5 层:             11×11          = 121 个像素
  第 10 层:            21×21          = 441 个像素

  规律:每加一层 3×3 卷积,感受野边长 +2。
  纯靠卷积增长很慢 —— 要看完 224×224 的整张图,
  得堆 112 层,太贵了。

【加上池化之后,增长变成指数级】

  卷积 3×3 → 池化 2×2 → 卷积 3×3 → 池化 2×2 → ...

  第 1 组卷积后:感受野 3×3
  第 1 次池化后:等效于原图 6×6
  第 2 组卷积后:原图 10×10
  第 2 次池化后:原图 20×20
  第 3 组卷积后:原图 28×28
  第 3 次池化后:原图 56×56
  第 4 次池化后:原图 112×112
  第 5 次池化后:原图 224×224   ← 全图覆盖!

  只用了 5 组卷积+池化,就从"看 9 个像素"
  长到了"看完整张图"。这就是池化真正
  不可替代的价值:它让感受野翻倍增长。

这也解释了那个"浅层看边缘、深层看语义"的规律为什么会自然发生:浅层神经元只能看到 9 个像素,在 9 个像素里你能看出什么?最多是一条边、一个亮暗交界——它别无选择。深层神经元能看到 112×112 的一整片区域,那里面装得下一整张猫脸,所以它才有可能学出"猫脸"这个概念。不是设计者规定了浅层学边缘,是感受野的物理限制逼它只能学边缘

层层堆叠:从边缘到语义的抽象阶梯

Analogy · 一层层剥洋葱

CNN 的层级抽象就像反过来剥洋葱:从外面最细的皮(像素)开始,一层层裹上更粗的组织(边缘、纹理),再裹上器官(五官),最后裹成整颗洋葱(一张脸)。浅层学得杂而细,深层学得少而抽象。这套结构不是人设计的规则,而是训练数据"逼"出来的自然分工。

CNN 到底学到了什么:把网络的"眼睛"拆开看

上面说浅层学边缘、深层学语义,你可能会问:这是猜的还是真的看到过?真的看到过。2013 年 Matthew Zeiler 和 Rob Fergus 发明了一套技术,能把 CNN 每一层的神经元"最兴奋的时候在看什么"直接画成图片——这项工作让 CNN 从"黑箱"变成了"半透明的箱子"。他们的做法说白了就是反过来问网络:什么样的图能让你这个神经元叫得最响?然后把那张图画出来。

画出来的结果,几乎每一层都能对上人类能理解的概念,这是让当年整个学界震惊的地方:

层级可视化看到的内容用画画来打比方
第 1 层各个角度的黑白条纹、几种基本的颜色块(红对绿、蓝对黄的对比边界)削好的几支铅笔和几支马克笔,还没落纸
第 2 层圆环、拐角、平行线、十字交叉、放射状纹路练笔画:画圆、画角、画交叉线
第 3 层网格状纹理、蜂窝、鳞片、毛发质感、文字笔画开始画材质:画布料的褶、画砖墙的缝
第 4 层可辨认的物体部件——狗的鼻子、鸟的腿、车轮、人脸的一只眼画五官:单画一只眼睛、一个鼻子
第 5 层完整的物体——整只狗的脸、整辆自行车、整个键盘五官组装成一整张脸,能认出是谁

这个发现的分量比它看起来更重,因为它意外地和生物学吻合了。1959 年,David Hubel 和 Torsten Wiesel 把电极插进猫的视觉皮层,发现猫脑子里有一类细胞专门对"某个特定角度的线条"放电——他们把这类细胞叫"简单细胞";再往上一层是"复杂细胞",对线条的角度敏感但对位置不那么敏感。这两人因此拿了 1981 年诺贝尔生理学奖。而 CNN 第一层学出来的东西,跟 Hubel 和 Wiesel 在猫脑里看到的几乎一模一样——没有人教它,它自己从数据里长成了这个样子。这是深度学习史上最漂亮的巧合之一。

这套可视化还带来一个巨大的实用价值,叫迁移学习(Transfer Learning,迁移学习——把在一个任务上学到的东西搬到另一个任务上用)。既然浅层学的是"边缘、纹理"这种所有图片都通用的东西,那我干嘛要为每个新任务重新学一遍?生活场景:一个学过素描的人去学油画——他不用从"怎么握笔"开始,构图、明暗、透视这些底子直接搬过来,只需要学油画特有的调色和笔触。这就是为什么今天你要做一个"识别芒果熟没熟"的模型,只需要下载一个在 ImageNet 上训练好的 ResNet,冻住前面几十层不动,只重新训练最后那一两层——用 500 张芒果照片、在一台笔记本上训 10 分钟,就能达到很不错的效果。没有迁移学习,这件事需要几十万张照片和一个机房。

CNN 家族的几张里程碑名片

年份模型贡献
1998LeNet-5Yann LeCun 用它读手写邮政编码,CNN 概念雏形。
2012AlexNetImageNet 大赛暴力碾压对手,深度学习复兴的第一枪。
2014VGGNet把网络堆到 16-19 层,证明"深"就是硬道理。
2014GoogLeNet提出 Inception 结构,一层里并联多种卷积核。
2015ResNet残差连接搞定"训练 100 层网络"的世纪难题。
2016~YOLO / Faster-RCNN不仅识别"是什么",还能标出"在哪里"——目标检测大爆发。
2020~ViT / ConvNeXtTransformer 反攻图像领域,CNN 也在吸收注意力机制。

LeNet-5 与 AlexNet:从邮局的支票到 ImageNet 的王座

表格里那几个名字每一个都值得单独讲讲,因为它们的每一步都是在解决一个具体的、当时卡死了所有人的问题。

LeNet-5(1998,Yann LeCun)是第一个真正跑在生产环境里的 CNN。它的任务朴素到不能再朴素:读手写的邮政编码和银行支票上的数字。它只有 7 层,参数量约 6 万个——按今天的标准这是个玩具。但它在 1990 年代末真的被部署到了美国的银行系统里,高峰期处理了全美 10% 到 20% 的手写支票。这是深度学习历史上第一次"真的在赚钱"。LeNet 确立的"卷积 → 池化 → 卷积 → 池化 → 全连接"这个骨架,直到今天还是所有 CNN 的基本模板。

然后 CNN 沉寂了 14 年。为什么?不是算法不行,是三样东西都不够:数据不够(当时最大的图像数据集只有几万张)、算力不够(LeNet 在当年的机器上训一次要好几天)、激活函数不行(用 Sigmoid,一深就梯度消失)。这三个条件到 2012 年前后同时凑齐了。

AlexNet(2012,Alex Krizhevsky / Ilya Sutskever / Geoffrey Hinton)是引爆点。它做对了四件事,每一件在今天都是标配:① 用 ReLU 代替 Sigmoid——训练速度提升了 6 倍,梯度消失问题大幅缓解;② 用 Dropout(训练时随机让一半神经元罢工)压制过拟合;③ 大规模数据增强——把每张图随机裁剪、左右翻转,等于把数据集凭空放大了几十倍;④ 用 GPU 训练——两块 GTX 580 显卡(每块只有 3GB 显存,今天一部手机的内存都比它多),把网络劈成两半分别塞进两块卡里,硬训了 6 天。

成绩单说明一切:把 ImageNet 分类的 Top-5 错误率从上一年的 26.2% 干到 15.3%这里要理解"降低 11 个百分点"在当时是什么概念——在那之前,这个比赛每年的进步是 1 到 2 个百分点,是靠一整年全世界几十个团队反复打磨手工特征换来的。AlexNet 一口气吃掉了未来十年的进步额度。这场比赛结束后的几个月内,几乎所有做计算机视觉的实验室都换了研究方向

VGG、Inception、ResNet:三种把网络变深的思路

AlexNet 证明了"深有用",接下来三年的主题就是怎么才能更深。三个团队给出了三种完全不同的答案,这三种思路今天都还活着。

VGG(2014,牛津大学)的答案是"傻堆但堆得整齐"。它做了一件极其重要的观察:两个 3×3 卷积叠起来,感受野等于一个 5×5,但参数少 28%;三个 3×3 叠起来等于一个 7×7,参数少 45%,而且中间多了两次非线性激活,表达力反而更强。算一下就清楚:一个 7×7 核有 49 个参数,三个 3×3 核只有 27 个。生活场景:搬一堆砖上五楼——一次抱 20 块砖走一趟很吃力还容易摔,分三趟每次抱 7 块,总重量差不多但轻松稳当得多。从 VGG 之后,3×3 成了卷积核的绝对默认尺寸,大核基本退出历史舞台。VGG 的另一个贡献是它极其规整、好懂、好改,至今还是很多论文的对比基线。

GoogLeNet / Inception(2014,谷歌)的答案是"不知道用多大的核,那就都用一遍"。选卷积核尺寸这件事一直让人头疼:3×3 看得细但视野小,5×5 视野大但参数多。Inception 的思路是——在同一层里并联放 1×1、3×3、5×5 三种核和一个池化,各算一遍,然后把结果拼在一起,让网络自己去挑该重视哪个生活场景:去医院看不明原因的肚子疼,医生不会赌一种检查,而是同时开 B 超、验血、CT,各个尺度都查一遍,再综合判断。
Inception 还顺手贡献了一个今天到处都在用的零件:1×1 卷积。这东西第一次听会觉得莫名其妙——只看一个像素的卷积核有什么用?关键在通道维度上:1×1 卷积不改变图的长宽,但能把通道数从 256 压到 64,相当于给后面那个昂贵的 5×5 卷积先"瘦身"。这一招让 GoogLeNet 在 22 层深度下参数量只有 VGG 的十二分之一。说白了它就是个"降维减负的中间商"——批发市场里那个把上百种货整合打包成几个标准箱再往下发的角色。

ResNet(2015,何恺明等,微软亚洲研究院)的答案最深刻:先弄清为什么深了反而更差。这一段值得单独讲,见下一节。

CNN 今天在哪儿?

你解锁手机的人脸识别、微信里的图像搜索、抖音的美颜滤镜、医院的 CT 结节筛查、特斯拉的车道识别、菜鸟的快递面单 OCR……背后几乎都有 CNN 或它的变体在跑。这些年虽然 Transformer 强势入侵图像领域(ViT),但 CNN 依然是"识图"最省算力、最容易部署、工程上最成熟的方案,尤其在手机端、边缘设备上仍是主流。

为什么 CNN 是 2012 年那场革命的主角

ImageNet 是 2010 年代前后计算机视觉界最重要的比赛——一百万张图、一千个类别,让各家算法比拼图像分类准确率。2010、2011 年冠军还在用手工设计特征加 SVM 的老套路,错误率高达 25%。2012 年 Hinton 的学生 Alex Krizhevsky 带着 AlexNet 参赛——一张 8 层的卷积网络,用两块 GTX 580 显卡训练了 6 天——直接把错误率砍到 15.3%,把第二名甩开近 10 个百分点。
这一战让整个学界瞬间清醒:手工特征时代结束了,深度学习时代开始了。之后的 VGG、GoogLeNet、ResNet 每一年都把准确率再刷一遍,2015 年 ResNet 的错误率已经低到 3.57%,第一次超过人类平均水平。可以说,CNN 一手把整个"AI 复兴"这场大戏拉开帷幕。这背后除了算法,还有两个基础条件:ImageNet 这样的大规模标注数据集,以及 GPU 提供的并行算力。

卷积、步长、填充:几个你会一直听到的术语

步长(stride)是"卷积核每次滑多远"——步长 1 表示逐像素移动,特征图和原图差不多大;步长 2 表示跳一格移动,特征图立刻缩小一半。填充(padding)是"要不要在图片边缘补零"——不补零,卷积后图像会一点点缩小;补零就能维持尺寸不变。通道(channel)是"每个像素有几个数字"——彩色图片有 R/G/B 三个通道,卷积核也要相应有 3 个厚度。这些看似繁琐的细节,就是 CNN 工程实现里最日常的调节旋钮,理解它们你才能真正会用 PyTorch 或 TensorFlow 搭出一个 CNN。

ResNet:让"深"这个字终于合法,残差连接为什么有效

2012 年 AlexNet 只有 8 层,2014 年 VGG 到了 19 层,人们以为一路堆下去就好——结果 20 层之后训练开始出问题:更深的网络反而误差更高。这不是过拟合(连训练误差都上升)——它是"退化问题":随着层数增加,梯度消失和优化难度呈指数级上升。
2015 年何恺明团队提出的 ResNet 想出了一个天才的办法——残差连接(skip connection):每两层的输入直接"抄近道"跳到输出上加起来。这样即使中间层学得再差,网络起码还有一条"直通车"能把信息传下去。加上残差连接的 ResNet 一口气训到 152 层,一举把 ImageNet 错误率打到 3.57%,第一次超过人类。今天 Transformer 里最核心的"残差连接",就是从 ResNet 借来的——可以说没有 ResNet,就没有 GPT。

那么这个"抄近道"的设计,为什么就能把 20 层的墙壁一举捅穿到 152 层?这里有两个各自都很漂亮的解释,我们都讲。

解释一:让"什么都不做"变成最容易的选项。先想清楚"退化问题"到底荒谬在哪:一个 56 层的网络,它的表现居然不如 20 层的网络。可是从逻辑上讲,56 层网络完全可以做到跟 20 层一样好——只要让后面那 36 层什么都不干,原封不动地把输入传出去就行了。既然理论上做得到,为什么实际做不到?因为对一个普通卷积层来说,"原封不动地传递"是一件极难学会的事——它得把自己那几十万个权重恰好调成一个"恒等变换"的组合,这在参数空间里是个概率极小的针尖。

残差连接的做法是把这件难事变成默认状态。它把公式从 输出 = F(输入) 改成 输出 = F(输入) + 输入。这一改,如果这一层想"什么都不做",它只要让 F 输出全 0 就行了——而让一层网络输出 0 是极容易的:所有权重往 0 上一压就成了。从"要精确凑出一个恒等变换"变成"往 0 上一躺",难度差了几个数量级。

生活场景:交作业。老规矩是"每位同学必须重抄一遍全文再交"——抄的过程中难免出错,一百个人接力抄下来,原文早就面目全非了。新规矩是"你只需要写下你要改的地方,其余照原文算"——不想改就交白纸,原文一字不动地保留。后者哪怕来一百个不上心的人接力,原文也不会被弄坏。这就是残差连接:它让每一层只负责学"该在原来的基础上加什么修正量"(这就是"残差"这个词的意思——残余的差值),而不是"从头重造一遍"。

解释二:给梯度修了一条不衰减的高速公路。回到上一节讲过的梯度消失——梯度反向传播时每过一层就乘一个小于 1 的数,几十层乘完趋近于 0。加了残差连接之后,反向传播的路径变成了两条并行的路:一条穿过中间那几层(会衰减),另一条是那根"抄近道"的直连(因为是直接相加,导数恒等于 1,一分不衰减)。1 加上一个衰减到接近 0 的数,还是约等于 1——所以梯度总能完好无损地传到最浅层。

【没有残差连接】梯度要一层层挤过去
  浅层收到的梯度 = 0.8 × 0.8 × 0.8 × ... (50 次)
                = 0.8^50 = 0.0000143
                → 几乎为 0,浅层学不动

【有残差连接】每一层的梯度多了一条 +1 的旁路
  单层的传递因子从 0.8 变成 (1 + 0.8) 这种形式
  更准确说:dL/d输入 = dL/d输出 × (1 + dF/d输入)
                                    ↑ 这个 1 来自直连

  哪怕 dF/d输入 衰减到 0,那个 1 还在
  → 0.8 变成 1.0,1.0^50 = 1.0
  → 梯度完好无损传到第一层

【生活类比】
  没有残差 = 层层转达的行政审批,
           每级都打个折,到最基层已经没声音了
  有残差   = 领导除了走流程,还建了个
           直通所有人的群,消息一步到位

这个设计有多重要?今天你能叫得出名字的每一个大模型都在用它。Transformer 的每一个模块里都有两处残差连接,GPT 的 96 层、Llama 的 80 层、Stable Diffusion 的 U-Net、AlphaFold 的主干——全是靠残差连接撑住的。残差连接可能是深度学习史上"投入产出比"最高的一个想法:改动小到只是加一个加号,收益是让"深度"这个词第一次真正兑现。ResNet 那篇论文至今引用超过 25 万次,是本世纪被引用最多的科学论文之一。

CNN 不止能看图:语音、文本、蛋白质、围棋

卷积的核心假设是"局部相关 + 平移不变"——只要一种数据满足这两条,卷积就能用。这个条件比"图片"宽泛得多,所以 CNN 早就跑出了图像的地盘。

语音与音乐。把一段声音画成"声谱图"(横轴时间、纵轴频率、颜色深浅表示能量),它就成了一张真正的图片,CNN 可以直接扫。为什么合理?因为一个"s"的摩擦音,无论出现在句子开头还是结尾,它在声谱图上的花纹是一样的——这就是平移不变性。今天的语音识别、音乐流派分类、鸟叫声识别、工厂机器异响检测,大量都用 CNN。

文本。2014 年 Yoon Kim 提出用 CNN 做句子分类,思路很妙:把一句话的每个词变成一个向量,横着排开成一张"图",然后用宽度等于词向量长度、高度等于 2 到 5 个词的卷积核去扫。这样的核实际上在探测"短语"——高度 3 的核就是在找"三个词组成的固定搭配",比如"很不错"、"完全不行"、"性价比高"。生活场景:读商品评论时你的眼睛在扫词组,看到"物流太慢"这三个字连在一起就知道是差评,不需要读完整段。这类模型又快又准,在情感分析、垃圾评论过滤上一度是最优选择。

蛋白质与基因。一条 DNA 序列是 ATCG 四个字母排成的长串,某些短片段(比如启动子序列)在哪个位置出现都代表同一个功能——完美符合平移不变性。DeepMind 的 AlphaFold 在预测蛋白质结构时,大量使用了卷积来处理氨基酸之间的"接触图"。

围棋。AlphaGo 的核心网络就是一个 CNN。19×19 的棋盘天然是一张"图",而围棋的定式、眼位、征子这些局部形状,出现在棋盘哪个角落其含义都一样——这又是一次完美的平移不变。AlphaGo 之所以能看懂"棋形"这种连职业棋手都说不清的直觉,靠的正是 CNN 从几百万局棋谱里自动提取局部形状特征的能力

反过来说,什么数据不适合卷积?表格数据。一张 Excel 表里的"年龄"列和"收入"列相邻纯属偶然,你把两列换个位置,含义一点没变——它没有"局部相关性",也没有"平移不变性",那两条假设全都不成立。对这类数据硬上 CNN,等于给它塞了两条错误的规矩,效果通常还不如一个简单的梯度提升树。这是理解"归纳偏置"的最好反例:偏置对了是助力,偏置错了是枷锁

ResNet:让"深"这个字终于合法

2012 年 AlexNet 只有 8 层,2014 年 VGG 到了 19 层,人们以为一路堆下去就好——结果 20 层之后训练开始出问题:更深的网络反而误差更高。这不是过拟合(连训练误差都上升)——它是"退化问题":随着层数增加,梯度消失和优化难度呈指数级上升。
2015 年何恺明团队提出的 ResNet 想出了一个天才的办法——残差连接(skip connection):每两层的输入直接"抄近道"跳到输出上加起来。这样即使中间层学得再差,网络起码还有一条"直通车"能把信息传下去。加上残差连接的 ResNet 一口气训到 152 层,一举把 ImageNet 错误率打到 3.57%,第一次超过人类。今天 Transformer 里最核心的"残差连接",就是从 ResNet 借来的——可以说没有 ResNet,就没有 GPT。

目标检测与分割:CNN 的下一步

"识图"其实分几个层次:图像分类只需要说"这是猫还是狗";目标检测要标出"猫在这个矩形框里";语义分割要精细到"每个像素是猫还是背景";实例分割更进一步——"这两只都是猫,但是两只不同的猫"。CNN 的家族分别对应这些任务:YOLO / SSD / Faster-RCNN 做目标检测,U-Net / FCN 做语义分割,Mask R-CNN 做实例分割。
这些技术直接决定了今天你手机相册"按人物分组"、微信里"识别二维码"、抖音里"抠图换背景"、特斯拉自动驾驶"识别车辆行人"这些功能背后的工程实现。CNN 让计算机不但能"认出画面",还能"知道东西在哪、有多大、是不是同一个"——这才是它真正强大的地方。

ViT 的挑战与 CNN 的局限:卷积会不会被淘汰

先说 CNN 自己的短板,这样才好理解 ViT 为什么有机会。CNN 有三个天生的局限。第一,看不了远处的关系。感受野是一层层慢慢长大的,要让图片左上角和右下角的信息"见上一面",得堆很多层。可有些判断偏偏需要全局:一张图里"沙滩 + 遮阳伞 + 人"要一起看才知道是度假,只看局部的沙子和布料看不出来。第二,对旋转和缩放不免疫。平移不变性它有,但你把猫的照片转 90 度,CNN 很可能就认不出来了——它得靠数据增强(训练时人为把图转来转去)硬灌进去。第三,"平移不变"这条假设有时候是错的。比如判断一张照片是不是"上下颠倒了",位置信息恰恰是关键,而 CNN 通过池化把位置信息主动模糊掉了。

2020 年之后,Transformer 的图像变种 ViT(Vision Transformer,视觉 Transformer——把图片切成小方块当"单词"来处理的架构) 横空出世,一举把 ImageNet 的最好成绩再往上推——很多人开始担心 CNN 是不是要被淘汰了?其实并没有。
ViT 的做法说白了就是把一张图切成 16×16 的小方块(叫 patch),每个方块当成一个"词",然后用处理句子的那套注意力机制去处理这些"词"生活场景:拼图——ViT 把照片剪成 196 块拼图碎片,然后让每一块都跟其余 195 块"打个照面",直接问"我跟你有关系吗"。这样第一层就能建立全局联系,不用像 CNN 那样爬几十层。

ViT 在数据量足够大(几亿张图以上)时确实更强,但在中小规模数据(几十万张)上,CNN 反而效果更稳、训练更快、部署更省。原因是 CNN 天生带有"平移不变性"、"局部性"这两个先验,等于给了模型一份"物理规律作业";而 ViT 什么都不假设,全靠数据从零学起——数据不够就学不好。
这个对比很像两种学生。CNN 是那种老师先教了公式再做题的学生——起步快,几百道题就能考及格,但天花板受公式框定。ViT 是那种不给公式、直接扔一万道题让他自己悟规律的学生——前一千道题惨不忍睹,但题量足够大时,他悟出来的规律比公式更全面、更灵活。数据是"小灶"就用 CNN,数据是"海量自助餐"就用 ViT,这是今天工程选型的基本经验。

还有一个让人玩味的后续:2022 年 Facebook 的 ConvNeXt 做了一件事——把 ViT 身上那些设计(大卷积核、更少的激活函数、LayerNorm 归一化、倒瓶颈结构)一条条搬回纯 CNN 上,结果纯 CNN 又追平甚至超过了同规模的 ViT。这说明当年 ViT 的胜利里,有相当一部分功劳其实来自训练技巧和结构细节的升级,而不是"注意力机制天生优于卷积"。就像两家餐馆的比试,最后发现赢的那家不是因为菜系更高明,而是因为换了更好的锅和火。

今天工程里最常见的组合是混合架构:底层用 CNN 提局部特征,高层用 Transformer 做全局理解,各取所长。CNN 没死,它更多是变成了"识图"这道大菜里的关键调料,而不是主菜。手机端跑的模型、边缘设备上的模型、实时视频推理,CNN 依然是首选——因为它算得快、模型小、耗电低。你手机里那个能实时抠人像背景的功能,跑的几乎肯定是一个几兆大小的 CNN,而不是一个几百兆的 ViT——因为后者会把你的电池在半小时内榨干

Recap · 收束

CNN 的三大心法——局部感知(一小块一小块看)、参数共享(同一个滤镜扫全图)、层级抽象(浅层看纹理、深层看语义)。它把"识图"从"要写复杂规则"变成"喂数据 + 训网络",从此让计算机真正"看得见"。今天你手机里的绝大多数视觉功能,功劳簿上都得记 CNN 一大笔。

☰ 主页
Xue Hai Wu Ya · § 5.3 · CNN