跳转至

P5-11.1 卷积神经网络(CNN)的直觉

Section ID: P5-11.1 Version: v2026.07.20

在 P5-10 章里,我们已经看到:深层神经网络会随着层数增加,学到更有用的表征(representation)。现在如果把这个视角进一步收缩到图像,就会自然出现下一个问题。

对于像图像这样具有空间结构的数据,为什么会说卷积神经网络(CNN)比一般的全连接层(fully connected layer)更自然?

回答这个问题的结构,就是卷积神经网络(CNN)。

卷积神经网络不是把整张图像一次性用同一种方式看完,而是反复观察小的局部模式(local pattern),并从中学出更大的视觉结构的神经网络。

当需要重新确认如何理解图像结构的基本定义时,可以回到概念词汇表里的卷积神经网络(CNN, convolutional neural network)条目重新对齐。

CNN 为什么适合图像的问题

  • 为什么卷积神经网络特别适合图像?
  • 所谓读取局部模式(local pattern)到底是什么意思?
  • 它和只使用全连接层的方式有什么不同?
  • 为什么从表征学习的角度看,CNN 很重要?

这一节首先要关住的核心是:因为图像是由相邻位置一起形成意义的,所以需要一种反复读取局部模式的结构。

也就是说,这一章真正改变的抓手,是从要不要把整张图像一次性混在一起看,转到要不要反复读取相邻位置的局部结构

这里先读的不是 optimizer、regularization 这样的训练流程,而是输入结构本身:相邻位置的线索,会按什么顺序、在多大范围内被捆在一起,并被抬升成更大的视觉结构。

这一节现在要读什么 直接交给下一节或补充学习什么
为什么图像的局部结构必须被反复读取 convolution、pooling 实际上怎样计算这种结构
全连接层和 CNN 读取输入方式的差异 在 CNN 之后,vision 结构应该按什么标准比较

具体运算里的 convolution 和 pooling,会在下一节 P5-11.2 接着讲。图像领域里表征学习的大框架,则已经在前面的 P5-10.1、P5-10.2 里铺好了。这一节做的事,是把那个大框架重新叠回图像场景上来读。CNN 之后的 vision 结构比较,会在补充学习 P5-11.3 里继续展开到应该从什么角度比较 CNN 和 Vision Transformer(ViT)这个层次。

局部模式与共享滤波器的判断标准

  • 能把 CNN 解释成反复读取图像局部结构的神经网络
  • 能说明为什么在图像里,位置与附近模式特别重要。
  • 能以入门层次比较全连接层和 CNN 的差异。
  • 能通过可执行的 Python 例子,确认读取局部模式的直觉。

为什么图像里的空间结构很重要

图像不是简单的数字列表。每个像素(pixel)都和周围像素一起形成意义。

例如:

  • edge 会出现在相邻亮度变化里
  • 角点(corner)会出现在多条 edge 的交汇里
  • 阀门、警示灯、小裂痕这类局部结构,也会通过附近像素的组合被显现出来

也就是说,在图像里,相邻位置之间的关系非常重要。

真正的重点是:图像这种数据,不只是数值本身要读,数值所在的位置,以及它和周围数值如何相连,也要一起读。

图像里重要的不只是某个值存在,而是这个值在哪里,以及它如何和周围连在一起。

只用全连接层时,为什么会别扭

从理论上说,也可以把图像拉平成一条长向量(flatten),然后送进全连接层。但这种方式无法把图像的空间结构,以更直观的方式保留给读者。

例如:

  • 它不能自然地突出相邻像素之间的关系
  • 同一种模式会在不同位置重复出现的直觉会变弱
  • 参数数量也可能变得非常大

也就是说,全连接层更接近把所有输入一次性混在一起,而对于先读取图像的局部结构来说,它并不那么自然。

如果把这种差异压成一张很短的表,大致如下。

视角 只使用全连接层 CNN
读取输入的方式 把整体拉平后一次性读取 反复读取小的局部区域
位置直觉 邻近像素的感觉容易被削弱 更自然地保留附近像素的关系
同一模式的复用 容易像每个位置都在单独学习 同一滤波器会在很多位置重复应用
入门直觉 一次性把所有值混起来 从小模式逐渐长成大结构

如果把同一图像场景分别交给这两种结构去读,差异会更直接。

同一场景 先用全连接层读取时容易留下的东西 先用 CNN 读取时更容易抓住的东西
压力表表盘图像 一个圆形仪表的整体印象 指针角度、刻度交叉、表盘边界这类局部线索
设备照片 整张照片的大颜色和大形状印象 阀门、警示灯、储罐边界这类重复出现的局部结构
表面检测图像 产品整体轮廓和平均亮度 小划痕、裂纹、污点这类局部异常

CNN 到底做了什么不同的事

CNN 不是一次性看完整张图像,而是移动一个小窗口(window)或滤波器(filter),反复寻找局部模式。

例如某个滤波器可能会:

  • 对垂直 edge 作出反应
  • 另一个滤波器可能对水平 edge 作出反应
  • 还有一些滤波器可能对更复杂的小形状作出反应

重要的是,这个滤波器不会只在图像里的一个位置使用,而会在很多位置被重复应用。

也就是说,CNN 可以被理解成一种结构:同一种模式无论出现在图像的哪里,都能被相似地看见。

如果先用图来读

仪表读数和对象检测,是解释 CNN 直觉时最常见的代表场景。因为这两个场景都很适合展示:模型不是从一开始就一下子知道这是仪表的状态这是某个物体,而是先读出小的线条、边界、角点、局部形状,再把这些组合一步步抬升成更大的判断。

如果先把图像场景 -> 人最先看到的线索 -> CNN 逐步堆起来的表征并排放在一起,大致会是这样。

场景 人最先看到的线索 CNN 逐步堆起来的表征
压力表表盘图像 短指针线、刻度交叉、圆形边界 needle edges -> dial parts -> gauge-state pattern
设备照片 阀门轮廓、警示灯边界、把手形状 edges/textures -> parts -> equipment-like region

下面三张图,会按步骤展示:通道如何组合,层级化表征又是怎样逐渐变大的。里面的数字和阵列不是搬运外部图片,而是只为了说明概念而重新简化出来的示意例子。

  1. 先看一个滤波器并不是把 RGB 通道彼此丢开,而是一起读取。
  2. 再看即使面对同一张照片,层越深时也会把更大的范围一起看进去。
  3. 最后看这个变宽的视野,怎样在 feature map 上合成更大的视觉线索。

图 1. 一个滤波器会一起读取各个通道

CNN channel and feature map intuition

读这张图时,首先要确认的不是如果有三个通道,CNN 就把图像完全拆成三个互不相干的部分处理,而是一个滤波器会一起读取同一位置上的多通道补丁,并把这些响应合成一张 feature map。颜色信息也会在局部模式内部一起被读取,最后整理成这个位置出现了什么强模式的响应图。

按下面这个顺序读就够了。

  1. 先看最上面的输入补丁被拆成红、绿、蓝三组数值。
  2. 再看每个通道都会产生一张局部响应图(partial map)。
  3. 最后看这些响应会在底部相加,合成一张最终 feature map。

也就是说,这张图真正的核心不是最终图会按通道各自保留,而是针对同一位置补丁的通道响应,会合成一个统一的模式响应

图 2. 层越深,看到的范围越大

CNN hierarchical vision flow

第二张图把同一张设备照片重复用了三次,只单独突出一个点:输入照片本身不变,但随着 layer 变深,receptive field 会扩大。 左边面板是早期 convolution 在小局部补丁里读取金属纹理、阀门边界这类局部线索的情形;中间面板是把更宽的范围一起看进去,从而读取管道连接部和储罐上半部这类被捆成一组的局部结构;右边面板则是把多个局部线索进一步汇在一起,从而读取到设备主体整体级别的线索。

这张图里尤其要记住:变的不是照片本身。变化的不是输入图像,而是一层能够一起读取的范围,以及它能在这个范围里捆起来的模式尺度。

图 3. 响应图也会合成更大的线索

CNN feature map hierarchy

第三张图把视线从照片本身移到了响应图上。早期 feature map 里,某些位置的 edge 或 texture 响应会先变强;更深的 part map 里,相邻响应一旦同时对齐,就会比较稳定地形成更大的局部模式;再往后的 object map 里,多个局部线索共同对齐时,就可能形成对象级别的 activation。

也就是说,在解释 CNN 时,真正重要的不是它有没有一下子把整张图背下来,而是早期 convolution 的响应,是否真的会沿着 feature map 一路堆成更大的对象线索。第三张图正是在响应图的角度上,再次把这个堆起来展示出来。

如果把压力表表盘图像压成一个非常简化的黑白场景,可以先这样想。

gauge-like image patch what stands out first
[[0, 1, 1, 0], [0, 1, 0, 0], [1, 1, 0, 0], [0, 0, 0, 0]] 细指针线、与刻度相交的位置、圆形边界候选

在设备场景里,早期线索也会先以局部响应的形式出现,比如阀门边界、储罐轮廓、警示灯形状。

equipment-like image patch what stands out first
[[pipe, pipe, tank, tank], [valve, tank, beacon, beacon], [valve, tank, tank, panel]] 阀门边界、延伸较长的储罐主体、矩形控制箱轮廓

这两张表并不是在真的描画高分辨率图像,而是在说明:解释 CNN 时,最先要抓住的问题,是这个场景里,哪一小部分会最先被读出来

在读取压力表时,也不是一上来就把图像当成安全区间警告区间这样的标签来读,而是先由前面这些小图像场景里的指针线、刻度交叉、圆形边界等局部线索逐步堆起来,最后抬升成仪表状态判断。

对象检测(object detection)也可以被读成一种流程:局部线索先聚集起来,然后再走向物体位置与标签判断。

flowchart TD
  A["图像像素"]
  B["边缘 / 纹理"]
  C["车轮 / 车窗 / 把手"]
  D["类似汽车的区域"]
  E["对象框 + 标签"]

  A --> B
  B --> C
  C --> D
  D --> E

这张图里要确认的结果是:对象检测也不是把整个场景一次性背下来,而是先读取前面场景表里那种阀门、警示灯之类的局部线索,让它们聚成一个equipment-like region,然后才走向最终的位置和标签判断。

从局部模式走向更大的结构

CNN 的直觉,也会自然连回 Part 5 前面已经看到的层级式表征学习。

  • 前面层:小的局部模式
  • 中间层:局部结构
  • 更深层:更大的对象线索

也就是说,CNN 不是把像素本身直接连到答案上,而是形成一种层级结构:像edge -> 局部结构 -> 对象线索这样,从小的局部模式逐步抬升到更大的视觉线索。所以,CNN 更适合被理解成把局部模式一层层堆成更大视觉表征的结构,而不只是某种专门用于图像的运算。

为什么 CNN 会看起来像一个转折点

CNN 在深度学习历史里之所以引起巨大关注,是因为它展示了一个事实:在图像识别里,模型能够学到比人手工设计的特征更强的层级化表征。

尤其是在 AlexNet 之后,CNN 同时展示了下面几点。

  • 深层神经网络确实可以在图像上产生很强的性能
  • 它可以和 GPU 训练结合,把规模做大
  • 表征学习可以大幅替代手工特征设计

也就是说,CNN 是在图像领域里,最有冲击力地展示深度学习表征学习视角的结构之一。

案例与示例

代表案例. 压力表表盘读取

假设现场摄像头要读取压力表表盘。人一开始很容易只凭一个圆形仪表的整体印象,就觉得不同状态看起来很像。但真正做区分时,还是得重新去看那些细小差异,比如指针尖端靠近哪一条刻度指针线与刻度以什么角度相交即使被反光遮住一部分,圆形边界和数字盘位置是否仍然稳定。CNN 非常适合这种读取方式:它先看这些局部结构,再逐步把它们的组合抬升成更大的仪表状态表征。

所以,这个案例里要确认的结果是:与其只剩下一个圆形仪表的整体印象,不如看指针尖端、刻度交叉这些局部线索是否真的先活起来,并把安全区间与警告区间更稳定地分开。

人最容易先看的标准 用 CNN 视角重读的标准
只看一个圆形仪表的整体印象时,很容易觉得状态相似 要看指针尖端位置、刻度交叉这类小差异是否先分开
有反光或阴影时,容易凭仪表整体印象粗略判断 要先读出到底是哪一个局部线索真的触发了不同响应
两者都是圆的,数字盘又相似,所以觉得混淆很自然 CNN 先读的是指针线刻度边界交叉位置这类局部差异,而不是整个圆形

同样的视角也适用于其他图像问题。不过这一节真正要抓住的重点,不是领域名称,而是:在整体印象之前,到底是哪一个局部线索先活了起来。

把三个案例放在一起看,就更容易明白:CNN 不该只被理解成一个图像模型名称,而更应该被理解成一种先读取局部结构、再谈整体印象的方式

场景 人最容易先看到的结果 从 CNN 视角真正需要区分的东西 接下来立刻要确认什么
压力表表盘读取 它看起来像一个圆形仪表,所以状态容易显得相似 指针尖端位置、刻度交叉、边界附近反应这类局部差异必须先活起来 看安全区间和警告区间是否能按局部线索更稳定地分开
设备场景再识别 只要设备整体印象相似,就容易觉得是同一个场景 比起光照和背景,阀门、管道、警示灯周围的局部结构可能是更稳定的线索 看保留住局部线索时,对同一设备场景的判断是否更稳定
工业视觉 只要产品整体形状相似,就容易觉得状态一样 小划痕、裂纹、污点位置这类局部差异必须比整体印象更早把缺陷候选分开 看哪一个 patch 会留下来成为更高优先级的复检候选

练习与例子

这个例子的目标,不是看整张图像,而是通过观察小区域来确认:在实际操作里,哪个位置会成为需要重新检查的候选。 它不会停在只抽出几个 patch,而是会把正常面板和带划痕的面板并排比较,看局部响应到底会怎样变化。

在读这个例子之前,先把这一节真正要确认的最小点固定下来,会更容易跟上。

确认点 在例子里马上要看的值 为什么重要
产生了多少个局部窗口 number of 2x2 patches 这说明 CNN 不是一次性看整张图,而是在反复读取许多局部区域
正常面板与缺陷面板的反应怎样分开 normal best, scratch best 因为即使同属一种产品图像,一旦出现局部缺陷,就能直接看见哪个位置的反应变大
哪个位置会成为实际操作中的复检候选 best patch position, score gap 因为在缺陷检测里,比起整体平均,更重要的是哪一个小区域需要被重新看
为什么正常面板也有反应,但缺陷面板优先级更高 normal best score, scratch best score 因为两边都可能有局部响应,但缺陷场景往往会暴露出更大的局部变化

输入:

  • 5x5 的正常面板亮度数组
  • 5x5 的带划痕面板亮度数组
  • 一个大小为 2x2 的小窗口

输出:

  • 所有可能的 2x2 局部 patch 数量
  • 正常面板和缺陷面板里最强局部响应的位置
  • 各位置的简单局部分数
  • 正常场景与缺陷场景之间的分数差

问题场景:

  • 在表面检测的操作里,比起产品整体印象,更重要的是哪一个小位置会成为重新检查的对象,所以有必要直接用这个场景来确认 CNN 的局部读取直觉

要确认的概念:

  • convolution 会通过反复扫描局部 patch 生成响应
  • 即使看起来像同一种产品,只要出现局部缺陷,某个位置的响应就可能更大
  • 在操作上,比起整体平均是否不同,更重要的是哪一个 patch 会成为需要再看的候选

从初学者角度看,这个例子最适合按下面三步来读。

阅读步骤 先看什么 紧接着要抓住的问题
1 normal_best, scratch_best 正常场景和缺陷场景里,哪个位置最先出现最强反应?
2 number of 2x2 patches, score gap 即使是同一个场景,为什么局部候选分数会比整体印象更重要?
3 两张响应图 局部异常候选是从哪里活起来的,这种差异有多明显?

输入(input):

这里使用上面整理好的正常面板、划痕面板,以及 2x2 窗口。

在看代码之前,先预测一下会发生哪些比较会更有帮助。

比较 可以先预测的变化 预测理由
normal best score 可能不大,但大概率不是 0 因为即使是正常面板,在边界附近也可能存在较弱的局部差异
scratch best score 可能会明显更大 因为在划痕所在位置,局部亮度变化更陡峭
score gap 大概率是正数 因为在操作里,需要重新查看的候选,往往会在缺陷一侧表现出比正常一侧更强的反应

这张表的目的,是先读出:不是有没有反应,而是在哪个场景里,更强的局部响应会先跳出来

# 这个例子用 2x2 局部窗口扫描正常面板和划痕面板,比较最强响应位置和 score gap。
import numpy as np

normal_panel = np.array([
    [5, 5, 5, 5, 5],
    [5, 6, 6, 6, 5],
    [5, 6, 6, 6, 5],
    [5, 6, 6, 6, 5],
    [5, 5, 5, 5, 5],
], dtype=float)

scratch_panel = np.array([
    [5, 5, 5, 5, 5],
    [5, 6, 6, 9, 9],
    [5, 6, 6, 9, 8],
    [5, 6, 6, 8, 7],
    [5, 5, 5, 5, 5],
], dtype=float)

def local_response(patch):
    return float(np.max(patch) - np.min(patch))

def scan_panel(panel):
    patches = []
    for i in range(panel.shape[0] - 1):
        for j in range(panel.shape[1] - 1):
            patch = panel[i:i+2, j:j+2]
            score = local_response(patch)
            patches.append({"position": (i, j), "patch": patch.copy(), "score": score})
    best = max(patches, key=lambda item: item["score"])
    return patches, best

normal_patches, normal_best = scan_panel(normal_panel)
scratch_patches, scratch_best = scan_panel(scratch_panel)

print("normal panel best =", normal_best["position"], "score =", round(normal_best["score"], 3))
print(normal_best["patch"])
print()
print("scratch panel best =", scratch_best["position"], "score =", round(scratch_best["score"], 3))
print(scratch_best["patch"])
print()
print("number of 2x2 patches =", len(normal_patches))
print("score gap =", round(scratch_best["score"] - normal_best["score"], 3))
print("inspection_priority =", "scratch panel" if scratch_best["score"] > normal_best["score"] else "normal panel")

在输出里,按顺序去看正常面板的最高响应位置、缺陷面板的最高响应位置,再看两个场景之间的 score gap 就可以了。

normal panel best = (0, 0) score = 1.0
[[5. 5.]
 [5. 6.]]

scratch panel best = (0, 2) score = 4.0
[[5. 5.]
 [6. 9.]]

number of 2x2 patches = 16
score gap = 3.0
inspection_priority = scratch panel

这个例子里真正要确认的重点如下。

  • CNN 不是只把整张图像看一遍,而是会反复读取小的局部窗口
  • 把正常场景与缺陷场景并排比较时,存在局部异常的位置,响应分数会更大
  • 在实际操作里,把响应最大的区域留下作为重新检查的候选这种感觉很重要
  • 这种局部信息后来还可以继续堆成更大的表征

如果把局部响应画成一张 4x4 的图,正常面板也会在多个位置出现较弱响应,但整体上不会出现特别大的差异。

正常面板的 2x2 局部响应图

而在带划痕的面板里,某个位置的响应会明显跳得更高,于是需要重新查看的候选位置就会更清楚地浮现出来。这正是为什么 CNN 应该被理解成一种反复读取局部模式、而不是只看整张图像整体印象的结构。

划痕面板的 2x2 局部响应图

比较 现在要抓住的重点
normal best 正常场景里也可能存在较弱的局部响应。
scratch best 在缺陷场景里,某个 patch 会跳出明显更大的响应,从而成为操作上的优先候选。
inspection_priority CNN 的直觉不是先看整张照片的整体印象,而是先看哪一个小区域应该最先被重新检查

读输出数字时,也要把有没有反应哪一个局部会最先成为优先候选分开来看。

比较 输出里先看到的事实 只看分数时容易留下的解读 加上 CNN 视角后会改变的解读
normal best 正常面板也会给出最高响应分数 1.0 会误以为正常场景也有反应,所以 CNN 好像并没有真正区分开。 正常场景当然也可能存在局部响应,但它们的强度和位置,不会像缺陷场景那样构成强烈的复检候选。
scratch best 划痕面板的最高响应会跃升到 4.0 容易把它看成只是数字单纯变大了。 在存在局部缺陷的位置,局部响应会显著增大,这说明 CNN 会先把小的异常位置显露出来,而不是先依赖整张图像的整体印象。
inspection_priority 最终的优先检查对象会变成 scratch panel 容易觉得它只是单纯选了更亮的一边。 真正关键的不是整体平均,而是它先选出了哪一个 2x2 patch 是应该重新查看的候选

也就是说,这个例子展示的是一种操作直觉:即使整张产品照片看起来差不多,只要靠近某个角落的 patch 响应突然变大,就应该重新检查。 CNN 之所以重要,不只是因为它会把图像分类得更好,更因为它是一种能在整体印象之前,先暴露局部缺陷候选的结构。

CNN 在深度学习入门课程里几乎总会被当作一个重要转折点。原因并不复杂。

  • 它会在图像领域里最直观地展示:前面的 P5-10.1、P5-10.2 所说的表征学习与层级式表征,到底是什么意思
  • 它也能帮助说明:GPU 与大规模数据的结合,究竟创造了怎样的性能转折
  • 而且在后面学习 vision transformer 之类的结构时,CNN 也会成为一个重要的比较基准

也就是说,CNN 是深度学习的历史、结构、实用性三条线汇在一起的一章。

这里也可以先停一下,把什么时候应该优先从局部模式,而不是从整体印象去读取图像分类问题短暂固定下来。这样进入下一节 convolution 时,结构解释的基准线会更稳。

先想到的问题 为什么要先有 CNN 的直觉 下一节会继续接到哪里
为什么同一个物体即使位置或背景变了,也应该被相似地读取? 因为比起一次性把整体混起来,更自然的方式是:在许多位置上反复读取局部模式 convolution 实际上如何计算各位置的响应
为什么当小划痕或局部结构很重要时,全连接的直觉会变弱? 因为局部线索必须比整体印象更早活起来 feature map 与 pooling 会保留什么信号
为什么 CNN 经常作为表征学习的代表结构出现? 因为它最直观地展示了局部线索如何一路堆成更大的视觉表征 层级式视觉表征的实际运算流程

检查清单

  • 能解释为什么对于像图像这样有空间结构的数据,CNN 会显得自然吗?
  • 能说明全连接层和 CNN 在读取输入方式上的差异吗?
  • 能解释 CNN 是一种会反复读取图像局部模式的神经网络吗?
  • 能不只把图像解释成所有像素数字的集合,而是先解释成相邻位置一起形成的局部结构吗?
  • 能说明在图像里,重要的不只是数值本身,还有位置和邻近关系吗?
  • 能解释为什么在压力表、设备场景、工业视觉这些案例里,最先要共同读取的是局部线索吗?
  • 当你发现自己只用整体印象解释图像问题时,能先想到局部模式的视角吗?
  • 当进入下一节 convolution 时,能先想到它到底会对哪一种局部模式产生多强的反应吗?

来源与参考资料