7.4 输入:词元嵌入与位置嵌入
嵌入(embedding)
下面讨论输入 X 从何而来。给定一个包含 N 个词元的序列(N 是以词元计量的上下文长度),形状为 的矩阵 X 为上下文中的每个词提供一个嵌入。Transformer 通过分别计算两种嵌入来完成这一过程:输入词元嵌入和输入位置嵌入。
第 6 章介绍过,词元嵌入(token embedding)是一个维度为 d 的向量,它将作为输入词元的初始表示。(随着向量在残差流中逐层向上传递,这个嵌入表示会发生变化并不断扩充:它会融入上下文,而且会依我们所构建的语言模型类型而发挥不同作用。)所有初始嵌入都存储在嵌入矩阵 E 中,词表 V 里的每个词元各占一行。(提醒一下,这里的 V 表示词元词表,与值向量无关。)因此,每个词都由一个 d 维行向量表示,而 E 的形状为 。
给定类似 Thanks for all the 的输入词元串,我们首先把这些词元转换成词表索引(最初使用 BPE 或 SentencePiece 对输入进行词元化时创建了这些索引)。因此,thanks for all the 的表示可能是 。接下来,我们通过索引从 中选择相应的行(第 5 行、第 4000 行、第 10532 行和第 2224 行)。
还可以用另一种方式理解如何从嵌入矩阵中选取词元嵌入:把词元表示成形状为 的 独热向量(one-hot vector),也就是为词表中的每个词设置一个维度。回想一下,独热向量中除一个元素外,其余元素全为 0;唯一取值为 1 的元素,其维度就是该词在词表中的索引。因此,如果单词 “thanks” 在词表中的索引为 5,那么 ,并且 ,如下所示:
与仅有一个非零元素 的独热向量相乘,只会选出与词 对应的行向量,所得结果就是词 的嵌入,如图 7.12 所示。

图 7.12 将嵌入矩阵 E 与索引 5 处为 1 的独热向量相乘,从而选出词 的嵌入向量。
我们可以扩展这一思路,用一个独热向量矩阵表示整个词元序列;Transformer 上下文窗口中的 N 个位置各对应一个独热向量,如图 7.13 所示。

图 7.13 与词元 ID 输入序列 W 对应的独热矩阵乘以嵌入矩阵 E,从而选出该输入序列的嵌入矩阵。
这些词元嵌入并不依赖位置。为了表示每个词元在序列中的位置,我们把词元嵌入与输入序列中各位置特有的位置嵌入结合起来。
这些位置嵌入从哪里获得?最简单的方法称为 绝对位置(absolute position):为截至某个最大长度的每个可能输入位置设置一个随机初始化的嵌入。例如,正如我们有单词 的嵌入一样,我们也会有位置 3 的嵌入。与词嵌入相同,这些位置嵌入会在训练过程中与其他参数一起学习。我们可以把它们存储在形状为 的矩阵 中。
为了生成能够捕捉位置信息的输入嵌入,只需把每个输入的词嵌入与其对应的位置嵌入相加。单个词元嵌入和位置嵌入的大小都是 ,所以它们的和也是 。这个新嵌入将作为后续处理的输入。图 7.14 展示了这一思路。

图 7.14 一种简单的位置建模方法:将绝对位置的嵌入加到词元嵌入上,生成一个维度相同的新嵌入。
输入的最终表示矩阵 是一个 矩阵,其中第 行是输入中第 个词元的表示。该表示的计算方法是:将 ——出现在位置 的词元 ID 所对应的嵌入——与 (位置 的位置嵌入)相加。
这种简单位置嵌入方法存在一个潜在问题:训练数据中输入起始位置的样本会非常多,而接近最大长度边界的位置所对应的样本则较少。后面这些位置的嵌入可能训练不充分,在测试时也可能无法很好地泛化。一种替代方案是选择一个静态函数,以更善于处理任意长度序列的方式,将整数输入映射为实值向量。最初的 Transformer 工作使用了不同频率的正弦和余弦函数组合。正弦位置嵌入(sinusoidal position embedding)也可能有助于捕捉位置之间的内在关系,例如输入中的位置 4 与位置 5 的关系,要比它与位置 17 的关系更密切。
更复杂的位置嵌入方法进一步扩展了捕捉位置关系的思路:它们直接表示相对位置,而不是绝对位置。这类方法往往在每一层的注意力机制中实现,而不是只在初始输入处加一次。目前最流行的此类位置嵌入机制是 旋转位置嵌入(Rotary Position Embedding, RoPE)(Su et al., 2024)。