Position Encoding(位置编码)

介绍位置编码的基本原理、常见方法(正余弦编码、可学习编码、RoPE、ALiBi)及长度外推问题的解决方案

什么是位置编码

  • 假设序列长度为 LL、模型维度为 dmodeld_{\text{model}},输入嵌入可表示为:

    InputEmbedding[i]=TokenEmbedding[i]+PositionalEncoding[i]\text{InputEmbedding}[i] = \text{TokenEmbedding}[i] + \text{PositionalEncoding}[i]
    • TokenEmbedding[i]\text{TokenEmbedding}[i]:表示 token 的语义信息

    • PositionalEncoding[i]\text{PositionalEncoding}[i]:表示 token 的位置信息

  • Transformer 没有循环或卷积结构,所以无法天然知道 token 的顺序,因此需要给每个 token 添加位置信息

  • 位置编码大体上分为两种方法:

    • 绝对位置编码:通过给序列中的每个 token 分配 “某个固定位置的向量”,包括正余弦位置编码(Transformers 模型)、可学习位置编码(BERT 模型)、旋转位置编码(LlaMa 模型)
    • 相对位置编码:显式地表示 token 之间 “距离” 的信息,而不是它们的绝对位置
  • 用整型值标记位置

    • 一种自然而然的想法是,给第一个 token 标记 1,给第二个 token 标记 2...,以此类推
    • 这种方法产生了以下几个主要问题
      • 模型可能遇见比训练时所用的序列更长的序列。不利于模型的泛化
      • 模型的位置表示是无界的;随着序列长度的增加,位置值会越来越大
  • 用 [0,1] 范围标记位置

    • 为了解决整型值带来的问题,可以考虑将位置值的范围限制在 [0, 1] 之内,其中,0 表示第一个 token,1 表示最后一个 token
    • 比如有 3 个 token,那么位置信息就表示成 [0, 0.5, 1];若有四个 token,位置信息就表示成 [0, 0.33, 0.69, 1]
    • 但这样产生的问题是,当序列长度不同时,token 间的相对距离是不一样的;例如在序列长度为 3 时,token 间的相对距离为 0.5;在序列长度为 4 时,token 间的相对距离就变为 0.33
  • 因此,需要这样一种位置表示方式,满足:

    • 它能用来表示一个 token 在序列中的绝对位置
    • 在序列长度不同的情况下,不同序列中 token 的相对位置 / 距离也要保持一致
    • 可以用来表示模型在训练过程中从来没有看到过的句子长度
  • 考虑到位置信息作用在 input embedding 上,因此比起用单一的值,更好的方案是用一个和 input embedding 维度一样的向量来表示位置

    • 很容易想到可以使用二进制编码
    • 但是这样编码出来的位置向量,处于一个离散的空间中,不同位置间的变化是不连续的
    • 如果能把离散空间转换到连续空间,那么就能解决位置距离不连续的问题
    • 同时,不仅能用位置向量表示整型,还可以用位置向量来表示浮点型

正余弦位置编码

  • 通过以上分析,需要一个有界又连续的函数,最简单的正弦函数可以满足这个条件

  • 考虑将位置向量中的每个元素都用一个 sin 函数来表示,那么第 t 个 token 的位置向量可以表示为

    PEt=[sin⁡(120t),sin⁡(121t),…,sin⁡(12i−1t),…,sin⁡(12dmodel−1t)]PE_t = \left [\sin\left (\frac {1}{2^0} t\right), \sin\left (\frac {1}{2^1} t\right), \dots, \sin\left (\frac {1}{2^{i-1}} t\right), \dots, \sin\left (\frac {1}{2^{d_{\text{model}}-1}} t\right) \right]
  • 显然,维度索引越大,对应的值随着 t 的变化程度越小

  • 由于 sin 的周期函数,从不同的 t 的角度来看,如果函数的频率偏大,波长偏短,那么不同 t 下的位置向量可能重合,为了避免这种情况,可以将这个频率设置为很小的值

    PEt=[sin⁡(w0t),sin⁡(w1t),…,sin⁡(wi−1t),…,sin⁡(wdmodel−1t)],wi=110000i/(dmodel−1)PE_t = \left [\sin (w_0 t), \sin (w_1 t), \dots, \sin (w_{i-1} t), \dots, \sin (w_{d_{\text{model}}-1} t) \right],\quad w_i = \frac {1}{10000^{i/(d_{\text{model}}-1)}}
  • 通过 sin 函数,实现了

    • 每个 token 的向量唯一(每个 sin 函数的频率足够小)
    • 位置向量的值是有界的,且位于连续空间中;模型在处理位置向量时更容易泛化,即更好处理长度和训练数据分布不一致的序列(sin 函数本身的性质)
  • 现在有个新的需求,不同的位置向量是可以通过线性变换得到的,这样就可以表示一个 token 的相对位置

    PEt+Δt=TΔt∗PEtPE_{t+\Delta t} = T_{\Delta t} * PE_t
  • 这里的 T 就是一个线性变换矩阵

  • 将 t 想象为一个角度,那么 Δt\Delta t 就是其旋转的角度,则有

    (sin⁡(t+Δt)cos⁡(t+Δt))=(cos⁡Δtsin⁡Δt−sin⁡Δtcos⁡Δt)(sin⁡tcos⁡t)\begin {pmatrix} \sin (t + \Delta t) \\ \cos (t + \Delta t) \end {pmatrix} = \begin {pmatrix} \cos \Delta t & \sin \Delta t \\ -\sin \Delta t & \cos \Delta t \end {pmatrix} \begin {pmatrix} \sin t \\ \cos t \end {pmatrix}
  • 由此,可以修改原来均为 sin 函数的位置编码,让位置两两一组,分别用 sin 和 cos 函数来表示

    PEt=[sin⁡(w0t),cos⁡(w0t),sin⁡(w1t),cos⁡(w1t),…,sin⁡(wdmodel2−1t),cos⁡(wdmodel2−1t)]PE_t = \left [\sin (w_0 t), \cos (w_0 t), \sin (w_1 t), \cos (w_1 t), \dots, \sin (w_{\frac {d_{\text{model}}}{2}-1} t), \cos (w_{\frac {d_{\text{model}}}{2}-1} t) \right]
  • 从而得到一个线性变换公式

    PEt+△t=T△t∗PEt=([cos(w0△t)sin(w0△t)−sin(w0△t)cos(w0△t)]...0.........0...[cos(wdmodel2−1△t)sin(wdmodel2−1△t)−sin(wdmodel2−1△t)cos(wdmodel2−1△t)])(sin(w0t)cos(w0t)...sin(wdmodel2−1t)cos(wdmodel2−1t))=(sin(w0(t+△t))cos(w0(t+△t))...sin(wdmodel2−1(t+△t))cos(wdmodel2−1(t+△t)))\begin {align*} PE_{t+\bigtriangleup t} &= T_{\bigtriangleup t} * PE_{t} \\ &=\begin {pmatrix} \begin {bmatrix} cos (w_0\bigtriangleup t)& sin (w_0\bigtriangleup t)\\ -sin (w_0\bigtriangleup t)& cos (w_0\bigtriangleup t) \end {bmatrix}&...&0 \\ ...& ...& ...\\ 0& ...& \begin {bmatrix} cos (w_{\frac {d_{model}}{2}-1 }\bigtriangleup t)& sin (w_{\frac {d_{model}}{2}-1}\bigtriangleup t)\\ -sin (w_{\frac {d_{model}}{2}-1}\bigtriangleup t)& cos (w_{\frac {d_{model}}{2}-1}\bigtriangleup t) \end {bmatrix} \end {pmatrix}\begin {pmatrix} sin (w_0t)\\ cos (w_0t)\\ ...\\ sin (w_{\frac {d_{model}}{2}-1} t)\\ cos (w_{\frac {d_{model}}{2}-1} t) \end {pmatrix}\\ & = \begin {pmatrix} sin (w_0 (t+\bigtriangleup t))\\ cos (w_0 (t+\bigtriangleup t))\\ ...\\ sin (w_{\frac {d_{model}}{2}-1}(t+\bigtriangleup t))\\ cos (w_{\frac {d_{model}}{2}-1}(t+\bigtriangleup t)) \end {pmatrix} \end {align*}
  • 正弦 / 余弦位置编码(Sinusoidal Positional Encoding)最初由 Transformer 模型提出:

    PE(pos,2i)=sin⁡(pos100002i/dmodel)PE(pos,2i+1)=cos⁡(pos100002i/dmodel)\begin {align*} \text{PE}_{(pos, 2i)} &= \sin\left (\frac {pos}{10000^{2i/d_{\text{model}}}}\right) \\ \text{PE}_{(pos, 2i+1)} &= \cos\left (\frac {pos}{10000^{2i/d_{\text{model}}}}\right) \end {align*}
    • pospos 为 token 在序列中的位置(0,1,2,...,L-1)

    • ii​ 为向量的维度索引(0,1,2,...,d_model/2 -1)

    • 输入:序列长度 L、嵌入维度 d_model

    • 输出:形状为 [L, d_model] 的位置编码矩阵,可以直接加到 token 嵌入上

  • 正余弦位置编码的性质

    • 两个位置编码的点积仅取决于偏移量 Δt\Delta t​,也即两个位置编码的点积可以反应出两个位置编码间的距离

      PEtT∗PEt+△t=∑i=0dmodel2−1[sin⁡(wit)sin⁡(wi(t+△t))+cos⁡(wit)cos⁡(wi(t+△t))]=∑i=0dmodel2−1cos⁡(wi(t−(t+△t)))=∑i=0dmodel2−1cos⁡(wi△t)\begin {align*} PE_t^T * PE_{t+\triangle t} &= \sum_{i=0}^{\frac {d_{\text{model}}}{2}-1} \left [\sin (w_i t)\sin (w_i (t+\triangle t)) + \cos (w_i t)\cos (w_i (t+\triangle t)) \right] \\ &= \sum_{i=0}^{\frac {d_{\text{model}}}{2}-1} \cos\left (w_i \left ( t - (t+\triangle t) \right)\right) \\ &= \sum_{i=0}^{\frac {d_{\text{model}}}{2}-1} \cos (w_i \triangle t) \end {align*}
    • 位置编码的点积是无向的

      PEtT∗PEt+△t=PEtT∗PEt−△tPE_t^T * PE_{t+\triangle t} = PE_t^T * PE_{t-\triangle t}
    • 因此,以上位置编码能够表示距离,但是却不能用来表示位置的方向性

  • 当位置编码随着输入被送入 attention 层时,其映射方式为

    PEtTWQTWKPEt+kPE_t^T W_Q^T W_K PE_{t+k}
  • 其推导如下

    QKT=(EWQ+PEWQ)(EWK+PEWK)T=(EWQ)(EWK)T+(EWQ)(PEWK)T+(PEWQ)(EWK)T+(PEWQ)(PEWK)T\begin {align*} Q K^T &= (E W_Q + PE W_Q) (E W_K + PE W_K)^T \\ &= (E W_Q)(E W_K)^T + (E W_Q)(PE W_K)^T + (PE W_Q)(E W_K)^T + (PE W_Q)(PE W_K)^T \end {align*}
  • 其中最后一项完全由位置编码确定

  • 关注两个特定位置 t 和 t+k 之间的注意力分数,则有

    (PEtWQ)(PEt+kWK)T=PEtWQWKTPEt+kT=PEtTWQTWKPEt+k\begin {align*} (PE_t W_Q)(PE_{t+k} W_K)^T &= PE_t W_Q W_K^T PE_{t+k}^T\\ &=PE_t^T W_Q^T W_K PE_{t+k} \end {align*}
  • 由此可见,位置编码在进入 attention 层后,内积的距离意识的模式遭到了破坏

  • 分析

    • 确定性
      • 与需要通过训练获得的可学习位置编码不同,正余弦位置编码由预先定义的固定函数生成,因此是确定性的
      • 对于任意位置 pos 和维度索引 i,其取值恒定,不依赖训练过程,也不引入额外的可学习参数
    • 有界性
      • 正弦和余弦函数的取值范围限制在 [−1,1][-1,1] 内,在与词嵌入相加时,不会显著改变组合后表示的整体尺度
      • 这种有界特性有助于保持表示的数值稳定性,从而使训练过程更加平稳
    • 平滑性
      • 正余弦函数随位置连续、平滑变化,因此相邻位置 pospos 与 pos+1pos+1 的位置编码彼此相似
      • 这一性质与自然语言中相邻词语往往具有强上下文相关性的直觉相一致
    • 外推能力
      • 由于正余弦位置编码由固定函数定义,而非从有限长度的训练数据中学习,它可以为任意位置生成编码
      • 因此,在处理超过训练序列长度的输入时,位置编码本身不会失效或产生未定义表示,相较于学习型位置嵌入具备更好的外推性(尽管模型整体性能仍可能受其他因素限制)
  • 尽管具备确定性和可外推的形式定义,正余弦位置编码在实践中并不能可靠地从训练序列长度泛化到显著更长的未见长度:

    • 高频维度的周期性问题
      • 正余弦位置编码由一组不同频率的正弦和余弦函数组成,其中高频分量的周期较短
      • 当位置 pospos 远超训练范围时,这些高频维度会发生周期性重复,导致不同位置之间出现相似甚至重叠的相位表示,从而削弱位置区分能力
    • 语义解读能力受训练范围限制
      • 模型在训练过程中仅在 [0,Ltrain][0, L_{train}] 的位置范围内接触到这些正余弦信号
      • 因此,模型实际学到的是如何在该有限区间内解读不同维度的相位组合,例如哪些频率对应 “近距离” 关系,哪些反映 “远距离” 依赖,哪些维度刻画整体结构上的衰减模式
      • 当位置超出训练长度时,虽然位置编码函数本身仍然定义良好,但这些相位组合落入了模型从未见过的分布区域,导致已学到的解读方式不再可靠

可学习位置编码

  • 可学习位置编码不依赖预定义的数学函数,而是将序列中的每个绝对位置视为一个可学习的 “符号”:

    • 在模型设计阶段预先设定最大支持序列长度 LmaxL_{max}(如 512、1024、2048)
    • 构造一个位置嵌入矩阵 P∈RLmax×dmodelP \in \mathbb {R}^{L_{max} \times d_{model}},其中第 ii 行 PiP_i 表示位置 ii 的嵌入向量,满足 0≤i<Lmax0 \le i <L_{max}
    • 该矩阵通常随机初始化,并在训练过程中通过反向传播与模型其他参数一同优化
  • 给定长度为 LL(L≤LmaxL \le L_{max})的输入序列:

    • 首先得到词向量 Etoken∈RL×dmodelE_{token} \in \mathbb {R}^{L \times d_{model}}

    • 再从 PP 中取出前 LL 个位置嵌入,构成

      Eposition=[P0,P1,…,PL−1]∈RL×dmodelE_{position} = [P_0, P_1, \dots, P_{L-1}] \in \mathbb {R}^{L \times d_{model}}
    • 最终输入表示为逐元素相加:

      Einput=Etoken+EpositionE_{input} = E_{token} + E_{position}
  • 外推能力受限

    • 位置嵌入仅为 [0,Lmax)[0, L_{max}) 范围内的位置定义
    • 当序列长度超过 LmaxL_{max} 时,模型无法直接处理,通常需要重新训练或引入额外策略
    • 相比之下,正弦位置编码可为任意位置生成定义良好的编码
  • 参数量增加

    • 额外引入 Lmax×dmodelL_{max} \times d_{model} 个可训练参数
    • 当 LmaxL_{max} 或 dmodeld_{model} 较大时,会显著增加模型规模、显存占用和过拟合风险
  • 数据依赖性强

    • 学习稳定、有效的位置表示通常需要充足的数据
    • 在数据有限的情况下,正弦编码的结构性归纳偏置往往更有利于泛化

旋转位置编码

  • 在正余弦位置编码中提到

    (sin⁡θ(t+Δt)cos⁡θ(t+Δt))=(cos⁡θΔtsin⁡θΔt−sin⁡θΔtcos⁡θΔt)∗(sin⁡θtcos⁡θt)=RΔt∗(sin⁡θtcos⁡θt)\begin {pmatrix} \sin\theta (t + \Delta t) \\ \cos\theta (t + \Delta t) \end {pmatrix} = \begin {pmatrix} \cos\theta\Delta t & \sin\theta\Delta t \\ -\sin\theta\Delta t & \cos\theta\Delta t \end {pmatrix} * \begin {pmatrix} \sin\theta t \\ \cos\theta t \end {pmatrix} = \mathcal {R}_{\Delta t} * \begin {pmatrix} \sin\theta t \\ \cos\theta t \end {pmatrix}
  • 由于 RΔt\mathcal {R}_{\Delta t} 是一个表示顺时针旋转的正交矩阵(不改变向量的模长,只改变方向),则 PEt+ΔtPE_{t+\Delta t} 其实就是以 PEtPE_t 为基础,顺时针旋转 θ∗Δt\theta * \Delta t 角度而来,因此有

    PEtT∗PEt+Δt=∥PEt∥∗∥PEt+Δt∥∗cos⁡(θΔt)PE_t^T * PE_{t+\Delta t} = \|PE_t\| * \|PE_{t+\Delta t}\| * \cos (\theta \Delta t)
  • 固定某个 t 不变,慢慢增大 Δt\Delta t 时,上式变小,因此相距较远的两个位置编码的内积越小,即内积可以用于反馈两个位置向量在绝对位置上的远近

  • 为了避免周期过小,导致距离较远的位置编码反而内积接近,可以让每次位置变动时的转动角度小一些,也即把 θ\theta 设置得小一些

  • 上文推导得到,经过 attention 层后,位置编码真正起作用的是引入了线性变化后的 PEtTWQTWKPEt+kPE_t^T W_Q^T W_K PE_{t+k}​,而引入了这个线性变化后,会极大的破坏位置编码设计之初的各种优良性质

  • 自然而然地,可以直接在 attention 层融入位置信息,也就是直接把位置编码作用于 qtTkt+Δtq_t^Tk_{t+\Delta t},下面用 m 和 n 表示两个位置

  • 在计算 qmTknq_m^Tk_n 时,这个相关性分数就是两个特征向量之间的乘积,在一定程度上衡量了两个向量之间的相似性,那么希望可以直接将位置编码的信息直接引入其中,也即根据 |n-m| 的结果,给这个内积计算一定的惩罚,当 |n-m| 较小时,拉近两个向量的距离;否则拉远两者的距离

  • 假如将 qmq_m 逆时针旋转 m 度,knk_n 逆时针旋转 n 度,那么当 m 和 n 差距较大时,两个向量的角度也变大,其内积随之降低

  • 这里同样需要引入参数 θ\theta,通过拉长三角函数周期的方式确保不同位置的向量不会发生碰撞,由此定义了一个逆时针正交旋转矩阵

    Ri=(cos⁡iθ−sin⁡iθsin⁡iθcos⁡iθ)\mathcal {R}_i = \begin {pmatrix} \cos i\theta & -\sin i\theta \\ \sin i\theta & \cos i\theta \end {pmatrix}
  • 其中,i 表示绝对位置,将上式作用于 attention 计算,得到

    (Rmqm)T(Rnkn)=[(cos⁡mθ−sin⁡mθsin⁡mθcos⁡mθ)∗(q0q1)]T[(cos⁡nθ−sin⁡nθsin⁡nθcos⁡nθ)∗(k0k1)]=(q0q1)∗(cos⁡((n−m)θ)−sin⁡((n−m)θ)sin⁡((n−m)θ)cos⁡((n−m)θ))∗(k0k1)=qmTRn−mkn\begin {align*} (\mathcal {R}_m q_m)^T (\mathcal {R}_n k_n) &= \left [\begin {pmatrix} \cos m\theta & -\sin m\theta \\ \sin m\theta & \cos m\theta \end {pmatrix} * \begin {pmatrix} q_0 \\ q_1 \end {pmatrix} \right]^T \left [\begin {pmatrix} \cos n\theta & -\sin n\theta \\ \sin n\theta & \cos n\theta \end {pmatrix} * \begin {pmatrix} k_0 \\ k_1 \end {pmatrix} \right] \\ &= \begin {pmatrix} q_0 & q_1 \end {pmatrix} * \begin {pmatrix} \cos ((n-m)\theta) & -\sin ((n-m)\theta) \\ \sin ((n-m)\theta) & \cos ((n-m)\theta) \end {pmatrix} * \begin {pmatrix} k_0 \\ k_1 \end {pmatrix} \\ &= q_m^T \mathcal {R}_{n-m} k_n \end {align*}
  • 可以发现

    • Rmqm,Rnkm\mathcal {R}_m q_m, \mathcal {R}_n k_m:两者分别赋予 qm,kmq_m, k_m 绝对位置信息
    • Rn−m\mathcal {R}_{n-m}​:绝对位置信息相乘的结果拥有了相对位置的概念
  • 前述讨论均在二维特征空间下进行,那么到了高维特征空间,位置编码如何设计,也即(其中 d 就是 hidden_size)

    qm=(q0q1q2q3⋯qd−2qd−1)q_m = \begin {pmatrix} q_0 \\ q_1 \\ q_2 \\ q_3 \\ \cdots \\ q_{d-2} \\ q_{d-1} \end {pmatrix}
  • 过小的 θ\theta 会导致旋转角度十分微弱,不同位置的向量几乎重合,那么应该如何设计高维位置向量的每一个维度的值?

  • 可以将 qmq_m 中的维度两两为一组,这样每一组都可以视为一个旋转速度不一样的指针,因此可以用 d//2d//2 个指针来表示 qmq_m 的位置向量,即

    Rmq=([cos⁡(mθ0)−sin⁡(mθ0)sin⁡(mθ0)cos⁡(mθ0)]⋯0⋯⋯⋯0⋯[cos⁡(mθd/2−1)−sin⁡(mθd/2−1)sin⁡(mθd/2−1)cos⁡(mθd/2−1)])(q0q1⋯qd−2qd−1)\mathcal {R}_m q = \begin {pmatrix} \begin {bmatrix} \cos (m\theta_0) & -\sin (m\theta_0) \\ \sin (m\theta_0) & \cos (m\theta_0) \end {bmatrix} & \cdots & 0 \\ \cdots & \cdots & \cdots \\ 0 & \cdots & \begin {bmatrix} \cos (m\theta_{d/2-1}) & -\sin (m\theta_{d/2-1}) \\ \sin (m\theta_{d/2-1}) & \cos (m\theta_{d/2-1}) \end {bmatrix} \end {pmatrix} \begin {pmatrix} q_0 \\ q_1 \\ \cdots \\ q_{d-2} \\ q_{d-1} \end {pmatrix}
  • 由于 RmR_m 是一个稀疏矩阵,因此经常拆分为以下算式

    (q0q1q2q3⋯qd−2qd−1)⊗(cos⁡mθ0cos⁡mθ0cos⁡mθ1cos⁡mθ1⋯cos⁡mθd/2−1cos⁡mθd/2−1)+(−q1q0−q3q2⋯−qd−1qd−2)⊗(sin⁡mθ0sin⁡mθ0sin⁡mθ1sin⁡mθ1⋯sin⁡mθd/2−1sin⁡mθd/2−1)\begin {pmatrix} q_0 \\ q_1 \\ q_2 \\ q_3 \\ \cdots \\ q_{d-2} \\ q_{d-1} \end {pmatrix} \otimes \begin {pmatrix} \cos m\theta_0 \\ \cos m\theta_0 \\ \cos m\theta_1 \\ \cos m\theta_1 \\ \cdots \\ \cos m\theta_{d/2-1} \\ \cos m\theta_{d/2-1} \end {pmatrix} + \begin {pmatrix} -q_1 \\ q_0 \\ -q_3 \\ q_2 \\ \cdots \\ -q_{d-1} \\ q_{d-2} \end {pmatrix} \otimes \begin {pmatrix} \sin m\theta_0 \\ \sin m\theta_0 \\ \sin m\theta_1 \\ \sin m\theta_1 \\ \cdots \\ \sin m\theta_{d/2-1} \\ \sin m\theta_{d/2-1} \end {pmatrix}
  • 为了满足不同维度索引的旋转特性,又不能让 θ\theta 太大,可以设

    θi=10000−2i/d, i=0,1,2,…,d/2−1\theta_i = 10000^{-2i/d},\ i = 0, 1, 2, \dots, d/2 - 1
  • 其中,10000 这个数决定了 θ\theta 的大小,称之为基数(base)

    • 较大的 base 使得 θ\theta​ 较小,相当于加大了分量的周期,使其变得更宽更平缓,此时训练范围内的可容忍位置距离都不会相位重合
    • 如果用 “大基数 + 长文本” 训练模型,那么每个圆盘的旋转速度都变慢,这样训练完后大部分圆盘都没有转完一圈,位置编码信息训练不到位
    • 如果用 “小基数 + 短数据” 训练模型,虽然有更多的圆盘旋转过一周,但并不是圆盘上的每个点都能训练到
    • 在研究位置编码的外推性或者研究基数选择对外推性的影响时,可以从以上角度进行思考
  • 目前训练长文本的一个常用方法:

    • 先用 “小基数 + 短数据” 做训练(让每个圆盘都尽量转满一圈)
    • 再用 “大基数 + 长文本” 做微调(弥补圆盘上的空隙)
  • 当已经有一个训练后的模型,希望继续在更长的文本上继续预训练 / 推理时,希望能够

    • 尽量不要便宜已经训练过的圆周范围,即尽可能利用已经训练好的位置相关信息
    • 尽量学到比 pretrain 更多的位置信息
  • 显然,当从位置 50 变动到 10000 时

    • 靠前的圆盘
      • 尽量让它学习到【绝对位置】信息,尝试突破 pretrain 看过的圆周部分(外推)
      • 对应长距离依赖(比如段落间、上下文的关联),对缩放不敏感,适合外推(Extrapolation)(不压缩频率,保留长距离旋转信息)
    • 靠后的圆盘
      • 尽量让它学习到【相对位置】信息,保持在 pretrain 看过的圆周部分,只做精细角度的训练(内插)
      • 对应短距离依赖(比如词内、相邻词的关联),对缩放更敏感,适合插值(Interpolation)(压缩频率,适配更长序列)
  • 最后一个圆盘的推导

    • 假设 pretrain 阶段的训练文本长度为 SpreS_{pre},最后一个圆盘的转动角度为 θd//2−1\theta_{d//2-1},则绕着圆盘转动一周会经过 2πθd//2−1\frac {2\pi}{\theta_{d//2-1}} 个 tokens,那么 pretrain 阶段转过的周数为:

      Spre∗θd//2−12π\frac {S_{pre} * \theta_{d//2-1}}{2\pi}
    • 假设 continue-pretrain/inference 阶段的文本长度为 SpostS_{post},理想的圆盘转动角度为 θd//2−1∗\theta^*_{d//2-1},那么希望:

      Spre∗θd//2−12π=Spost∗θd//2−1∗2π\frac {S_{pre} * \theta_{d//2-1}}{2\pi} = \frac {S_{post} * \theta^*_{d//2-1}}{2\pi}
    • 求解得:

      θd//2−1∗=SpreSpost∗θd//2−1\theta^*_{d//2-1} = \frac {S_{pre}}{S_{post}} * \theta_{d//2-1}
    • 因此,对于最后一个圆盘,只需要对原始的旋转角度乘以缩放因子 SpreSpost\frac {S_{pre}}{S_{post}} 即可满足严格限制在预训练学习到的位置范围内

    • 在实际操作时,一般通过控制 base 来实现这个需求,即令下式在 i=d//2−1i=d//2-1 的条件下成立即可,其中 λ\lambda 即为 base 的缩放因子

      1(10000λ)2i/d=SpreSpost∗1100002i/d\frac {1}{(10000 \lambda)^{2i/d}} = \frac {S_{pre}}{S_{post}} * \frac {1}{10000^{2i/d}}
    • 从而得到

      λ=(SpostSpre)dd−2\lambda = \left (\frac {S_{post}}{S_{pre}} \right)^{\frac {d}{d-2}}
  • 事实上,将这个固定的 λ\lambda 值带入到前面的圆盘的基数中,也均可以实现位置的外推;同时受到 i 的影响,越往前的圆盘,超出 pretrain 训练过的位置越多

ALiBi

  • 在普通注意力机制中,注意力分数为:

    scoreij=Qi⋅Kjd\text{score}_{ij} = \frac {Q_i \cdot K_j}{\sqrt {d}}
  • ALiBi(Attention with Linear Biases)不修改 token embedding,也不使用显式位置向量,而是直接在注意力分数中加入距离惩罚:

    scoreij=Qi⋅Kjd−mh(i−j)\text{score}_{ij} = \frac {Q_i \cdot K_j}{\sqrt {d}} - m_h (i - j)
    • ii 为当前 token 的位置

    • jj 为被关注的 token 的位置

    • mhm_h 为第 hh 个注意力头的固定斜率(不同头使用不同斜率)

![alibi 原理图](/img/llm/alibi 原理图.png)

  • 该设计使得:

    • 距离越远,惩罚越大,注意力权重越小,模型天然偏向关注局部上下文

    • 不引入额外位置向量,能够在训练长度之外自然外推,可用于长序列建模

  • 对于任意一对位置 (i,j)(i, j),ALiBi 只关注它们的相对距离 ∣i−j∣|i - j|,并对注意力得分施加线性、无参数增长的惩罚

  • 具体而言,注意力分数会额外减去一项与距离成正比的偏置:

    Δij=m⋅∣i−j∣\Delta_{ij} = m \cdot |i - j|
    • 其中 mm 为固定斜率,不随序列长度增长
    • 因此在任意长度的序列中,例如距离为 50005000 的位置对,惩罚始终为 5000×m5000 \times m,与训练时的最大上下文无关
    • 这一机制使模型在长序列推理时仍能保持稳定表现
    • 同时,模型不需要额外训练位置编码,偏置直接作用于 attention 分数,使得远距离 token 的位置信息依然可区分
    • 因此,Alibi 在长序列外推时表现比 RoPE 更稳定
  • 实际设计中,ALiBi 为每个注意力头分配不同的线性斜率(HH 是注意力头个数):

    mh=12h/Hm_h = \frac {1}{2^{h/H}}
    • 低序号头 (hh 小):衰减快,偏向捕捉局部依赖

    • 高序号头 (hh 大):衰减慢,偏向捕捉长距离依赖

    • 这种设计使多头注意力在序列长度上天然分工,提高模型对不同范围依赖的建模能力

长度外推问题

  • 为什么会出现长度外推问题

    • Transformer 的位置编码在训练区间之外缺乏泛化能力,长度外推性本质上来自train-short 与 test-long 的结构性矛盾

    • 在训练阶段,序列长度通常较短:

      • 受限于训练成本,长序列显著增加计算量与内存开销

      • 真实语料存在严重长尾分布,大部分文本并不长,因此设置极大 max_length\text{max\_length} 在统计意义上并不有效

    • 在测试阶段,希望模型在远超训练长度的输入上仍保持性能,即test-long:

      Ltest≫LtrainL_{\text{test}} \gg L_{\text{train}}
    • 但由于 Transformer 的位置编码是按训练域拟合的函数,超过训练位置后会出现无法控制的外推偏差

  • 当输入长度超出训练区间数倍时,模型常出现以下退化现象:

    • 生成语义不连贯或无意义文本

    • 注意力坍塌,仅关注序列开头或结尾

    • 失去对上下文的有效利用

    • 出现重复、幻觉或乱码式输出

    • 多轮对话质量显著下降

    • 推理任务准确率骤降至接近随机水平

  • 为了做到长度外推性,需要解决两个主要问题

    • 预测阶段的位置编码外推偏差:当模型在推理时遇到训练中未出现过的位置索引,即使位置编码本身是非学习式(如正弦编码、RoPE),也会产生外推偏差,其原因在于:

      • 虽然位置编码函数本身可定义在无限区间上,但上层参数(如注意力、前馈层)是在训练区间内拟合该位置嵌入分布的
      • 未见过的位置将产生未被模型参数 “校准” 的向量,从而导致注意力结构和表示空间发生漂移
      • 学习式位置编码(如 APE、T5 相对位置偏置)更明显地无法外推,但非学习式编码同样会影响上层参数的泛化性
      • 因此,位置编码不仅要形式上可外推,更需要在训练过程中避免对有限长度区间的过拟合
    • 长序列导致注意力熵显著增大:在推理时,序列长度 Ltest≫LtrainL_\text{test} \gg L_\text{train} 会改变注意力的统计结构:

      • 随着 LL 增大,softmax 分布的熵上升,注意力更分散

      • 如果训练阶段仅在短序列上优化,模型会倾向于将注意力集中在局部区域,并学习到与短上下文相关的归纳偏置

      • 长序列输入会破坏这种偏置,导致:

        AttnEntropy(L_test)≫AttnEntropy(L_train)\text{AttnEntropy}(L\_\text{test}) \gg \text{AttnEntropy}(L\_\text{train})

        结果是注意力无法集中,各 token 难以聚焦于关键信息,最终造成性能下降

RoPE 的理论推导

1. RoPE 的核心目标

  • 在 Transformer 中,注意力得分为

    scoremn=Qm⋅Kn\text{score}_{mn} = Q_m \cdot K_n
  • 若希望注意力依赖相对位置 (m−n)(m-n) 而非绝对位置 (m,n)(m,n),需满足

    ⟨f(q,m),f(k,n)⟩=g(q,k,m−n)\langle f (q,m), f (k,n) \rangle = g (q,k,m-n)
    • 其中 f(⋅)f (\cdot) 为加入位置后的向量

2. 用复数形式推导

  • 将二维向量映射为复数,如 q↦q0+iq1q \mapsto q_0 + i q_1,内积可写为

    ⟨q,k⟩=Re⁡[qk∗]\langle q,k \rangle = \operatorname {Re}[q k^*]
  • 设

    f(q,m)=Rf(q,m)eiΘf(q,m)f(k,n)=Rf(k,n)eiΘf(k,n)\begin {align*} f (q,m) &= R_f (q,m) e^{i\Theta_f (q,m)}\\ f (k,n) &= R_f (k,n) e^{i\Theta_f (k,n)} \end {align*}
  • 代入得到

    Re⁡[f(q,m)f∗(k,n)]=g(q,k,m−n)\operatorname {Re}[f (q,m) f^*(k,n)] = g (q,k,m-n)

3. 分解模长和长度

  • 得到两组条件

    {Rf(q,m)Rf(k,n)=Rg(q,k,m−n)Θf(q,m)−Θf(k,n)=Θg(q,k,m−n)\begin {cases} R_f (q,m) R_f (k,n)=R_g (q,k,m-n)\\ \Theta_f (q,m)-\Theta_f (k,n)=\Theta_g (q,k,m-n) \end {cases}
  • 对模长:当 m=nm=n 时有

    Rf(q,m)Rf(k,m)=∥q∥∥k∥ ⇒ Rf(q,m)=∥q∥R_f (q,m) R_f (k,m)=\Vert q\Vert\Vert k\Vert\ \Rightarrow\ R_f (q,m)=\Vert q\Vert
  • 对角度,说明位置相关性仅体现在角度差:

    Θf(q,m)−Θf(k,m)=Θ(q)−Θ(k)\Theta_f (q,m)-\Theta_f (k,m)=\Theta (q)-\Theta (k)

4. 角度的等差结构

  • 若位置递增的角度增量为常数 θ\theta,则

    φ(m)=mθ.\varphi (m)=m\theta.
  • 因此得到复数形式的旋转位置编码

    f(q,m)=q,eimθf(k,n)=k,einθ\begin {align*} f (q,m)=q,e^{im\theta}\\ f (k,n)=k,e^{in\theta} \end {align*}

5. 转为 2D 旋转矩阵形式

  • 对二维向量 (q0,q1)(q_0,q_1),旋转 mθm\theta 等价于 f(q,m)=(cos⁡(mθ)−sin⁡(mθ)sin⁡(mθ)cos⁡(mθ))(q0 q1).f (q,m)= \begin {pmatrix} \cos (m\theta) & -\sin (m\theta)\\ \sin (m\theta) & \cos (m\theta) \end {pmatrix} \begin {pmatrix} q_0\ q_1 \end {pmatrix}.

6. 注意力分数依赖相对位置

  • 将 dd 维向量分成 d/2d/2 个二维子空间,每个子空间使用不同频率 θi\theta_i,则

    (Qmrot)⊤Knrot=Re⁡![∑i=0d/2−1q[2i:2i+1],k[2i:2i+1]∗,ei(m−n)θi](Q_m^{\text{rot}})^\top K_n^{\text{rot}} = \operatorname {Re}!\left [\sum_{i=0}^{d/2-1} q_{[2i:2i+1]}, k_{[2i:2i+1]}^*, e^{i (m-n)\theta_i} \right]
  • 结果仅依赖位置差 (m−n)(m-n),实现相对位置编码并具备良好外推性

7. 直观理解

  • 将每个 token 的某个维度对映成二维子向量
  • 每个位置对该子向量施加固定角度增量
  • 注意力内积的有效位置信息来自旋转差,即 (m−n)(m-n)
  • 高频维度捕获局部依赖;低频维度捕获长程依赖

更通俗的推导

  • RoPE(Rotary Position Embedding)把每个 token 的表示按维度两两分组,当成复数:

    x=(x1,x2,x3,x4,… )⇒(x1+ix2,x3+ix4,… )x = (x_1, x_2, x_3, x_4, \dots) \Rightarrow (x_1 + i x_2, x_3 + i x_4, \dots)
  • 对第 pp 个位置,引入一个角度 θp\theta_p,做旋转:

    xp′=xp⋅eiθpx_p^{\prime} = x_p \cdot e^{i \theta_p}
  • 展开成实数就是:

    x2k′=x2kcos⁡θp−x2k+1sin⁡θpx2k+1′=x2ksin⁡θp+x2k+1cos⁡θp\begin {aligned} x_{2k}^{\prime} &= x_{2k} \cos \theta_p - x_{2k+1} \sin \theta_p \\ x_{2k+1}^{\prime} &= x_{2k} \sin \theta_p + x_{2k+1} \cos \theta_p \end {aligned}
  • 关键在 attention 的内积:

    ⟨qp′,kq′⟩\langle q_p^{\prime}, k_q^{\prime} \rangle
  • 代入旋转:

    qp′=qp⋅eiθpkq′=kq⋅eiθq\begin {align*} q_p^{\prime} = q_p \cdot e^{i\theta_p}\\ k_q^{\prime} = k_q \cdot e^{i\theta_q} \end {align*}
  • 内积变成:

    ⟨qp′,kq′⟩=⟨qp,kq⟩⋅ei(θp−θq)\langle q_p^{\prime}, k_q^{\prime} \rangle = \langle q_p, k_q \rangle \cdot e^{i (\theta_p - \theta_q)}
  • attention 的结果只依赖 相对位置差 p−qp-q,而不是绝对位置 —— 这就是 RoPE 能编码相对位置的本质

YaRNRoPE

  • 论文:[2309.00071] YaRN: Efficient Context Window Extension of Large Language Models

  • 传统 NTK-aware Scaling 的问题:

    • 对所有维度使用统一的 NTK 缩放系数,高频维度(靠后的圆盘)缩放过度,低频维度(靠前的圆盘)缩放不足;
    • 超长序列(如 64k/128k)下,位置编码的 “相对位置” 信息会逐渐丢失
  • YarnRoPE 的改进思路:

    • 分段 NTK 缩放:将维度分为低频段和高频段,低频段用小缩放系数(保留绝对位置),高频段用大缩放系数(保留相对位置)
    • 动态适配序列长度:仅当序列长度超过预训练长度时才缩放
    • 频率偏移修正:避免缩放后频率重叠,进一步提升外推稳定性
  • 基础 NTK 公式

    λ=(SpostSpre)2d−2,θi∗=1(10000λ)2i/d\lambda = \left (\frac {S_{post}}{S_{pre}} \right)^{\frac {2}{d-2}}, \quad \theta^*_i = \frac {1}{(10000 \lambda)^{2i/d}}
  • 分段缩放

    inv_freqi={1base2i/d⋅α(i<cutoff)(低频段:小缩放)1(base⋅λ)2i/d(i≥cutoff)(高频段:NTK 缩放)\text{inv\_freq}_i = \begin {cases} \frac {1}{\text{base}^{2i/d}} \cdot \alpha & (i < \text{cutoff}) \quad \text{(低频段:小缩放)} \\ \frac {1}{(\text{base} \cdot \lambda)^{2i/d}} & (i \geq \text{cutoff}) \quad \text{(高频段:NTK 缩放)} \end {cases}
这篇文档有帮助吗?

On this page

页面信息