什么是RoPE-旋转位置编码?

本文介绍了RoPE旋转位置编码在大模型中的应用,包括其概念、特点、与传统位置编码的比较以及其在Transformer中的优势,特别强调了其在处理长文本和线性Attention中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

RoPE位置编码是大模型中最常见的位置编码之一。像是谷歌的PaLM和meta的LLaMA等开源大模型都是RoPE位置编码,那么RoPE有什么特点呢?

本文将介绍如下内容:

  • RoPE旋转位置编码概要
  • 什么是位置编码?
  • RoPE及其特点
  • 总结

一、RoPE旋转位置编码概要

本文提出RoPE旋转位置编码方式,其关键思想是将上下文token表示和仅与位置相关的旋转矩阵相乘。RoPE具有良好的外推性和远程衰减的特性,应用到Transformer中体现出较好的处理长文本的能力。此外,RoPE还是目前唯一一种可用于线性Attention的相对位置编码。

中文原文Transformer升级之路:2、博采众长的旋转式位置编码 - 科学空间|Scientific Spaces

代码地址https://github.com/ZhuiyiTechnology/roformer

论文地址ROFORMER: ENHANCED TRANSFORMER WITH ROTARY
POSITION EMBEDDING

在这里插入图片描述

二、什么是位置编码?

我们知道句子中不同词语之前的位置信息十分重要,但是self-attention框架无法直接利用位置信息,因此研究者提出了许多方法将位置信息编码到学习过程中。一是绝对位置编码方法,将位置信息直接加入到输入中;二是相对位置编码方法,研究者通过微调attention的结构,使它具有识别token位置信息的能力。

1、绝对位置编码

绝对位置编码比较简单,研究者一般会将绝对位置信息加到输入中:在输入的第 k k k个向量 x k x_k xk中加入位置向量 p k p_k pk得到 x k + p k x_k+p_k xk+pk,其中 p k p_k pk仅与 k k k相关 。计算 p k p_k pk的方法一般有两种:

训练式:将位置向量设置为可训练的参数,如Bert就将位置向量初始化设为512×768的矩阵,并在训练中更新。但是这种方法有个明显的缺点就是不具备外推性,如果预训练时句子最长设为512,它就无法处理更长的句子了。
编码式:最著名的就是《Attention is all you need》中提出的Sinusoidal位置编码(如下所示, p i , 2 t p_i,2t pi,2t表示位置 k k k的向量的第 2 i 2i 2i个分量, d d d表示向量维度),它显式的编码了位置信息,且具有一定的外推性。
在这里插入图片描述

2、相对位置编码

我们前面讲到相对位置编码是微调Attention矩阵的计算方式,先看看绝对位置编码怎样计算Attention矩阵:
在这里插入图片描述
可以看到计算attention矩阵的过程如公式(1)所示,其中第一项和位置信息无关,第二至四项和位置信息相关。因此研究者通常是直接修改第二至四项的内容,直接在attention矩阵中添加相对位置信息。 常见的有以下几种方法:

XLNET式: 如(2)所示,xlnet将(1)中的二至四项都做了改变,具体的 p n p_n pn替换为了Sinusoidal生成式编码 R ~ n − m \tilde{\mathbb{R}}_{n-m} R~nm,将 p m p_m pm换成了两个可以训练的向量 u , v u,v u,v
在这里插入图片描述
T5式: 如(3)所示,它的作者认为输入和位置间不应过多的交互,因此将第二、三项删除,将第四项都替换为一个可学习的偏执 b m , n b_{m,n} bm,n,这仅仅是在Attention矩阵的基础上加一个可训练的偏置项而已,十分简单。
在这里插入图片描述

DeBerta式: 和T5的构造相反,它舍弃了公式(1)中第四项,保留了第二、三项并将位置信息替换为了相对位置向量 R ~ n − m \tilde{\mathbb{R}}_{n-m} R~nm

在这里插入图片描述

三、RoPE及其特点

Attention的核心运算是内积,所以我们希望经过内积的结果能够带有相对信息。那么我们希望
q m q_m qm k n k_n kn 的内积仅与输入 x m x_m xm x n x_n xn和他们的相对位置 m − n m-n mn有关,那么我们可以假设存在函数 g g g,使得:
在这里插入图片描述

1、RoPE的表示形式

为了方便理解我们可以先考虑二维形式,然后借助复数的运算法则来理解。首先分别用复数的指数形式表示各个向量变化,即有:
在这里插入图片描述

PS1. 向量内积与复数乘积的关系为内积 < i , j > = R e ( i j ∗ ) <i,j>=Re(ij*) <i,j>=Re(ij),其中 R e Re Re表示复数的实部。
PS2. 这个形式证明过程可以参考论文的3.4.1节。但是要注意的是向量内积是标量,而 g ( x m , x n , m − n ) g(x_m,x_n,m-n) g(xm,xnmn)是向量,所以其公式(21) 应改为 q m T k n = < f q ( x , m ) , f k ( m , n ) > = R e [ ( x m , x n . m − n ) ] q^{T}_mk_n=<f_q(x,m),f_k(m,n)>=Re[(x_m,x_n.m-n)] qmTkn=<fq(x,m),fk(m,n)>=Re[(xm,xn.mn)],这样公式(24)才好理解。

q m q_m qm为例,假设 e i m θ e^{im\theta} eimθ表示为模长为1的复数,根据复数乘法的几何意义, ( W q x m ) e i m θ (W_qx_m)e^{im\theta} (Wqxm)eimθ变换实际上对应着向量 W q x m W_qx_m Wqxm的旋转,所以我们称之为“旋转式位置编码”,它还可以写成矩阵形式:
在这里插入图片描述
q m q_m qm为例,考虑多维情况,可以得到旋转式位置编码的一般形式为: q m = R Θ , m d W q x m q_m=R^d_{\Theta,m}W_qx_m qm=RΘ,mdWqxm ,其中:
在这里插入图片描述

PS3. 矩阵 R Θ , m d R^d_{\Theta,m} RΘ,md为正交矩阵,它不会改变向量的模长,因此通常来说它不会改变原模型的稳定性。

2、RoPE的优点
  • 远程衰减: 参考Sinusoidal位置编码形式,RoPE中将 θ i = 1000 0 − 2 i / d \theta_i=10000^{-2i/d} θi=100002i/d,作者并证明了RoPE具有远程衰减的优点,相对距离更大的token之间的联系更少。

  • 可用于线性Attention:Attention的空间和时间复杂度都是 O ( n 2 ) O(n^2) O(n2)级别的, n n n是序列长度,所以 n n n当比较大时Transformer模型的计算量难以承受。因此有研究者提出了线性注意力机制,将复杂度将至 O ( n ) O(n) O(n)。线性注意力机制详见:线性Attention的探索:Attention必须有个Softmax吗? - 科学空间|Scientific Spaces

    线性注意力机制的表达式为:
    在这里插入图片描述
    其中 φ ( ⋅ ) \varphi(\cdot) φ()为非负函数,像原生注意力中的softmax就位非负函数。因为线性Attention计算方式不一样了,所以前面提到的一些相对位置编码方式都不再适用。

    前面我们提到RoPE是通过旋转输入的方式添加位置信息,并不会改变各个参数的归一化值。因此,我们可以只在分子中将旋转矩阵乘以 φ ( ⋅ ) \varphi(\cdot) φ(),即:
    在这里插入图片描述

四、总结

本文作者详细梳理了位置编码的流派,提出了一种旋转位置编码方式RoPE,并从数学角度证明RoPE带来的诸多优点。RoPE能够应用于线性注意力中,这使得它在不引入爆炸计算量的前提下能够接受更长的输入,这可能是许多大模型都应用RoPE的原因。

参考:
【论文阅读】RoPE为何成为大模型中最常见的位置编码?

<think>好的,我现在需要帮助用户理解RoPE旋转位置编码的原理和实现方式。首先,我得回顾一下用户提供的引用内容,确保准确引用相关信息。用户给出的引用[1]到[4]都涉及RoPE的不同方面,比如基本原理、与Sinusoidal编码的比较、几何解释等。 首先,我应该明确RoPE的核心思想。根据引用[1],RoPE通过旋转操作来平衡绝对和相对位置编码,不需要额外参数,直接与自注意力机制结合。我需要解释清楚这个旋转是如何实现的,可能需要涉及二维向量的旋转矩阵。 接下来,用户提到想了解原理和实现方式,所以需要分两部分。原理部分需要说明绝对位置信息如何通过旋转转化为相对位置关系。可能得用数学公式展示,比如二维情况下的旋转矩阵,然后推广到高维。引用[4]提到绝对位置编码的局限性,而RoPE通过旋转缓解了这个问题,这点需要强调。 然后,实现方式部分,根据引用[2],RoPE是乘性的,而Sinusoidal是加性的。需要说明在自注意力机制中,如何将位置信息融入query和key的向量中,可能涉及复数乘法的运算,但实际实现可能用实数矩阵运算。引用[3]中的图形化理解可能有帮助,可以提到几何上的旋转效果。 用户提供的示例中使用了数学公式的格式,我需要确保所有公式正确使用$...$和$$...$$。例如,二维旋转矩阵应该用行内公式,而更复杂的公式如式(1)可能需要独立成段。 另外,用户要求生成相关问题,我需要考虑与RoPE相关的问题,比如优势、数学推导、与Sinusoidal的区别、具体实现步骤等。这些问题需要自然引出,并确保覆盖用户可能感兴趣的方面。 需要注意引用标记的正确使用,比如在提到相对位置捕捉时添加[^1],在比较加性和乘性时引用[^2]。同时,要避免直接复制引用内容,而是用自己的话组织,保持流畅。 可能还需要检查是否有遗漏的关键点,比如RoPE的高效性,无需额外参数,这在引用[1]和[^4]中都有提到,应该包含在优点中。此外,多维情况下的处理,如分块应用旋转,可能也需要解释,如引用[4]中的图3所示。 最后,确保回答结构清晰,分原理、数学表达、实现步骤、优点、示例代码等部分,帮助用户逐步理解。示例代码部分可能需要用Python展示如何将位置编码应用到query和key上,注意代码的正确性和注释。</think>### RoPE旋转位置编码原理及实现 #### 一、核心原理 RoPE(Rotary Position Embedding)通过**复数平面旋转**实现位置编码。其核心思想是将词向量的每个维度视为二维平面坐标,通过旋转角度与位置序号关联,使得词向量间的点积能够自动携带相对位置信息[^1]。 数学表达为: $$ \boldsymbol{q}_m = \boldsymbol{W}_q\boldsymbol{x}_m \cdot e^{im\theta} $$ $$ \boldsymbol{k}_n = \boldsymbol{W}_k\boldsymbol{x}_n \cdot e^{in\theta} $$ 其中$m,n$为绝对位置序号,$\theta$为预设角度参数,复数乘法对应二维旋转操作[^2]。 #### 二、数学推导(二维示例) 1. 将词向量维度两两分组:$[x_1,x_2],[x_3,x_4],...$ 2. 对每个二维组应用旋转矩阵: $$ \begin{bmatrix} \cos m\theta & -\sin m\theta \\ \sin m\theta & \cos m\theta \end{bmatrix} \begin{bmatrix} x_{2d} \\ x_{2d+1} \end{bmatrix} $$ 3. 高维情况下将各二维组拼接,形成完整旋转操作[^4] #### 三、实现步骤 1. **位置参数生成**:计算每个位置的旋转角$\theta_d = 10000^{-2d/D}$ 2. **频率矩阵构造**:生成$\cos(m\theta_d)$和$\sin(m\theta_d)$矩阵 3. **旋转操作实现**: ```python # 伪代码示例 def apply_rope(q, k, pos): # 将q,k按维度拆分复数形式 q_complex = q.view(q.shape[0], -1, 2) # [batch, dim/2, 2] k_complex = k.view(k.shape[0], -1, 2) # 计算旋转矩阵 rotation = get_rotation_matrix(pos) # [dim/2, 2, 2] # 应用旋转 q_rotated = einsum('bdi, dij -> bdj', q_complex, rotation) k_rotated = einsum('bdi, dij -> bdj', k_complex, rotation) return q_rotated.flatten(), k_rotated.flatten() ``` #### 四、核心优势 1. **相对位置感知**:$ \boldsymbol{q}_m^T\boldsymbol{k}_n = (\boldsymbol{W}_q\boldsymbol{x}_m)^T\boldsymbol{W}_k\boldsymbol{x}_n \cdot e^{i(n-m)\theta} $,点积结果仅依赖相对位置$n-m$[^1] 2. **长度外推性**:旋转操作保持向量模长不变,增强模型处理长文本能力 3. **计算高效**:无需存储位置编码矩阵,可融合到注意力计算中[^3] #### 五、几何解释 每个维度对的旋转相当于在多个二维平面上同时进行旋转变换(见图3)。这种变换保持向量模长不变,仅改变相位关系,使注意力机制能通过夹角大小判断位置相关性[^4]。 ```python # 实际应用示例(简化版) import torch class RotaryEmbedding(torch.nn.Module): def __init__(self, dim): super().__init__() inv_freq = 1.0 / (10000 ** (torch.arange(0, dim, 2).float() / dim)) self.register_buffer("inv_freq", inv_freq) def forward(self, x, seq_len): t = torch.arange(seq_len, device=x.device).type_as(self.inv_freq) freqs = torch.einsum("i,j->ij", t, self.inv_freq) return torch.cat((freqs, freqs), dim=-1) ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值