Transformer模型中,位置编码是必不可少的,Attention模块是无法捕捉输入顺序的,要加入Token位置信息有两个方向:
1、绝对位置编码:将位置信息融入到输入中;
2、相对位置编码:微调Attention结构,使其能分辨不同位置的Token。
远程衰减性-Distant Decay:位置编码应能捕获到序列中相隔较远的单词之间的关系,即相隔较远的单词之间的位置编码相似度应较低。具备远程衰减性的位置编码可以使模型学习到更多的长距离依赖关系,从而提高模型的性能。
绝对位置编码
使用固定的正弦和余弦函数,每个token不同位置编码是通过正弦和余弦函数生成的,可以捕获到不同位置之间的关系,且具有良好的远程衰减性。当两个位置的编码相差较大时相似度较低,便于模型区分这些位置。当两个位置相隔较近时相似度较高,便于模型理解它们之间的关系。
简单暴力,短文本性能高;但外推性差;长度超限只能截断/插值;参数量 len×d。
相对位置编码
只编码距离不编码绝对下标。
Relative Position Representation-RPR
在注意力得分里加一项可学习偏置 a_ij = f(i−j), f 是 2k+1 个可学习标量(距离截断到 ±k)。A_ij = (q_i^T k_j) / √d + a_{i−j}
天然对长度外推友好;同一距离共享参数,广泛用于 Transformer-XL、T5。
旋转位置编码--RoPE
目前LLM标配,通过绝对位置编码的方式实现相对位置编码。RoPE(q,m) = R_θ^m · q,R_θ^m 是 2×2 旋转块对角矩阵,θ = 10000^(-2i/d) 。保持线性形式,可插值到任意长度(LLaMA-2 Long 32 k 即用线性插值 RoPE)。只改矩阵乘法,零额外参数;绝对位置隐性、相对位置显性。
ALiBi(Attention Linear Biases)
不给向量,直接给注意力分数加线性负偏置 −m·|i−j|;斜率 m 随头序号固定。
-
零参数量;外推性能极佳(BLOOM 用 2048 训练→ 8500 推理仍稳定)。
-
缺点:短距离惩罚过大,极短文本效果略差。
绝对PE与RoPE对比
绝对PE:给每个 token 附加一个唯一向量,模型把“位置”当成额外特征。
PE(pos, 2i) = sin( pos / 10000^(2i / d) )
PE(pos, 2i+1) = cos( pos / 10000^(2i / d) )
-
pos:token 下标(从 0 开始) -
i:维度编号(从 0 到 d/2-1) -
d:向量维度
在纯自注意力里,q、k、v 是同一输入 x 经过三个独立线性投影得到的,因此在“加”绝对位置编码时,它们先被加上完全相同的 PE 向量;但在处理非常长的序列时可能效果不佳,因为绝对位置编码的分辨率有限,且在微调预训练模型时,序列长度的变化可能导致模型性能下降。
RoPE:不给向量,而把 query/key 向量旋转一个与下标差有关的角度,让注意力系数自带相位差 ⇒ 位置信息隐式进入内积。把 q、k 的内部二维子向量按各自下标旋转不同角度——v 向量不旋转(因为注意力里只用它做“内容”,不参与相似度打分)
RoPE通过引入旋转矩阵来动态地调整词嵌入向量,以反映它们在序列中的相对位置。RoPE 对于每个位置 i 定义了一个旋转矩阵 Ri。这个矩阵可以分解为两个部分,cosine矩阵和sine矩阵。对于一个维度为 d 的向量,将其分为两半,前一半与cosine矩阵相乘,后一半与sine矩阵相乘。
一个序列中的词嵌入向量 v,对于位置 i,RoPE将通过以下方式修改向量:
vi,1:d/2是向量的前一半,𝑣𝑖,𝑑/2+1:𝑑vi,d/2+1:d是后一半。
RoPE适用于单个序列内部的位置编码,也适用于不同序列之间的相对位置编码。当两个序列被拼接在一起时,RoPE可以通过不同的旋转矩阵来区分这两个序列的位置信息,从而帮助模型理解它们之间的关系。
- 灵活性:RoPE允许模型在训练过程中动态学习位置信息,使模型能适应不同长度的序列。
- 效率:相较于添加额外的位置编码向量,RoPE只需要计算旋转矩阵,更为高效。
- 长距离依赖性:RoPE通过相对位置编码帮助模型捕获更长距离的依赖关系。
对于序列中的每一个位置 i,构建一个基于该位置的旋转矩阵 Ri,Ri 一部分是基于余弦函数的旋转,另一部分是基于正弦函数的旋转,Ri(cos) 和 Ri(sin) 。
𝑅𝑖(𝑐𝑜𝑠)=𝑑𝑖𝑎𝑔(cos(𝑖/100002𝑗/𝑑));𝑅𝑖(𝑠𝑖𝑛)=𝑑𝑖𝑎𝑔(sin(𝑖/100002𝑗/𝑑))
diag 表示创建一个对角矩阵,对角线元素由给定的数组或列表决定;j 是从0开始的索引,直到 d/2−1,代表了向量中的位置;100002𝑗/𝑑 为缩放频率。
完整的旋转矩阵 Ri 为
,Ri 与原始向量 v 结合,又由于只对向量的一半进行旋转,因此可以简化为
,这样,原始的词嵌入向量 v 转换成了带有位置信息的新向量 v′。这个新的向量在后续的计算中将包含关于它在序列中的相对位置的信息,而不仅仅是其语义信息。RoPE能够在不增加模型参数的情况下,有效地将位置信息嵌入到词嵌入中,同时保持了模型的计算效率。
位置向量计算示例
日志:Received block 123
token : [Received, block, 123]
ID : [ 1234, 5678, 9101 ]
下标 i: 0 1 2
维度取 d=4 最简明,head=1,忽略batch
绝对PE:
PE(i,2t) = sin( i / 10000^(2t/d) )
PE(i,2t+1) = cos( i / 10000^(2t/d) )
这里 d=4,因此 t=0,1 两组角度。
| i | t=0 | t=1 | 最终4维向量 |
|---|---|---|---|
| 0 | sin0=0 | cos0=1 | [0, 1, 0, 1] |
| 1 | sin(1/1)≈0.8415 | cos(1/1)≈0.5403 | [0.8415, 0.5403, 0.0998, 0.9950] |
| 2 | sin2≈0.9093 | cos2≈-0.4161 | [0.9093, -0.4161, 0.1987, 0.9801] |
位置0:
PE(0,0) = sin(0/1) = 0
PE(0,1) = cos(0/1) = 1
PE(0,2) = sin(0/100) = 0
PE(0,3) = cos(0/100) = 1
向量 = [0, 1, 0, 1]
位置1:
PE(1,0) = sin(1/1) = 0.84147098
PE(1,1) = cos(1/1) = 0.54030231
PE(1,2) = sin(1/100) ≈ 0.00999983
PE(1,3) = cos(1/100) ≈ 0.99995000
向量 = [0.8415, 0.5403, 0.0100, 0.9999]
位置2:
PE(2,0) = sin(2) ≈ 0.90929743
PE(2,1) = cos(2) ≈ -0.41614684
PE(2,2) = sin(2/100) ≈ 0.01999867
PE(2,3) = cos(2/100) ≈ 0.99980000
向量 = [0.9093, -0.4161, 0.0200, 0.9998]
位置3:
PE(3,0) = sin(3) ≈ 0.14112001
PE(3,1) = cos(3) ≈ -0.98999250
PE(3,2) = sin(3/100) ≈ 0.02999550
PE(3,3) = cos(3/100) ≈ 0.99955000
向量 = [0.1411, -0.9899, 0.0300, 0.9996]
| 维索引 | 偶/奇 | 三角函数 | 角度 = pos / ? | 例 pos=1 |
|---|---|---|---|---|
| 0 | 偶 | sin | pos / 1 | sin(1) |
| 1 | 奇 | cos | pos / 1 | cos(1) |
| 2 | 偶 | sin | pos / 100 | sin(0.01) |
| 3 | 奇 | cos | pos / 100 | cos(0.01) |
每连续两维 (2i, 2i+1) 共用同一个角度分母,然后sin→偶下标,cos→奇下标。
RoPE:
只给query/key向量加旋转,不改动token嵌入本身。
假设 q_i(或k_i)已经拿到4维向量:q_i = [a, b, c, d]
① 两两复数化
把相邻两维看成复数:
z_0 = a + bj
z_1 = c + dj
② 距离-旋转
对内积另一端q_i · k_j只关心相对距离Δ=i-j,给出自身位置i的旋转因子(后面与k_j做内积时再用Δ=i-j)。旋转角 θ_t = 10000^(-2t/d) → t=0: θ_0=1 rad, t=1: θ_1=0.01 rad
ẑ_t = z_t · e^(i·i·θ_t)(e^(iα)=cosα + i sinα)
| i | t=0 旋转 | t=1 旋转 | 旋转后4维实部/虚部 |
|---|---|---|---|
| 0 | e^(i·0)=1+0j | e^(i·0)=1+0j | q_0 不变 |
| 1 | e^(i·1)≈0.5403+0.8415j | e^(i·0.01)≈0.99995+0.0100j | 实部/虚部线性组合即可 |
| 2 | e^(i·2)≈-0.4161+0.9093j | e^(i·0.02)≈0.9998+0.0200j | 同上,用2×2块对角乘 |
-
绝对PE给每个token额外贴一个4维向量;
-
RoPE把
q,k内部每2维旋转一个与下标成正比的角度,不产生新参数,也不改变嵌入表。
如:输入 token-1(位置 i=1)的嵌入 x = [1.0, 0.5, -0.5, 1.5] # 4 维
投影后(假设 W_Q=W_K=W_V=I,方便手写,所以 q=k=v=x)
-
旋转角(与 i=1 对应)
二维一组,角度 = i / 分母-
组 0(维 0&1)(分母=1) θ₀ = 1 rad
-
组 1(维 2&3) (分母=100) θ₁ = 0.01 rad
-
-
块对角旋转矩阵(2×2×2), R(α) = [[cosα -sinα], [sinα cosα]]
R₀ = R(1) ≈ [[ 0.5403, -0.8415], [ 0.8415, 0.5403]]
R₁ = R(0.01) ≈ [[ 0.99995, -0.0100], [ 0.0100, 0.99995]]
3. 把 q 与 k 按复数视角旋转(v 不动)
q₀ = [1.0, 0.5] // 二维复数 1+0.5i
q₁ = [-0.5, 1.5] // -0.5+1.5i
同理 k₀, k₁, 旋转后实部/虚部(即新的 4 维向量)
q̂₀ = Re[(1+0.5i) e^{i·1}]
= [1·cos1 - 0.5·sin1, 1·sin1 + 0.5·cos1]
≈ [0.5403 - 0.5·0.8415, 0.8415 + 0.5·0.5403]
≈ [0.1196, 1.1117]
q̂₁ = Re[(-0.5+1.5i)e^{i·0.01}]
≈ [-0.5100, 1.4900]
拼接得旋转后 query,q̂ = [0.1196, 1.1117, -0.5100, 1.4900]
对 k̂ 做完全相同的旋转(因为同一位置 i=1),得到 k̂ ≈ [0.1196, 1.1117, -0.5100, 1.4900]
v 保持原样,v = [1.0, 0.5, -0.5, 1.5]
注意力分数只与相对距离有关,若后来 token-j=3 的旋转角 = 3θ₀, 3θ₁,则
A_{1,3} ∝ q̂₁^T k̂₃ = Re[ z₁ e^{i(1-3)θ} ]
只出现角度差 (1-3),绝对下标 1 本身被消掉——外推任意长序列,差角可插值。
RoPE旋转角度的变化:只关心 「相对距离 Δ = i − j」 ,与绝对下标无关;距离每增加 1,角度就线性增加一个固定步长。下面用 4 维向量展示角度怎么变。
角度步长公式:维度 d=4 ⇒ 两组二维平面(t=0,1)
θ_t = 10000^(−2t / d) (单位:弧度/步)
t=0 : θ_0 = 10000^0 = 1.0000 rad / 步
t=1 : θ_1 = 10000^(−2/4) = 0.0100 rad / 步
相对距离 → 旋转角(Δ = i−j)
| 相对距离 Δ | 组-0 旋转角 (Δ·θ_0) | 组-1 旋转角 (Δ·θ_1) |
|---|---|---|
| 0(自身) | 0 rad | 0 rad |
| +1 | 1.0000 | 0.0100 |
| +2 | 2.0000 | 0.0200 |
| +3 | 3.0000 | 0.0300 |
| −1 | −1.0000 | −0.0100 |
| −2 | −2.0000 | −0.0200 |
旋转矩阵即时值
组-0(大角度)Δ=+1:R = [[ cos1 -sin1 ] ≈ [[ 0.5403 -0.8415 ]
[ sin1 cos1 ]] [ 0.8415 0.5403 ]]
Δ=+2:R = [[ cos2 -sin2 ] ≈ [[ -0.4161 -0.9093 ]
[ sin2 cos2 ]] [ 0.9093 -0.4161 ]]
组-1(小角度)Δ=+10:R = [[ cos0.1 -sin0.1 ] ≈ [[ 0.9950 -0.0998 ]
[ sin0.1 cos0.1 ]] [ 0.0998 0.9950 ]]
RoPE 的旋转角度 = 相对距离 Δ × 固定步长 θ_t
步长只由维度索引 t 决定,与绝对下标、词汇、内容全部无关;距离每远一格,角度线性增加,远处用大角度(t=0),近处用小角度(t=1…),从而实现“远疏近密”的相对位置感知。
再使用‘日志:Received block 123’做演示
预先算好的角度步长
d=4 ⇒ 两组二维平面
-
组 0(维 0-1):θ₀ = 1 rad / 步
-
组 1(维 2-3):θ₁ = 0.01 rad / 步
| token | 绝对下标 i | 相对距离 Δ=i-j(例 j=0) | 组-0 旋转角 Δ·θ₀ | 组-1 旋转角 Δ·θ₁ | 2×2 块对角矩阵 R(Δ)(维 0-1 块示例) |
|---|---|---|---|---|---|
| Received | 0 | Δ=0 | 0 rad | 0 rad | 单位矩阵 [[1,0],[0,1]] |
| block | 1 | Δ=+1 | 1.0000 rad | 0.0100 rad | [[0.5403,-0.8415],[0.8415,0.5403]] |
| 123 | 2 | Δ=+2 | 2.0000 rad | 0.0200 rad | [[-0.4161,-0.9093],[0.9093,-0.4161]] |
若 j=1,Δ 依次变成 -1,0,+1,角度符号跟着变负即可
RoPE 把 相邻两维 看成 一个复数(实部 + 虚部),然后乘 e^(i·角度) 实现旋转。
-
4 维向量 → 2 个复数 → 2 次旋转
-
768 维向量 → 384 个复数 → 384 次旋转
为了代码清晰把“第 0 个复数”叫 组 0,“第 1 个复数”叫 组 1 ……以此类推。
参考:
6721

被折叠的 条评论
为什么被折叠?



