跳到主要内容

它怎么知道自己错了,又该往哪儿改

这一章讲三件事: 「答得有多差」这个数具体怎么量出来; 十个参数怎么一次就全部算清各自该往哪挪; 以及一个最常被搞混的区分 —— 反向传播只负责算方向,它不是学习算法。 它在全书链条里的位置是第 7 级台阶,也是全书理论最厚的一章。 这一章有全书唯一一条从头走到一万次更新之后的完整数值走查。 遇到的生词都在当场解释。

1. 顶层全景

第 07 章走完的地方:
输入 [0.02, 0.7] → 网络 → 输出 [0.62586, 0.59613]
期望 [0, 1 ]
↑ 差得很远

│ ① 量一下到底差多少 —— 用第 06 章那把平方尺子

一个数:0.27741

│ ② 从这个数出发,倒着往回扫一遍,
│ 算出十个参数「各自该往哪挪、挪多少」

十个方向(这一步叫反向传播)

│ ③ 照方向各挪一小步(这一步叫梯度下降,第 06 章讲过)

十个新参数 → 重新前向算一遍 → 输出离期望近了一点点

└───────────── 重复一万次 ─────────────┐

输出 [0.00793, 0.99198],误差 0.000063612

图说:②和③是两件事,不是一件。这是本章最要紧的一个区分。
这条链就是本章的主走查,它接着上一章那组数字往下走。

一条口径先写死,免得后面混:本章一律说「更新一次 / 更新一万次」,不用「轮」这个字。 「一轮」在这本书后面另有所指(整个训练集完整过一遍),那是第 09 章的事。

2. 第一步:量出「差了多少」

现象先行

上一章那张网给了 [0.62586, 0.59613],期望是 [0, 1]。 你一眼能看出「差得很远」,但机器需要一个数。

做法:第 06 章那把尺子,直接拿来用

书用的是平方误差:每个输出神经元各算一笔,再加起来1

o₁ 这一头: 期望 0,实际 0.62586
差 = 0 − 0.62586 = −0.62586
平方的一半 = 0.5 × 0.62586² = 0.19585

o₂ 这一头: 期望 1,实际 0.59613
差 = 1 − 0.59613 = 0.40387
平方的一半 = 0.5 × 0.40387² = 0.08156

加起来: 0.19585 + 0.08156 = 0.27741 ← 书给的数,我们算下来是 0.277404

图说:「一半」是那个方便求导的写法(第 06 章讲过,求导会掉一个 2 下来正好约掉)。
0.27741 这个数是书给的,两个分项是我们算的。

这个数不只是给人看的分数

书列了损失函数的四个作用,其中第三个最要紧2:

作用说明
衡量准确性给「答得有多差」一个数
优化模型有了这个数,才谈得上「让它变小」
算反向传播的信号它本身就是下一步的起点
评估模型比较训练集、验证集上的损失,看模型的泛化情况

第三条是这一章的入口:整条回传链的第一节,就是「损失对输出的斜率」。

另有一整类尺子,量的不是「差多远」

书还提了一件事:损失函数分两大流派 —— 一派量两个数隔多远(平方误差就属于这一派), 另一派量两个概率分布差多远3

那一类里最常用的叫交叉熵,分类任务基本都用它。 但要到第 09 章那个真项目里才用得上,所以那里再讲 —— 那里会给一个具体的数:模型说「第一类的可能性是 0.7」而答案正是第一类, 它要挨多重的罚。

3. 第二步的准备:「往下坡走」有几种走法

第 06 章讲的是「下坡」这件事本身。这一节讲怎么下得更快更稳。 它不改变方向怎么算,只改变「拿到方向之后怎么迈步」。

现象先行:一次拿多少数据来算

书给的第一版是标准梯度下降:把所有样本算一遍,汇总出总误差,再更新一次参数4

毛病很实在: 数据集一大,更新一次就要把所有样本过一遍 —— 第 01 章那个线上赛数据集有 16000 张图,更新一次要看完 16000 张。 更新一万次?算不完。

三档:全部、一个、一小批

① 全部算一遍再更新
准 —— 方向是所有样本一起给的
慢 —— 大规模数据上「求解效率是很低的」

② 每次随机抽一个样本就更新 ← 这一档叫 SGD
快 —— 用很少的样本就能把参数迭代到接近最优
抖 —— 一个样本给的方向不一定朝着全局最优;
而且容易困在局部最优和「鞍点」附近

③ 每次抽一小批 ← 这一档叫 mini-batch
折中,而且收敛更稳(收敛 = 损失稳定下来、不再明显往下掉)
⇒ 书的原话:「现如今使用梯度下降法往往都是指小批量梯度下降法」

图说:这三档的差别只在「一次拿多少样本来算方向」,
算方向的办法(第 4—7 节)完全一样。

两个词就地解释(书用了但没解释):

意思
局部最优一个小坑。四周都比它高,所以走不出去,但它不是真正的谷底
鞍点像马鞍的中间那一点:一个方向上是低谷,另一个方向上是山脊。 站在那儿脚下几乎是平的,于是就不动了

SGD 有一个反直觉的好处,书专门点了:正因为它每次只看一个样本、方向抖, 它反而有更大的概率跳出一个较差的小坑,收敛(收敛 = 损失稳定下来、不再明显往下掉) 到更好的地方5

拿到方向之后,还能再加三样东西

这三样都不改方向怎么算,只改「怎么迈这一步」。

加什么直觉代价 / 参数
加惯性(Momentum)保留一部分上一步的方向。同一个方向连着走就加速,方向变来变去就衰减6「只会盲目地跟随最大下降梯度」——进坡底时可能冲出去。惯性系数一般取 0.9
先探一步再算(Nesterov)先按惯性往前挪到大概会到的位置,在那儿算方向,再回来修正这一步梯度变化大的时候更灵敏7
每个参数各自调步长(Adam)不再所有参数共用一个学习率,每个参数根据自己过去的梯度大小自己定步子2014 年提出,论文的默认值:0.9、0.999、0.0018
普通梯度下降 加惯性 先探一步
↓ ↓ ↓ ⌐→ 探
↓ ↓↓ (加速) ↓ └ 修正
↓ ↓↓↓ ↓
每步只看当下 连着一个方向就越走越快 先看看照这个惯性会冲到哪儿

图说:三样东西是叠加关系,不是替代关系。
Adam 把「惯性」和「每个参数各自的步长」合在了一起,所以它今天是默认选择。

书对 Adam 的评价是:「无论数据稀疏与否都能取得相对较好的效果」——稀疏指的是 数据里绝大多数位置都是 0 的那种情况——所以在实际应用中使用较为广泛9第 09 章那个真项目用的就是它。

4. 现在解决那个真问题:十个参数怎么一次算清

这是本章第一个承重点。

现象先行:笨办法有多笨

你要知道「w₅ 该往哪挪」。最笨的办法:把 w₅ 加一丁点,重新前向算一遍, 看损失变大还是变小。

十个参数就要重算十次。 而第 13 章那个巡航网络有几十万个参数, 第 11 章讲到的一个经典模型有 1.38 亿个 ——这条路彻底走不通。

做法:一条中学微积分的法则

书给的是链式法则:如果 y = f(u) 而 u = g(x),那么 y 对 x 的变化率 = (y 对 u 的变化率) × (u 对 x 的变化率)10

说人话:一环扣一环的时候,把沿路每一环的「变化率」乘起来就行。

拧水龙头 → 水流大小 → 水池水位

多拧一格,水流大 3 个单位;水流多 1 个单位,水位每秒涨 2 厘米
⇒ 多拧一格,水位每秒多涨 3 × 2 = 6 厘米

图说:这就是链式法则的全部内容——沿路的变化率相乘。
这个比方到此为止,下面一律说「变化率」。

书点明了它为什么正好适用于神经网络:网络里的每一个神经元都可以看作是一个复合函数, 它的输出值只与它的输入值有关11。 (书这一句用的字是「节点」,在这里指的就是神经元 —— 这个词在书里还有别的用法, 第 9 节会把它们拆开;为免混淆,本节一律说「神经元」。)

于是「w₅ 变一点,总误差变多少」就可以拆成一串:

w₅ 变 → o₁ 的加权和变 → o₁ 的输出变 → 总误差变
↑ ↑ ↑
第三项 第二项 第一项

把这三项的变化率乘起来,就得到「总误差对 w₅ 的变化率」。

从后往前扫一遍,顺手把所有参数都算了

关键在于:靠近输出的那几项,所有参数都要用到。 所以只要从输出端往回扫一遍,把每一层的中间结果存下来, 十个参数的方向就在这一遍里全部算完了 —— 不用重算十遍。

这就是「反向传播」这个名字的来历:误差的信号从输出端往回传。

5. 一个最常被搞混的区分

这是本章第二个承重点,而且书自己特意澄清了它。

书的原话很直接:

BP 算法实际上是一种在神经网络训练过程中用来计算梯度的方法; 这个梯度会反馈给某种学习算法(例如梯度下降法)用来更新权值, 「这里梯度下降法才是学习算法」12

┌───────────────────┐ ┌───────────────────┐
│ 反向传播 │ 方向 │ 梯度下降 │
│ 「往哪挪」 │ ─────▶ │ 「挪多少」 │
│ │ │ 照方向 × 学习率 │
└───────────────────┘ └───────────────────┘
只算,不改 真正动手改参数

图说:两件事,两个名字,别合成一个。
换掉梯度下降(比如换成 Adam),反向传播那一半一个字都不用改。

为什么这个区分要紧(判断,我们的): 因为它决定了你怎么读框架文档 —— 你会看到框架里有个叫优化器的部件 —— 它就是「拿梯度去改参数」的那一半, 而且是可以随便换的(SGD、Adam、Momentum…); 「算梯度」那一半却从来不给你选。 原因就在这条区分上。

书还给了它的来历和分量: 这个算法由以 McClelland 和 Rumelhart 为首的科学家小组提出; 书说**「在实际应用中,大约 80% 的神经网络模型都采取了 BP 网络或 BP 网络的变化形式」**13

这个 80% 该怎么读: 它说的不是「80% 的模型叫 BP 网络」, 而是「绝大多数模型都靠这套算梯度的办法来训练」。按今天的情况,这个比例只会更高。

四步一个循环

书把整件事总结成一个循环14:

① 数据从输入层进,穿过隐藏层到输出层,得到结果 ← 前向传播(第 07 章)
② 算出结果和真实值之间的误差,把这个误差从输出层
往隐藏层反向传播,一直传到输入层 ← 反向传播(本章)
③ 沿路根据误差调整各个参数(权重和偏置),
让总损失变小 ← 梯度下降
④ 回到 ①,反复

6. 主走查(上):更新一个靠近输出的权重

从这里开始,每一步都有具体的数。所有初值和两端的结果是书给的。

先把上一章的中间结果搬过来

out_h1 = 0.60874 out_h2 = 0.64245
out_o1 = 0.62586 out_o2 = 0.59613
期望: o₁ → 0 o₂ → 1
总误差 E = 0.27741
w₅ = 0.2(它连的是 h₁ → o₁)

拆成三项,逐项算

第一项:总误差随 o₁ 的输出怎么变
只有 o₁ 那一笔和它有关,平方项求导之后正好是
实际 − 期望 = 0.62586 − 0 = 0.62586

第二项:o₁ 的输出随它的加权和怎么变(也就是 sigmoid 的变化率)
sigmoid 有个很好用的性质:它的变化率 = 输出 × (1 − 输出)
= 0.62586 × (1 − 0.62586) = 0.62586 × 0.37414 = 0.23417

第三项:o₁ 的加权和随 w₅ 怎么变
加权和 = w₅ × out_h1 + w₆ × out_h2 + b₂,对 w₅ 求导只剩
out_h1 = 0.60874

三项相乘:
0.62586 × 0.23417 × 0.60874 = 0.089211
↑ 这就是「总误差对 w₅ 的变化率」——正数,说明把 w₅ 调大会让误差变大,
所以该把它调小。

照方向挪一步(这一步是梯度下降干的)

新的 w₅ = 旧的 w₅ − 学习率 × 0.089211
= 0.2 − 0.5 × 0.089211
= 0.155395

↑ 学习率 0.5 这个数**书没有写出来**,是我们反推出来的——理由见第 8 节。

其余三个输出侧的权重同法(结果也是我们算的):

权重变化率更新后
w₅+0.0892110.155395
w₆+0.0941510.252925
w₇−0.0591910.129595
w₈−0.0624690.231234

注意 w₇ 和 w₈ 的变化率是负的 —— 因为 o₂ 的输出 0.596 比期望的 1 , 所以要把通往它的权重调大

7. 主走查(中):靠近输入的那些权重多一层

这是这条走查上最容易卡住的一步,也是「反向传播」这个名字真正兑现的地方。

为什么它多一层

看 w₁ —— 它连的是 i₁ → h₁。问题在于:

┌──▶ o₁ ──┐
i₁ ──w₁──▶ h₁ ──┤ ├──▶ 总误差
└──▶ o₂ ──┘

图说:h₁ 的输出**同时流向两个输出神经元**。
所以 w₁ 一动,o₁ 那一笔误差和 o₂ 那一笔误差**都会变**。
两条路径要分别算,然后加起来。

书讲得很清楚:i₁ 和 w₁ 传播到 h₁,而 h₁ 的输出会分别传播到 o₁ 和 o₂, 所以两笔误差都是 w₁ 的函数,要把两条路加起来15

算给你看

── 先算「总误差随 h₁ 的输出怎么变」,两条路相加 ──

经 o₁ 这条路: (o₁ 那一侧已经算出来的中间量 0.146551) × w₅
= 0.146551 × 0.2 = +0.029310

经 o₂ 这条路: (o₂ 那一侧的中间量 −0.097236) × w₇
= −0.097236 × 0.1 = −0.009724

加起来: 0.029310 − 0.009724 = 0.019587
↑ 注意两条路一正一负,部分抵消了

── 再乘上剩下两项 ──

h₁ 的 sigmoid 变化率 = out_h1 × (1 − out_h1)
= 0.60874 × 0.39126 = 0.238177

h₁ 的加权和随 w₁ 怎么变 = i₁ = 0.02

── 三项相乘 ──

总误差对 w₁ 的变化率 = 0.019587 × 0.238177 × 0.02 = 0.0000933

新的 w₁ = 0.1 − 0.5 × 0.0000933 = 0.099953

图说:**注意这个数有多小** —— 0.0000933,比 w₅ 那个 0.089 小了将近一千倍。
这就是第 07 章讲的梯度消失在这条走查上的样子:
离输出越远,回传过来的信号越弱,那一层学得越慢。
这些中间值是我们算的;书给了公式(图片)和做法,没给数。

输入侧四个权重的更新结果(我们算的):

权重变化率更新后
w₁+0.00009330.099953
w₂+0.00326550.198367
w₃+0.00011260.299944
w₄+0.00394240.398029

为什么 w₂ 比 w₁ 大三十多倍: 因为它俩只差最后那一项 —— w₁ 乘的是 i₁ = 0.02,w₂ 乘的是 i₂ = 0.7。输入大的那个权重,被调得多。 这是合理的:这次的错误,输入大的那一路负的责任也大。

一条口径:所有参数必须同步更新

书特意强调了两遍:在求每个参数更新值的时候,其他参数在这一轮中仍然用更新前的值16

❌ 错的做法:算 w₁ 时用了刚更新过的 w₅(0.155395)
✅ 对的做法:算 w₁ 时 w₅ 还用旧值 0.2

图说:上面第 7 节算「经 o₁ 这条路」时乘的正是 0.2,不是 0.155395。
这和第 06 章那条「θ₀ 和 θ₁ 必须同步更新」是同一条规矩,只是这里有十个参数。

8. 主走查(下):更新一次,和更新一万次

这一节是这条走查的落点,而且我们在这里发现了两件书没写的事。

更新一次的效果

更新前: 总误差 = 0.27741 输出 [0.62586, 0.59613]
更新一次后:总误差 = 0.26537 ← 书给的数

降幅: (0.27741 − 0.26537) / 0.27741 = 4.3%

图说:辛辛苦苦把十个参数各挪了一下,误差只降了 4%。
这就是为什么训练要跑成千上万次——单次更新的效果非常小。

更新一万次的效果

更新 10000 次之后:
总误差 = 0.000063612 ← 书给的数
输出 = [0.00793003941675692, 0.9919789331998798] ← 书给的数
期望 = [0, 1 ]

误差从 0.27741 降到 0.000063612 —— **降到了原来的四千三百分之一**。

图说:输出已经非常接近期望了,但永远到不了正好 0 和 1
——因为 sigmoid 的输出天生就在 0 和 1 之间,取不到端点。

我们的复现,以及两件书没写的事

我们把这条走查从头到尾重算了一遍,目的是确认它能用。结果是:能用,而且一位不差。

判断(我们的,不是书里的):这条走查里有两个参数书没写出来, 我们是从它给的结果反推出来的。

第一,学习率是 0.5。 书全程没有写这条走查用的学习率是多少 (只在讲单层感知器时说过 η 取 0 到 1 之间)。我们试了一遍: 只有取 0.5 时,更新一次之后的总误差才正好是书给的 0.26537。

第二,那一万次更新里,两个偏置一直没动。 书说「偏置参数用同样的方法更新」, 但如果真的连偏置一起更新,更新一次之后的误差是 0.2641,不是书写的 0.26537; 而只更新八个权重、偏置保持 b₁ = 0.3、b₂ = 0.2 不变时, 一万次之后的输出正好是 [0.00793003941675692, 0.9919789331998798] —— 和书给的十七位数字完全一致。

如果错,会错在: 如果书用的其实是别的学习率加上别的偏置更新方式、 恰好也能得到同样的数字,那我们这两条反推就只是「一个说得通的解释」而不是「唯一的解释」。 判据是:换任何一组别的设定,能不能同样复现出那十七位数字。

这条复现的实际价值: 它说明这本书的数值是可靠的(尽管它的定义有几处出错, 见第 15 章)。而且你现在可以自己拿这十个初值把整条链跑一遍,一位一位地核。

9. 这些式子太长了:换一种画法

这一节是原书 8.2.6,它的动机极其诚实。

书自己给的理由

书说得很直白:大多数神经网络的训练都离不开前向和反向传播,其中涉及大量运算, 「如果仅使用公式来描述的话会很复杂,如 8.2.5 小节所示」17

它指的就是上面第 6、7 节那一堆三项相乘。 十个参数就这么长, 几十万个参数根本没法写。

做法:把计算过程画成一张图

节点是数据,边是运算。(书用的字是「操作」,同一个意思; 本拆解一律说「运算」,免得和第 04 章那些图像操作混在一起。)

图上的东西对应什么
节点一个数、一串数,或者一堆按维度码好的数
一次运算:加、乘、过激活函数

节点之间的连接关系书叫拓扑结构18

书给了一个带数的小例子19:

a = 1 ──┐
├──▶ c = a + b = 3 ──┐
b = 2 ──┘ ├──▶ e = c × d = 9
└──▶ d = b + 1 = 3 ──┘

图说:这四个数是书给的。
前向:顺着箭头算一遍,得到 9。
反向:逆着箭头走一遍,每条边上挂着它那一段的变化率,沿路乘起来
——就是第 4 节那条链式法则,只是画成了图。

这张图的价值不在好看,在于「求导变成了沿着图往回走一遍」 —— 而「沿着图往回走」是可以让程序自动完成的。

书还点了一句非常要紧的话:这套东西是今天几大深度学习框架共同的底座20

这解释了第 09 章那句「框架替你干了这件事」到底是怎么干的: 你写下的每一个运算,都在悄悄地往这张图上添一条边,外加一个存放它结果的节点; 你说一句「反向传播」,它就沿着图倒着走一遍,把所有梯度算出来。 你不用写第 6、7 节那些式子,是因为图替你记住了每一条边。

「节点」这个词,书里有三个意思,其中两个正相反

这一节说「节点是数据」;可讲链式法则那一节说「每个节点都可以看作是一个复合函数」11, 再往后讲 TensorFlow 的组件时,书把 OP 直接译成了「节点」21 —— 而 OP 就是运算。 同一个词,一次当数据讲,两次当运算讲。

还有第三种用法: 第 07 章那句「每一层的每一个节点都与上下层节点全部连接」里, 「节点」指的是神经元。这一种是行业通用的,不算错 —— 但它和上面那两种加在一起,同一本书里「节点」就有了三个意思。

判断(我们的,不是书里的):这是书自己的口径没统一,不是三样东西。

业界通行的画法恰好是反过来的:节点是运算,在边上流动的是数据。 那种「流动的数据」有个正式名字叫张量 —— 意思就是「一堆按维度码好的数」: 一个数、一排数、一张表格,再往上还有更多层的,统统叫张量。 TensorFlow 这个名字就是这么来的 —— 张量在图上流,流经的每个点是一次运算。 所以书讲 TensorFlow 那一节译成「节点」,用的其实是业界那一套,和这一节打架。

两套画的是同一件事,区别只在于把「运算」摆在点上还是边上 —— a + b 这一步,一套画成「a、b 两个点,中间一条标着『加』的边,通到 c 点」, 另一套画成「a、b 两条线汇进一个标着『加』的点,再拉出一条线」。 走一遍的结果完全一样。

本拆解的口径写死成两条:讲网络结构时一律说「神经元」,不说「节点」,把这个词整个让出来; ② 「节点」只在计算图上出现,采用书 §8.2.6 那一套 —— 节点是数据,边是运算 —— 因为上面那张小图是书画的,换了约定就不是它了。 但你出门看任何一份框架文档,那里的「节点」指的是运算,别当成两件事。

如果错,会错在: 如果作者在讲 TensorFlow 那一节只是照抄官方的组件名单 (tensor / graph / OP / session)、并没有打算给「节点」下第二个定义, 那这就不算矛盾,只算转述别人术语时没加区分。判据是那句话的上下文 —— 它确实是在列 TensorFlow 自己的组件名。但对读者的后果一样:同一页上「节点」有两个意思。

10. 作者的判断与证据

说法是哪一类
那条走查的初值、0.27741、0.26537、一万次之后的输出有证据,而且我们完整复现过,一位不差
学习率 = 0.5、一万次里偏置没更新不在书里。这是我们从书给的结果反推出来的,写成了判断块
「BP 只算梯度,梯度下降才是学习算法」有证据: 书自己特意澄清的,而且这是最常被搞混的一处
「大约 80% 的神经网络模型采取 BP 网络或其变化形式」作者的估计,没有给依据。 方向没错,别当精确统计引
三档梯度下降与三种改进的演进教科书式的共识,书的表述准确
Adam「无论数据稀疏与否都能取得相对较好的效果」作者的评价。 在多数场景成立,但不是定论 —— 有些任务上朴素的 SGD 加惯性反而更好(这是通用知识,不在书里)
引入计算图的理由是「公式太复杂」作者的坦白,而且很诚实 —— 它把一个抽象概念的动机说清楚了
「节点」在书里有三个意思(数据 / 运算 / 神经元)书自己的口径没统一。 已在第 9 节当场判过,并写死了本拆解的两条口径
损失函数分两大流派有证据(分类框架);但这一节在书里是一张长清单,大部分名字全书再没用过

11. 边界与局限

  • 这一章对应原书 §8.2.3—8.2.6。 原书第 8 章太密,我们拆成三章; 那条数值走查横跨第 07 章和本章,是同一组数字的前半程和后半程。
  • 原书那一节列了九种损失函数的名字。 我们只讲了这条走查真正用到的平方误差, 并给交叉熵留了一句话的账(第 09 章还)。其余六个名字全书再没用过第二次, 我们把它们退回原文地图,需要时按图去查。
  • 公式本体全部是图片。 本章所有中间值都是我们按书给的初值和做法重算的, 已在当场标明哪些是书给的、哪些是我们算的。
  • 书没有写这条走查的学习率。 我们反推为 0.5(见第 8 节的判断块)。
  • 书没有讲梯度爆炸。 讲了梯度消失,但它的反面(信号越传越大直到溢出)一个字没提。
  • 书没有讲什么时候该停。 这条走查跑了一万次就收工了, 「怎么知道该停了」要到第 09 章看损失曲线、第 13 章看那个反直觉的教训。
  • 计算图只讲到概念为止。 静态图和动态图的差别、自动求导怎么实现,书都没碰。

12. 可带走的

全章主走查一行写完:

接上一章的输出 [0.62586, 0.59613] → 用平方尺子量出总误差 0.27741(两笔:0.19585 + 0.08156)。

→ 把「总误差对 w₅ 的变化率」拆成三项相乘:0.62586 × 0.23417 × 0.60874 = 0.089211 → 照学习率 0.5 挪一步,w₅ 从 0.2 变成 0.155395

→ 靠近输入的 w₁ 多一层:两条路径相加得 0.019587,再乘两项 = 0.0000933(比 w₅ 小近千倍)→ w₁ 从 0.1 变成 0.099953(算它时 w₅ 仍用旧值 0.2)。

→ 更新一次后总误差 0.26537(只降 4.3%)→ 更新一万次后 0.000063612, 输出 [0.00793, 0.99198]

初值和两端结果是书给的,中间值和学习率是我们算 / 反推的。

  1. 「差了多少」要有一个数 —— 这里用平方误差,两个输出各算一笔加起来;
  2. 这个数不只是分数,它本身就是反向传播的起点;
  3. 梯度下降有三档,差别只在一次拿多少样本算方向: 全部 / 一个 / 一小批; 今天说「梯度下降」默认指的是一小批那一档;
  4. 拿到方向之后还能加三样东西: 加惯性、先探一步再算、每个参数各自调步长(Adam);
  5. 链式法则:一环扣一环时,把沿路每一环的变化率乘起来 —— 这让「一次回传算清所有参数」成为可能;
  6. 反向传播只算方向,梯度下降才是真正改参数的那一步 —— 这是最常被搞混的一处,书自己特意澄清了;
  7. 靠近输出的权重直接三项相乘;靠近输入的权重多一层 —— 因为一个隐藏神经元的输出同时流向多个输出神经元,几条路径要分别算再相加;
  8. 同一次更新里,所有参数都用更新前的旧值来算 —— 同步更新,和第 06 章是同一条规矩;
  9. 单次更新的效果非常小(这条走查只降了 4.3%),所以训练要跑成千上万次;
  10. 回传的信号离输出越远越弱 —— 这条走查上,w₁ 的梯度比 w₅ 小了近一千倍, 这就是梯度消失的具体样子;
  11. 把计算过程画成图,求导就变成沿着图往回走一遍 —— 这正是几大框架能替你算梯度的底座。

13. 原文地图

主题原书章原文位置
损失函数的定义与四个作用第8章 深度学习基础及车辆识别项目实践text/09-ch08.txt:95(搜「衡量模型的预测值与真实值之间差异」) · text/09-ch08.txt:101(搜「计算反向传播信号」)
损失函数两大类:距离度量 / 概率分布第8章 深度学习基础及车辆识别项目实践text/09-ch08.txt:107(搜「基于距离度量的损失函数」) · text/09-ch08.txt:109(搜「基于概率分布的损失函数」)
标准梯度下降的毛病第8章 深度学习基础及车辆识别项目实践text/09-ch08.txt:121(搜「求解效率是很低的」)
随机梯度下降:快、能跳出较差的局部最优、易困在鞍点第8章 深度学习基础及车辆识别项目实践text/09-ch08.txt:123(搜「随机抽取一个样本」) · text/09-ch08.txt:123(搜「鞍点」)
小批量梯度下降;「往往都是指小批量」第8章 深度学习基础及车辆识别项目实践text/09-ch08.txt:125(搜「往往都是指小批量梯度下降法」)
Momentum:动力参数 0.9、加速与衰减、会冲出坡底第8章 深度学习基础及车辆识别项目实践text/09-ch08.txt:131(搜「动力参数」) · text/09-ch08.txt:135(搜「盲目地跟随最大下降梯度」)
Nesterov 的前瞻项第8章 深度学习基础及车辆识别项目实践text/09-ch08.txt:137(搜「下一时刻的参数」)
Adam:提出者、年份、三个默认值、适用面第8章 深度学习基础及车辆识别项目实践text/09-ch08.txt:143(搜「Adaptive Moment Estimation」) · text/09-ch08.txt:147(搜「无论数据稀疏与否」)
BP 的来历与「80%」第8章 深度学习基础及车辆识别项目实践text/09-ch08.txt:153(搜「Rumelhart」) · text/09-ch08.txt:153(搜「80%」)
BP 四步循环第8章 深度学习基础及车辆识别项目实践text/09-ch08.txt:157(搜「这就是前向传播过程」)
「这里梯度下降法才是学习算法」第8章 深度学习基础及车辆识别项目实践text/09-ch08.txt:165(搜「才是学习算法」)
链式法则;每个节点都是复合函数第8章 深度学习基础及车辆识别项目实践text/09-ch08.txt:167(搜「链式法则」) · text/09-ch08.txt:173(搜「每个节点都可以看作是一个复合函数」)
w₅ 的三项拆解第8章 深度学习基础及车辆识别项目实践text/09-ch08.txt:215(搜「以权重参数w为例」) · text/09-ch08.txt:219(搜「链式求导」)
输入侧权重多一层:两条误差路径相加第8章 深度学习基础及车辆识别项目实践text/09-ch08.txt:251(搜「都是w的函数」)
同步更新的口径(强调了两次)第8章 深度学习基础及车辆识别项目实践text/09-ch08.txt:245(搜「仍然用更新前的值」) · text/09-ch08.txt:281(搜「都要同步更新」)
一次更新 0.27741 → 0.26537;一万次后的输出第8章 深度学习基础及车辆识别项目实践text/09-ch08.txt:291(搜「0.26537」) · text/09-ch08.txt:291(搜「10000次」)
计算图:引入理由、节点与边、拓扑结构第8章 深度学习基础及车辆识别项目实践text/09-ch08.txt:297(搜「仅使用公式来描述的话会很复杂」) · text/09-ch08.txt:297(搜「拓扑结构」)
「节点」的另一个用法:OP第8章 深度学习基础及车辆识别项目实践text/09-ch08.txt:345(搜「OP(节点)」)
计算图的小例子 a=1、b=2 → e=9第8章 深度学习基础及车辆识别项目实践text/09-ch08.txt:311(搜「a=1,b=2」)
计算图是几大框架共同的底座第8章 深度学习基础及车辆识别项目实践text/09-ch08.txt:329(搜「都广泛采用了计算图」)

Footnotes

  1. 出处:「第8章 深度学习基础及车辆识别项目实践」第 209 段(text/09-ch08.txt:209,搜「采用平方误差作为衡量标准」)。总误差的数值见第 291 段(text/09-ch08.txt:291,搜「0.27741」)。两个分项(0.19585、0.08156)是我们按 0.5×(期望−实际)² 算的,书只给了总和。

  2. 出处:「第8章 深度学习基础及车辆识别项目实践」第 95—103 段(text/09-ch08.txt:95,搜「衡量模型的预测值与真实值之间差异」;text/09-ch08.txt:101,搜「计算反向传播信号」)。

  3. 出处:「第8章 深度学习基础及车辆识别项目实践」第 107 段(text/09-ch08.txt:107,搜「基于距离度量的损失函数」)与第 109 段(text/09-ch08.txt:109,搜「基于概率分布的损失函数」)。原文各列了四五个具体名字,完整清单在书里是一张表格图片;这些名字全书后面基本没再用,我们退回原文地图。

  4. 出处:「第8章 深度学习基础及车辆识别项目实践」第 121 段(text/09-ch08.txt:121,搜「求解效率是很低的」)。

  5. 出处:「第8章 深度学习基础及车辆识别项目实践」第 123 段(text/09-ch08.txt:123,搜「跳出一个相对较差的局部最优解」)。「局部最优」和「鞍点」这两个词书用了但没解释,本节的解释是我们补的通用知识。

  6. 出处:「第8章 深度学习基础及车辆识别项目实践」第 131 段(text/09-ch08.txt:131,搜「动力参数」)与第 135 段(text/09-ch08.txt:135,搜「盲目地跟随最大下降梯度」)。

  7. 出处:「第8章 深度学习基础及车辆识别项目实践」第 137 段(text/09-ch08.txt:137,搜「下一时刻的参数」)。

  8. 出处:「第8章 深度学习基础及车辆识别项目实践」第 143 段(text/09-ch08.txt:143,搜「Adaptive Moment Estimation」)与第 145 段(text/09-ch08.txt:145,搜「0.999」)。原文给的三个默认值是两个移动平均衰减率 0.9、0.999 和步长 0.001。

  9. 出处:「第8章 深度学习基础及车辆识别项目实践」第 147 段(text/09-ch08.txt:147,搜「无论数据稀疏与否」)。「有些任务上 SGD 加惯性反而更好」是通用知识,不在书里。

  10. 出处:「第8章 深度学习基础及车辆识别项目实践」第 167—171 段(text/09-ch08.txt:167,搜「链式法则」)。

  11. 出处:「第8章 深度学习基础及车辆识别项目实践」第 173 段(text/09-ch08.txt:173,搜「每个节点都可以看作是一个复合函数」)。 2

  12. 出处:「第8章 深度学习基础及车辆识别项目实践」第 165 段(text/09-ch08.txt:165,搜「才是学习算法」)。原文还补了一句:除了梯度下降法,也可以采用其他的学习算法;而且 BP 原则上可以计算任何函数的导数,不限于神经网络。

  13. 出处:「第8章 深度学习基础及车辆识别项目实践」第 153 段(text/09-ch08.txt:153,搜「Rumelhart」)与同段(text/09-ch08.txt:153,搜「80%」)。书末参考文献 [13] 是 RUMELHART、HINTON、WILLIAMS 1986 年发表在 Nature 上的那篇(text/13-fm.txt:29,搜「back-propagating errors」)。

  14. 出处:「第8章 深度学习基础及车辆识别项目实践」第 157—163 段(text/09-ch08.txt:157,搜「这就是前向传播过程」)。

  15. 出处:「第8章 深度学习基础及车辆识别项目实践」第 251 段(text/09-ch08.txt:251,搜「都是w的函数」)。原文:h₁ 的输出会分别传播到 o₁ 和 o₂,所以两笔误差都是 w₁ 的函数,要根据链式法则把两条路加起来。本节所有中间值都是我们按书给的初值算的,公式本体在书里是图片。

  16. 出处:「第8章 深度学习基础及车辆识别项目实践」第 245 段(text/09-ch08.txt:245,搜「仍然用更新前的值」)与第 281 段(text/09-ch08.txt:281,搜「都要同步更新」)。同一条口径书强调了两次。

  17. 出处:「第8章 深度学习基础及车辆识别项目实践」第 297 段(text/09-ch08.txt:297,搜「仅使用公式来描述的话会很复杂」)。

  18. 出处:「第8章 深度学习基础及车辆识别项目实践」第 297 段(text/09-ch08.txt:297,搜「拓扑结构」)。原文:节点代表数据(标量、矢量、张量等),边表示操作(函数)。

  19. 出处:「第8章 深度学习基础及车辆识别项目实践」第 311 段(text/09-ch08.txt:311,搜「a=1,b=2」)。原文给的四个数是 a=1、b=2、c=3、d=3、e=9;箭头怎么连是我们按这几个数还原的(原图是图片)。

  20. 出处:「第8章 深度学习基础及车辆识别项目实践」第 329 段(text/09-ch08.txt:329,搜「都广泛采用了计算图」)。构建计算图的五个步骤见第 317—327 段。

  21. 出处:「第8章 深度学习基础及车辆识别项目实践」第 345 段(text/09-ch08.txt:345,搜「OP(节点)」)。原文把 TensorFlow 的四个组件列为 tensor(张量)、graph(计算图)、OP(节点)、session(会话)。「节点是运算、边上流的是张量」这一说法本身不在书里,来自通用知识。