小叶正在做一个扫描图像的小实验。画面里有一条亮色纸带,背景较暗。第一项任务是找出纸带两侧的亮暗边缘,第二项任务只是判断画面里是否出现了明显的亮暗变化。两项任务用的是同一张图,要求保留的信息却不同:第一项离不开位置,第二项可能只需要一个存在与否的判断。

如果让 AI 帮忙写图像处理代码,它可能给出卷积、激活、池化等步骤。知道这些名称,并不足以判断代码是否合适。小叶需要看懂:每一步拿哪些数据作比较,得到的数字代表什么,哪些原本可区分的情况在处理后变得一样。

本章就沿着这个实验理解卷积与池化。所有案例和数值都是为教学构造的简化条件,不是实测图像或模型性能。先从一行亮度数据开始,再把同样的思路放回二维图像。我们关心的是怎样组织局部计算,以及这种组织方式怎样影响后面的识别和定位。

一、找边缘,为什么不能只找亮点

先把图像中的一行抽出来。小叶沿着这一行从左往右记录十个格子的亮度:

可复制模板
格子编号: 1  2  3  4  5  6  7  8  9 10
亮度数值: 0  0  0  4  4  4  0  0  0  0

这里用 0 表示暗、4 表示亮,亮度采用本例自己的数值尺度。第 4 至第 6 格属于亮色纸带,第 3、4 格之间和第 6、7 格之间发生了突变。

假如程序只检查“亮度是否大于 2”,它能挑出亮色区域,却不能直接说明哪里发生了变化。第 5 格虽然很亮,左右邻居也很亮;它位于亮区内部。相反,第 3 格本身很暗,右边却已经进入亮区,它附近恰好值得检查。边缘取决于相邻位置之间的关系,单独一个格子的数值不够。

这就引出了局部窗口:每次取出附近的一小段数据,联合判断其中的关系。小叶暂定窗口宽度为三格,观察左、中、右三个位置。判断窗口中央附近有没有左右亮度变化时,可以比较右侧与左侧。右边比左边亮,得到一个正响应;右边比左边暗,得到一个负响应;两边一样亮,响应为零。

窗口是一种明确的观察范围。三格窗口看不到很远处的结构,所以它擅长回答“附近有没有变化”,还无法凭一次比较回答“整条纸带有多宽”。这个限制也带来了好处:程序不必为了判断一个局部边缘,把整张图的每个像素都拿来参与同一次计算。

如果没有局部关系这个前提,把数据随意排成一个表格再使用小窗口,就未必合理。图像里相邻像素通常有空间联系,一段录音中相邻采样有时间联系;但把学生的学号、身高、消费额随便排成相邻三列,并不会自动产生同样的局部规律。窗口能否帮助任务,先取决于数据的排列是否有意义。

小叶现在得到的第一项判断是:需要识别的是变化,应当设计比较邻域的规则。接下来要解决的是怎样把这个规则写成可重复执行的计算,让程序走到每个位置都做同一件事。

二、卷积核:把一种局部比较写成权重

用右边亮度减去左边亮度,可以写成一组权重:

这组权重叫作卷积核。这里的三个位置依次对应窗口的左、中、右:左侧贡献取负,中间暂不参与,右侧贡献取正。权重决定这个小窗口在检查哪一种关系。它不是从图像中截取的一块亮度,也不是最后输出的结果。

把核盖在 [0,0,4] 这个窗口上,得到右侧减左侧的结果 4。这个正值说明,窗口横跨了由暗变亮的过渡。把它盖在 [4,4,0] 上,得到 −4,表示反方向的变化。对 [4,4,4],结果是 0,说明左右没有差别,尽管这一小块整体很亮。不过,[0,4,0] 也会得到零:它的中间很亮,两端却相等。这个核检查的是两端的亮度差,零响应不能证明窗口内部完全均匀。

把三格窗口的亮度记为 ,其中 是窗口左端的编号,本例计算可以统一写成:

表示这一个窗口给出的响应。权重在本例中无单位,所以响应仍使用同一亮度尺度;它是有方向的亮度差,不是边缘存在的概率。即使得到 4,也不表示“有百分之四的可能性”,更不是四个边缘。

小叶还可以换一个核。例如 [1/3,1/3,1/3] 会计算附近三格的平均亮度。孤立亮点被周围较暗的数值拉低,突然变化会变得平缓。这有时适合减轻细小波动,有时会模糊本来需要保留的边缘。窗口大小相同,权重不同,操作关注的性质便不同。因此,“加一层卷积”没有完整说明程序在做什么,还要看核的取值或它通过什么任务学习出来。

本章先采用深度学习中常见的计算约定:窗口中的数据与核按相同次序配对,直接加权求和。严格的离散卷积会先翻转核;这里不翻转的操作称为互相关,深度学习卷积层通常沿用“卷积”的名称。对于我们这个固定的方向核,翻转后正负方向会对调,所以查看手写算例或库函数时,要先确认约定。这一差别可以用一句操作规则记住,不影响我们继续理解局部检测。PyTorch 卷积层文档

同一个核怎样检查整条数据?把窗口逐格向右移动即可。每到一个位置记录一个响应,直到窗口再也不能完整放进原条带。核保持不变,变的是它当前覆盖的数据。

三、特征图:响应的大小、方向与位置各有含义

十格输入配上三格窗口,在不越过边界、每次右移一格的条件下,一共可以放八次。完整结果是:

可复制模板
窗口中心对应原格子: 2  3  4  5   6   7  8  9
响应:               0  4  4  0  −4  −4  0  0

这些按位置排列的响应构成一张特征图。虽然这里是一行数据,也可以沿用这个名称。原输入回答“各处有多亮”,这张特征图回答“各处的左右亮度差有多大、方向如何”。表示的内容变了,空间顺序还在。

原来第 3、4 格之间只有一处暗到亮的突变,为什么会出现两个相邻的正响应?因为中心在第 3 格和第 4 格的两个窗口都跨过了这个边界。一个边缘可以影响多个窗口,所以响应格子的个数不能直接当成边缘数量。要把这片响应进一步转换成一条边缘位置,还需要明确定位规则,例如合并相邻响应,再利用它们所覆盖的原始位置范围。

小叶也不能把输出的第一个位置误当成原图的第一个格子。这里输出第一个值来自原第 1 至第 3 格,我们用中间的第 2 格作为对齐位置。保存这种对应关系,后面才能把检测结果标回图像。图像处理中的位置常常就是在这类不起眼的转换里发生偏移的。

原始条带、带符号响应以及两个方向通道
图 A11-01|原始条带、带符号响应以及两个方向通道

很多神经网络会在卷积后接上 ReLU 激活函数,它把负数变成零,正数原样保留。写成公式就是 。应用到上面的响应后,得到 [0,4,4,0,0,0,0,0]。这个结果突出了从暗到亮的一侧,却同时抹去了从亮到暗的那一侧。

小叶可以根据任务决定是否这样处理。若他只找暗到亮的过渡,保留正响应很合适;若他需要纸带两边,只有这一张激活后的特征图就不够了。

一种简单的安排是再使用方向相反的核 [1,0,-1],也在后面接 ReLU。这样得到两个通道:一个保留向右变亮的响应,另一个保留向右变暗的响应。图中最后两行展示的正是这种分开记录。另一种安排是取原响应的绝对值,得到“变化强度”,但这样会合并方向:同样强的变亮和变暗成为相同数值。

这几种处理都能执行,选择依据却不同。想保留方向,就分别记录;只关心变化强不强,可以合并符号;想回到原图定位,还要保留位置。理解特征图,首先要分清每张图中的数值到底表示什么,不能把所有亮起来的区域都笼统叫作“识别到了目标”。

四、权重共享:同一种规则不用在每个位置重学

小叶并不希望图像左边用一种边缘标准、右边又换一种标准。同样的亮暗过渡出现在不同位置,原则上应受到同样的检查。把一组核权重反复用于各个位置,叫作权重共享。

共享的是规则,不是结果。同一个核遇到均匀亮区会输出零,遇到边界会输出正数或负数;结果随局部输入而变。如果把所有位置的输出强行设成相同,反而无法知道哪里有边缘。

这项操作仍然可以放进前面学过的矩阵语言中。先缩小为五格输入,核仍为 [-1,0,1],无填充、步长为一。三个输出可以统一写成:

矩阵每一行负责一个输出;相同的三格权重依次向右错开。窗口之外的输入不参与这一行计算。这个表示帮助我们看见两件事:每次只访问局部数据,同一套权重又在各行重复出现。实际程序通常不必真的建立这张大矩阵,可以直接按窗口计算。

核固定且没有偏置时,这就是对输入的线性变换。把两个输入条带相加再处理,等于分别处理后把响应相加;把亮度整体乘上同一倍数,响应也乘上这倍数。这里讨论的是不包含截断、激活等额外处理的数学操作。若每个响应最后再加同一个偏置,这一步属于仿射变换;偏置会整体移动响应基准,但不会破坏空间上的权重共享。

接上 ReLU 后,整个操作就不再是线性的。例如,某位置对两个输入分别产生 2 和 −2 的响应。先把输入相加,该位置响应抵消为零,激活后仍是零;分别激活则得到 2 和 0,再相加是 2。两条计算路径不再相同。这个区别解释了为什么神经网络不能只靠不断堆叠线性变换来获得任意复杂的判断:中间需要能改变这些线性关系的操作。

权重共享还减少了需要确定的参数。不过,参数少不等于计算只做一次。十格条带仍然要检查八个窗口;图像变大,窗口数量也会增多。小叶查看模型时要把两类成本分开:一类是存多少套权重,另一类是这些权重在多大范围内被使用。更大图像可能不增加这一层的参数量,却增加运算和中间结果的存储量。

局部性与共享之所以值得放在一起,是因为它们把“各处重复检查相同模式”变成了一个具体的结构假设。这个假设适合当前边缘任务;如果任务要求左侧和右侧有不同含义,就还需要位置资料或后续能区分位置的处理。《动手学深度学习》:从全连接层到卷积

五、回到图像:二维窗口与多通道怎样配合

现在把一行数据放回图像。为了看清计算,小叶构造五行六列的灰度图,每一行都是 [0,0,4,4,0,0]。中间两列较亮,其余较暗,形成一条竖直亮带。二维卷积核也有行和列,每次与一块同样大小的图像区域对齐。

考虑下面的三行三列核:

它在三行里分别比较右侧与左侧,再取这三个差值的平均。这样,输出综合了附近几行的左右变化,而不是只依赖某一行。对于上面的竖直亮带,三行中的变化一致,所以得到的响应与一行比较相同。在上下行有少量不同的图像中,三行平均会改变响应,也可能把只出现在一行中的细小变化削弱。

不填充、每次水平或竖直移动一格,得到三行四列的特征图,每行是 [4,4,−4,−4]。输入的行列数之所以缩小,是因为窗口必须完整放进图像。图中的核已经包含三分之一这个系数;计算时不需要再额外除一次。

二维图像、方向核与带符号特征图
图 A11-02|二维图像、方向核与带符号特征图

这个核比较的是左右,突出的是竖直边界附近的响应。“沿水平方向比较”和“检测竖直边缘”并不矛盾:要发现一条竖直分界线,通常需要从它的一侧跨到另一侧。若要检测水平边缘,可以改成比较上方与下方。把核的空间排列想清楚,比只背“横向核、纵向核”的名字更可靠。

真实彩色图像往往有红、绿、蓝三个输入通道。同一个位置的三组数共同描述颜色。一个普通卷积层要生成一个输出通道,会为每个输入通道准备一份空间权重,在对应窗口内分别加权,随后把各输入通道的贡献加起来。需要偏置时,再加这一输出通道的偏置。

这意味着,一个输出通道不必对应一种原始颜色。它可能利用红色与绿色的差别,也可能综合多种颜色中的相似变化。比如只看一个像素、使用一乘一窗口,给红、绿、蓝通道的权重分别为 1、−1、0,就能输出这个位置的红绿差值。窗口虽然没有覆盖邻居,仍然能混合通道信息。空间范围与通道组合,是两个可以分别考虑的选择。

多个输出通道意味着准备多套这种规则。另看一组用于比较参数量的设定:输入为3通道、32行32列,输出为8个通道,每套使用3×3空间窗口。每个输出通道需要3×3×3,即27个权重;8个通道共216个权重,若各加一个偏置,共224个参数。它们在整张图上共享。

如果每个空间位置都单独保存一套同样大小的规则,并让输出仍有32行32列,就要为每个位置和输出通道各保存28个参数,总数变成229,376。两种安排都使用局部窗口、8个输出通道并包含偏置,参数量从224增加到229,376,差异来自规则有没有在空间上共享。这个比较显示了需要保存的规则数量,并不直接比较两种模型的训练效果。

新一层的“通道”因此可以理解为:每个位置同时记录了几类响应。输入是三通道,不要求输出也只能是三通道;输出变成八通道,也不是图像突然获得了八种人眼可见的颜色。它获得了八组可供后续使用的数值描述。

六、步长与填充:检查得多密,边界怎样处理

到目前为止,小叶每次只移动一格。这个移动距离叫作步长。步长为二时,窗口每次向右跨两格,计算的位置就更稀疏。仍用最初十格条带,三格窗口从第 1、3、5、7 格开始,共输出四个响应 [0,4,−4,0]。

较大的步长减少了输出数量,也省去了一部分窗口计算。但它改变了观察位置,不只是把原结果显示得更紧凑。对于这条较宽的亮带,两侧变化还在;换成非常细或频繁交替的结构,隔格检查可能漏过某些变化,或者让它们以不同的形态出现。需要准确定位时,应当评估这种空间间隔能否满足要求。

有时小叶希望输出与输入保持相同长度,方便后续逐位置对齐。三格窗口无法以原第一格为中心完整放下,因为左边缺一格。这时可以在输入两端各补一个数,这项操作叫作填充。最简单的是补零;三格窗口、步长一、两端各补一格,便可以输出十个值。

填充不是找回画面外的信息,而是明确采用一种边界假设。想象输入是一条全部为 4 的均匀亮条带。内部左右一样亮,理应没有边缘;如果两端补零,再用原来的方向核处理,左端会产生 4,右端会产生 −4。程序把人为添加的暗背景与真实亮区之间的差异检测出来了。

对于“图像之外视作暗背景”的任务,这可能是合适的处理。对于“图像只是从一大片均匀亮区域裁下来”的任务,边缘响应就不代表真实场景中有一条分界线。还可以复制最外侧像素作为填充值,或采用反射等规则;关键是确认哪种假设适合当前数据,而不是见到边缘异常就反复调整核。

输出长度可以用一个简洁的式子记录。在一维情况下,输入长度为 ,核宽为 ,左右各填充 个值,步长为 。核内相邻权重对应相邻格子,而且只使用完整窗口时:

这里 都以格子数计,且填充后至少能放下一个窗口。符号 表示向下取整。这个式子的含义是:先放下第一个完整窗口,再看剩余长度允许它向右移动多少个完整步长。最后不足一个步长的部分,不会变成一个额外的完整窗口。

对十格条带,三格窗口、不填充、步长二,能放四次;两端各补一格且仍用步长二,则能放五次。填充与步长要一起看,不能把“补了一格”自动理解为“保持原尺寸”。二维图像按高度和宽度分别计数,普通空间卷积不会因为窗口在图上移动就把输出通道数也算进这两个尺寸里。

回到上一节的三十二行三十二列案例:三乘三窗口、每边填充一格、步长一,空间尺寸保持三十二行三十二列;八套核使输出有八个通道。把这四个条件连起来,小叶就能判断代码里的输出形状是否合理,也能继续追踪某个输出对应原图的大致位置。

七、感受野:后面的一个响应,能看到多大范围

第一层只看三格,是否意味着整个系统永远只能看三格?不是。小叶可以把第一层产生的特征图当成新的输入,继续用局部窗口进行组合。后面一格所依据的原始范围会扩大,这个范围叫作它相对于原输入的感受野。

先考虑连续两层宽度三、步长一的操作。第一层某个输出对应原始三格;第二层再取第一层连续三个输出,它们分别覆盖原第 1 至第 3 格、第 2 至第 4 格、第 3 至第 5 格。合在一起,第二层这个位置可以依赖原第 1 至第 5 格。

因此,两层三格窗口的感受野宽度是五格,不是九格。相邻窗口共享了很多输入,计算覆盖范围时不能把重复位置也当成新增信息。在二维情况下,连续两层三乘三、步长一的普通卷积,其内部位置的结构感受野是五乘五。

这里说的是由连接方式允许覆盖的范围。有些具体权重为零,有些激活当前被截断,对当前输出真正起作用的输入可能更少。我们的方向核中间权重就是零。感受野宽度告诉小叶“最远可以利用到哪里”,不保证范围里的每一格对当前结果都有相同作用,也不表示网络已经有效识别了范围内的全部内容。

还要注意中间的步长。如果第一层已经每隔两格输出一次,那么下一层走过三个相邻输出时,它们在原输入上对应的间隔会更大。用三格窗口、步长二做第一层,再用三格窗口、步长一做第二层,第一层窗口可依次覆盖原第 1 至第 3、第 3 至第 5、第 5 至第 7 格,第二层就能覆盖七格。

扩大感受野的用途,是让后面的计算有机会组合原先分开的局部现象。例如,单独一个方向响应只提示某处发生亮暗变化;更大的范围可能同时包含亮带左右两侧,从而让系统比较边缘方向和间距。窗口覆盖得再大,如果权重和后续规则没有学会利用这些关系,也不会自动获得“这是一条纸带”的理解。《动手学深度学习》:特征图与感受野

小叶由此可以区分两个排查方向:若有关联的两处信息从未能进入同一判断范围,需要考虑网络怎样汇总;若范围已经覆盖,结果仍不好,就要继续检查数据、训练目标及模型实际学到的关系。把所有识别问题都归结为“核不够大”,会错过后一类原因。

八、池化:把局部响应汇总成更少的数

为完成开头的第二项任务,先考察其中一步:判断某一小片区域里有没有明显的暗到亮过渡,暂不要求记住响应发生在这片区域内的哪一格。小叶可以先提取相应方向的响应,再把邻近结果汇总。

池化就是按窗口对数值做汇总。本节先用两格窗口、步长二、无填充,把不重叠的两格分为一组。对原条带卷积后再做 ReLU,输入池化层的是 [0,4,4,0,0,0,0,0],它已经是特征响应,不是最初的亮度。

最大池化每组保留最大值,结果为 [4,4,0,0]。第一组里有一个强响应,尽管另一个位置为零,汇总后仍然保留 4。对于“这两格内有没有很强的相应特征”,这种汇总有用。但它不再告诉后续,强响应是在组内第一格还是第二格。

平均池化每组取平均,结果为 [2,2,0,0]。它保留的是局部平均响应水平。第一组只有一半位置响应较强,因此平均值比最大值小。输出 2 不代表边缘的方向核算错了,而是现在报告的统计量变了。

要看出这两种汇总关注的差别,可以暂时比较两个四格响应区域:[8,0,0,0] 和 [2,2,2,2]。它们的平均值都是 2,最大值却分别为 8 和 2。第一个区域有一处很强的峰值,第二个区域较均匀。小叶若要筛选局部强峰,平均值会把这两个区域混在一起;若要比较整体平均强度,只看最大值又会忽略响应分布。

最大池化也可能突出异常尖峰。一个由噪声造成的很大数值同样会被选中;平均池化则可能把面积很小但真实重要的特征冲淡。哪一种合适,取决于特征和完成标准。不能仅凭“最大听起来更强”决定整个模型的汇总方式。

普通最大池化和平均池化通常按每个通道分别操作,保留通道身份。两个方向通道各自池化,仍能区分变亮与变暗;若提前把它们混成一张图,这种区别就可能消失。这些基本池化本身不需要学习权重,窗口和步长是设定,取最大或平均是固定规则。PyTorch 最大池化、平均池化文档

把整张特征图作为一个窗口,叫作全局池化。每个通道只留下一个数,表示全图最强响应或平均响应。它适合把空间信息变成图像层面的描述,也会丢掉大量位置细节。在主例中,正方向激活的全局最大值是 4;如果只交出这个数,后续无法知道强响应原来靠左还是靠右,也无法从中数出几个独立边缘。

池化会不会缩小尺寸,要看步长和边界处理。这里两格窗口、步长二,使八个位置变成四个;若每次只移动一格,窗口就会重叠,输出数量不同。池化不是“固定除以二”的指令,而是带有明确空间范围的汇总操作。小叶读取代码时,要把汇总统计量和取样位置一起确认。

九、位置移动后,结果到底会不会变

权重共享常带来一种有用的性质:在远离边界、步长为一且其他条件一致时,输入里的模式移到哪里,响应图里的相应模式也跟着移到哪里。这叫作平移等变。变化被以对应的方式保留了下来。

例如,亮带在图中向右移动一格,检测出的边缘响应也向右移动。响应的局部形状可以保持,整张按坐标排列的特征图却不是原封不动。对定位任务,这是好事,因为输出位置理应跟着目标走。

平移不变要求的是另一件事:输入移动后,输出保持相同。比如一个只报告“是否出现亮带”的判断,理想情况下不应因为亮带从左边移到右边,就突然改成“没有”。等变帮助保留位置关系,不变帮助忽略不重要的位置变化;两者要根据输出任务区分。

最大池化有时能减小对局部位移的敏感性,但不保证对任何平移都不变。只看四格特征图,两格一组取最大:

池化前的四格响应 池化后的两格响应
[4,0,0,0] [4,0]
[0,4,0,0] [4,0]
[0,0,4,0] [0,4]

第一行的强响应向右移一格,仍在同一组内,结果不变;再移一格,越过分组边界,结果便发生变化。我们没有更换强度、核或判断标准,只改变了峰值所在的位置,就足以推翻“用了最大池化就对平移完全不敏感”这个说法。

池化窗口内移动与跨窗口移动的区别
图 A11-03|池化窗口内移动与跨窗口移动的区别

若对这三行都做全局最大池化,确实都会得到 4。这是因为本例移动没有改变数值集合,全局最大也不记录位置。但在真实图像中,目标移到边缘可能被裁掉,填充会改变局部窗口,较大步长也会改变取样位置。前面的特征图未必只是简单平移,其全局最大值自然也未必保持。

实际检查时,可以把“哪里有响应”和“整体有没有相应现象”分开,再改变位置,看哪些步骤应随之改变、哪些步骤希望保持稳定,进而核查算法声称的性质是否成立。

池化还会影响感受野。步长为一的三格卷积后,连续两个输出联合覆盖原始四格;再用两格窗口、步长二池化,每个池化结果就对应这一段四格范围。后续若用三格窗口跨过三个相邻的池化结果,它们在原输入上间隔两格,总共覆盖八格。范围变大与空间位置变粗可以同时发生,选择时需要同时考虑较大范围的信息和定位精度。

十、用一小段程序看清数据经过了什么

小叶可以把主例写成一段只用 Python 基础功能的程序。这里不训练模型,也不调用现成深度学习层,目的是把窗口、响应和池化之间的数据关系摊开。程序假定输入是一维数列,核能完整放入输入,只处理无填充、卷积步长为一的情况。

可复制模板
def correlate_valid(values, kernel):
    width = len(kernel)
    result = []
    for start in range(len(values) - width + 1):
        window = values[start:start + width]
        score = sum(v * w for v, w in zip(window, kernel))
        result.append(score)
    return result

def pool_pairs(values):
    # 本例要求长度为偶数,两格一组,不填充。
    assert len(values) % 2 == 0
    maximum, average = [], []
    for start in range(0, len(values), 2):
        pair = values[start:start + 2]
        maximum.append(max(pair))
        average.append(sum(pair) / 2)
    return maximum, average

strip = [0, 0, 0, 4, 4, 4, 0, 0, 0, 0]
response = correlate_valid(strip, [-1, 0, 1])
positive = [max(0, r) for r in response]
negative = [max(0, -r) for r in response]
maximum, average = pool_pairs(positive)

print(response)
print(positive)
print(negative)
print(maximum)
print(average)

输出依次为:

可复制模板
[0, 4, 4, 0, -4, -4, 0, 0]
[0, 4, 4, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 4, 4, 0, 0]
[4, 4, 0, 0]
[2.0, 2.0, 0.0, 0.0]

阅读这段程序时,重点看每一步接收的对象。response 是原亮度的局部差值;positive 和 negative 分别保留两个方向;池化在本例中只作用于 positive。如果误把 strip 直接交给池化,输出汇总的是原始亮度,回答的便不再是“附近有没有相应方向的边缘”。代码能运行,并不能代替这项含义核对。

zip 将窗口中的亮度与核权重逐一配对,sum 把贡献相加,切片负责取出当前窗口。暂时不熟悉语法,也可以跟着这三件事看懂计算。程序设计课程会详细讲列表、循环和函数;此处只需要理解各步输入输出的含义。

还可以用简单输入检验自己的理解。把十格全改成同一个亮度,当前无填充差分结果应全为零;把亮暗对调,方向响应应反号;换成平均核,输出应该跟随局部平均亮度。这样的小试验是在核对某个操作是否符合已知性质,不是在证明整个视觉系统已经可靠。

最大池化和平均池化也不具有相同的数学性质。对于固定分组,平均池化是线性汇总;最大池化不是。取两个二格输入 [1,0] 与 [0,1],分别取最大再相加,结果为 2;先逐格相加得到 [1,1],再取最大,结果为 1。最大值来自哪个位置会随输入改变,这正是它与固定加权平均不同的地方。

小叶因此能把处理链拆开理解:卷积使用共享权重进行局部组合,激活改变响应的表达方式,池化汇总局部统计量。它们可以连在一起,也可以为某个任务调整组合,不能把三步都解释成同一种“把图变小”。

十一、从手设规则到可训练模型,怎样回到任务

本章的核由我们手工指定,因为“右侧减左侧”容易与边缘对应。在可训练的卷积神经网络中,核权重通常由数据和训练目标共同确定。初始化时的一组数字未必具有可解释的边缘形状;训练的目标,是让各层形成有助于任务的数值变换。

“学习核”可以先理解成:保留局部连接和共享方式,调整其中的权重,让模型输出更符合训练要求。网络结构规定哪些数据能够互相组合、哪些位置共用规则;训练则决定这些组合里的具体数字。这里的两件事不能互相替代:即使权重优化得很好,已经被全局汇总丢掉的位置也不会凭空回来。

手设差分核还有明确的局限。照明阴影、纸上的文字和另一种物体都可能产生亮暗边缘,仅凭局部强响应并不能判定“这就是目标纸带”。实际识别可能需要方向、间距、颜色、纹理以及更大范围的组合;边缘响应可以成为这些后续判断的输入。

回到最初的两项任务,小叶可以作出具体选择。

如果要找出亮带两侧位置,他应保留有符号响应,或分别保留两个方向通道,同时记录响应与原图的坐标对应。主例中,正响应集中在中心编号 3、4,负响应集中在 6、7;结合原数据可知,两次跳变分别位于第 3、4 格之间和第 6、7 格之间。他可以在这些候选附近核对相邻亮度,进一步定位。这个安排保留了完成判断所需的方向和位置,而不把每个非零响应误算成独立边缘。

对于主例中的亮带,小叶还可以把响应取绝对值,再做全局最大汇总,用来判断当前核是否检测到了足够明显的亮暗变化。例如在本教学尺度下,把判定条件设为“变化强度大于 3”,主例的最大强度为 4,判断为有。这里的门槛是人为设定,真实使用时需要根据实际亮度尺度和样本调整。若每格明暗交替,三格窗口两端始终相等,这个核甚至会全程输出零;所以汇总可以报告它已经检测到的变化,却不能据零结果排除所有亮暗变化。

如果任务后来变成“画出纸带的精确区域”,只留下一个全局最大值就不够。多个不同位置、不同宽度的亮带都可能得到相同的最大值。小叶需要保留更细的空间特征,必要时结合原图或较早层的结果,不能仅把一个数放大成许多像素就期待恢复被汇总掉的边界细节。

这也提供了一种与 AI 协作的具体方式。小叶可以先让它展示每一步的输入输出形状与一组小样本的中间结果,然后追问:当前数值表示亮度、方向响应还是局部最大?目标移动时哪些结果会随位置移动?最后输出还包含定位需要的信息吗?这些问题来自对计算的理解,比只要求“用更先进的网络提高准确率”更容易找到可以核查的环节。

当这些结构选择已经清楚,下一步才是研究如何评价输出与目标的差距、怎样调整可训练参数。A12 将用损失函数和优化直觉继续处理这件事。对于现在的小叶,已经可以根据任务决定局部检查什么、哪些响应需要分开、怎样汇总,以及在汇总之前必须留下哪些信息。

练习与参考分析

练习一:整体变亮,边缘响应也一定变大吗

小叶把主例换成 [2,2,2,5,5,5,2,2,2,2],仍用 [-1,0,1]、无填充、步长一。请判断两侧响应的方向和强度。如果把这条新数列的每一格再加上 10,响应会怎样?这与把每一格都乘以 2 有什么不同?

参考分析: 新数列亮区与暗区的差是 3,所以完整响应为 [0,3,3,0,−3,−3,0,0]。方向与原例相同,幅度较小。虽然暗区和亮区的绝对数值都比原例更大,局部反差却由 4 降为 3。边缘响应衡量反差,不能由“画面整体更亮”直接判断。

每格同时加 10 后,左右两侧增加的部分在相减时抵消,响应保持不变。每格都乘以 2,则左右差值也加倍。这个结论针对当前无填充差分操作,并假定没有亮度上限截断。如果真实图像的亮度达到上限后被截断,或者改成在边界固定补零,条件就发生了改变,需要分别检查。

练习二:把输出尺寸与参数量分开算

输入是一张三通道、二十行二十列的图像。普通卷积层有四个输出通道,核为三乘三,每边补一格,步长二,每个输出通道有一个偏置,不使用分组或空洞卷积。输出形状和参数量分别是什么?随后按通道做二乘二、步长二、无填充最大池化,结果形状怎样变化?

参考分析: 每个方向的输出长度都是10,所以卷积输出为4通道、10行10列。每个输出通道需要27个核权重和1个偏置,4个通道共112个参数。输入的20行20列决定规则使用多少次,不会让共享的核在每个位置增加一套参数。

池化后空间尺寸变成五行五列,输出通道仍为四。池化汇总每个通道内部的空间响应,没有在本题中合并通道,也没有新增可训练权重。若一段代码给出十六个输出通道,不能以“池化会增加特征”为理由接受;需要检查是否还有题目未说明的卷积、通道重排或其他操作。

练习三:最大值相同,位置就可以恢复吗

两张一维特征图分别为 [0,6,0,0] 和 [0,0,6,0]。先分别做两格窗口、步长二的最大池化,再分别做全局最大池化。小叶想凭最后的数值判断强响应在前半段还是后半段,这个计划是否可行?

参考分析: 局部池化的两个结果分别为 [6,0] 和 [0,6],前后半段仍可区分;再做全局最大池化,都只剩 6。仅凭这个最后数值,无法判断来自哪张特征图。问题不是算法不够聪明,而是两个不同输入已经被映射成同一记录。

可以保留局部池化结果,或者额外记录最大值的来源位置,但后者也是保存了额外信息,并不是从最大值本身恢复位置。若只保留每组最大值,即使能分清前后半段,也未必能分清强响应位于组内哪一格。定位精度必须与实际保留下来的信息对应。

练习四:均匀区域为什么被检测出了边缘

小叶输入 [5,5,5,5,5],用 [-1,0,1]、步长一、两端各补一个零,得到非零边界响应。他据此认为图像里有两条真实边缘。请说明这个判断缺了什么条件,并比较复制边界值进行填充会发生什么。

参考分析: 零填充结果为 [5,0,0,0,−5]。非零响应来自人为补入的零与原数据的差异,并不能独自证明实际画面外存在暗背景。如果原图只是均匀区域的一小段裁剪,这两个响应反映的是处理边界。

复制两端数值后,窗口看到的仍都是 5,全部响应为零。两种结果各自符合自己的边界假设。先检查输入范围与填充规则,再判断这种假设是否适合任务,才能分清非零响应来自真实的场景变化,还是人为设置的边界。

练习五:窗口叠加为什么不是尺寸相乘

两层一维卷积都使用宽度三的核。方案甲两层步长都为一;方案乙第一层步长为二,第二层步长为一。只考察远离边界的输出,不使用空洞卷积。请比较两者相对于原输入的结构感受野,并说明感受野更大是否足以证明识别更准确。

参考分析: 方案甲的三个第一层窗口可分别覆盖原第 1 至第 3、第 2 至第 4、第 3 至第 5 格,合起来是五格。方案乙覆盖第 1 至第 3、第 3 至第 5、第 5 至第 7 格,合起来是七格。窗口有重叠,要看位置范围的并集,不能直接把三乘三当作九格。

七格表示第二层有机会利用更远的信息,第一层输出同时变得更稀疏。这种选择可能有助于组合较远的现象,也可能损害细节。识别效果还取决于任务、数据和实际权重;结构上的范围不是准确率。某些权重为零时,当前数值对一部分输入还可能没有依赖,但不改变此处按连接范围作出的结构计数。

练习六:为两个输出目标安排不同的处理

小叶要让同一个程序支持两个输出:一是报告图中有没有强烈亮暗变化,二是在原图中标出这些变化的位置。AI 建议先用一套只比较一个方向的核做卷积,接上ReLU和全局平均池化,再把结果交给两个输出模块。请指出这条共同处理链可能丢掉什么,给出更符合两个目标的安排。

参考分析: 单一方向卷积后接 ReLU,可能丢掉另一方向的变化;全局平均又把空间位置和局部峰值分布汇总掉。强烈变化只占很小区域时,平均值未必很大;位置模块仅凭全局平均无法知道响应来自哪里。两个模块放在最后,并不会自动补回前面丢失的信息。

可以先保存有符号响应或两个方向通道,让定位模块继续使用带空间坐标的特征;存在判断模块再根据目标选择变化强度及其汇总方式,例如取绝对值后检查全局最大是否超过适当门槛。这里给出的是一个可以验证的基础安排,实际任务还应区分噪声、阴影与真正关心的变化。不同输出需要不同信息,因而适合在尚未丢掉这些信息的位置分开处理。