跳到主要内容

顺序一直被忽略着 — 让上一步的输出流回下一步

这一章讲三件事: 为什么前十一章的模型对「谁先谁后」完全没有感觉; 把上一步的输出流回下一步之后,顺序是怎么被找回来的; 以及找回顺序要付什么代价。 它在全书链条里的位置: 前十一章一直在给模型加能力——加弯折、加窗、借别人的模型。 可它们全都漏了一样东西:时间。 这一章是全书最难堪的一章: 它开口第一件事,是拿一行代码把上一章的成果打成平手。

1. 先看现象:把时间打乱,答案一模一样

上一章那个气温预测任务,输入是一个 [240, 14] 的方块: 往回十天、每小时取一个点,一共 240 个时刻;每个时刻有 14 项气象读数。

现在做一件很简单的事:把这 240 个时刻的先后彻底打乱,再喂进上一章那个模型。

原来的顺序: 第 1 小时 → 第 2 小时 → …… → 第 240 小时
打乱之后: 第 173 小时 → 第 6 小时 → …… → 第 88 小时

只要训练和测试都用同一种打乱法,模型算出来的结果 —— **一模一样。**

图说:这不是巧合,也不是模型不够聪明。是它的结构决定了它不可能感觉到顺序。

书自己把这件事放进了章末练习,让读者亲手验一遍1

为什么必然如此:乘法和加法不分先后

前十一章的模型,核心零件都是密集层——一层里每个输出单元干的事是: 把每个输入乘上一个可调的数,然后全部加起来。

输出 = 输入₁×权重₁ + 输入₂×权重₂ + 输入₃×权重₃ + ……

你把这些加号两边的东西调换位置,和还是那个和。

图说:书的说法是,从输入元素到输出之间的那些路径**是相互对称的**[^2]。
对称在这里是个坏消息 —— 对称意味着「谁排在前面」这件事,压根没有地方存放。

而且上一章还亲手补了一刀: 因为密集层只吃一维的输入,[240, 14] 必须先被拉平成 [3360]这一拉,240 个时刻就被搅成了一锅数。 上一章原话是,扁平化会舍弃原数据里的排序信息。

2. 更难堪的一件事:一行代码就打平了上一章

上一章是带着一个悬而未决的问题收尾的: 那两条曲线是被治得贴在一起了, 可它们贴在什么水平上?这个水平算好算坏?

现在回答它。第 03 章立过一条纪律:先找一个不动脑子的笨办法算出成绩,摆在旁边当参照。

这个任务的笨办法是一句话:

「24 小时之后的气温,就等于现在的气温。」

这个策略连模型都不是,它只是把输入里最后那个气温读数原样抄成答案。 书还说明了为什么它不算胡来:凭日常经验,明天此刻的气温本来就和今天此刻接近2

跑一遍,它的平均绝对误差是:

常识基准的平均绝对误差:0.290331

上一章那个正则化版的多层模型,最好的验证误差:约 0.29

图说:**打了个平手,笨办法甚至还稍微好一点。**
也就是说 —— 上一章那套「诊断 → 加正则化 → 两条曲线重新贴住」的手术,
最后交付出来的东西,**没有超过一行代码。**

书对这件事的态度很坦率:这种现象在机器学习里并不罕见,模型要下些功夫才打得过常识策略, 有时还得靠仔细设计和超参数调优才做得到3

这就是第 03 章那条纪律真正的用处。 它不是一道手续, 它是唯一能拦住你「训了半天其实白训」的东西。 上一章那两条漂亮的曲线,任何一条单独看都不会告诉你这件事。

那这个任务上,机器学习到底能不能赢? 书的回答是能——而赢的关键,就是把顺序找回来。

3. 承重节:让上一步的输出流回下一步

这一节是本章的地基。上面那两件事都指向同一个缺口:模型里没有地方放「先后」。

换一种吃法:一次只吃一个时刻

密集层是一口把 240 个时刻全吞下去。换一种吃法:

一次只吃一个时刻,吃完 240 次。

第 1 步:吃第 1 小时的 14 个读数 → 吐出一串数
第 2 步:吃第 2 小时的 14 个读数 + 上一步吐出来的那串数 → 吐出新的一串数
第 3 步:吃第 3 小时的 14 个读数 + 上一步吐出来的那串数 → 吐出新的一串数
……
第 240 步:吃第 240 小时的读数 + 第 239 步的那串数 → 这就是整层的最终输出

图说:关键在每一行的第二个加数 —— **上一步的产物,回流成了下一步的输入。**

「上一步的输出流回来当下一步的输入」,这个动作就叫循环; 带这个动作的层叫循环层,由这种层搭起来的模型叫循环神经网络(RNN)4

这个名字你出门会撞见,所以留着它。

顺带把它的反面也命名了: 前十一章那些层——密集层、卷积层、池化层——输出都不回流, 数据只朝一个方向走到底。书把它们统称为前馈层4所以这一章加进来的东西,一句话就是:给数据加了一条往回走的路。

那串回流的数有个名字:状态

每一步吐出来、又流回去的那串数,书管它叫状态5

状态就是这个模型的记忆。 它是模型「到目前为止看过些什么」的全部残留: 第 100 步的状态里,压着前 99 个小时的气象读数留下的痕迹。

为什么有了状态,顺序就进来了? 因为同一个输入落在不同的位置上,碰到的状态不同, 吐出来的东西就不同。 书举了两个好例子5:

例子同一个东西,含义为什么会变
摩尔斯电码一个「划」是什么意思,取决于它前后那串点和划
英文单词 last它是「最后」还是「持续」,取决于前后是什么词

而对称的密集层做不到这一点: 它对第 1 个时刻和第 240 个时刻一视同仁。

每一步用的其实是同一个零件

上面那 240 步,看起来像 240 个不同的加工站。书说不是——它们是同一个函数被调了 240 次6

这个被反复调用的函数,书管它叫这一层的元胞。有一句被书引用的形容,精确得可以直接背下来:

一个循环层,就是「包裹在 for 循环里的元胞」。6

书还给了这个 for 循环的伪代码,只有三行,而且值得一行行读7:

状态 = 0 ← 开局的记忆是空的

对输入序列里的每一个时刻 x:
状态 = f( W·x + U·状态 ) ← 这一行就是全部

两组可调的数:
W —— 管「这一时刻的新读数怎么用」
U —— 管「上一步的记忆怎么用」

图说:整个循环层只有这两组数,**它们在 240 步里被反复使用,一次都不换。**

⚠ 最简单的那种循环层里,「输出」和「状态」是同一样东西——吐出去的和流回来的是同一串数。 书明说更高级的变种会把这两者分开处理,甚至有多个状态8本章第 6 节会见到一个带门的变种;而「有两个状态」那种,要到第 14 章接线时才用得上。

顺带解决了一件老麻烦:输入可以不一样长

密集层的输入形状是写死的:你说好 [3360],就永远是 [3360]

而 for 循环转几圈是你说了算的,所以循环层能吃任意长度的序列9

但这个好处这里要先泼一盆冷水: 它在气温任务上用不上(每个样例都是 240 步), 而下一章处理长短不一的影评时,书反而把所有句子一律裁/补到 500 个词—— 理由是那一步要把整批数据凑成一个方方正正的张量。 这个好处书从头到尾没有真的用上,本拆解也不会再指望它。

4. 参数共享的第二次出现:1537 打赢 107585

这一节回答一个反直觉的问题:多了「记忆」这个能力,参数是不是要多很多?

正相反,少得多。

先看两个模型的账

书搭的循环模型只有两层:一个 32 单元的循环层,加一个 1 单元的密集层输出气温10注意它不需要扁平化了——序列输入直接就能进循环层,反倒是硬塞一个扁平化进去会报错。

循环层 1504 个参数
密集输出层 33 个参数
─────────────────────────
合计 1537 个参数

上一章那个多层模型:107 585 个参数 —— **是它的将近 70 倍**

验证集上的平均绝对误差:
循环模型 约 0.27
上一章的模型 约 0.29
常识基准 0.2903

图说:参数少了 70 倍,误差反而降了。**而且这一次是真的赢过了那一行代码。**

书对这个提升的评价很克制:误差的减少虽小,却是实实在在的11

为什么参数能这么少:同一组数用了 240 遍

回到第 3 节那三行伪代码:WU 在 240 个时刻里被反复使用,一次都不换。

书给这件事的正式名字是参数共享,而且直接把它和第 06 章接上了12:

第 06 章的卷积这一章的循环
同一组数被反复用在哪每一个空间位置(窗滑过全图)每一个时刻(元胞转过整段序列)
书里的说法利用空间维度的平移不变性利用时间维度的平移不变性
换来什么参数少、算得快、不容易过拟合同上

这是同一个想法的第二次出场,不是一件新东西。 第 06 章那句 「关键不在窗小,在同一块窗扫遍全图」,换成时间维度就是这一章: 关键不在元胞小,在同一个元胞转遍整段时间。

书还说明了不共享会怎样: 每个时刻各配一套自己的 WU, 参数会暴涨、算力吃紧、还更容易过拟合,而且模型能处理的时刻数会被写死12

训练时怎么调这两组数

和第 02 章那一套完全一样:从损失端往回走,一路求导。 唯一的区别是这次要往回走的是时间——从第 240 步倒着回溯到第 1 步。

所以训练循环网络这件事有个专门的名字:基于时间的反向传播13名字新,机制没有新东西。

5. 代价:算不快,而且记不远

第 04 章立下的记账习惯在这里要用:多了顺序这个能力,付了什么?

代价一:每一步都得等上一步

循环这个动作本身就是串行的: 第 100 步要用第 99 步的状态, 所以第 100 步不可能和第 99 步同时算。

密集层 / 卷积层:每个输入元素的运算互不依赖 → 显卡可以一次全算完
循环层: 第 t 步依赖第 t−1 步的状态 → 只能一步一步排队

书写明了:循环层正向传播的耗时和「输入的采样点数量」挂钩,
反向传播再花掉同样一份[^15]。

图说:这个任务的输入有 240 个时刻 —— 排 240 次队,再倒着排 240 次。
**这就是为什么书把这一章的训练搬到了 Node 里跑,而不是放在浏览器里。**

补充(不在书里,来自通用知识): 这条硬伤在 2017 年之后成了循环网络退场的直接原因—— 后来的主流结构把「必须排队」这一条彻底去掉了,才有了今天动辄几千亿参数的模型。 这条线索第 14 章交代完整。

代价二:序列一长,前面的信息就没了

最简单的那种循环层还有第二处硬伤,而且更隐蔽。

理论上第 240 步的状态里压着前 239 步的痕迹。实际上压不住。

书给的解释是梯度消失——训练时那个「该往哪挪」的信号, 从损失端一路往回传,每经过一步就缩小一点;传够几十上百步之后,它就小到不起作用了14

原书把它类比成另一件事:**层摞得太多的网络也会训不动**,
信号从损失端往回传,每过一层缩一点,传到最前面几层时已经小到推不动任何数。
**这个毛病本书前十一章一次都没讲过,这里是第一次出现。**

**而对循环层来说,240 个时刻就相当于 240 层** —— 同一个毛病,换了个身份。

后果:模型学不会「很久以前那件事,和现在这件事有关」这种长距离的依赖关系。

图说:它不是记不住,是**训练时那个「你该记住它」的信号传不回去。**

6. 治法:给元胞加两道闸门

这一节回答:怎么让状态在很多步之间不被冲掉。

先看它要解决的具体场面

书举的例子来自影评分类15:

一条影评开头写「这个电影还不错」,中途话锋一转, 「然而,它不如其他基于同类概念的电影」。

要判断这条影评是好评还是差评,模型得学会把前半句的溢美之词基本忘掉。

注意这里要的是两个相反的能力: 有时候要把旧记忆原封不动带下去, 有时候要主动把它扔掉。 最简单的那种元胞两样都做不到——它每一步都被新输入搅一遍。

做法:让数据自己学出「记多少、忘多少」

书给了一种叫 GRU 的元胞(全名门控循环单元——「门」就是下面那两样东西,一个能开能关的闸)。它把原来那一个方程扩成四个, 多出来的两样东西,书管它们叫门16:

它控制什么极端情况下会怎样
更新门这一步的新状态里,旧记忆占多少、新算出来的占多少取 0 时,旧状态原封不动抄到下一步——这正是它对付梯度消失的关键
重置门算这一步的临时状态时,旧记忆参与多少取 0 时,旧记忆的作用被整个抹掉

「门」这个字在这里不是比喻,它就是一个 0 到 1 之间的数,乘在旧记忆上: 乘 1 就是全放行,乘 0 就是全挡住,乘 0.3 就是放行三成。

而这两个数不是你定的,是模型自己算的——它们各由一组可调的权重从「当前输入 + 旧状态」算出来。 换句话说:该记多少、该忘多少,是从数据里学出来的。

结果:误差再降一点,时间涨三倍

把模型里的元胞从最简单的那种换成 GRU,其他一个字不改17:

验证误差: simpleRNN 约 0.27 → GRU 约 0.266
每批耗时: simpleRNN 950 毫秒 → GRU 3000 毫秒(同一台机器,CPU 上跑)

图说:误差降了不到 2%,**耗时涨了两倍多**。
书的判断是:如果目标是尽可能准,这个代价值得付。

还有一种更复杂的元胞叫 LSTM(长短期记忆),1997 年就有了18书说实际场景里一般用 GRU 或 LSTM 这两种,最简单的那种对多数真问题太弱。

一句让人松口气的话

书在讲完这四个方程之后,专门写了一段19:

人类工程师没有必要弄懂这些细节。 你给模型的结构,只是划定了一个搜索范围; 具体怎么处理序列,是训练过程自己在这个范围里找出来的。

这句话对读者的意义是:上面那张门的表,记住「学出该记多少该忘多少」这一句就够了。

7. 主走查:同一份气象数据,四个做法

这一章每个承重机制在这条走查上各占一步。数字全部来自书里。

发生了什么具体的数 / 状态
1造一个样例(和上一章同一份数据、同一个任务)往回十天每小时一点 → [240, 14];答案是 24 小时后那一行的气温
2先做个实验:把这 240 个时刻打乱重排上一章那个模型算出来的结果 一模一样
3诊断密集层的乘加是对称的 → 顺序没有地方存放;扁平化 [240,14][3360] 又亲手搅了一遍
4做法零:一行代码的常识基准——「24 小时后 = 现在」平均绝对误差 0.290331
5拿它去比上一章那个正则化版的模型上一章约 0.29 —— 打平,笨办法甚至稍好
6做法一:换成 32 单元的循环层 + 1 单元密集输出不再需要扁平化;硬加一个扁平化反而会报错
7循环层内部:第 1 步吃第 1 小时的 14 个读数,状态从 0 起吐出 32 个数,这 32 个数流回去当第 2 步的状态
8第 2 步吃第 2 小时的读数 加上 那 32 个数用的是同一组 WU——一直用到第 240 步
9数参数循环层 1504 + 输出层 33 = 1537 个;上一章那个是 107 585 个,将近 70 倍
10看误差约 0.27 —— 第一次真正赢过 0.2903 那条线
11但看时间240 步只能排队算,训练被迫搬到 Node 里跑,浏览器里几乎跑不动
12做法二:把元胞换成 GRU(多了更新门和重置门)验证误差 约 0.266
13再看时间950 毫秒/批 → 3000 毫秒/批,同一台机器
14收账顺序这个能力,拿串行(不能并行)训练时间涨三倍换来

8. 作者的判断与证据

书里给了证据的:

  • 常识基准是 0.290331,上一章的模型打不赢它。 有具体输出,书还给出了算这个数的函数名和位置2
  • 循环模型用 1537 个参数达到约 0.27。 有完整的参数量清单和曲线1011
  • GRU 降到约 0.266,但每批从 950 毫秒涨到 3000 毫秒。 两个数都在书里,并注明是 CPU 后端上测的17
  • 密集层对顺序不敏感。 书给了两条依据:一是数学上的对称性,二是让读者在章末练习里亲手验120

属于作者判断、书里没给证据的:

  • 「GRU 的代价绝对值得付」。 这是一句取舍判断,书没有给出「什么场景下不值得」的界限17
  • 「人类工程师没必要弄懂 GRU 的全部细节」。 这是教学立场,不是实验结论19
  • 梯度消失是最简单那种元胞学不会长距离依赖的原因。 书给的是类比(和深层前馈网络同一个毛病), 在这本书里没有做实验去分离这个原因14

判断(我们的,不是书里的): 这一章最值钱的不是循环这个结构,是第 2 节那一记耳光。 一个被完整诊断、完整治疗、两条曲线漂亮地贴在一起的模型,输给了一行代码。 这件事如果发生在你自己的项目里,没有任何一条曲线会告诉你—— 你会一直以为自己在做机器学习,直到有人问「你和不做比过吗」。 如果错,会错在: 如果你的任务本来就没有「不动脑子的笨办法」可比 (比如从零生成一段文本),那这条纪律用不上,得换成第 15 章那种参照物。

9. 边界与局限

  • 这一章的提升幅度其实很小。 0.2903 → 0.27 → 0.266,换来的是训练时间涨了两三倍书没有讨论「这个提升值不值得上生产」。
  • GRU 的四个方程,书自己说是「粗略概括」。 更新门和重置门各自的权重怎么初始化、 为什么这样接线更好,书没有讲,也明说了不必懂19
  • LSTM 只出现在一句话和一条脚注里。 书说它更复杂、更常用, 但这本书从头到尾没有拆开它的内部结构——本章下面几章用到它时,也是当成一个黑箱在用。
  • 梯度消失没有被量化。 没有实验说明「多少步之后信息就没了」。
  • 序列长度的限制只在算力上被提到。 240 步已经让训练搬去了 Node, 更长的序列(比如一整年)书没有试过。
  • 「能吃任意长度」这个好处,全书没有一个模型真的用上。 书自己在下一章 就把所有影评一律裁/补到 500 个词,因为一批数据必须凑成一个方方正正的张量; 第 14 章的日期任务同样补零到固定长度。这条性质在这本书里始终停在纸面上。
  • 这一章的模型仍然只输出一个数。 输入是一串、输出是一个; 输入一串输出也是一串的情况,要到第 14 章。
  • 最大的时代缺口在这里: 书把循环层当成处理序列的主力, 而 2017 年之后主流做法已经把「必须排队」这条硬伤整个绕开了。第 14 章交代。

10. 可带走的

  1. 密集层对顺序完全无感,这是结构决定的,不是训练不够。 它做的乘法和加法是对称的,顺序没有地方存放;
  2. 扁平化是第二道伤:[240, 14] 拉成 [3360],240 个时刻被搅成一锅数;
  3. 动手之前先跑那个笨办法。 这个任务的笨办法是「24 小时后的气温 = 现在的气温」, 一行代码,误差 0.2903——它打平了上一章那个精心调过的模型;
  4. 循环 = 上一步的输出流回来当下一步的输入。 流回来的那串数叫状态,它就是模型的记忆;
  5. 一个循环层就是「包裹在 for 循环里的元胞」。 三行伪代码: 状态从 0 起,每一步 状态 = f(W·当前输入 + U·旧状态);
  6. WU 在 240 步里被反复使用。 这叫参数共享, 和第 06 章卷积核扫遍全图是同一个想法——一个共享在空间上,一个共享在时间上;
  7. 结果是 1537 个参数打赢 107 585 个: 0.27 对 0.29,并且真正超过了那条基准线;
  8. 两处硬伤要记住: 第 t 步必须等第 t−1 步算完,没法并行; 序列一长,训练信号往回传时会一路缩小,长距离的依赖学不会;
  9. 治法是给元胞加两道闸门(GRU): 更新门管「旧记忆留多少」,重置门管「旧记忆参与多少」; 两个门的开度由数据自己学出来;
  10. 收账: GRU 把误差从 0.27 压到 0.266,每批耗时从 950 毫秒涨到 3000 毫秒顺序这个能力不是白给的。

11. 原文地图

主题原书章原文位置
序列数据的定义;反转气压序列意义全变第 9 章text/21-ch09.txt:19(搜「元素是有序的」)
密集层为何对顺序无感:对称性、扁平化第 9 章text/21-ch09.txt:41(搜「抹除了采样的时间顺序信息」) · text/21-ch09.txt:43(搜「相互对称的」)
常识基准:24 小时后 = 现在,MAE 0.290331第 9 章text/21-ch09.txt:49(搜「24小时后的气温就是当前的气温」) · text/21-ch09.txt:61(搜「0.290331」) · text/21-ch09.txt:62(搜「大致相等」)
打不过基准这件事在机器学习里不罕见第 9 章text/21-ch09.txt:64(搜「下些功夫才能打败」)
循环层的内部结构;元胞;状态回流第 9 章text/21-ch09.txt:72(搜「包裹在for循环中的元胞」) · text/21-ch09.txt:80(搜「前馈层」)
状态是记忆;摩尔斯电码与 last 的例子第 9 章text/21-ch09.txt:91(搜「莫尔斯编码」)
三行伪代码第 9 章text/21-ch09.txt:88(搜「该状态为会被初始化为零」) · text/21-ch09.txt:90(搜「W和U分别是输入和状态」)
输出和状态是同一样东西;更高级的变种会分开第 9 章text/21-ch09.txt:93(搜「其输出和状态是同一个东西」)
能吃任意长度的序列第 9 章text/21-ch09.txt:95(搜「任意数量采样点」)
参数共享;和卷积的空间平移不变性对照第 9 章text/21-ch09.txt:97(搜「时间维度的平移不变性」)
基于时间的反向传播第 9 章text/21-ch09.txt:99(搜「向前回溯时间」)
模型结构:32 单元 + 1 单元密集层,不必扁平化第 9 章text/21-ch09.txt:103(搜「不再有必要扁平化」)
参数量 1537 对 107 585;误差 0.27 对 0.29第 9 章text/21-ch09.txt:165(搜「Total params: 1537」) · text/21-ch09.txt:169(搜「107 585」)
不能并行;复杂度和采样点数挂钩第 9 章text/21-ch09.txt:171(搜「不可能并行化」) · text/21-ch09.txt:173(搜「互无依赖」)
梯度消失;GRU 与 LSTM 的定位第 9 章text/21-ch09.txt:177(搜「过于简单」) · text/21-ch09.txt:179(搜「梯度消失问题」)
更新门与重置门;影评转折的例子第 9 章text/21-ch09.txt:194(搜「更新门」) · text/21-ch09.txt:196(搜「这个电影还不错」)
不必弄懂全部细节;结构只是划定假设空间第 9 章text/21-ch09.txt:200(搜「没有必要弄懂」)
GRU 结果 0.266;3000 毫秒对 950 毫秒第 9 章text/21-ch09.txt:217(搜「3000毫秒」)
LSTM 出处(1997)第 9 章text/21-ch09.txt:223(搜「Long Short-Term Memory」)
在 Node 里训练并用 TensorBoard 看曲线第 9 章text/21-ch09.txt:119(搜「在资源有限的浏览器环境中训练」) · text/21-ch09.txt:134(搜「tf.node.tensorBoard」)

Footnotes

  1. 出处:「第 9 章 针对序列和文本的深度学习」第 41 段(text/21-ch09.txt:41,搜「只要训练和测试阶段的做法是一样的就行」)。书把这件事放进了章末练习(1),让读者自己验证。第 19 段(text/21-ch09.txt:19,搜「元素是有序的」)则给了序列数据的定义,并拿鸢尾花数据集做反例——换四个特征的顺序对预测毫无影响 2

  2. 出处:「第 9 章」第 49 与 61 段(text/21-ch09.txt:49,搜「24小时后的气温就是当前的气温」;text/21-ch09.txt:61,搜「0.290331」)。书在第 59 段的脚注里给出了算这个基准的函数名 getBaselineMeanAbsoluteError() 及其所在文件。 2

  3. 出处:「第 9 章」第 62 与 64 段(text/21-ch09.txt:62,搜「大致相等」;text/21-ch09.txt:64,搜「下些功夫才能打败」)。原文明说 MLP「无论有没有使用正则化,在常识性基准策略的准确率面前都不能稳操胜券」。

  4. 出处:「第 9 章」第 23 与 80 段(text/21-ch09.txt:23,搜「循环神经网络」;text/21-ch09.txt:80,搜「前馈层」)。原文把不带回流的那些层(密集层、卷积层、池化层)统称为前馈层。 2

  5. 出处:「第 9 章」第 91 段(text/21-ch09.txt:91,搜「莫尔斯编码」)。原文给状态下的定义是:「状态是RNN层能『记住』它曾见过的输入序列中的采样点的关键所在。」 2

  6. 出处:「第 9 章」第 72 段与第 74 段脚注(text/21-ch09.txt:72,搜「包裹在for循环中的元胞」)。这句形容书注明引自 Eugene Brevdo。 2

  7. 出处:「第 9 章」代码清单 9-1,第 88~90 段(text/21-ch09.txt:88,搜「该状态为会被初始化为零」;text/21-ch09.txt:90,搜「W和U分别是输入和状态」)。注意:我们文本副本里的数学符号在转码时丢失了,所以本节的伪代码是按书里的文字说明重写的,不是原样照抄。

  8. 出处:「第 9 章」第 93 段(text/21-ch09.txt:93,搜「其输出和状态是同一个东西」)。

  9. 出处:「第 9 章」第 95 段(text/21-ch09.txt:95,搜「任意数量采样点」)。原文点明密集层做不到这一点,因为它的输入形状是固定的。

  10. 出处:「第 9 章」代码清单 9-2 与第 103 段(text/21-ch09.txt:103,搜「不再有必要扁平化」)。原文说明 32 这个单元数是手动调超参数试出来的;并警告如果把扁平化层放在循环层之前,程序会报错——因为循环层的输入至少要三维(含批次维度)。 2

  11. 出处:「第 9 章」第 165 与 169 段(text/21-ch09.txt:165,搜「Total params: 1537」;text/21-ch09.txt:169,搜「107 585」)。原文:「这一气温预测误差的减少虽小,却是实实在在的。」 2

  12. 出处:「第 9 章」第 97 段(text/21-ch09.txt:97,搜「时间维度的平移不变性」)。原文明确把循环层和卷积层并列:「conv2d层利用空间维度的平移不变性,而RNN层则利用时间维度的平移不变性。」不共享的后果也在同一段。 2

  13. 出处:「第 9 章」第 99 段(text/21-ch09.txt:99,搜「向前回溯时间」)。原文说循环网络的反向传播和前馈网络「基本上是一样的」,唯一区别是回溯的方向是时间。

  14. 出处:「第 9 章」第 179 段(text/21-ch09.txt:179,搜「梯度消失问题」)。原文把它类比成层数过多的前馈网络:「对于RNN而言,大量的采样点就相当于上述问题中过多的层。」 2

  15. 出处:「第 9 章」第 196 段(text/21-ch09.txt:196,搜「这个电影还不错」)。

  16. 出处:「第 9 章」第 192~196 段(text/21-ch09.txt:194,搜「更新门」;text/21-ch09.txt:196,搜「重置门」)。原文说明更新门取 0 时「状态会被原封不动地从当前采样点复制到下一个采样点」,并称这是 GRU 对付梯度消失的重要原因。四个方程里的数学符号在我们的文本副本里丢失,所以本节按文字说明重述,没有照抄公式。

  17. 出处:「第 9 章」第 217 段(text/21-ch09.txt:217,搜「3000毫秒」)。原文同段给出验证误差最低约 0.266,并在第 225 段脚注注明这两个耗时是在基于 CPU 的后端上测得的。 2 3

  18. 出处:「第 9 章」第 177 段与第 223 段脚注(text/21-ch09.txt:177,搜「过于简单」;text/21-ch09.txt:223,搜「Long Short-Term Memory」)。脚注给的出处是 Hochreiter 与 Schmidhuber 发表于 1997 年《Neural Computation》第 9 卷第 8 期的论文。

  19. 出处:「第 9 章」第 200 段(text/21-ch09.txt:200,搜「没有必要弄懂」)。原文:「输入RNN的结构化数据会勾勒出模型的假设空间,然后神经网络会自动通过由数据驱动的训练流程在假设空间中找出处理序列数据所需的细节。」 2 3

  20. 出处:「第 9 章」第 43 段与图 9-1 说明(text/21-ch09.txt:43,搜「相互对称的」)。原文:「这种对称性在处理序列数据时是不好的,因为它会使模型无法感知元素间的顺序。」