跳到主要内容

一串换一串 — 一份状态压不下整个输入,于是有了注意力

这一章讲三件事: 输出是一串东西的时候,模型该怎么搭; 这样搭出来会卡在哪儿;以及那个解法为什么后来变成了整个行业的地基。 它在全书链条里的位置: 第 12 章让模型感觉到了顺序,第 13 章让它吃得下文字。 可它们的输出仍然是一个数或一个类别。这一章的输出是一串。 而且这一章有全书最大的一个时代缺口——书写在那件事发生之前。

1. 先看任务:同一个日期,几十种写法

书挑的任务朴素得让人放心:把乱七八糟的日期字符串,统一成一种标准写法。

输入可能长这样(书列了 18 种,都是同一天):

23Jan2015 012315 01/23/15 1/23/15
JAN 23, 15 Jan 23, 2015 23.01.2015 2015.1.23
20150123 2015/01/23 2015-01-23 ……

输出永远是这一种: 2015-01-23

图说:年月日谁在前、月份写全称还是缩写、补不补零、拿什么符号连——
排列组合下来,同一个日期至少几十种写法。

书自己承认这件事不用机器学习也能做,只是那份代码会非常臃肿——至少上百行, 而且写起来费时费力1

⚠ 书还专门用一条脚注排掉了一个坑: 上面这 18 种格式里没有歧义。 要是数据里同时有「月/日/年」和「日/月/年」,那 01/02/2019 到底是几月几号 根本无法确定——这种数据这个任务做不了2

这一章的新东西在输出上

前十三章的模型,输出永远是一样东西: 一个数(气温)、或者几个类别的概率(正面/负面)。

这个任务不是。它必须吐出整整十个字符,而且每个字符都得对。

输出的形状: [样例数, 10, 13]
│ └─ 每一位上,13 个候选字符各自的概率
└───── 标准日期写法固定 10 个字符

那 13 个候选是:0~9 十个数字、连字符,加上两个有特殊用途的字符(下面会讲)。

图说:**这就是「输出是一串」的具体样子** —— 十个位置,每个位置做一次十三选一。
所以书说这个任务本质上还是分类,只是要连做十次[^3]。

2. 顶层全景:把模型劈成两半

这一节先给整条链子,细节留给后面。

输入「JUL 18, 2034」


┌───────────────┐
│ 前一半:读 │ 把整个输入读一遍,攒成一份内部状态
│ (编码器) │
└───────┬───────┘
│ ①「读完之后的那份状态」
│ ②「读的过程中每一步的输出」← 注意力要用的是这个

┌───────────────┐
│ 后一半:写 │ 拿着上面那些东西,一个字符一个字符地吐
│ (解码器) │
└───────┬───────┘

「2034-07-18」

图说:①是最朴素的连法,②是这一章真正的主角。

前一半有个名字叫编码器——它做的事是把整个输入读一遍,攒成一份内部表示。

后一半叫解码器,它拿着这份表示,一个字符一个字符地往外吐。 这两半合起来的搭法,书管它叫编码器-解码器架构3

3. 后一半怎么知道自己写到哪儿了

这一节回答一个很容易被跳过、但不搞清楚后面全乱的问题。

模型有两个输入,不是一个

第一个输入好懂:那串乱七八糟的日期字符。

第二个输入很反直觉:它是答案本身,只是往右挪了一格4

训练时,正确答案是: 2034-07-18
喂给后一半的第二个输入: <ST>2034-07-1
└── 一个特殊符号,意思是「序列从这儿开始」

对齐着看:
第二个输入: <ST> 2 0 3 4 - 0 7 - 1
要它吐出的: 2 0 3 4 - 0 7 - 1 8

图说:每一格都是「看着左边这个,猜右边那个」。

为什么要把答案喂回去? 书给了一个很好的类比5:

人说话的时候,脑子里同时在做两件事:一是想清楚要表达什么, 二是回想自己已经说到哪儿了。 后者才能保证话说得连贯、不重复、不漏。 模型也一样:生成每个字符时,它需要两份信息——原始输入,和已经生成的部分。

但推断时哪来的答案

这是全节的关键一步。 训练时你知道正确答案,可上线之后没有答案可喂。

做法:让它自己吐出来的字符,接到自己的输入尾巴上,再吐下一个6:

第 1 步:第二个输入 = 「<ST>」 → 吐出「2」
第 2 步:第二个输入 = 「<ST>2」 → 吐出「0」
第 3 步:第二个输入 = 「<ST>20」 → 吐出「3」
……
第 10 步:第二个输入 = 「<ST>2034-07-1」 → 吐出「8」

最后把开头那个特殊符号扔掉,剩下的就是「2034-07-18」。

图说:**训练时是一次算完十个位置,推断时要跑十次。**
这两种模式的差别,是所有生成式模型都有的,第 15 章会再见到一次。

每一步「从 13 个候选里挑一个」,挑的办法是取概率最大的那个7这个办法有名字,而且有更好的替代品,第 7 节讲。

4. 瓶颈:一份状态压不下整个输入

这一节是这一章的转折点,也是注意力存在的全部理由。

最朴素的那条连法

前一半读完之后,它最后那一步的状态被拿出来,当成后一半的开局状态8

「JUL 18, 2034」→ 前一半逐字符读 → 读到最后一个字符时的那份状态

└──→ 后一半的开局状态

第 12 章说过循环层的开局状态一般全是零。
**这里把它换成了一份有内容的数,上游的信息就这么传了下来。**

图说:这条路走得通,书也确实这么接了。**问题是这份状态是固定大小的。**

它为什么不够

书把毛病说得很直白9:

这份初始状态,是一个装着「整个输入序列」的向量。 事实证明,这种表示对解码器而言过于浓缩,解码器很难解读。 输入越长、越复杂,情况越糟——机器翻译里那种长句子就是典型。

「JUL 18, 2034」 12 个字符 → 压进 64 个数,勉强
一个 40 词的英语句子 → 压进同样 64 个数
一段 200 词的文章 → 还是那 64 个数

图说:输入可以任意长,而那份状态的大小是写死的。
**这是一个瓶颈,而且是结构上的瓶颈,不是训练不够。**

注意这里有个岔路口很容易走错: 直觉的解法是把状态做大书没有走这条路,因为再大也还是固定的,而且输入长度没有上限。

5. 承重节:注意力 — 每写一个字符就回头看一遍输入

这一节是本章的地基。

先说它做什么,再说它叫什么

不再只用「读完之后的那一份状态」,
而是把**读的过程中每一步的输出全部留着**(输入 12 个字符,就是 12 份)。

然后:**每要写一个输出字符,就把这 12 份挨个看一遍,
按「和我现在要写的这个字符有多相关」给它们打分,
再照分数把它们混成一份专供这一步用的信息。**

写第 1 个字符时,分数可能主要落在输入的前两个字符上;
写第 2 个字符时,可能主要落在第二、第三个上。

图说:**这个动作就叫注意力。**
它做的事一句话讲得完:**开拓后一半的视野**[^11] ——
从「只能看那一份压缩状态」变成「整个输入都摊在眼前,想看哪儿看哪儿」。

注意力这个名字你出门一定会撞见,所以留着它。

关键在于:分数不是人定的

书特意强调了这一点10:

和神经网络里其他权重一样,怎么分配注意力是训练出来的,不是硬编码的。

所以模型能学会「根据输入本身、以及已经写出来的部分,决定这一步该看哪儿」。

它不是一个说法,它是一个能打印出来的矩阵

这是这一章最漂亮的地方,而且第 10 章那张热图在这里派上了用场。

注意力的分数摆在一起,就是一个 10 行 12 列的表11:

输入的 12 个字符 →
J U L ' ' 1 8 , ' ' 2 0 3 4
输出 ┌──────────────────────────────────────────────────────
「2」│ · · · · · · · · ▓ · · ·
「0」│ · · · · · · · · · ▓ · ·
「3」│ · · · · · · · · · · ▓ ·
「4」│ · · · · · · · · · · · ▓
「-」│ · · · · · · · · · · · ·
「0」│ · ▓ · · · · · · · · · ·
「7」│ ▓ ▓ ▓ · · · · · · · · ·
……

▓ = 分数高 · = 分数低

图说:**这张图是可以真的打印出来看的**,书里就是这么演示的。
写年份最后那个「4」时,亮的正好是输入里年份的最后一位「4」;
写月份「7」时,亮的是输入里的「JUL」。
⚠ 上面这张图是按书里的文字描述画的示意图,**具体的亮度值书没有印出来**。

书对这一列的解读值得抄下来: 写输出的「4」时,同一列上其他位置的分数都很低—— 意思是生成这个字符时,几乎没用到输入里其他字符的信息11这是符合常理的。

分数怎么算出来的

书给的做法只有两步,而且没有引入任何新机制12:

① 拿后一半每一步的输出,和前一半每一步的输出,**两两做点积**
(点积 = 对位相乘再求和,第 06 章卷积那一下用的就是它)
后一半 10 步 × 后半特征 64 个
前一半 12 步 × 前半特征 64 个
沿着「64 个」这一维配对相乘求和 → 得到一个 10 × 12 的表

② 把这张表过一遍归一化指数函数(第 05 章那个把一串数变成一组概率的动作)
→ 每个数都是正的,而且每一列加起来等于 1

图说:第 ① 步是在问「这两步的内容有多合拍」,
第 ② 步把「合拍程度」变成了「注意力该分多少」。
**注意力矩阵就是这么来的,没有第三步。**

分完之后怎么用

拿这张表去加权取用前一半那 12 份输出,混出来的东西书管它叫上下文13:

注意力矩阵 [10, 12] × 前一半的输出 [12, 64] → 上下文 [10, 64]
└ 输出的每一步,配一份专属的信息

然后把上下文和后一半自己的输出拼在一起:[10, 64] + [10, 64] = [10, 128]

最后过一个小模型(一个隐藏层 + 一个 13 选 1 的输出层),
这个小模型在十个位置上是**同一个**,只是被调用了十次。

图说:到这一步,「写第 k 个字符」需要的两份信息就齐了 ——
**上下文管「原文里该看哪儿」,后一半自己的输出管「我已经写到哪儿了」。**

训练用的误差尺子是分类交叉熵(第 05 章那把,专治「几选一」),优化器用 adam14

6. 主走查:「JUL 18, 2034」走完全程

这一章每个承重机制在这条走查上各占一步。形状和数字来自书里,注意力矩阵的具体亮度值书没印,已标明。

发生了什么具体的数 / 状态
1输入「JUL 18, 2034」12 个字符;书支持的最长输入就是 12,不够的在后面补零
2每个字符查一张表变成一串数第 13 章那个动作,只是这次查的是字符不是词;每字符 64 个数
3前一半逐字符读过去用的是 LSTM;要求它把每一步的输出都留着,不是只留最后一个
4前一半的输出形状 [12, 64]——12 步,每步 64 个数
5取最后那一步,当后一半的开局状态这份状态要传两遍,因为 LSTM 有两个状态(第 12 章那种只有一个)
6诊断瓶颈不管输入 12 个字符还是 200 个词,都被压进这固定的一份里
7解法:注意力。后一半每一步的输出 × 前一半每一步的输出,做点积沿 64 那一维配对 → 得到 [10, 12] 的表
8过一遍归一化指数函数每个数为正、每列和为 1——这就是注意力矩阵
9把它画成热图看写「4」那一步,亮的是输入末尾的「4」;写「7」那一步,亮的是「JUL」。(亮度值书未印出)
10拿这张表去加权取用前一半的输出[10,12] × [12,64]上下文 [10, 64]
11上下文和后一半自己的输出拼起来[10, 128]
12过一个小模型,十个位置共用同一个[10, 13],十个位置各给 13 个候选字符打分
13推断第 1 步:第二个输入只有「<ST>取分数最高的 → 「2」
14把「2」接到第二个输入尾巴上,再跑一次第二个输入变成「<ST>2」 → 吐出 「0」
15重复到第 10 步第二个输入「<ST>2034-07-1」 → 吐出 「8」
16扔掉开头那个特殊符号「2034-07-18」
17收账训练两轮损失就降到接近零、准确率接近 100%;代价是推断要跑十次模型,不是一次

7. 挑字符的办法还可以更好

第 3 节说每步取概率最高的那个。这是一种做法,而且有名字:贪心解码15

贪心:每一步都挑当前最高的那个,挑完就不回头。

问题:这一步挑了最高的,可能会让后面几步都变糟 ——
**整条路加起来未必是最好的那条。**

另一种做法是同时留住几条候选路,走一段再比,**它叫集束搜索**。

图说:书只给了名字和一句解释,**具体算法推给了一篇外部文章**[^16]。

这个取舍在第 15 章会以另一种形式再出现一次——那次不是「怎么挑最好的」, 而是「故意别总挑最好的」。

8. 时代坐标:这本书停在哪一步

这是全书最大的一处缺口,必须当场交代清楚。

书是怎么定位注意力的

书把注意力当成一个加在循环网络上的增强件: 它给的出处是 2014—2015 年前后那一批工作,并说当时这是深度学习领域的一个巨大突破16

书还给了一个让人安心的背书:当时最顶尖的机器翻译系统(谷歌的那套) 用的架构和这里是一样的,只是层更多、数据更多17

但后来发生的事,书里一个字都没有

补充(不在书里,依据我们的 ai-book-reference 书架): 2017 年那篇论文的做法是把循环整个去掉,只留注意力。 也就是说,注意力不再是循环网络的补丁,它反过来成了整个架构本身。 今天你听到的所有「大模型」,底座都是这一套。18

这本书的立场: 循环网络是主角,注意力是加在它上面的增强件
2017 年之后的实情: 注意力是主角,循环被整个删掉了

为什么必须删掉循环?**第 12 章那条硬伤:第 t 步必须等第 t−1 步算完。**
去掉它,一整句话可以一次算完 —— 这是训练规模能涨几个数量级的直接原因。

图说:书成稿于 2019 年 9 月,**比那篇论文晚两年**。
所以这不是作者判断失误,是这本书的时间位置决定的。

判断(我们的,不是书里的): 这一章的教学价值不但没有因为过时而下降,反而更高了。 因为它是从瓶颈里长出注意力的:先有「一份状态压不下」,才有「那就每步回头看一遍」。 今天大部分材料是反过来讲的——上来就摆一堆公式,不说它在解决什么问题。 如果错,会错在: 如果你的目的是动手实现今天的主流结构, 那这一章缺的东西太多(自己看自己、多组并行的注意力、位置怎么编码), 要去看我们书架上那两本专讲这件事的书。

9. 作者的判断与证据

书里给了证据的:

  • 这个任务两轮就能训到准确率接近 100%。 书给了训练命令和结果描述19
  • 注意力矩阵能画出来,而且亮的位置符合常理。 书给了实际截图并逐格解读11
  • 那份初始状态对解码器来说过于浓缩。 书用的措辞是「事实证明」9
  • 各个形状对得上: [12,64][10,64][10,12][10,128][10,13]—— 书把每一步的形状都印出来了1213

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

  • 「用传统程序写至少要上百行」。 这是估计,书没有真写一份来比1
  • 「顶尖机器翻译系统用的是同一套架构」。 书给了系统名字,没有给论文出处17
  • 「嵌入适用于任何有限的离散集合」(音乐流派、机场……)。这是推广, 书在这一章只演示了字符这一种20

书自己坦白的:

  • LSTM 的内部结构书没讲。 原话是此处不深入,知道它和第 12 章那个门控结构类似就够了, 并把细节推给了一篇外部博客21

10. 边界与局限

  • 任务小得几乎是玩具。 输入最长 12 个字符、输出固定 10 个、候选只有 13 个。 真实的机器翻译要面对的规模差几个数量级,书自己也说了。
  • 注意力只讲了一种。 后一半看前一半的那种; 自己看自己的那种(今天的主流)书里一个字没有。
  • 位置信息靠循环带进来,书没讨论别的办法。 这一点在去掉循环之后会立刻变成问题—— 而书没有走到那一步。
  • 集束搜索只有一个名字和一句话。 算法推给了外部文章15
  • 没有讨论输出长度可变的情况。 这个任务的输出恒定 10 个字符, 真实的生成任务要靠一个「结束符」来决定什么时候停,书没有涉及。
  • 两个特殊字符的作用只说了一半。 序列开始符讲清了, 填充符只在最后数 13 的时候顺带提了一句。
  • LSTM 为什么有两个状态,书只说了「它就是有两个」。 没有讲这两个各管什么。

11. 可带走的

  1. 输出可以是一串。 做法是把输出摊成 [长度, 候选数]—— 十个位置各做一次十三选一,本质还是分类,只是连做十次;
  2. 模型劈成两半:前一半读、后一半写。 名字是编码器解码器;
  3. 后一半有两个输入。 一个是前一半传来的东西, 一个是右移一格的答案——训练时喂正确答案,推断时喂它自己上一步吐的字符;
  4. 推断要跑十次模型,不是一次。 每次把新吐的字符接到输入尾巴上;
  5. 瓶颈在中间那份状态: 输入可以任意长,而那份状态的大小是写死的; 把状态做大治不了本,因为输入长度没有上限;
  6. 注意力 = 每写一个字符,就回头把输入每一步的输出看一遍,按相关程度加权取用;
  7. 它是训练出来的,不是人定的规则——模型自己学会该看哪儿;
  8. 它是一个能打印出来的矩阵。 这个任务里是 10 行(输出)× 12 列(输入); 写年份那四位时亮的正好是输入里年份的位置;
  9. 算法只有两步: 两边的输出两两做点积 → 过一遍归一化指数函数。 加权取用之后混出来的那份信息叫上下文;
  10. 每步挑概率最高的那个字符叫贪心解码;想更好就得同时留住几条候选路(集束搜索);
  11. 最要紧的一条:这本书写在 2017 年那篇论文之后、大模型时代之前。 书里注意力是循环网络的补丁;后来它反过来把循环整个替换掉了,而这本书没有这一步。

12. 原文地图

主题原书章原文位置
序列到序列任务的定义与例子第 9 章text/21-ch09.txt:542(搜「序列到序列」)
日期任务:18 种格式;传统程序上百行第 9 章text/21-ch09.txt:560(搜「至少能得到数十种方式」) · text/21-ch09.txt:562(搜「至少上百行代码」)
歧义格式排除(01/02/2019)第 9 章text/21-ch09.txt:573(搜「01/02/2019」)
输出是三维张量;10 个位置、13 个候选第 9 章text/21-ch09.txt:597(搜「OUTPUT_VOCAB_SIZE」) · text/21-ch09.txt:713(搜「11种可能的字符」)
编码器-解码器;两个输入;右移一格第 9 章text/21-ch09.txt:599(搜「编码器」) · text/21-ch09.txt:601(搜「2034-07-1」)
人说话的类比第 9 章text/21-ch09.txt:603(搜「人类说话的原理」)
推断时逐字符生成第 9 章text/21-ch09.txt:605(搜「逐个生成需要输出的字符」) · text/21-ch09.txt:611(搜「直到输出的长度达到预期长度」)
用编码器最终状态当解码器初始状态第 9 章text/21-ch09.txt:617(搜「初始状态」) · text/21-ch09.txt:662(搜「最后采样点对应的结果」)
瓶颈:那份状态过于浓缩第 9 章text/21-ch09.txt:619(搜「过于浓缩」)
注意力开拓视野;分配是学出来的第 9 章text/21-ch09.txt:621(搜「开拓解码器」)
注意力矩阵的实际解读(JUL 18, 2034)第 9 章text/21-ch09.txt:591(搜「JUL 18, 2034」) · text/21-ch09.txt:587(搜「注意力矩阵」)
注意力怎么算:点积 + 归一化指数;形状第 9 章text/21-ch09.txt:678(搜「点积」) · text/21-ch09.txt:685(搜「矩阵每列之和为1」)
上下文;拼接;共用同一个小模型第 9 章text/21-ch09.txt:687(搜「上下文」) · text/21-ch09.txt:693(搜「拼接」) · text/21-ch09.txt:713(搜「timeDistributed」)
LSTM 有两个状态第 9 章text/21-ch09.txt:676(搜「LSTM层包含两个状态」)
损失函数与优化器第 9 章text/21-ch09.txt:721(搜「分类交叉熵」)
训练两轮到接近 100%第 9 章text/21-ch09.txt:584(搜「接近100%」)
注意力的时代定位;GNMT第 9 章text/21-ch09.txt:617(搜「巨大理论突破」) · text/21-ch09.txt:623(搜「谷歌的神经机器翻译」)
字符嵌入;嵌入适用于任何离散集合第 9 章text/21-ch09.txt:647(搜「音乐流派」)
LSTM 内部结构不讲,推给外部博客第 9 章text/21-ch09.txt:649(搜「Understanding LSTM Networks」)
贪心解码与集束搜索第 9 章text/21-ch09.txt:739(搜「贪心解码」)

Footnotes

  1. 出处:「第 9 章 针对序列和文本的深度学习」第 560562 段(text/21-ch09.txt:560,搜「至少能得到数十种方式」;text/21-ch09.txt:562,搜「至少上百行代码」)。18 种格式的清单见第 566570 段。 2

  2. 出处:「第 9 章」第 573 段脚注(text/21-ch09.txt:573,搜「01/02/2019」)。原文说这种数据「无法确定日期背后的真实含义」。

  3. 出处:「第 9 章」第 599 段与图 9-10(text/21-ch09.txt:599,搜「编码器」)。原文给的两个输入形状是 [numExamples, INPUT_LENGTH](输入最长 12)与 [numExamples, OUTPUT_LENGTH]

  4. 出处:「第 9 章」第 601 段(text/21-ch09.txt:601,搜「2034-07-1」)。原文给的例子正是:目标是「2034-07-18」时,第二个输入是「<ST>2034-07-1」。

  5. 出处:「第 9 章」第 603 段(text/21-ch09.txt:603,搜「人类说话的原理」)。原文说人说话时大脑做两件事:具象化概念本身、回忆至今说过的话。

  6. 出处:「第 9 章」第 605~611 段与图 9-10(text/21-ch09.txt:605,搜「逐个生成需要输出的字符」;text/21-ch09.txt:611,搜「直到输出的长度达到预期长度」)。原文在第 607 段脚注里给出了实现这个逐步流程的函数名 runSeq2SeqInference() 及其所在文件。

  7. 出处:「第 9 章」第 727 段(text/21-ch09.txt:727,搜「argMax」)。原文说明推断时对输出张量做取最大值的运算得到最终字符,并把它追加到解码器输入尾部。

  8. 出处:「第 9 章」第 617 与 662 段(text/21-ch09.txt:617,搜「初始状态」;text/21-ch09.txt:662,搜「最后采样点对应的结果」)。原文点明循环层的初始状态一般全是零,而这里被换成了编码器的最终状态。

  9. 出处:「第 9 章」第 619 段(text/21-ch09.txt:619,搜「过于浓缩」)。原文:「事实证明这种表示对解码器而言过于浓缩,解码器很难解读这种表示形式。对于那些较长的或者更复杂的序列,情况更是如此。」 2

  10. 出处:「第 9 章」第 621 段(text/21-ch09.txt:621,搜「开拓解码器」)。原文明确说注意力用的「不只是编码器的最终输出,还包含编码器所有输出的序列」,并强调分配策略是训练学出来的,不是硬编码的。

  11. 出处:「第 9 章」第 587 与 591 段(text/21-ch09.txt:587,搜「注意力矩阵」;text/21-ch09.txt:591,搜「JUL 18, 2034」)。原文逐格解读了那张热图:输出字符「4」那一列上,只有输入末尾「4」那一格的值较高,其余都低。书给的是颜色深浅的定性描述,没有印出具体数值,所以本章那张示意图只标了亮 / 不亮。 2 3

  12. 出处:「第 9 章」第 678~685 段(text/21-ch09.txt:678,搜「点积」;text/21-ch09.txt:685,搜「矩阵每列之和为1」)。原文给出的形状是:编码器输出 [null, 12, 64]、解码器输出 [null, 10, 64]、点积结果 [null, 10, 12] 2

  13. 出处:「第 9 章」第 687~697 与 713 段(text/21-ch09.txt:687,搜「上下文」;text/21-ch09.txt:693,搜「拼接」;text/21-ch09.txt:713,搜「timeDistributed」)。原文说明拼接后的形状是 [null, 10, 128],最后经由一个在时间维度上被反复调用的同一个小模型变成 [null, 10, 13] 2

  14. 出处:「第 9 章」第 721~726 段(text/21-ch09.txt:721,搜「分类交叉熵」)。

  15. 出处:「第 9 章」第 739 段(text/21-ch09.txt:739,搜「贪心解码」)。原文只给了集束搜索的名字和一句话解释,具体算法推给了一篇外部文章。 2

  16. 出处:「第 9 章」第 617 段与第 556 段脚注(text/21-ch09.txt:617,搜「巨大理论突破」)。书给的两篇出处是 Alex Graves 的「Generating Sequences with Recurrent Neural Networks」,以及 Bahdanau、Cho、Bengio 的「Neural Machine Translation by Jointly Learning to Align and Translate」。

  17. 出处:「第 9 章」第 623 段(text/21-ch09.txt:623,搜「谷歌的神经机器翻译」)。原文说生产级模型「使用的LSTM层和训练数据会更多」,但架构相同。 2

  18. 补充(不在书里,依据我们的 ai-book-reference 书架):2017 年之后注意力反过来取代了整个循环架构。依据: book=deep-learning-with-python-2e §11-text-transformer 事实=该章写明 2017 年 Vaswani 等人的论文「Attention Is All You Need」提出的结构「只用一种叫神经注意力的机制,不用任何循环层和卷积层」,并指出这种结构在 2017—2018 年间取代了此前统治文本任务的双向 LSTM。同一章还写明该结构本身不感知词序,顺序要靠位置嵌入手动注入——这正是这本 JS 书完全没有走到的那一步。 想看它拆到能手算的程度,另见 book=build-large-language-model §03-attention-core。

  19. 出处:「第 9 章」第 584 段(text/21-ch09.txt:584,搜「接近100%」)。原文说默认训练两个轮次「已足以将损失值降至接近于零,格式转换准确率升至接近100%」,并说明示范用的推断样例来自与训练集无重叠的测试集。

  20. 出处:「第 9 章」第 647 段(text/21-ch09.txt:647,搜「音乐流派」)。原文举的其他例子还有「新闻网站上的文章」「某个国家及地区的飞机场分布」。同段还说明 maskZero 这个配置是让下游忽略全零的采样点,避免对已经生成完毕的部分做无谓计算。

  21. 出处:「第 9 章」第 649 段(text/21-ch09.txt:649,搜「Understanding LSTM Networks」)。原文:「此处还不会深入讲解其内部结构,目前知道它的结构和GRU(见图9-4)类似就足够了。」