Transformer模型中的位置编码

自然语言处理(NLP)随着基于Transformer的模型取得了显著的进步。这些模型中的一项关键创新是位置编码,它有助于捕捉语言的序列特性。在这篇文章中,您将了解:

  • Transformer模型中位置编码的必要性
  • 不同类型的位置编码及其特性
  • 如何实现各种位置编码方案
  • 现代语言模型中如何使用位置编码

让我们开始吧!

语言模型中的位置编码
照片作者:Svetlana Gumerova。部分权利保留。

概述

本文分为五个部分,它们是:

  • 理解位置编码
  • 正弦位置编码
  • 学习式位置编码
  • 旋转位置编码 (RoPE)
  • 相对位置编码

理解位置编码

考虑这两个句子:“狐狸跳过狗”和“狗跳过狐狸”。它们包含相同的单词,但顺序不同。在循环神经网络中,模型按顺序处理单词,自然地捕捉到这种差异。然而,Transformer模型并行处理所有单词,使其在没有额外信息的情况下无法区分这些句子。

位置编码通过提供每个token在序列中的位置信息来解决这个问题。每个token通过模型的嵌入层转换为一个向量,向量的大小称为“隐藏维度”。位置编码通过创建一个具有相同隐藏维度的向量来添加位置信息。

位置编码被添加到注意力模块的输入中。在点积操作期间,这些编码会强调相邻token之间的关系,帮助模型理解上下文。这使得模型能够区分具有相同单词但顺序不同的句子。

最常见的几种位置编码是:

  1. 正弦位置编码(原始Transformer中使用):使用由正弦和余弦函数构建的常数向量
  2. 学习式位置编码(BERT和GPT中使用):在训练期间学习向量
  3. 旋转位置编码(RoPE,Llama模型中使用):使用由旋转矩阵构建的常数向量
  4. 相对位置编码(T5和MPT中使用):基于token之间的距离而不是绝对位置
  5. 带有线性偏差的注意力(ALiBi,Falcon模型中使用):一种基于token距离添加到注意力得分的偏差项

每种类型都有其独特的优点和局限性,我们将在下面详细探讨。

正弦位置编码

原始Transformer论文引入了正弦位置编码。使用确定性函数为每个位置生成唯一的模式,如下面的公式所示:

$$
\begin{aligned}
PE(p, 2i) &= \sin\left(\frac{p}{10000^{2i/d}}\right) \\
PE(p, 2i+1) &= \cos\left(\frac{p}{10000^{2i/d}}\right)
\end{aligned}
$$

其中 $d$ 是隐藏维度(必须是偶数),$i$ 的取值范围是从0到 $d/2$。位置编码 $PE(p, k)$ 代表位置 $p$ 的向量中的第 $k$ 个元素。常数10000是原始Transformer论文建议的。它应该大于最大序列长度。

以下是PyTorch实现:

在此实现中,div_term 计算 $1/N^{2i/d}$($i$ 从 0 到 $d/2-1$)。position 矩阵的形状为 (seq_len,1)。在正弦和余弦函数中它们的乘积会产生一个形状为 (seq_len, dim//2) 的矩阵。结果会被交错放入形状为 (seq_len, dim) 的输出矩阵 pe 中。

正弦编码有两个关键优势:它们是确定性的,并且可以外插到比训练期间看到的更长的序列。由于正弦函数的特性,可以通过其位置编码向量的点积轻松计算token之间的相对位置。

然而,这些编码无法适应数据特征,对于非常长的序列可能效果不佳。

学习式位置编码

像GPT-2这样的模型使用学习式位置编码。以下是PyTorch实现:

nn.Embedding 层充当一个查找表,将整数索引映射到维度为 dim 的向量。在 forward() 函数中,positions 张量具有 (batch_size, seq_len, dim) 的形状,与输入 x 匹配。位置编码在注意力操作之前被加到 x 上。

学习式位置编码通过训练适应数据特征,在正确训练的情况下可能提供更好的性能。但是,它们无法外插到更长的序列,并且可能过拟合。它们还增加了模型的大小,因为它们是模型参数的一部分。

旋转位置编码 (RoPE)

大多数现代大型语言模型使用旋转位置编码 (RoPE)。它们通过旋转矩阵编码相对位置,每个位置代表角度的几何级数。公式为:

$$
\begin{aligned}
\hat{x}_m^{(i)} &= x_m^{(i)} \cos(m\theta_i) + x_m^{(d/2+i)} \sin(m\theta_i) \\
\hat{x}_m^{(d/2+i)} &= x_m^{(d/2+i)} \cos(m\theta_i) – x_m^{(i)} \sin(m\theta_i) \\
\end{aligned}
$$

其中 $\theta_i = 10000^{-2i/d}$,$d$ 是嵌入维度,$m$ 是位置索引,$i$ 的取值范围是从 0 到 $d/2-1$。以矩阵形式表示为:

$$
\mathbf{\hat{x}}_m = \mathbf{R}_m\mathbf{x}_m = \begin{bmatrix}
\cos(m\theta_i) & -\sin(m\theta_i) \\
\sin(m\theta_i) & \cos(m\theta_i)
\end{bmatrix} \mathbf{x}_m
$$

其中 $\mathbf{x}_m$ 代表位置 $m$ 处向量中的一对 $(i, d/2+i)$ 元素。

以下是PyTorch实现:

register_buffer() 调用缓存了正弦和余弦计算,以提高效率。inv_freq 变量计算所有 $i$ 的 $\theta_i$,position 代表 $m$(索引从 0 到 max_seq_len-1),而 sinusoid_inp 包含 $m\theta_i$,其矩阵形状为 (max_seq_len, dim//2)rotate_half() 函数将向量 $(x_1, x_2, \cdots, x_{d-1}, x_{d})$ 转换为 $(-x_{d/2+1}, -x_{d/2+2}, \dots, x_{d/2-1}, x_{d/2})$。然后,apply_rotary_pos_emb() 将旋转矩阵应用于输入。

RoPE 提供了几个优势:

  • 旋转矩阵 $\mathbf{R}_m$ 将 2D 输入向量按角度 $m\theta_i$ 进行几何旋转。
  • 转置 $\mathbf{R}_m^\top = \mathbf{R}_m^{-1}$ 代表反向旋转。因此,相对位置可以很容易地计算为 $\mathbf{R}_{m-n} = \mathbf{R}_m\mathbf{R}_n^\top$。
  • 由于角度的几何级数,它可以外插到更长的序列。
  • 由于 $\cos^2t+\sin^2t=1$,RoPE 保留了 $\mathbf{x}_m$ 的向量范数,有助于训练稳定性。

相对位置编码

虽然以前的实现使用绝对 token 位置,但通常重要的是 token 之间的相对位置。以下是使用相对位置编码的简化实现:

relative_position 矩阵的形状为 (length, length),每个元素表示 token $i$ 和 $j$ 之间的相对位置。这是通过将 $N\times 1$ 矩阵 context_position 从 $1\times N$ 矩阵 memory_position 中减去来计算的。

relative_position_bucket 将值移位为非负数,并从 relative_attention_bias 张量中查找位置编码向量。

相对位置编码自然地处理可变长度序列,并且对于翻译等任务效果很好,因此成为T5等模型的选择。

带有线性偏差的注意力(ALiBi)是一种相关的方法,它向注意力得分添加一个偏差矩阵,而不是操作输入序列。在上面的代码中,您可以看到 relative_positon_bucket 用于查找一系列向量作为位置编码,然后将其添加到注意力模块的输入序列中。在ALiBi中,输入序列直接用于计算注意力得分。但在之后,relative_positon_bucket 的矩阵会被缩放并添加到注意力得分矩阵中,然后才进行 softmax 操作。ALiBi 中的缩放因子计算为 $m_h=1/2^{8h/H}$,其中 $h$ 是头索引,$H$ 是总注意力头数。

进一步阅读

以下是一些关于该主题的进一步阅读材料:

总结

在这篇文章中,您了解了位置编码及其在Transformer模型中的重要性。特别是,您了解到:

  • 位置编码是必需的,因为Transformer会并行处理token。
  • 不同类型的位置编码具有不同的优缺点。
  • 正弦编码是确定性的,并且可以外插到更长的序列。
  • 学习式编码很简单,但不能外插。
  • RoPE在长序列上提供了更好的性能。
  • 相对位置编码关注token之间的距离。

暂无评论。

留下回复

Machine Learning Mastery 是 Guiding Tech Media 的一部分,Guiding Tech Media 是一家领先的数字媒体出版商,专注于帮助人们了解技术。访问我们的公司网站以了解更多关于我们的使命和团队的信息。