7.4 RoPE 与长度外推:旋转位置编码、NTK 与 YaRN

1.从 3.8 那个旋转矩阵说起

先带你回看一个细节。3.8 节讲 Transformer 的正弦位置编码时,我推过这么一步:对任意偏移 Δ\Delta,位置 pos+Δpos+\Delta 的编码可以写成位置 pospos 编码的线性函数,而且那个 2×22\times2 矩阵只依赖 Δ\Delta、不依赖绝对位置 pospos。把它抄下来:

(cos(ωΔ)sin(ωΔ)sin(ωΔ)cos(ωΔ))\begin{pmatrix}\cos(\omega\Delta)&\sin(\omega\Delta)\\-\sin(\omega\Delta)&\cos(\omega\Delta)\end{pmatrix}

你盯着这个矩阵看一眼——它就是一个旋转矩阵。也就是说,正弦编码之所以能"表达相对位置",本质是因为它对位置的变换是旋转,而旋转量只跟位置差有关。这是个很漂亮的巧合,但 3.8 那套方案用它用得不够爽,原因有两个:

第一,正弦编码是"加"在输入上的。 它把位置向量 PEPE 直接加到 token 的表示 xx 上,x+PEx+PE。可我们真正在乎的,是注意力打分时 QQKK内积里有没有相对位置信息。位置信息先加到 xx,再经过若干层线性变换变成 QQKK,这中间位置信号会被一次次稀释,能不能完整活到内积那一刻,其实没有保证。

第二,它编码的是绝对位置。 相对位置只是正弦公式的一个"副产品"——靠那个旋转矩阵的性质间接得到的。既然相对位置才是注意力真正想用的,那为什么不一上来就直接把相对位置"烤"进内积里?

RoPE(Rotary Position Embedding,旋转位置编码,Su 等人 2021 年的 RoFormer 论文)干的就是这件事。它的口号一句话:别加位置了,直接旋转 QQKK,让它们的内积天然只依赖相对位置。

2.目标:让内积只依赖相对位置

把目标说精确。设 qmq_m 是第 mm 个位置上某个查询向量,knk_n 是第 nn 个位置上某个键向量。我们希望找到一个对位置的变换 ff,使得打分时

f(qm,m), f(kn,n)=g(qm,kn, mn)\langle f(q_m, m),\ f(k_n, n)\rangle = g(q_m, k_n,\ m-n)

也就是内积只跟相对位置 mnm-n 有关,跟绝对位置 mmnn 本身无关。这样模型学到的就是"差了多远"该打多少分,换个地方这套打分照样成立——这正是外推能力(换个没见过的长度还能用)的根基。

ff 该长什么样?答案有点意外但事后想很自然:旋转

3.为什么是旋转:复数视角

先看最简单的二维情形,最能看清道理。把 qmq_m 的两个分量拼成一个复数 qm=qm,0+iqm,1q_m = q_{m,0} + \mathrm{i}\,q_{m,1}。在复数里,给一个数"乘 eiθe^{\mathrm{i}\theta}"就是把它旋转 θ\theta。我们干脆定义位置变换就是乘旋转因子:

f(qm,m)=qmeimθ,f(kn,n)=kneinθf(q_m, m) = q_m\,e^{\mathrm{i}m\theta},\qquad f(k_n, n) = k_n\,e^{\mathrm{i}n\theta}

两个二维向量的点积,等于这两个复数乘积的实部。于是

f(qm,m), f(kn,n)=Re ⁣[qmeimθkneinθ]=Re ⁣[qmknei(mn)θ]\langle f(q_m,m),\ f(k_n,n)\rangle=\mathrm{Re}\!\left[q_m\,e^{\mathrm{i}m\theta}\cdot\overline{k_n\,e^{\mathrm{i}n\theta}}\right]=\mathrm{Re}\!\left[q_m\overline{k_n}\,e^{\mathrm{i}(m-n)\theta}\right]

那个 ei(mn)θe^{\mathrm{i}(m-n)\theta} 只含相对位置 mnm-n,绝对位置 mmnn 在这一步彻底抵消掉了。目标达成。

你可能会问:为什么非得是旋转,平移、缩放不行吗?因为要让"各自带上绝对位置 mmnn 之后,内积里却只剩 mnm-n",唯一能做到的正交变换就是旋转(反射也算,但反射会打乱方向、不实用)。而且旋转保范数——它不改变 qmq_mknk_n 的长度,所以不会破坏向量的尺度,注意力分数该多大还是多大,训练稳。这两条(保相对位置 + 保范数)是 RoPE 能干净工作的数学底座。

4.推广到高维:分块旋转

实际模型的 QQKK 是高维向量,不是二维。怎么推广?RoPE 的做法很直接:把 dd 个维度两两配对,每一对当成上面那个二维情形,各转各的,角度不同。

dd 是偶数(每头维度数),把它分成 d/2d/2(2i,2i+1)(2i,\,2i+1),第 ii 对的旋转角速度记为 θi\theta_i。定义一个 d×dd\times d 的分块对角旋转矩阵

Rm=blockdiag ⁣(R(mθ0), R(mθ1), , R(mθd/21)),R(α)=(cosαsinαsinαcosα)R_m=\mathrm{blockdiag}\!\Big(R(m\theta_0),\ R(m\theta_1),\ \ldots,\ R(m\theta_{d/2-1})\Big),\qquad R(\alpha)=\begin{pmatrix}\cos\alpha&-\sin\alpha\\ \sin\alpha&\cos\alpha\end{pmatrix}

位置 mmQQ 旋转一下:q~m=Rmqm\tilde{q}_m=R_m q_m;同理 k~n=Rnkn\tilde{k}_n=R_n k_n。打分时

q~mk~n=(Rmqm)(Rnkn)=qmRmRnkn\tilde{q}_m^{\top}\tilde{k}_n=(R_m q_m)^{\top}(R_n k_n)=q_m^{\top}R_m^{\top}R_n\,k_n

旋转矩阵有个好性质 Rα=RαR_\alpha^{\top}=R_{-\alpha}(转置就是反向旋转),所以 RmRn=RnmR_m^{\top}R_n=R_{n-m},代入得

q~mk~n=qmRnmkn\tilde{q}_m^{\top}\tilde{k}_n=q_m^{\top}R_{n-m}\,k_n

又是只剩相对位置 nmn-m。漂亮,干净利落。

角速度 θi\theta_i 怎么取。 RoPE 沿用了正弦编码那套频率设计:

θi=100002i/d,i=0,1,,d/21\theta_i=10000^{-2i/d},\qquad i=0,1,\ldots,d/2-1

也就是角速度随维度索引 ii几何级数衰减(base 取 1000010000)。ii 小的维度(低维)θi\theta_i 大、转得快、频率高;ii 大的维度(高维)θi\theta_i 小、转得慢、频率低。这和 3.8 节正弦编码里"低维高频、高维低频"是同一个思路——不同维度负责不同"刻度":高频维度周期短,负责精细的近距离相对位置;低频维度周期长,负责粗略的远距离相对位置。你看,RoPE 和正弦编码本就是同源的,只是前者把"加位置"换成了"旋转 Q/KQ/K"。

还有个工程上很讨喜的点:RoPE 不改注意力公式,不增加参数,连 VV 都不碰——只是在 QQKK 进 softmax 之前各自乘个旋转矩阵。所以它能像一块积木一样塞进任何现成的 Transformer,几乎零成本。这也是它能迅速铺开的原因之一。

5.为什么 RoPE 成了主流

位置编码的方案不止一种,简单对比一下你就能看出 RoPE 为什么能赢:

  • 绝对位置编码(3.8 的正弦、或可学习的位置向量):位置靠"加",多层之后稀释;而且本质编码的是绝对位置。外推时一过训练长度,没见过的绝对位置就直接 OOD(超出分布)。
  • ALiBi(Press 等人 2021):不编码位置向量,而是直接在注意力分数上加一个随距离线性衰减的偏置——离得越远扣越多分。简单粗暴,相对位置,但它"只看距离不看内容",且外推能力一般,后来被 RoPE 这条线比下去了。
  • RoPE:相对位置、烤进内积、不增参数、保范数、外推相对友好(下一节专门讲怎么外推)。

到 2026 年,几乎所有主流的 decoder-only 大模型——LLaMA 全系、Qwen、DeepSeek、GLM、Kimi、Mistral——位置编码都用 RoPE。这就是为什么值得单开一节把它讲透。

6.长度外推:训练 4k,推理 32k 怎么办

RoPE 虽然外推相对友好,但不是天生就能外推。真正的问题来了:模型训练时上下文只给到 LtrainL_{\text{train}}(比如 4k),推理时却想撑到 LtestL_{\text{test}}(比如 32k、100k)。位置一超过 LtrainL_{\text{train}},旋转角 mθim\theta_i 就会出现训练时没见过的大角度,模型一下子 OOD,效果直接崩。

注意,这和 7.3 节讲的是两码事。7.3 讲的是"算力/显存撑不撑得住"(O(n2)O(n^2) 的计算和 KV cache 的显存),是划不划得来的问题;本节讲的是"位置编码泛化泛不泛",是能不能用的问题。长上下文要真正落地,这两半都得解决——光把注意力改成稀疏、把 KV cache 量化了,位置编码外推不了,照样白搭。这就是为什么这一节要紧跟在 7.3 后面。

于是有了下面这套"长度外推"的方法。核心思想就一个:想方设法让推理时的旋转角别超出训练时见过的范围,或者让没见过的维度"见多识广"一点。

位置插值(Position Interpolation,PI)。 Chen 等人 2023 年提的,最朴素的一招。思路是:推理时把位置 mm 整体缩放成 msm\cdot ss<1s<1),让所有位置"压"回训练见过的角度范围。比如训练 4k、想推到 32k,就令 s=4/32=1/8s=4/32=1/8,相当于把 [0,32k][0,32k] 线性压成 [0,4k][0,4k]

代价很直接:所有频率被一视同仁地压扁,近距离的分辨率全盘下降——原来相邻两个位置在第 ii 维差 θi\theta_i,现在差 sθi<θis\theta_i<\theta_i,挤在一起了,近距离的精细相对位置就模糊了。好在它只要少量长文本微调就能 work,实现又极简(改一个缩放系数),所以是工程上最常用的"快速外推"。

NTK-aware。 bloc97 在 2023 年提的,从频率轴入手,比 PI 更精细。关键观察是:RoPE 不同维度的频率不一样,它们的命运也不同。

  • 高频维度ii 小、θi\theta_i 大):周期短,训练长度内早就转过好几圈了,见多识广,本来就能外推。
  • 低频维度ii 大、θi\theta_i 小):周期长,训练时可能连一个完整周期都没走完,一外推就踩进没见过的角度,这才是崩的根源。

NTK 的招:调大 base(1000010000\to 一个更大的数),效果是把低频维度变得更慢(周期拉得更长,让它别急着踩出训练范围),而高频维度几乎不动——等于牺牲一点低频的"远距离分辨",换取外推能力,同时保住高频负责的近距离精度。和 PI 相比,NTK 更好地保留了近距离的精细建模。

YaRN。 Peng 等人 2023 年提的,是 NTK 的精修版,目前效果最好的外推方法之一。它引入一个判据叫临界波长(critical wavelength)λi=2π/θi\lambda_i=2\pi/\theta_i

  • 波长 λi<Ltrain\lambda_i < L_{\text{train}}(短于训练长度)的维度——训练时已经转过完整周期,保持不变
  • 波长 λi>Ltrain\lambda_i > L_{\text{train}} 的维度——训练时没转完,做插值(类似 PI,但只对这些维度做)。

也就是说 YaRN 分频段、分力度处理:能外推的维度别瞎动,不能外推的维度才压。最后再配一个温度系数修正一下注意力分布的熵(外推后分数会变得过尖或过平,得校准一下)。DeepSeek 的长上下文扩展、Qwen 的长文本版本都用过 YaRN 或它的变体。

三句话区分它们,方便记:

  • PI:在位置轴上整体压(所有频率一起压),简单,但近距离分辨率全降。
  • NTK-aware:在频率轴上拉伸低频,保住高频的近距离精度。
  • YaRN分频段精细处理(短波不动、长波插值)+ 熵修正,效果最好。

7.和 7.3、9.2 串起来

把这一节放进大图景里:一个真正的长上下文大模型,是三件事叠起来的结果——

  • 架构上算得少、算得快:稀疏注意力/NSA/混合架构(7.3)+ FlashAttention(7.3);
  • 位置编码上能外推:RoPE + YaRN/NTK(本节);
  • 显存上装得下:KV cache 量化、PagedAttention(9.2、8.1)。

三个一起,才是 2026 年长上下文能落地的完整答案。少了哪一块——比如架构优化到飞起,但位置编码外推不了——长上下文照样立不住。

8.练习

Q1. RoPE 为什么用"旋转"来编码位置,而不是平移或缩放?

因为唯一能让"各自带上绝对位置 mmnn 之后,内积里却只剩相对位置 mnm-n"的变换是正交变换(旋转/反射)。旋转还保范数,不改变 QQKK 的长度,注意力分数的尺度稳定。平移和缩放都不满足"在内积里抵消成相对位置"这一条。

Q2. 位置插值(PI)和 NTK-aware 的核心区别是什么?各自牺牲了什么?

PI 在位置轴上整体缩放,对所有频率一视同仁地压,近距离分辨率全盘下降;NTK 在频率轴上只拉伸低频维度(负责外推的),高频(负责近距离精细)几乎不动,所以近距离精度保得更好。PI 简单但牺牲近距离分辨率,NTK 更精细、实现略复杂。

Q3.(大厂面试题) 训练长度 4k,想让模型支持 32k 上下文,你会怎么做?为什么不能光靠"把窗口开到 32k 重新训练"?

光把窗口开到 32k 重训成本太高:注意力 O(n2)O(n^2)、长文本数据也未必够。工程做法是三件事配合:架构上用稀疏注意力/混合架构省算力(7.3),KV cache 量化省显存(9.2),位置编码上用 RoPE + YaRN/NTK 把外推做到 32k(本节),再加少量长文本继续预训练微调。三个维度一起上才经济可行——光解决架构、位置编码外推不了,照样立不住。

9.小结

位置编码是长上下文"另一半"硬骨头。RoPE 把相对位置烤进 QKQ\cdot K 的内积——简洁、不增参数、保范数、外推友好,成了 2026 年主流 LLM 的标配;而长度外推三件套(PI/NTK/YaRN)让它能从训练长度延展到更长的推理长度。到这里,第七卷的前沿架构和位置编码就都备齐了。下一篇我们退一步,用一张选型决策树把这些架构串起来,告诉你什么场景该选什么。

下一章见。

相关标签
深度学习前沿架构位置编码RoPE长上下文