这个公式其实是数学中的**旋转矩阵(Rotation Matrix)在二维空间的应用。我们可以从极坐标(Polar Coordinates)**的角度来推导,这样最直观。
1. 准备工作:极坐标表示#
假设一个点 P(x,y) 在圆心为原点的圆上,它距离原点的距离(半径)为 r,与 x 轴的正方向夹角为 α。
根据三角函数,我们可以把它的坐标写成:
- x=rcosα
- y=rsinα
2. 进行旋转#
现在,我们要把这个点逆时针旋转一个角度 θ。旋转后的新点记为 P′(x′,y′)。
新点 P′ 的半径依然是 r,但它与 x 轴的夹角变成了 α+θ。
所以新坐标可以表示为:
- x′=rcos(α+θ)
- y′=rsin(α+θ)
3. 使用三角恒等式展开#
利用高中的三角函数加法公式:
cos(α+θ)=cosαcosθ−sinαsinθ
sin(α+θ)=sinαcosθ+cosαsinθ
我们将这两个展开式代入 x′ 和 y′ 的表达式中:
x′=r(cosαcosθ−sinαsinθ)=(rcosα)cosθ−(rsinα)sinθ
y′=r(sinαcosθ+cosαsinθ)=(rsinα)cosθ+(rcosα)sinθ
4. 代回原始坐标#
记得第一步里的 x=rcosα 和 y=rsinα 吗?把它们替换进去,就得到了你看到的公式:
- x′=xcosθ−ysinθ
- y′=ycosθ+xsinθ (整理一下顺序即 xsinθ+ycosθ)
线性代数视角(更进一步)#
在机器学习和 Transformer 的论文(如 RoPE)中,通常会写成矩阵乘法的形式,看起来更简洁:
[x′y′]=[cosθsinθ−sinθcosθ][xy]
为什么 RoPE 要用这个?
因为这种旋转变换是线性的,而且它有一个神奇的特性:它保持向量的长度(模长)不变,只改变方向。 这使得模型在处理位置信息时,不会因为位置太远而导致向量数值爆炸。
下面我给一个“能手算完”的玩具例子:5 个词、8 维(4 个 pair),分别算一遍不使用 RoPE 和使用 RoPE 的 QK⊤。我会把每一步都写出来(包括每个 pair 的旋转、每个距离的点积分解与求和),最后把 5×5 的分数矩阵写出来。
设定前提(为了让计算可控)#
这些简化不影响你要理解的结论:
-
位置:5 个词的位置是 p=0,1,2,3,4
-
维度:d=8⇒4 个二维 pair:Pair 1 (维 1-2), Pair 2 (维 3-4), Pair 3 (维 5-6), Pair 4 (维 7-8)
-
角速度:每个 pair 的“每移动 1 步的旋转角速度”取一个简单的值(玩具版):
ω1=1,ω2=0.5,ω3=0.25,ω4=0.125(单位:弧度/位置)
(注:真实 RoPE 用的是 ωi=θ−2i/d 这种形式,但计算流程完全一样。)
-
最关键的简化:所有 Token 的原始 Q 和 K 都取同一个向量:
v=[1,0,1,0,1,0,1,0]
也就是每个 pair 都是 [1,0]。这样 RoPE 后每个 pair 会变成 [cos(pω),sin(pω)],点积能清晰地看到“只和距离 Δ=t−p 有关”。
1. 不使用 RoPE:直接算 QK⊤#
1.1 先写出 Q 和 K
5 个词都一样,所以:
Q=vvvvv,K=vvvvv
其中 v=[1,0,1,0,1,0,1,0]。
1.2 计算任意一个分数项 (QK⊤)p,t=Qp⋅Kt=v⋅v
把 8 维逐项相乘再求和:
v⋅v=1⋅1+0⋅0+1⋅1+0⋅0+1⋅1+0⋅0+1⋅1+0⋅0=4
1.3 得出完整的 QK⊤ 矩阵
整个 QK⊤ 是一个全 4 的矩阵:
QK⊤=4444444444444444444444444
解释:不带位置时,注意力分数完全不知道谁离谁近,所有位置一视同仁。
2. 使用 RoPE:先旋转,再算 Q′K′⊤#
2.1 RoPE 对每个 pair 怎么旋转
对任意位置 p 和任意一个 pair(角速度 ω),二维旋转结果是:
原始 pair 是 [1,0],旋转角为 θ=pω,所以:
[1,0]R(p)[cos(pω),sin(pω)]
因此 token 在位置 p 的 8 维向量(4 个 pair 拼起来)是:
qp′=kp′=[cos(pω1),sin(pω1),cos(pω2),sin(pω2),cos(pω3),sin(pω3),cos(pω4),sin(pω4)]
2.2 算出 5 个位置的 qp′(四舍五入到 4 位小数)
-
位置 p=0:
q0′=[1.0000,0.0000,1.0000,0.0000,1.0000,0.0000,1.0000,0.0000]
-
位置 p=1(角分别是 1, 0.5, 0.25, 0.125):
q1′=[0.5403,0.8415,0.8776,0.4794,0.9689,0.2474,0.9922,0.1247]
-
位置 p=2(角分别是 2, 1, 0.5, 0.25):
q2′=[−0.4161,0.9093,0.5403,0.8415,0.8776,0.4794,0.9689,0.2474]
-
位置 p=3(角分别是 3, 1.5, 0.75, 0.375):
q3′=[−0.9900,0.1411,0.0707,0.9975,0.7317,0.6816,0.9305,0.3663]
-
位置 p=4(角分别是 4, 2, 1, 0.5):
q4′=[−0.6536,−0.7568,−0.4161,0.9093,0.5403,0.8415,0.8776,0.4794]
(因为我们设定了 Q=K,所以 kp′=qp′)
3. 一步一步计算 Q′K′⊤#
分数矩阵元素是:(Q′K′⊤)p,t=qp′⋅kt′=qp′⋅qt′
3.1 先完整算一个具体例子:(p=0,t=1)
把 8 维逐项乘加。因为 q0′ 的每个 pair 都是 [1,0],所以每个 pair 只取到了对方的 cos 分量:
q0′⋅q1′=0.5403+0.8776+0.9689+0.9922≈3.3790
所以 (Q′K′⊤)0,1≈3.3790。
3.2 再算一个“不是从全 1 取 cos”的例子:(p=1,t=2)
这里必须把每个 pair 都做完:
-
Pair 1 (ω1=1):
[0.5403,0.8415]⋅[−0.4161,0.9093]=−0.2248+0.7652≈0.5403
(理论值即 cos(1))
-
Pair 2 (ω2=0.5):
[0.8776,0.4794]⋅[0.5403,0.8415]=0.4742+0.4034≈0.8776
-
Pair 3 (ω3=0.25):
[0.9689,0.2474]⋅[0.8776,0.4794]=0.8503+0.1186≈0.9689
-
Pair 4 (ω4=0.125):
[0.9922,0.1247]⋅[0.9689,0.2474]=0.9613+0.0309≈0.9922
把 4 个 pair 加起来:
q1′⋅q2′≈0.5403+0.8776+0.9689+0.9922=3.3790
你会发现:距离 Δ=1 的 (1,2) 得分与 (0,1) 完全一样!
4. 把“所有距离”都算出来,然后拼成 5×5 矩阵#
由于每个 pair 满足三角恒等式:
cos(pω)cos(tω)+sin(pω)sin(tω)=cos((t−p)ω)
总分数公式直接化简为:
Score(p,t)=∑i=14cos((t−p)ωi)
接下来我们对每个距离 Δ=∣t−p∣ 进行求和:
- Δ=0:S0=1+1+1+1=4.0000
- Δ=1:S1=0.5403+0.8776+0.9689+0.9922=3.3790
- Δ=2:S2=−0.4161+0.5403+0.8776+0.9689=1.9707
- Δ=3:S3=−0.9900+0.0707+0.7317+0.9305=0.7429
- Δ=4:S4=−0.6536−0.4161+0.5403+0.8776=0.3481
最终拼出的矩阵(每条对角线相同,即 Toeplitz 矩阵):
Q′K′⊤=S0S1S2S3S4S1S0S1S2S3S2S1S0S1S2S3S2S1S0S1S4S3S2S1S0≈4.00003.37901.97070.74290.34813.37904.00003.37901.97070.74291.97073.37904.00003.37901.97070.74291.97073.37904.00003.37900.34810.74291.97073.37904.0000
5. 你要的“距离长短”到底在哪里#
对比两种结果:
- 不使用 RoPE:所有位置之间分数都一样(全是 4.0000),模型从 QK⊤ 里完全看不出距离。
- 使用 RoPE:分数随距离 ∣t−p∣ 的增大而稳步下降(4.0000 → 3.3790 → 1.9707 → 0.7429 → 0.3481),距离信息就完美体现在了最终的 Q′K′⊤ 数值衰减里。