跳到主要内容

卷积 — 让一小片可调的数滑过整张图

这一章讲三件事: 为什么图片不能打散成一排;卷积每滑到一处具体算什么; 以及一张 32×32 的图穿过七层之后,形状是怎么一步步变成 10 个类别得分的。

它在全书链条里的位置: 前七章的模型都假定输入是一排数。 这一章是第一次让模型「知道」输入本身有形状。

需要的基础: 第 06 章的层与矩阵乘;第 07 章的分小撮。

1. 先看现象:打散成一排,既贵又蠢

一张 32×32 的灰度图有 1 024 个像素。要接一层第 06 章那样的层, 每个像素都连到下一层每个神经元——这种连法叫全连接

代价有两笔,第二笔更要命:

  • 贵。 下一层哪怕只有 1 000 个神经元,权重就有 1 024 × 1 000 ≈ 一百万个;

  • 蠢。 打散成一排之后,「第 5 个像素和第 6 个像素挨着」这件事就没了 ——在模型眼里它们和第 5 个与第 500 个一样远。

书里给出的替代方案是卷积,它靠两条特性同时解决这两笔账1:

特性什么意思解决哪笔账
局部连接一次只看一小片,不看全图蠢那一笔:小片里的像素本来就挨着
权重共享滑到哪儿用的都是同一小片可调的数贵那一笔:要调的数一共有多少个(这个数就叫参数量)和图的大小无关

书里还说,这两条特性天然带来一定程度的平移不变性—— 同一个东西挪到图的另一个角落,照样能被认出来1

全章主走查:一张 3×3 的小图,一个 2×2 的核,滑四个位置
═══════════════════════════════════════════════════════════════
输入 [[1, 2, 3], 核 [[0, 1],
[4, 5, 6], [2, 3]]
[7, 8, 9]]
───────────────────────────────────────────────────────────────
§2 ① 左上角 → 25 §2 ③ 左下角 → 43
§2 ② 右上角 → 31 §2 ④ 右下角 → 49
§3 ⑤ 加上步长与补零两个旋钮,输出尺寸怎么变
§5 ⑥ 多个输入通道:三张图各卷一次再相加 → 25 + 271 + 805 = 1101
§7 ⑦ 串成七层:1×32×32 一路走到 10 个类别得分,测试 0.8800
═══════════════════════════════════════════════════════════════

2. 主走查:四个位置,四个数

先交代一个术语上的坑,书里用提醒框标了出来。

严格的数学卷积要先把那一小片翻转再做点积(点积就是两排数按位置对应相乘、再全部加起来); 这一步在工程上既繁琐又毫无收益, 所以实现中普遍直接采用互相关(不翻转,直接按位置对应相乘再相加)。 卷积核本身是学出来的,翻不翻转只影响参数符号的命名,并不影响表达能力2

所以:书里后文说的「卷积」,一律指不翻转的那一种3。你在任何框架里看到的也都是这一种。

现在走主走查。 输入是 3×3、核是 2×2,核在输入上滑四个位置4:

① 左上角:核盖住 [[1,2],[4,5]]
0×1 + 1×2 + 2×4 + 3×5 = 0 + 2 + 8 + 15 = 25

② 右上角:核盖住 [[2,3],[5,6]]
0×2 + 1×3 + 2×5 + 3×6 = 0 + 3 + 10 + 18 = 31

③ 左下角:核盖住 [[4,5],[7,8]]
0×4 + 1×5 + 2×7 + 3×8 = 0 + 5 + 14 + 24 = 43

④ 右下角:核盖住 [[5,6],[8,9]]
0×5 + 1×6 + 2×8 + 3×9 = 0 + 6 + 16 + 27 = 49
─────────────────────────────────────────────────
输出 [[25, 31],
[43, 49]] 3×3 的输入 → 2×2 的输出

注意四个位置用的是同一组核参数(0, 1, 2, 3)。 这就是「权重共享」的全部含义 ——它不是一种优化技巧,而是「这个特征在哪儿都算特征」这个假设的直接表达。

再注意输出比输入小了一圈:3×3 变成了 2×2。 只要核大于 1×1,每卷一次都会缩一圈——这是下一节那个「补零」旋钮要解决的问题。

还有一个下标约定要记住,书里同样用提醒框标了: 本书所有矩阵下标都从 0 开始,与主流框架保持一致; 这与教科书全本「从 1 开始」的约定不同,对照公式时要留意起点偏移5

3. 两个旋钮:滑多快、边上补不补

第一个旋钮:步长。 每次滑动跨越几个元素6取 2 就等于隔一个算一次,输出尺寸大致减半。

书里给了一个 4×4 输入、步长为 2 的例子,输出是 [[30, 42], [78, 90]]7

第二个旋钮:零填充。 在输入四周补若干圈 0 再做卷积8它解决的正是上一节那个「每卷一次缩一圈」的问题—— 补一圈再卷,输出就能和输入一样大。

书里给的输出尺寸公式9:

输出高 = (输入高 + 2×补零圈数 − 核高) ÷ 步长 + 1
输出宽 = (输入宽 + 2×补零圈数 − 核宽) ÷ 步长 + 1

拿书里的实测对一遍10:

输入 8×8,核 3×3,补 1 圈
步长 1:(8 + 2 − 3) ÷ 1 + 1 = 8 → 输出 8×8,尺寸不变 ✓
步长 2:(8 + 2 − 3) ÷ 2 + 1 = 4.5 → 取整 4 → 输出 4×4,宽高各减半 ✓

「3×3 核 + 补 1 圈」这个组合值得背下来:它保持尺寸不变。 你在别人的网络定义里会反复看到 kernel_size=3, padding=1, 看到就知道这一层不改尺寸,只改通道数。

4. 拿一个固定的核当探针:边缘检测

这一节是全章最直观的一段:不训练,直接把核的值写死。

书里选的是一个 3×3 的核,中心为 8、四周为 −1, 它对像素邻域的强度突变特别敏感,在图像处理里常用于提取边缘11

这个核长这样 它在干什么
┌──────────────┐ 每个位置算的是:
│ −1 −1 −1 │ 中心像素 × 8 − 周围八个像素之和
│ −1 8 −1 │
│ −1 −1 −1 │ 周围和中心一样亮 → 结果接近 0(平坦区域)
└──────────────┘ 中心比周围亮很多 → 结果很大(边缘)

书里把这个核写进卷积层的权重,对一张灰度图跑一遍, 结果是右图清晰勾勒出原图主体的轮廓11

这个实验的意义不在结果,在于它揭示了一件事: 卷积核就是一个特征探针,而训练做的事就是「把这些探针的值学出来」。 手工设计探针是几十年前的做法;今天的做法是让数据决定探针长什么样。

5. 多通道:输入侧相加,输出侧堆叠

结论先行:真实的一层卷积有两个方向的「多」,规则不一样,别混。

输入侧的「多」叫输入通道。 彩色图的每个像素是红绿蓝三个分量, 所以输入不是一张表,是三张表叠在一起;上一层的输出层数越多,这个数越大12

输出侧的「多」叫输出通道。 一个核只能产出一张结果图、对应一种特征模式; 要在一层内并行提取多种模式,就安排多组核,最终堆出多张结果图12

那些结果图,书里叫特征图(教科书全本里译作「特征映射」,这本书统一用更口语的说法)13

两个方向的规则完全不同
═══════════════════════════════════════════════════════
输入通道方向 D 张输入 × D 个核 → 各卷各的 → 按位相加 → 1 张输出
⚠ 是相加,不是拼接;D 张进去,出来只有 1 张

输出通道方向 上面那件事重复 P 次(每次用一组不同的核)
→ 得到 P 张输出,按通道堆叠
═══════════════════════════════════════════════════════

书里那张图给了具体的数:三个输入通道各自卷出 25、271、805, 按位相加得到 110114这个 1101 就是「输入通道相加」这条规则的样子。

所以一层卷积的核是一个四维的东西: 输出通道数 × 输入通道数 × 核高 × 核宽15读别人的模型定义时,weight.shape 打出来就是这四个数。

张量布局又要交代一次,书里用提醒框标了: 本书把特征图写成「通道 × 高 × 宽」,与教科书全本用的「高 × 宽 × 通道」顺序不同; 卷积核也相应地写成「输出通道 × 输入通道 × 核高 × 核宽」15

最后一步是过激活函数。 书里在这里加了一条工程惯例: 激活函数通常单独作为一个算子,不放在卷积层内部,便于两者自由组合16这就是为什么你在模型定义里看到的是 convrelu 分开写。

6. 汇聚层:把一小片响应压成一个

结论先行:卷积不改变尺寸(配上补零的话),真正缩小尺寸的是这一层。

书里的说法是:汇聚层的核心作用是对特征图做下采样—— 把局部区域的多个响应压成一个,从而减少特征数量、提供一定程度的平移不变性17。 「下采样」里的采样,指的就是「从一堆数里按某种规则挑出一部分来代表整体」。

尺寸缩小之后还有一笔连带的好处: 若紧跟全连接层,能直接降低后续层的参数量、 省下显卡上的那块内存;这块内存的俗称就叫显存,后面讲大模型时它会反复出现17

两种常见做法17:

做法怎么压特点
平均汇聚窗口内取平均平滑性更好
最大汇聚窗口内取最强的那个保留显著特征更激进

主流选择书里也给了: 窗口过大虽然压得更狠,却也会丢太多信息; 当前主流做法是在每个特征图上划分 2×2 不重叠区域、配合最大汇聚做下采样18

这一层没有任何可学习的参数——它只是一个固定的压缩规则。 所以它不算在「层数」里:第 09 章那个「18 层」数的是带参数的层,不含汇聚层19

下一章那个带直连边的小零件里,同样会出现「压一压尺寸」和「把数值拉回刻度」这两件事 ——第 09 章第 2 节会把它们摆在一起讲。

7. 主走查续:七层形状,和 0.8800

卷积神经网络这一族,英文缩写就叫 CNN

这一族最早的成功案例叫 LeNet-5。 书里提到,1990 年代起, 基于它的支票号码识别系统就已在美国多家银行落地20

书里实现的这一版和原始论文有 4 处差异,提醒框里列了出来21: 不再用连接表削减通道;汇聚层退化成无参数、无激活的最简形式; 卷积层激活统一改为折线那一条;输出层直接用全连接线性层。

主走查第 ⑦ 步:一张 1×32×32 的图穿过七层,每一层之后的形状22:

输入 (1, 1, 32, 32)
C1 6 个 5×5 卷积核 → (1, 6, 28, 28) 32 − 5 + 1 = 28
S2 2×2 最大汇聚,步长 2 → (1, 6, 14, 14) 28 ÷ 2 = 14
C3 16 个 5×5 卷积核 → (1, 16, 10, 10) 14 − 5 + 1 = 10
S4 2×2 平均汇聚,步长 2 → (1, 16, 5, 5) 10 ÷ 2 = 5
C5 120 个 5×5 卷积核 → (1, 120, 1, 1) 5 − 5 + 1 = 1
展平 → (1, 120)
F6 全连接 120 → 84 → (1, 84)
F7 全连接 84 → 10 → (1, 10) 10 个类别得分

这张表值得逐行核一遍,因为每一行都能用第 3 节那个公式算出来。 特别是 C5 那一行:5×5 的输入配 5×5 的核,输出正好是 1×1 ——这一层名义上是卷积,实际上等价于一次全连接。

再看通道数的走向:1 → 6 → 6 → 16 → 16 → 120。 空间尺寸一路缩小,通道数一路变大——这是卷积网络最典型的形状, 后面第 09 章那个十八层的也是同一个走向。

训练设定: 为缩短时间只取手写数字数据集的一个子集, 训练 1 000 条、验证 200 条、测试 200 条23; 预处理两件事:缩放到 32×32(网络要求),把像素值平移缩放到 −1 到 1 之间24; 每步喂 64 条,每步挪 0.1,训 5 轮25

结果26:

[Test] accuracy/loss: 0.8800 / 0.4177

再做一次单条预测:真实类别 2,预测类别 227

0.8800 怎么读? 十类任务里随机猜是 0.1,所以 0.88 已经远超随机; 但手写数字这个任务上,一个训练充分的模型能到 0.99 以上。 差距的来源是训练集只有 1 000 条、只训了 5 轮——这是书里为了跑得快主动做的取舍。

8. 作者的判断与证据

书里给了证据的:

  • 四个位置的数 25 / 31 / 43 / 49——书里的图里逐位置写出了乘加过程4;
  • 步长与补零对尺寸的影响——公式加两次实测,两边对得上10;
  • 七层的形状演化——逐层打印,每一行都能用公式核22;
  • 测试成绩 0.8800——实际打印输出26

属于作者主动交代的边界:

  • 实现与原论文的 4 处差异——提醒框里逐条列出21;
  • 手写实现比工程实现慢几个数量级——见下一节28;
  • 只取子集是为了缩短运行时间——书里明说23

判断(我们的,不是书里的):这一章最容易被读快的地方,是第 5 节那两个「多」。 输入通道方向是相加、输出通道方向是堆叠——这两条规则方向相反,而书里只用一段带过。 读岔了的直接后果是:你算不对任何一层的参数量,也读不懂别人网络定义里那四个数。 如果错,会错在: 如果读者只调用框架、从不自己数参数量,这道区分确实可以不要。 判据是:随便找一个卷积层定义,能不能一口说出它的核张量是哪四个数、总共多少个参数。

9. 边界与局限

这一章没覆盖的:

没讲什么依据 / 为什么值得知道
感受野怎么随层数累积书里把它整个留成了动手练习29
空洞卷积、转置卷积知识点图里列了,正文没有实现
一个像素属于哪个类别这类任务全书的图像任务都是「整张图属于哪一类」
数据增强训练图像模型的标配手法,全书没有
1×1 卷积第 09 章会用到,但那里是当作「对齐形状的工具」用的

一件书里主动点破、但值得单独摊开的事:手写实现和工程实现差几个数量级。

书里在给出多通道卷积的实现时写道:这份实现采用嵌套循环逐位置滑窗, 目的是让读者看清四步分解的对应关系,与生产代码相差几个数量级; 实际工程中应直接调用框架的卷积——它们底层用显卡上的 im2col + GEMM 实现, 可一次性处理整批多通道输入28

这两个名字值得拆一下,因为它们解释了「为什么卷积能快」:

  • im2col —— 把每个滑动窗口盖住的那一小片拉直成一行, 整张图变成一个大矩阵。卷积于是被改写成了一次矩阵乘法。

  • GEMM —— 通用矩阵乘法。几十年来被优化到极致的那一个运算; 显卡的整个架构就是围着它设计的。

所以卷积快不是因为卷积特别,而是因为它被翻译成了矩阵乘法。 这条思路后面还会再见到一次:第 15 章把注意力切成好几份之后塞进批那一维,用的是同一个套路。

出门会撞见的名字:

  • nn.Conv2d —— 卷积层;四个最常调的参数是输入通道、输出通道、核大小、步长与补零30;

  • nn.MaxPool2d / nn.AvgPool2d —— 第 6 节那两种汇聚;

  • 汇聚 / 池化(pooling) —— 同一件事的两种中文译法, 这本书用「汇聚」,而大多数中文资料用「池化」;

  • 特征图(feature map) —— 第 5 节那些结果图,教科书全本译作「特征映射」13;

  • padding='same' —— 有些框架提供这个写法,意思就是「自动补到尺寸不变」, 等价于第 3 节那个「3×3 核补 1 圈」。

10. 可带走的

  1. 全连接对图片有两笔账:参数量爆炸,以及丢掉「相邻」;
  2. 卷积靠局部连接和权重共享同时解决这两笔,顺带带来一定的平移不变性;
  3. 实现里的「卷积」都不翻转核,严格说是互相关;翻不翻转不影响表达能力;
  4. 主走查四个数:25、31、43、49,四个位置用的是同一组核参数;
  5. 只要核大于 1×1,每卷一次输出就缩一圈;补零是为了抵消这件事;
  6. kernel_size=3, padding=1 保持尺寸不变,这个组合值得背下来;
  7. 输入通道方向是相加(25 + 271 + 805 = 1101),输出通道方向是堆叠,别混;
  8. 卷积核张量是四维的:输出通道 × 输入通道 × 核高 × 核宽;
  9. 汇聚层没有可学习参数,所以不算在「多少层」里;
  10. 七层形状一路缩尺寸、涨通道,最后 C5 那一层实际上等价于一次全连接;
  11. 手写实现比工程实现慢几个数量级,因为后者把卷积翻译成了矩阵乘法。

11. 原文地图

主题原书章原文位置
两条核心特性第5章 卷积神经网络text/06-ch05.txt:4(搜「设计灵感来自生物视觉」)
互相关与下标约定第5章 卷积神经网络text/06-ch05.txt:47(搜「严格的数学卷积需要先把卷积核翻转」) · text/06-ch05.txt:80(搜「本书所有矩阵下标都从 0 开始」)
四个位置的数第5章 卷积神经网络text/06-ch05.txt:62(搜「25」)
步长与补零第5章 卷积神经网络text/06-ch05.txt:143(搜「在所有空间维度上每隔」) · text/06-ch05.txt:175(搜「输出特征图就会比输入小一圈」) · text/06-ch05.txt:260(搜「输出尺寸符合预期」)
边缘检测第5章 卷积神经网络text/06-ch05.txt:266(搜「拉普拉斯算子常用于提取边缘」)
多通道两个方向第5章 卷积神经网络text/06-ch05.txt:318(搜「同时提取多种特征」) · text/06-ch05.txt:346(搜「多通道卷积的实现可以拆成」)
张量布局与特征图译名第5章 卷积神经网络text/06-ch05.txt:332(搜「译为」) · text/06-ch05.txt:341(搜「为了对齐主流深度学习框架的张量布局」)
汇聚层第5章 卷积神经网络text/06-ch05.txt:481(搜「核心作用是对特征图做下采样」) · text/06-ch05.txt:498(搜「采样窗口过大」)
七层形状第5章 卷积神经网络text/06-ch05.txt:751(搜「conv1」) · text/06-ch05.txt:670(搜「与原始论文有」)
训练设定与成绩第5章 卷积神经网络text/06-ch05.txt:556(搜「为了缩短实验运行时间」) · text/06-ch05.txt:830(搜「0.8800」)
手写实现与工程实现第5章 卷积神经网络text/06-ch05.txt:409(搜「与生产代码相差几个数量级」)

Footnotes

  1. 出处:「第5章 卷积神经网络」第 4 段(text/06-ch05.txt:4,搜「设计灵感来自生物视觉」)。原文:与全连接层不同,卷积层和汇聚层依赖两条核心特性——局部连接和权重共享,由此天然带来一定程度的平移不变性(对小幅缩放、旋转也有一定鲁棒性),并显著减少参数量。 2

  2. 出处:「第5章 卷积神经网络」第 47 段(text/06-ch05.txt:47,搜「严格的数学卷积需要先把卷积核翻转」)。原话:这一步在工程上既繁琐又毫无收益,所以实现中普遍直接采用互相关运算;CNN 里卷积核本身就是可学习参数,翻不翻转只影响参数符号的命名,并不影响表达能力,二者其实等价。

  3. 出处:「第5章 卷积神经网络」第 53 段(text/06-ch05.txt:53,搜「除非特别强调」)。原话:除非特别强调,本书后文中的「卷积」都默认指互相关。

  4. 出处:「第5章 卷积神经网络」第 62 段(text/06-ch05.txt:62,搜「25」)。这是书里图 5.2 的四个子图,每个子图下方都写出了完整的乘加过程:0×1 + 1×2 + 2×4 + 3×5 = 25,以及 31、43、49 三个位置。 2

  5. 出处:「第5章 卷积神经网络」第 80 段(text/06-ch05.txt:80,搜「本书所有矩阵下标都从 0 开始」)。原文接着说:这与《神经网络与深度学习》主书「从 1 开始」的约定不同,对照公式时请留意起点偏移。

  6. 出处:「第5章 卷积神经网络」第 143 段(text/06-ch05.txt:143,搜「在所有空间维度上每隔」)。原文说明这等价于对输出做下采样,并把这个跨度称为步长。

  7. 出处:「第5章 卷积神经网络」第 157 段(text/06-ch05.txt:157,搜「30」)。这是书里图 5.3 给出的步长为 2 的四个位置结果:30、42、78、90。

  8. 出处:「第5章 卷积神经网络」第 175 段(text/06-ch05.txt:175,搜「输出特征图就会比输入小一圈」)。原文说明补零既能让卷积核宽度与输出尺寸彼此独立,也避免了「大核必然小输出」的两难。

  9. 出处:「第5章 卷积神经网络」第 195 段(text/06-ch05.txt:195,搜「零填充宽度」)。

  10. 出处:「第5章 卷积神经网络」第 260 段(text/06-ch05.txt:260,搜「输出尺寸符合预期」)。实际打印输出见第 255–258 段(text/06-ch05.txt:255,搜「When kernel_size=3」)。 2

  11. 出处:「第5章 卷积神经网络」第 266 段(text/06-ch05.txt:266,搜「拉普拉斯算子常用于提取边缘」)。原文说明它是一个 3×3 的卷积核,中心为 8、四周为 −1,对像素邻域的强度突变特别敏感;可视化结果见第 287 段(text/06-ch05.txt:287,搜「勾勒出原图主体的轮廓」)。 2

  12. 出处:「第5章 卷积神经网络」第 318 段(text/06-ch05.txt:318,搜「同时提取多种特征」)。原文分别说明输入通道数(灰度图为 1、彩色图为 3、上一层输出特征图层数越多则越大)与输出通道数(安排 P 组卷积核、堆出 P 张特征图)。 2

  13. 出处:「第5章 卷积神经网络」第 332 段(text/06-ch05.txt:332,搜「译为」)。原话:《神经网络与深度学习》将 Feature Map 译为「特征映射」,本书统一使用更口语化的「特征图」。 2

  14. 出处:「第5章 卷积神经网络」第 358 段(text/06-ch05.txt:358,搜「该过程的示意图见图」)。图 5.7 里三个输入通道各自卷出 25、271、805,按位相加得到 1101。

  15. 出处:「第5章 卷积神经网络」第 341 段(text/06-ch05.txt:341,搜「为了对齐主流深度学习框架的张量布局」)。原话:本书把特征图写成 D × M × N,与主书使用的 M × N × D 顺序不同;卷积核也相应地写成 P × D × U × V。 2

  16. 出处:「第5章 卷积神经网络」第 404 段(text/06-ch05.txt:404,搜「激活函数通常单独作为一个算子」)。原文:不放在卷积层内部,便于卷积层与激活函数自由组合。

  17. 出处:「第5章 卷积神经网络」第 481 段(text/06-ch05.txt:481,搜「核心作用是对特征图做下采样」)。两种做法见第 484–487 段(text/06-ch05.txt:485,搜「平均汇聚」)。 2 3

  18. 出处:「第5章 卷积神经网络」第 498 段(text/06-ch05.txt:498,搜「采样窗口过大」)。原话:当前主流做法是在每个特征图上划分 2 × 2 不重叠区域,配合最大汇聚做下采样,在保留显著响应与降低分辨率之间取得平衡。

  19. 出处:「第5章 卷积神经网络」第 543 段(text/06-ch05.txt:543,搜「许多卷积网络以」)。原话:例如 ResNet18 里的 18 指带可学习参数的层(卷积 + 全连接),不计入无参数的汇聚层。

  20. 出处:「第5章 卷积神经网络」第 651 段(text/06-ch05.txt:651,搜「支票号码识别系统」)。原文:1990 年代起,基于 LeNet-5 的支票号码识别系统就已在美国多家银行落地。

  21. 出处:「第5章 卷积神经网络」第 670 段(text/06-ch05.txt:670,搜「与原始论文有」)。四处依次是:C3 层不再使用连接表来削减卷积通道数;汇聚层退化为无参数、无激活的最简形式;卷积层激活函数统一改为 ReLU;输出层直接使用全连接线性层。 2

  22. 出处:「第5章 卷积神经网络」第 751 段(text/06-ch05.txt:751,搜「conv1」)。这是书里用一个 [1, 1, 32, 32] 的随机张量做一次前向、逐层打印形状的实际输出;逐层解读见第 761 段(text/06-ch05.txt:761,搜「逐层张量形状的演化清晰可见」)。 2

  23. 出处:「第5章 卷积神经网络」第 556 段(text/06-ch05.txt:556,搜「为了缩短实验运行时间」)。原文:本章只取 MNIST 的一个子集,训练集 1 000 条、验证集 200 条、测试集 200 条。 2

  24. 出处:「第5章 卷积神经网络」第 598 段(text/06-ch05.txt:598,搜「本实验主要做两件事」)。原文两件:调整图像大小到 32 × 32(LeNet 期望的尺寸),以及把像素值从 [0, 1] 线性平移缩放到 [−1, 1]。

  25. 出处:「第5章 卷积神经网络」第 773 段(text/06-ch05.txt:773,搜「训练时采用交叉熵损失」)。原文:优化器选随机梯度下降(学习率 0.1),在训练集上跑 5 个回合;批大小见同段之后的代码,为 64。

  26. 出处:「第5章 卷积神经网络」第 830 段(text/06-ch05.txt:830,搜「0.8800」)。实际输出为 [Test] accuracy/loss: 0.8800/0.4177 2

  27. 出处:「第5章 卷积神经网络」第 850 段(text/06-ch05.txt:850,搜「The true category is 2」)。

  28. 出处:「第5章 卷积神经网络」第 409 段(text/06-ch05.txt:409,搜「与生产代码相差几个数量级」)。原话:下面的实现采用 Python 嵌套循环逐位置滑窗,目的是让读者看清四步分解的对应关系,与生产代码相差几个数量级;实际工程中应直接调用 torch.nn.Conv2d 或 torch.nn.functional.conv2d——它们底层用 GPU 的 im2col + GEMM 实现,可一次性处理整批多通道输入。 2

  29. 出处:「第5章 卷积神经网络」第 205 段(text/06-ch05.txt:205,搜「查阅资料给出感受野」)。这是动手练习 5.1,三问全部留给读者,正文没有给出感受野的推导。

  30. 出处:「第5章 卷积神经网络」第 915 段(text/06-ch05.txt:915,搜「class torch.nn.Conv2d」)。书里在第 5.4 节列出了它的完整签名与张量布局说明。