跳到主要内容

层一多就出的两个坑 — 信号传不回去,和神经元卡死

这一章讲三件事: 为什么层一多训练反而更难;两类最常见的故障各长什么样、各有多严重; 以及工程上「一小撮一小撮地喂」到底怎么做。

它在全书链条里的位置: 第 06 章说「加一层能画弯的」,但那个例子只涨了半个百分点。 这一章解释为什么——加层是有代价的,而且代价可以量出来。

需要的基础: 第 06 章那条 A(1−A) 的反向公式。这一章全部两类故障都从它出发。

1. 先看现象:层越加越多,损失反而更难降

理论上,网络越深,能表达的函数就越丰富。可实践里常常相反:加深之后损失反而更难下降。

书里给的病根很直接:梯度需要从输出端逐层相乘传回输入端1。 第 06 章那条反向公式说得很清楚——每过一层,上游的梯度就要被乘上一个数。 如果那个数总是小于 1,连乘几次之后梯度就被压没了。

这一章的做法是:把它量出来。 书里搭了一个五层小网络, 在弯月数据上只跑一个回合,然后打印每一层权重梯度的长度2

为什么只跑一个回合? 因为不需要跑完——单步反向就已经能看清衰减规律。 这个设计很聪明:它把「训练效果」和「梯度能不能传回去」这两件事彻底分开了。

全章主走查:一个五层网络,弯月数据,只跑一个回合,打印每层梯度的长度
═════════════════════════════════════════════════════════════════════
网络 2 → 3 → 3 → 3 → 3 → 1(四个隐藏层各 3 个神经元,加一个输出层)
─────────────────────────────────────────────────────────────────────
§3 ① 激活用 S 形 fc5 0.4650 … fc1 0.001497 跨 2.5 个数量级
§4 ② 激活换成折线 各层回到相近量级
§5 ③ 折线 + 偏置初始化成 −8 五层全是 0.0
§6 ④ 换成带泄露的折线 fc5 0.06857 … fc1 1.355e-8 恢复成非零
═════════════════════════════════════════════════════════════════════

这四组数全部是书里的实际打印输出。四次实验的网络结构完全相同,
①② 之间只换激活函数,③④ 之间也只换激活函数。

2. 起点不能全设成同一个值

结论先行:第 05 章那个「参数全零」的做法,到多层就不成立了。

书里的理由写得很干脆:如果把所有权重和偏置都置为 0, 前向时同一层所有神经元会输出相同的值,反向时它们也会获得相同的梯度, 更新后仍然一致——多个神经元退化成同一个3

为什么会退化
────────────────────────────────────────────────
同一层的 10 个神经元,权重全是 0
→ 前向:10 个输出完全相同
→ 反向:10 个梯度完全相同
→ 更新:10 组权重挪的方向和幅度完全相同
→ 下一轮:还是完全相同
────────────────────────────────────────────────
结果:一层 10 个神经元,实际能力等于 1 个

书里管这个现象叫对称权重。 破解它的办法最直接:随机初始化, 最常用的两种分布是高斯分布(中间高两边低的那种钟形分布)和均匀分布4

注意这和第 05 章不矛盾: 那里说「单层模型不存在对称性问题」—— 单层的每个输出对应不同的类别,本来就不对称。一到多层,情况就变了。

起点具体该怎么定、方差取多少合适,这一章还没讲。 书里在这里只给了「随机」两个字, 真正把它讲清楚要到第 13 章——那一章会证明「随便随机」也是不够的。

3. 主走查 ①:S 形激活,四组梯度跨 2.5 个数量级

实验设定: 五层网络(四个隐藏层各 3 个神经元 + 一个输出层), 激活统一用那条 S 形曲线,在弯月数据上只跑一个回合2

书里的实际打印输出5:

层 梯度的长度 比上一层小多少倍
─────────────────────────────────────────────
fc5(最靠近输出) 0.46500510
fc4 0.22919254 约 2 倍
fc3 0.035656445 约 6 倍
fc2 0.010207750 约 3.5 倍
fc1(最靠近输入) 0.0014970693 约 7 倍
─────────────────────────────────────────────
首尾之比:0.4650 ÷ 0.001497 ≈ 311 倍,跨约 2.5 个数量级

书里给的解释是:即便用了针对折线激活设计的初始化,S 形版本的梯度仍随层数衰减 ——从输出层的约 0.47 降到第一层的约 1.5 × 10⁻³,跨度约 2.5 个数量级; 这是因为这条曲线两端饱和、导数最大只有 0.25,逐层累乘后把梯度不断压小5

「导数最大只有 0.25」这个数值得记住,因为它是第 06 章那条公式的直接后果:

A(1 − A) 什么时候最大?
──────────────────────────────
A = 0.5 时,0.5 × 0.5 = 0.25 ← 最大值
A = 0.9 时,0.9 × 0.1 = 0.09
A = 0.99 时,0.99 × 0.01 = 0.0099
──────────────────────────────
最好的情况都只有 0.25,而且实际训练中很少停在 0.5 附近

四层连乘,最理想也只剩 0.25⁴ ≈ 0.0039。 这就是梯度消失—— 靠近输入那几层等于收不到任何指示,参数几乎停在原地1

这个数字有个可比的参照物: 假设你把每步挪的幅度设成 0.01, 那么最后一层每步挪 0.0047,而第一层每步挪 0.000015—— 第一层要挪够最后一层一步的距离,得等三百多步。

4. 主走查 ②:换成折线激活,各层回到相近量级

同一个网络、同一份数据、同样只跑一个回合,只把激活函数换成折线那一条。

书里的结论是:S 形版本各层梯度仍逐层衰减(跨约 2.5 个数量级), 而折线版本各层梯度保持在相近量级——最大与最小仅差约一个数量级,远小于 S 形; 梯度消失现象基本消除6

原因书里也给了:折线激活在正区的导数恒为 1, 配合按层缩放的初始化逐层保持前向的散布稳定, 梯度回传时不会像 S 形那样被指数级压小6

但书里紧跟着补了一句边界,这句很重要:「不过深而窄的网络中仍会缓慢衰减」6换句话说,折线激活不是根治,只是把病压住。 真正的根治要等到第 09 章那条直连边。

5. 主走查 ③:偏置设成 −8,五层梯度全是精确的 0

折线激活缓解了上一个坑,但它自己带来一个新的。

书里的说法是:当输入小于 0 时,折线激活的输出恒为 0、导数也恒为 0。 如果某次参数更新让某个神经元在所有训练样本上的输入都跌到 0 以下, 那么它的梯度就恒为 0、参数无法再更新,这个神经元从此不再被激活7

书里管这个叫死亡神经元问题(原文用的是「死亡 ReLU 问题」这个说法)。

怎么把它复现出来? 书里的手法很直接:把偏置故意初始化成一个较大的负数 −8, 这样输入经线性变换后大概率落进负半轴8

实际打印输出9:

fc1 0.0
fc2 0.0
fc3 0.0
fc4 0.0
fc5 0.0

注意这不是「很小」,是精确的 0。 书里的话是:所有层的梯度都精确为 0—— 神经元被卡在负半轴,损失对参数的导数始终为 0,参数从此不再更新9

这两个坑的区别值得单独说一遍:

梯度消失死亡神经元
梯度长什么样很小但不是 0(0.001497)精确的 0
还能不能恢复能,只是很慢不能——梯度是 0 就永远是 0
换激活函数救得了吗能缓解
病根曲线两端饱和,导数被压小负半轴导数恒为 0

「不能恢复」这一条是死亡神经元更凶的地方: 梯度消失只是慢, 而一旦梯度精确等于 0,任何优化器都无能为力——0 乘以任何步长还是 0。

6. 主走查 ④:换成带泄露的版本,梯度恢复成非零

只换激活函数,其他配置完全相同(偏置仍然初始化成 −8)10

实际打印输出11:

层 梯度的长度
────────────────────────────
fc5 0.068568639
fc4 0.0013541706
fc3 1.3334247e-05
fc2 1.3713631e-07
fc1 1.3553412e-08
────────────────────────────
首尾之比:0.06857 ÷ 1.355e-8 ≈ 500 万倍

书里的评语分两半,两半都要读: 前一半是好消息——梯度从全零恢复成非零值,死亡神经元问题被解除,参数可以正常更新; 后一半是坏消息——梯度仍随层数沿反向衰减, 这是因为负半轴斜率默认只有 0.01——比完全关死好得多,仍非完美11

这就是第 06 章第 3 节那句「为什么带泄露的那一版能把卡死的神经元救回来」的答案: 把负半轴的 0 换成 0.01,梯度就从「精确的 0」变成「很小的数」。 而很小的数至少还能乘、还能传,精确的 0 不能。

代价也一目了然:0.01 连乘四次就是 10⁻⁸。 所以这一版救活了神经元,却把梯度消失又请了回来。 书里给的进一步办法是:把负半轴斜率调大,或者改用更复杂的激活函数11

判断(我们的,不是书里的):这四组实验的排列方式,比它们各自的结论更有价值。 ①→② 换激活救了第一个坑,③→④ 换激活救了第二个坑, 而 ④ 的数据同时显示第一个坑又回来了。 这条链子讲的其实是一件事:每个补救都有代价,而代价往往是把上一个问题请回来。 如果错,会错在: 书里并没有明说这四组是一条链,它们分属两个小节、各有各的结论; 把它们连成一条链是我们的读法。判据是:去看 4.4.2 与 4.4.3 两节的结尾, 作者是否在任何一处把四组数放在一起比过。

7. 分小撮怎么做:批大小,和那个数据迭代器

第 03 章第 2 节欠的账,这一节还。

先说清一个词:所谓批量,在这里就是「一次拿多少条」的意思。 书里按这个数把做法分成三种12:

每步用多少条名字代价
全部 N 条一次全塞的梯度下降每步都要遍历整张训练集,又费内存又费时间
只用 1 条随机梯度下降单步成本最低,而且带噪声的梯度反而有助于跳出局部的坑
抽 K 条小批量梯度下降两者的折衷,这是实际用的那一种

书里对小批量的说法是:每步从训练集随机抽取 K 条样本算梯度, 既能利用显卡的并行加速、又能保持一定噪声12

K 取多少? 书里给的经验值是:常用范围大致是几十到几百, 工程上通常取 2 的幂(如 16、32、64、128)以便底层做合并访存优化12

「带噪声反而有好处」这句话值得多想一层。 全量梯度是最准的方向, 但最准的方向会一路滑进离起点最近的那个坑里; 而每步只看一小撮,方向会抖,抖动有机会把它从浅坑里晃出来。 局部最优(周围都比它高、但不是全局最低的那个位置)因此没那么可怕。

具体怎么取这一小撮? 书里说手动管理索引(每条样本在数据集里的编号)既繁琐又容易出错, 工程上的标准做法是交给数据迭代器:训练前注册整张数据集, 训练时每次迭代(循环转一圈)自动按指定的批大小返回一批13

两个对象分工
────────────────────────────────────────────────────
Dataset 回答「一条样本怎么取」
实现两件事:给一个下标返回对应样本、返回总条数

DataLoader 回答「怎么按批迭代」
传入上面那个对象和批大小,它自己生成下标列表
(要打乱就设 shuffle=True),按批切好返回
────────────────────────────────────────────────────

书里给的两档用法值得记: 特征和标签都已经是张量的小数据集, 直接套现成的封装即可;样本需要在线读取或额外预处理时,再写一个自定义子类13

8. 顺带记住:输出层别再叠一层挤压

这是一条一行的规矩,但漏了会让训练变得莫名其妙。

书里在搭鸢尾花那个网络时,用提醒框写了出来: 与第 06 章那个两层版本相比,这里输出层不再接激活函数,而是直接输出未归一化分数; 理由有两条14:

  1. 判断类别只需要比较各类别得分的相对大小,并不需要显式的概率;
  2. 框架的多类交叉熵内部已经先归一化、再取了一次对数(对数就是「10 的几次方等于这个数」里的那个次数, 它把连乘变成连加、把很小的正数拉开成很大的负数),模型再叠一层归一反而会让数值不稳定。

第二条是关键,而且它有个通用形态: 框架里凡是名字带 WithLogits 或者文档写着「内部已含 Softmax」的损失函数, 你的模型最后一层就不能再叠归一。

为什么叠两次会不稳定? 因为归一化的输出被压在 0 到 1 之间, 再取对数会得到很大的负数;而合起来算能把中间那一步的极值消掉。 这和第 05 章那个「先减最大值」是同一类手法——把两步合并,躲开中间的极端值。

这条规矩后面还会再撞见一次: 第 16 章那个编码器的输出同样不叠挤压, 第 16 章第 6 节会说明那里为什么也这么做。

9. 换个数据集再跑一遍:鸢尾花上,加一层隐藏层值多少

这一节是本章的案例实践,而且它是全书唯一一处「同一份数据、两种模型」的纵向对照。 书里明说了这一点:本节把第 3.3 节那台只会画直线的分类器(能判断样本属于哪一类的模型 就叫分类器)替换为本章实现的前馈神经网络, 再在同一份数据上重跑一遍,与第 3.3 节形成对照15

完整设定,逐项列出:

这一章(前馈网络)第 05 章(一条直线)
数据鸢尾花 150 条
切分按 6 : 2 : 2 → 90 / 30 / 30120 / 15 / 15
预处理标准化,统计量只从训练集来压到 0 到 1 之间
模型4 → 16 → 3,中间一道折线激活4 → 3,一层
输出层不叠挤压(见上一节)叠了一次归一
每步喂多少批大小 16,训练集打乱全量
优化器Adam,每步挪 0.01每步挪 1.0
轮数150300
测试成绩书里没有打印0.9333

最后一行必须照实说:书里第 4.5.6 节给了模型评价的代码,但正文没有贴出打印结果16; 第 4.5.7 节的单条预测也只给了代码,没给输出17所以「加一层隐藏层值多少」这个问题,书里没有给出可比的数。

能确定的只有一件事,而且是从曲线上读的: 书里说可视化结果显示 两条损失曲线一同下降,验证集准确率随之稳步上升、后期趋于平稳18。 从那张图的纵轴范围看,验证集准确率落在 0.75 到 0.95 这一区间。

判断(我们的,不是书里的):这是全书最可惜的一处留白。 书里花了整整一节铺垫「与第 3.3 节形成对照」,把切分、模型、优化器全换了一遍, 最后却没有把那个能回答「值不值」的数字打出来。 而且即便打出来也不好比——两边的切分、预处理、优化器、轮数全都不一样, 30 条测试样本对 15 条测试样本,差一条就是 3.3 个百分点对 6.7 个百分点。 如果错,会错在: 这一节的目的可能本来就是「走通流程」而不是「做对照」, 「形成对照」那句话只是承上启下。判据是:去数一数这两节之间有几项设置是相同的 ——答案是只有数据集本身。

所以这份拆解的态度是: 第 05 章那个 0.9333 和这一章这个没打印的数, 放不到同一把尺子上。 想知道「加一层值不值」,得自己把两边的设置对齐再跑一遍 ——而这恰恰是这本书教会你的事。

10. 边界与局限

这一章没覆盖的:

没讲什么依据 / 为什么值得知道
起点的散布该取多大这一章只说「随机」,第 13 章才给公式
直连边治梯度消失最有效的手段,第 09 章才出现
逐层把数值拉回同一把刻度同上,第 13 章
梯度爆炸这一章只讲了「变小」,「变大」那一半在第 10 章
批大小和每步挪多远的关系第 12 章第 2 节有一组实验

出门会撞见的名字:

  • 梯度消失(vanishing gradient) —— 第 3 节那种「越靠近输入越小」;

  • 死亡 ReLU(dying ReLU) —— 第 5 节那种「精确为 0」; 中文资料里也写作「神经元死亡」;

  • torch.utils.data.Dataset / DataLoader —— 第 7 节那两个对象;

  • drop_last —— 数据条数除不尽批大小时,最后那一小撮不足数怎么办; 书里把它留成了思考题19;

  • 未归一化分数(logits) —— 第 8 节那个「输出层直接吐出来的东西」, 第 05 章已经挂过这个名字。

补充(不在书里,来自通用知识): 第 4 节那个「针对折线激活设计的初始化」, 在文献里通常按提出者的姓氏称呼;书里的代码注释写明它的标准差取 sqrt(2/输入维), 专为折线激活设计,能逐层保持前向的散布稳定20第 13 章会讲另一族按输入输出两边一起算的版本。

11. 可带走的

  1. 加层的代价是梯度要逐层相乘传回去,乘的数小于 1 就会被压没;
  2. 参数不能全设成同一个值,否则同一层所有神经元退化成一个;
  3. S 形激活的导数最大只有 0.25,四层连乘最理想也只剩 0.0039;
  4. 实测:五层网络首尾梯度 0.4650 对 0.001497,跨 2.5 个数量级;
  5. 换成折线激活,各层回到相近量级,但书里自己说「深而窄的网络中仍会缓慢衰减」;
  6. 折线激活带来新坑:输入全落负半轴时梯度精确为 0,而 0 是救不回来的;
  7. 实测:偏置初始化成 −8,五层梯度全是 0.0;换带泄露的版本恢复到 0.06857 … 1.355e-8;
  8. 每个补救都有代价,带泄露的版本救活了神经元,却把梯度衰减请了回来;
  9. 一小撮的大小通常取 2 的幂,几十到几百;带噪声的梯度反而有助于跳出浅坑;
  10. 损失函数内部已含归一化时,模型最后一层不要再叠一次。

12. 原文地图

主题原书章原文位置
梯度要逐层相乘第4章 前馈神经网络text/05-ch04.txt:960(搜「根源在反向」)
对称权重第4章 前馈神经网络text/05-ch04.txt:925(搜「如果把所有权重和偏置都置为 0」)
五层网络与打印工具第4章 前馈神经网络text/05-ch04.txt:971(搜「构造一个 5 层前馈网络」) · text/05-ch04.txt:1018(搜「实现一个梯度打印工具」)
S 形版本的四组梯度第4章 前馈神经网络text/05-ch04.txt:1054(搜「The gradient of the Layers」) · text/05-ch04.txt:1062(搜「跨度约 2.5 个数量级」)
折线版本第4章 前馈神经网络text/05-ch04.txt:1066(搜「重新跑一遍」)
死亡神经元与两组数第4章 前馈神经网络text/05-ch04.txt:1101(搜「死亡 ReLU 问题」) · text/05-ch04.txt:1136(搜「所有层的梯度都精确为 0」) · text/05-ch04.txt:1166(搜「梯度从全零恢复成非零值」)
小批量梯度下降第4章 前馈神经网络text/05-ch04.txt:1194(搜「批量梯度下降法」) · text/05-ch04.txt:1208(搜「2 的幂」)
数据迭代器第4章 前馈神经网络text/05-ch04.txt:1234(搜「手动管理索引既繁琐」) · text/05-ch04.txt:1250(搜「一条样本怎么取」)
输出层不叠挤压第4章 前馈神经网络text/05-ch04.txt:1321(搜「这里输出层不再接激活函数」)
鸢尾花的完整设定第4章 前馈神经网络text/05-ch04.txt:1274(搜「按 6 ∶ 2 ∶ 2 的」) · text/05-ch04.txt:1316(搜「沿用 PyTorch 自带算子搭一个两层全连接网络」) · text/05-ch04.txt:1489(搜「跑 150 个回合」)

Footnotes

  1. 出处:「第4章 前馈神经网络」第 960 段(text/05-ch04.txt:960,搜「根源在反向」)。原文:理论上网络越深可表达的函数空间越广,但实践中深网络的损失反而更难下降,根源在反向传播——梯度需要从输出端逐层相乘传回输入端;如果中间各层用两端饱和的激活函数,饱和区的导数几乎为零,几层之后梯度便被指数级压缩为零,这就是梯度消失问题。 2

  2. 出处:「第4章 前馈神经网络」第 971 段(text/05-ch04.txt:971,搜「构造一个 5 层前馈网络」)。原文:四个隐藏层加一个输出层,通过参数在三种激活之间切换;打印工具见第 1018 段(text/05-ch04.txt:1018,搜「实现一个梯度打印工具」),只训练 1 个回合的理由见第 1028 段(text/05-ch04.txt:1028,搜「不必跑完整训练就能从单步梯度看到衰」)。 2

  3. 出处:「第4章 前馈神经网络」第 925 段(text/05-ch04.txt:925,搜「如果把所有权重和偏置都置为 0」)。原话:前向传播时同一层所有神经元会输出相同的激活值,反向传播时它们也会获得相同的梯度,更新后仍然一致——多个神经元退化成同一个,这就是对称权重现象。

  4. 出处:「第4章 前馈神经网络」第 934 段(text/05-ch04.txt:934,搜「破解对称权重最直接的办法」)。原文:最常用的两种分布是高斯分布和均匀分布。

  5. 出处:「第4章 前馈神经网络」第 1054 段(text/05-ch04.txt:1054,搜「The gradient of the Layers」)。这是书里五层网络在 S 形激活下单步反向的实际打印输出,五个数依次为 0.0014970693、0.010207750、0.035656445、0.22919254、0.46500510。解读见第 1062 段(text/05-ch04.txt:1062,搜「跨度约 2.5 个数量级」),原文写明这条曲线的导数最大只有 0.25。 2

  6. 出处:「第4章 前馈神经网络」第 1066 段(text/05-ch04.txt:1066,搜「重新跑一遍」)。原文接着说:ReLU 版本各层梯度保持在相近量级(最大与最小仅差约一个数量级,远小于 Sigmoid),梯度消失现象基本消除;原因在于 ReLU 在正区的导数恒为 1;同一句末尾用括号补了一句「不过深而窄的网络中仍会缓慢衰减」 2 3

  7. 出处:「第4章 前馈神经网络」第 1101 段(text/05-ch04.txt:1101,搜「死亡 ReLU 问题」)。原话:x < 0 时 ReLU 输出恒为 0、导数也恒为 0;如果某次参数更新让某个神经元在所有训练样本上的输入都跌到 0 以下,那么它的梯度就恒为 0,参数无法再更新,这个神经元从此不再被激活。

  8. 出处:「第4章 前馈神经网络」第 1110 段(text/05-ch04.txt:1110,搜「把偏置故意初始化为一个较大的负数」)。原文说明这样输入经线性变换后大概率落入负半轴,恰好触发这个故障。

  9. 出处:「第4章 前馈神经网络」第 1136 段(text/05-ch04.txt:1136,搜「所有层的梯度都精确为 0」)。实际输出见第 1129–1134 段(text/05-ch04.txt:1130,搜「fc1 0.0」),五层全部是 0.0。 2

  10. 出处:「第4章 前馈神经网络」第 1141 段(text/05-ch04.txt:1141,搜「仅换激活函数」)。原文:其他配置与上面完全相同。

  11. 出处:「第4章 前馈神经网络」第 1166 段(text/05-ch04.txt:1166,搜「梯度从全零恢复成非零值」)。实际输出见第 1160–1164 段(text/05-ch04.txt:1160,搜「1.3553412e-08」)。原文接着说:但梯度仍随层数沿反向衰减,这是因为负半轴斜率默认只有 0.01——比 ReLU 好得多,仍非完美;要进一步减弱这种衰减,可以把负半轴斜率调大,或者改用 ELU、GELU、Swish 等更复杂的激活函数。 2 3

  12. 出处:「第4章 前馈神经网络」第 1194 段(text/05-ch04.txt:1194,搜「批量梯度下降法」)。原文依次介绍三种,并说明小批量每步从训练集随机抽取 K 条样本算梯度,既能利用 GPU 并行加速、又能保持一定噪声;K 的取值经验见第 1208 段(text/05-ch04.txt:1208,搜「2 的幂」)。 2 3

  13. 出处:「第4章 前馈神经网络」第 1234 段(text/05-ch04.txt:1234,搜「手动管理索引既繁琐」)。两个对象的分工见第 1250 段(text/05-ch04.txt:1250,搜「一条样本怎么取」);两档用法见第 1256 段(text/05-ch04.txt:1256,搜「常见用法分两档」)。 2

  14. 出处:「第4章 前馈神经网络」第 1321 段(text/05-ch04.txt:1321,搜「这里输出层不再接激活函数」)。原话:分类决策只需要比较类别得分的相对大小,并不需要显式概率;同时 nn.CrossEntropyLoss 内部已经做了 log_softmax,模型再叠一层 Softmax 反而会让数值不稳定。

  15. 出处:「第4章 前馈神经网络」第 1188 段(text/05-ch04.txt:1188,搜「与第3.3节的 Softmax 分类器形成对照」)。原文同时给出配置:损失取交叉熵、优化器选 Adam、评价指标取准确率。

  16. 出处:「第4章 前馈神经网络」第 1544 段(text/05-ch04.txt:1544,搜「载入训练阶段保存的最优快照」)。这一小节只有代码,正文没有贴出打印结果——这与书里其他小节的写法不同,其余小节几乎都会在代码后跟一段「输出结果为」。

  17. 出处:「第4章 前馈神经网络」第 1553 段(text/05-ch04.txt:1553,搜「最后用同一份模型对测试集的单条样本做预测」)。同样只有代码,没有输出。

  18. 出处:「第4章 前馈神经网络」第 1520 段(text/05-ch04.txt:1520,搜「两条损失曲线一同下降」)。原话:验证集准确率随之稳步上升,后期趋于平稳。

  19. 出处:「第4章 前馈神经网络」第 1227 段(text/05-ch04.txt:1227,搜「不足」)。这是书里的思考题:当样本总数不能被批大小整除时,最后一个小批量将不足 K 个样本,应该如何处理。

  20. 出处:「第4章 前馈神经网络」第 758 段(text/05-ch04.txt:758,搜「专为ReLU设计」)。这是书里在包装初始化函数时写下的代码注释,原文写明标准差取 sqrt(2/fan_in),专为 ReLU 设计,逐层保持前向方差稳定。