🗒️大模型中的位置向量

type
status
date
slug
summary
tags
category
icon
password
💡
本文探讨了Transformer模型中位置编码的重要性,介绍了绝对位置编码如训练式学习和三角式函数,以及相对位置编码如Transformer的相对位置表示、自适应编码和DeBERTa的方向编码。同时讨论了大模型的外推性问题及可能的解决方法,如CNN式处理和复数式位置编码的运用。

绪论

众所周知,transformer模型之所以能够取得如此卓越的效果,其中的Attention机制功不可没,它的本质是计算输入序列中的每个token与整个序列的注意力权重。假设 分别表示词向量 q 位于位置 m 和词向量 k 位于位置 n ,在未添加位置信息的时候, ,则两者的注意力权重计算如下:
我们会发现,在未加入位置信息的情况下,无论 q 和 k 所处的位置如何变化,它们之间的注意力权重 均不会发生变化,也就是位置无关,这显然与我们的直觉不符。对于两个词向量,如果它们之间的距离较近,我们希望它们之间的的注意力权重更大,当距离较远时,注意力权重更小。
为了解决这个问题,我们需要为模型引入位置编码,让每个词向量都能够感知到它在输入序列中所处的位置信息。我们定义如下函数,该函数表示对词向量 q 注入位置信息 m ,得到 ,则 之间的注意力权重可表示为:
位置编码的主要作用如下
  • 提供位置信息:位置编码为每个序列元素提供其在序列中的位置,使得模型可以识别和区分序列中不同位置的元素。
  • 增强模型的表达能力:通过加入位置编码,模型不仅可以学习元素的内容信息,还可以学习元素的位置信息,从而更好地捕捉序列中的依赖关系和模式。
  • 与自注意力机制结合:位置编码与自注意力机制结合,使得模型能够同时关注到序列中元素的相对位置和全局上下文信息,这对于处理长距离依赖和全局信息非常重要。
为什么不直接用token的索引作为它的位置编码?
  • 因为序列长度是可变的,因此token的索引也随之变化,当句子非常长的时候索引也会变的非常大。此外直接用索引作为位置编码会损害模型的泛化能力,即缺乏处理没见过的长度的能力。
  • 用normalize把索引归一化到0-1之间会产生另一个问题。同一个归一化的值,比如0.1, 在不同长度的序列中表示的位置不同,这就会导致不同长度序列中,第m个token与第n个token的相对距离是变化的,这不利于绝对位置和相对位置的计算。
理想情况下,位置编码应满足以下条件
  • 为每个时间步骤(单词在句子中的位置)输出唯一的编码。
  • 任何两个时间步骤之间的距离在不同长度的句子之间应该是一致的。
  • 我们的模型应该方便地推广到更长的句子。它的值应该是有界的。
  • 它必须是确定性的。
位置编码主要有两种实现形式:
  1. 绝对位置编码 (absolute PE):将位置信息加入到输入序列中,相当于引入索引的嵌入。比如Sinusoidal, Learnable, FLOATER, Complex-order, RoPE
  1. 相对位置编码 (relative PE):通过微调自注意力运算过程使其能分辨不同token之间的相对位置。比如XLNet, T5, DeBERTa, URPE

三角函数式(Sinusoidal)位置编码

Transformer论文中用到的绝对位置编码

三角函数式(Sinusoidal)位置编码是在原Transformer模型中使用的一种显式编码。以一维三角函数编码为例:
notion image
pos是位置,i是维度索引,d_model是嵌入总维度。每个维度的位置编码都对应一个正弦波,波长从2π到10000 · 2π,对应的频率从高频到低频。你可以把这个位置编码想象成一个包含d_model/2对的sin和cos向量, 每一对sin和cos都对应一个频率。
对于一个正弦函数, y = Asin(Bx + C) + D. 其波长为λ=2π/|B| 和周期计算一样,为从一个最高点到下一个最高点的距离。 频率与波长成反比关系。波长越长,变化越慢,即频率越低。回到我们的位置编码,从位置编码公式中我们不难得出,波长的计算和有关。
  • 对于较小的 i,分母较小,波长较短, 频率较高,当i=0时, 波长为2π, 频率为1/2π。这意味着正弦和余弦函数的变化较快。
  • 对于较大的 i,分母较大,波长较长, 频率较低,当i=d/2时, 波长为10000 · 2π,频率为1/(10000 · 2π)。这意味着正弦和余弦函数的变化较慢。

位置编码python实现

notion image
从图中可以看出,当维度较低时,频率高变化快,随着维度增大,频率变低。相邻两个token的位置编码的差异主要在左边低维度部分,即高频部分。
根据三角函数的性质,位置 α+β 处的编码向量可以表示成位置 α 和位置 β 的向量的组合,因此可以外推到任意位置:
Sinusoidal位置编码还具有远程衰减的性质,具体表现为:对于两个相同的词向量,如果它们之间的距离越近,则他们的内积分数越高,反之则越低。如下图所示,我们随机初始化两个向量q和k,将q固定在位置0上,k的位置从0开始逐步变大,依次计算q和k之间的内积。我们发现随着q和k的相对距离的增加,它们之间的内积分数震荡衰减。
notion image
因为Sinusoidal位置编码中的正弦余弦函数具备周期性,并且具备远程衰减的特性,所以理论上也具备一定长度外推的能力。

为什么使用正弦位置编码

  1. sin、cos值在[-1, 1]之间,保证了位置编码矩阵的每个值都处于一个稳定范围
  1. 每个位置的位置编码都是唯一的,这有利于绝对位置编码
  1. 不同位置之间的位置编码也可以进行计算, 这有利于相对位置计算
  1. 正弦位置编码具备远程衰减性,即随着两个token间距离的增大,这两个token的位置编码的内积会变小。这是符合直觉的,一般来说距离越远的两个token,关联性也就越小

可学习位置编码

与固定的位置编码不同,学习的位置嵌入是通过训练模型来学习的。这种方法的基本思想是为每个位置创建一个可训练的嵌入向量,并在训练过程中更新这些向量。
实现方式
  • 初始化嵌入矩阵:为每个位置初始化一个嵌入向量。例如,如果序列长度是 seq_length,嵌入维度是 d_model,那么初始化的嵌入矩阵大小将是 [seq_length, d_model]。
  • 学习嵌入向量:在模型训练过程中,这些嵌入向量会像其他模型参数一样被优化。
  • 应用嵌入向量:在将嵌入向量输入到模型中时,将输入序列中的每个位置映射到其对应的嵌入向量。例如,如果输入序列是 [token1, token2, ..., tokenN],则位置嵌入是 [pos_embedding1, pos_embedding2, ..., pos_embeddingN]。

可学习位置编码的python实现

可学习位置编码的优缺点

优点

  • 灵活性:学习的位置嵌入可以根据任务和数据的不同而自动调整,而不是依赖于固定的数学函数。
  • 适应性:这种方法允许模型更好地适应特定任务中的位置模式。

缺点

  • 序列长度的限制:可学习位置嵌入通常需要预先定义一个最大序列长度(max length)。如果输入序列长度超过了这个预定义的最大长度,模型就无法处理这些超长序列,因为没有为这些超长序列的位置预留嵌入向量
  • 计算和存储开销:了支持较长的序列,可学习位置嵌入需要存储更多的嵌入向量,这会增加模型的参数数量,从而增加计算和存储的开销。对于特别长的序列,这个问题会更加突出。
  • 泛化能力有限:可学习位置嵌入在训练时只能学习到固定范围内位置的嵌入。如果在推理阶段遇到比训练时更长的序列,模型可能无法很好地泛化到这些新的位置。因此,可学习位置嵌入在处理未见过的长序列时可能表现不佳。

旋转位置编码

在这里先直接抛出一个直观的结论:RoPE位置编码通过将一个向量旋转某个角度,为其赋予位置信息
在绝对位置编码中,尤其是在训练式位置编码中,模型只能感知到每个词向量所处的绝对位置,并无法感知两两词向量之间的相对位置。对于Sinusoidal位置编码而言,这一点得到了缓解,模型一定程度上能够感知相对位置。
对于RoPE而言,作者的出发点为:通过绝对位置编码的方式实现相对位置编码。回顾我们此前定义的位置编码函数,该函数表示对词向量 q 添加绝对位置信息 m ,得到  :
RoPE希望  与  之间的点积,即  中能够带有相对位置信息 。那么  如何才算带有相对位置信息呢?只需要能够将  表示成一个关于 qkmn 的函数 即可,其中 mn 便表示着两个向量之间的相对位置信息。
因此我们建模的目标就变成了:找到一个函数 ,使得如下关系成立:.

二维位置编码

为了简化问题,我们先假设词向量是二维的。作者借助复数来进行求解,在此我们省略求解过程,直接抛出答案,最终作者得到如下位置编码函数,其中 m 为位置下标,  为一个常数:
为了更好地理解上面的函数,我们先简单复习一下线性代数中的旋转矩阵。在二维空间中,存在一个旋转矩阵  ,当一个二维向量左乘旋转矩阵时,该向量即可实现弧度为  的逆时针旋转操作。 
我们以二维向量 (1,0) 为例,将其逆时针旋转45度,弧度为  ,将得到新的二维向量  ,向量的模长未发生改变,仍然是1。计算过程如下: 
notion image
回看我们求解得到的位置编码函数  ,感叹数学之美,我们得到的是一个向量旋转的函数,左侧的  是一个旋转矩阵,  表示在保持向量 q 的模长的同时,将其逆时针旋转  。这意味着只需要将向量旋转某个角度,即可实现对该向量添加绝对位置信息,这就是旋转位置编码的由来。
我们进一步验证RoPE是否能通过绝对位置编码的方式实现相对位置编码。当我们求两个向量之间的点积会发现,它们的点积是一个关于 q 、 k 、 m-n 的函数  ,所以函数  实现了以绝对位置编码的方式实现相对位置编码。 
notion image
为了更加形象生动地理解旋转位置编码,我们结合图形描述如何为一个二维向量赋予位置编码。假设存在向量 q=(1,0) ,位置编码函数  中的  是一个常量,我们不妨设为1,则:
向量 q 位于位置0,1,2,3时,分别将向量 (1,0) 旋转0,1,2,3弧度,就可以为其赋予对应的绝对位置信息。如下图所示,只需要对向量进行旋转操作,即可对向量添加对应的位置信息。并且向量旋转具有周期性
notion image
到此为止,我们已经弄明白了旋转位置编码的来源、数学意义,以及它是如何使用绝对位置实现相对位置编码,大道至简,惊叹数学的优雅。

推广到多维

上述我们介绍了如何为一个二维向量赋予绝对位置信息:旋转一定的角度即可。但我们知道词向量的维度一般是几百甚至上千,如何将我们上述旋转的结论推广到多维呢?分而治之即可,我们把高维向量,两两一组,分别旋转。最终高维向量的旋转可表示成如下公式,可以认为左侧便是高维向量的旋转矩阵:
notion image

远程衰减性

在此前的推导中,我们说过  可以是一个任意常量,我们不妨将其设为1,以便查看其性质。我们随机初始化两个向量q和k,将q固定在位置0上,k的位置从0开始逐步变大,依次计算q和k之间的内积。我们发现随着q和k的相对距离的增加,它们之间的内积分数呈现出一定的震荡特性,缺乏了重要的远程衰减性,这并不是我们希望的。
notion image
借鉴Sinusoidal位置编码,我们可以将每个分组的  设为不同的常量,从而引入远程衰减的性质。这里作者直接沿用了Sinusoidal位置编码的设置,  。则我们可以将高维向量的旋转矩阵更新为如下
notion image
上式中的旋转矩阵十分稀疏,为了节省算力,可以以下面的方式等效实现:
notion image
我们继续随机初始化两个向量q和k,将q固定在位置0上,k的位置从0开始逐步变大,依次计算q和k之间的内积。我们发现随着q和k的相对距离的增加,它们之间的内积分数呈现出远程衰减的性质,这正是我们希望的。
notion image
在原始的RoPE中,沿用了Si‍‍nusoidal位置编码的设置,令  ,但  一定要取  吗?我们继续深入探讨一下  中base的取值的影响。依然结合图像来进行说明,此次我们初始化两个全一向量q和k(为了让图像显得不那么杂乱‍‍),将q固定在位置0上,k的位置从0开始逐步变大,依次计算q和k之间的内积。当我们将base取不同的值的时候,q和k的内积随着相对位置变化趋势如下图。
notion image
‍‍如上图我们可以总结得到一些规律,base的不同取值会影响注意力远程衰减的程度。当base大于500时,随着base的提升,远程衰减的程度会逐渐削弱。但太小的base也会破坏注意力远程衰减的性质,例如base=10或100时,注意力分数不再随着相对位置的增大呈现出震荡下降的趋势。更极端的情况下,当base=1时,其实也就是上面我们提到的,将所有  都设为1的情况,将完全失去远程衰减特性,如下图所示。
notion image
对于base的性质的研究,与大模型的长度外推息息相关,如NTK-Aware Scaled RoPE、NTK-by-parts、Dynamic NTK等长度外推方法,本质上都是通过改变base,从而影响每个位置对应的旋转角度,进而影响模型的位置编码信息,最终达到长度外推的目的。目前大多长度外推工作都是通过放大base以提升模型的输入长度,例如Code LLaMA将base设为1000000,LLaMA2 Long设为500000,但更大的base也将会使得注意力远程衰减的性质变弱,改变模型的注意力分布,导致模型的输出质量下降。如下图所示。
notion image
RoPE位置编码,以向量旋转这种简单巧妙的方式,实现了绝对位置编码,并且具备相对位置编码的能力。RoPE目前广泛应用于各种大模型,包括但不限于Llama、Baichuan、ChatGLM、Qwen等。基于RoPE的长度外推工作不断涌现,并且获得了非常优秀的效果。如果当前你需要研究大模型的长度外推工作,那么弄清楚RoPE的底层原理则为一门必修课。

代码实验

llama中的代码实验
chatglm中的代码实现

参考文章

 
💡
有关Notion安装或者使用上的问题,欢迎您在底部评论区留言,一起交流~
大模型之ChatGLM大模型之LLaMA
  • Twikoo