模型架构 / 位置编码 原理笔记入门 18 分钟阅读 查看源文件 ↗

位置编码:绝对位置与相对位置#

本页内容6 个部分

1. 为什么需要位置编码?#

Self-Attention 的计算中,QKTQK^T 算的是所有 token 两两之间的点积。把输入序列打乱顺序,每一对 token 的点积不会变——因为点积只关心"谁和谁配对",不关心"谁在前谁在后"。数学上说,Self-Attention 是 permutation equivariant(排列等变的)。

但"猫吃鱼"和"鱼吃猫"意思完全不同。**位置信息是必须的,但 Attention 机制里不自带。**所以要额外注入。

位置编码的演进史是一个不断追问"怎样的位置信息最有用"的过程:

2. 第一代:Sinusoidal(正弦位置编码)(2017,原始 Transformer)#

**设计动机:**不想增加可学习参数(那时候模型还不大,参数珍贵),而且希望能泛化到训练时没见过的长度。

PE(pos,2i)=sin⁡(pos100002i/d),PE(pos,2i+1)=cos⁡(pos100002i/d)PE_{(pos, 2i)} = \sin\left(\frac{pos}{10000^{2i/d}}\right), \quad PE_{(pos, 2i+1)} = \cos\left(\frac{pos}{10000^{2i/d}}\right)

pospos = 位置,ii = 维度索引。不同维度用不同频率的正弦/余弦

**直觉理解:**想象一个多位二进制计数器。最低位每步翻转一次(0101010...),次低位每两步翻转一次(0011001100...),高位变化更慢。Sinusoidal 编码用正弦/余弦代替方波,实现了同样的"多频率编码"——低维高频(编码精细位置),高维低频(编码粗粒度位置)。

理论优势:PEpos+kPE_{pos+k} 可以表示为 PEposPE_{pos} 的线性变换(旋转矩阵),这意味着模型理论上可以通过线性操作学到相对位置信息。

**实际问题:**虽然理论上能编码相对位置,但实验发现模型并不能很好地利用这个性质。外推能力也不如预期——训练 512 长度的模型在 1024 长度上性能显著下降。

2.1 具体数值示例(d=8d=8,即 4 对 sin/cos)#

其中 i=0,1,2,3i = 0, 1, 2, 3(因为 d=8d = 8,有 4 对 sin/cos)。先算每个维度的频率:

i=0:  1100000/8=11=1(变化最快)i=0:\;\frac{1}{10000^{0/8}} = \frac{1}{1} = 1 \quad\text{(变化最快)}

i=1:  1100002/8=1100000.25=110=0.1i=1:\;\frac{1}{10000^{2/8}} = \frac{1}{10000^{0.25}} = \frac{1}{10} = 0.1

i=2:  1100004/8=1100000.5=1100=0.01i=2:\;\frac{1}{10000^{4/8}} = \frac{1}{10000^{0.5}} = \frac{1}{100} = 0.01

i=3:  1100006/8=1100000.75=11000=0.001(变化最慢)i=3:\;\frac{1}{10000^{6/8}} = \frac{1}{10000^{0.75}} = \frac{1}{1000} = 0.001 \quad\text{(变化最慢)}

**位置 0 的编码:**把 pos=0pos=0 代入,sin⁡(0)=0\sin(0)=0,cos⁡(0)=1\cos(0)=1:

PE0=[sin⁡(0),cos⁡(0),sin⁡(0),cos⁡(0),sin⁡(0),cos⁡(0),sin⁡(0),cos⁡(0)]=[0,1,0,1,0,1,0,1]PE_0 = [\sin(0),\cos(0),\sin(0),\cos(0),\sin(0),\cos(0),\sin(0),\cos(0)] = [0,1,0,1,0,1,0,1]

位置 1 的编码:

PE1=[sin⁡(1),cos⁡(1),sin⁡(0.1),cos⁡(0.1),sin⁡(0.01),cos⁡(0.01),sin⁡(0.001),cos⁡(0.001)]PE_1 = [\sin(1),\cos(1),\sin(0.1),\cos(0.1),\sin(0.01),\cos(0.01),\sin(0.001),\cos(0.001)]

≈[0.841,  0.540,  0.100,  0.995,  0.010,  1.000,  0.001,  1.000]\approx [0.841,\;0.540,\;0.100,\;0.995,\;0.010,\;1.000,\;0.001,\;1.000]

位置 2 的编码:

PE2=[sin⁡(2),cos⁡(2),sin⁡(0.2),cos⁡(0.2),sin⁡(0.02),cos⁡(0.02),sin⁡(0.002),cos⁡(0.002)]PE_2 = [\sin(2),\cos(2),\sin(0.2),\cos(0.2),\sin(0.02),\cos(0.02),\sin(0.002),\cos(0.002)]

≈[0.909,  −0.416,  0.199,  0.980,  0.020,  1.000,  0.002,  1.000]\approx [0.909,\;{-0.416},\;0.199,\;0.980,\;0.020,\;1.000,\;0.002,\;1.000]

**规律:**低维(i=0i=0)变化很快,相邻位置差异大;高维(i=3i=3)变化极慢,相邻位置几乎相同。模型可以从低维读取精细位置,从高维读取粗粒度位置,两者结合唯一标识每个位置。

2.2 第三步:相加#

Token Embedding + 位置编码 = 最终输入:

"我"(位置0) = [ 0.12, -0.34, 0.56, 0.78, -0.11, 0.42, -0.67, 0.23]

+ [ 0.000, 1.000, 0.000, 1.000, 0.000, 1.000, 0.000, 1.000]

= [ 0.120, 0.660, 0.560, 1.780, -0.110, 1.420, -0.670, 1.230]

"爱"(位置1) = [ 0.45, 0.67, -0.23, 0.11, 0.89, -0.34, 0.56, -0.12]

+ [ 0.841, 0.540, 0.100, 0.995, 0.010, 1.000, 0.001, 1.000]

= [ 1.291, 1.210, -0.130, 1.105, 0.900, 0.660, 0.561, 0.880]

"猫"(位置2) = [-0.33, 0.21, 0.44, -0.55, 0.33, 0.77, -0.11, 0.66]

+ [ 0.909, -0.416, 0.199, 0.980, 0.020, 1.000, 0.002, 1.000]

= [ 0.579, -0.206, 0.639, 0.430, 0.350, 1.770, -0.108, 1.660]

现在同样的"猫"如果出现在位置 0,加的就是位置 0 的编码,最终向量会不一样。这样模型就能区分"猫爱我"和"我爱猫"了。

2.3 优缺点总结#

✅ 优点

  • **零参数,直接可用。**公式固定,无需训练,算出来就能用。
  • **理论上支持任意长度。**sin/cos 是连续函数,任意 pos 都能算出编码。
  • **每个位置编码唯一。**不同频率的 sin/cos 组合,不同位置不可能得到完全相同的向量。
  • 理论上能编码相对位置。PEpos+kPE_{pos+k} 可以通过一个只取决于 kk 的旋转矩阵从 PEposPE_{pos} 得到。

❌ 缺点

  • **相对位置性质模型难以利用。**线性关系藏在 sin/cos 里,是隐式的——实验证明模型并不能很好地发现和利用它。
  • **长度外推效果差。**训练时只见过 pos ∈ [0, 512],推理时 pos > 512 的行为不可预测。
  • **本质是绝对位置编码。**模型看到的是"我在位置 5",而不是"我在他前面 3 个位置",旋转矩阵的理论优势停留在纸面。
  • **与 token embedding 相互干扰。**位置信息和语义信息混合在同一向量里,若数值尺度差距过大,一方会淹没另一方。

**一句话总结:**Sinusoidal 编码在 2017 年是一个聪明的设计——零参数、零训练、能用。但它的"相对位置"优势只停留在理论上,实际上模型用不好。这就是为什么后来 RoPE 出现了——不是让模型自己去发现相对位置关系,而是直接在数学上强制让注意力分数只反映相对位置。

3. 第二代:Learnable(可学习位置编码)(2018,BERT / 2020,ViT)#

**设计动机:**Sinusoidal 是人为设计的,不一定是最优的。既然模型那么多参数都能学好,为什么位置编码不能也学?

Inputi=TokenEmbedi+PEi,PE∈RLmax⁡×d (可训练参数)\text{Input}_i = \text{TokenEmbed}_i + PE_i, \quad PE \in \mathbb{R}^{L_{\max} \times d} \text{ (可训练参数)}

**具体怎么参与模型?**就是另一张查找表,和 Token Embedding 并列,按位置索引查出向量,然后加在一起:

# 模型初始化时创建两张查找表
token_embed = nn.Embedding(vocab_size, d_model)   # 32000×4096,按 token ID 查
pos_embed   = nn.Embedding(max_len, d_model)      # 512×4096,按位置编号查

# 前向传播:输入 "I love cats" → token IDs [42, 1567, 9823]
tok = token_embed([42, 1567, 9823])   # 用 token ID 查 → 3×4096
pos = pos_embed([0, 1, 2])             # 用位置 0,1,2 查 → 3×4096

X = tok + pos    # 逐元素相加 → 送入第一个 Transformer Block

位置 0、1、2 各自对应表里的一行向量(随机初始化,跟着模型一起训练),和 token 向量加在一起就完事了。

**简单粗暴,效果还不错。**BERT 用它、GPT-2 用它、ViT 也用它。

致命缺陷:长度固定。PEPE 矩阵的行数 Lmax⁡L_{\max} 是预先定好的。训练时用 512,推理时就不能超过 512——因为第 513 个位置没有对应的位置向量(索引越界)。虽然可以用插值等 hack 来延伸,但效果不理想。

**另一个问题:编码的是绝对位置。**位置 5 和位置 10 之间的关系,需要模型自己从数据中推断出来——它和"位置 105 和位置 110"的关系可能完全不同,即使相对距离相同。

3.1 优缺点总结#

✅ 优点

  • **简单直接,效果好。**就是一张查找表,让模型自己学。训练长度范围内效果与 Sinusoidal 相当,有时略好——不受 sin/cos 形式限制,可学到任意位置表示。
  • **灵活性高。**Sinusoidal 的多频率设计未必最优,Learnable 没有这个限制,模型可以学到它认为最有用的任何位置表示。
  • **实现极其简单。**一行代码 nn.Embedding(max_len, d_model),不需要任何 sin/cos 计算逻辑。

❌ 缺点

  • **长度固定,无法外推。**训练矩阵(如 BERT 的 512×768)锁死了最长输入。插值可以强行扩展,但插值出来的向量模型从未见过,行为不可预测。
  • **编码的是绝对位置,不是相对位置。**位置 5 和 8 的关系,与位置 100 和 103 的关系(相对距离同为 3)对应的编码完全不同,模型需要分别学习,浪费数据和参数。
  • **增加了参数量。**BERT 的 512×768 = 393K 参数虽占比小,但这些参数只服务于位置编码,不像注意力矩阵那样逐层复用。
  • **长尾位置训练不充分。**若训练数据平均句子短(如 50 token),则位置 0–50 训练充分,位置 400–512 可能只被训练极少次,学得不好。

**一句话总结:**Learnable 编码是"让模型自己搞定"的思路,简单有效,但代价是长度被锁死、相对位置需要模型自己学。当模型规模小、序列不太长时(BERT、ViT 的场景)这些问题不大。但到了 LLM 时代,序列长度从 512 涨到 32K 甚至 128K,长度固定和绝对位置这两个缺点就成了硬伤,这才是 RoPE 登场的根本原因。

4. 第三代:RoPE(旋转位置编码)(2021,Su et al. → LLaMA / Qwen / Mistral 标配)#

设计动机:我们真正需要的是相对位置,不是绝对位置。"token A 在 token B 前面 3 个位置"比"token A 在位置 5"更有用。而且我不想增加参数、不想受长度限制。

核心思想:不给 token 加位置向量,而是根据位置对 Q 和 K 做旋转。位置 pospos 的 token,其 Q 和 K 被旋转 pos×θpos \times \theta 角度。

具体做法:把 dkd_k 维向量两两分组,每一组做二维旋转:

R(θ)=(cos⁡θ−sin⁡θsin⁡θcos⁡θ),RoPE(q,pos)=R(pos⋅θ1)⊕R(pos⋅θ2)⊕⋯R(\theta) = \begin{pmatrix} \cos\theta & -\sin\theta \\ \sin\theta & \cos\theta \end{pmatrix}, \quad \text{RoPE}(q, pos) = R(pos \cdot \theta_1) \oplus R(pos \cdot \theta_2) \oplus \cdots

不同维度对用不同的基频 θi=10000−2i/d\theta_i = 10000^{-2i/d}(和 Sinusoidal 的频率设计一样)

关键性质:旋转后的 Q 和 K 做点积,旋转角度会"相消",结果只取决于两个 token 的位置差:

⟨RoPE(q,m),RoPE(k,n)⟩=f(q,k,m−n)\langle \text{RoPE}(q, m), \text{RoPE}(k, n) \rangle = f(q, k, m - n)

注意力分数天然只反映相对位置 m−nm-n,和绝对位置无关

4.1 具体数值示例(d=8d=8,句子"我爱猫")#

以 d=8d=8 为例,Q 向量被分为 4 对,每对独立做二维旋转。

第一步:取出"我"(位置0)的 Q 向量并两两分组

"我" 的 Q = [(1.0, 0.5), (0.8, -0.3), (0.6, 0.2), (-0.4, 0.7)]
第0对          第1对           第2对           第3对

每一对当成一个二维向量,独立做旋转。

第二步:每一对的旋转频率不同

和 Sinusoidal 一样,不同的对用不同的频率:

第0对:θ0 = 1/10000^(0/8) = 1.0      (高频,变化快)
第1对:θ1 = 1/10000^(2/8) = 0.1
第2对:θ2 = 1/10000^(4/8) = 0.01
第3对:θ3 = 1/10000^(6/8) = 0.001  (低频,变化慢)

第三步:根据位置计算旋转角度

旋转角度 = 位置 × 频率:

位置0:"我"
    第0对旋转角度 = 0 × 1.0   = 0
    第1对旋转角度 = 0 × 0.1   = 0
    第2对旋转角度 = 0 × 0.01  = 0
    第3对旋转角度 = 0 × 0.001 = 0

位置1:"爱"
    第0对旋转角度 = 1 × 1.0   = 1.0 弧度
    第1对旋转角度 = 1 × 0.1   = 0.1 弧度
    第2对旋转角度 = 1 × 0.01  = 0.01 弧度
    第3对旋转角度 = 1 × 0.001 = 0.001 弧度

位置2:"猫"
    第0对旋转角度 = 2 × 1.0   = 2.0 弧度
    第1对旋转角度 = 2 × 0.1   = 0.2 弧度
    第2对旋转角度 = 2 × 0.01  = 0.02 弧度
    第3对旋转角度 = 2 × 0.001 = 0.002 弧度

第四步:对每一对做二维旋转

二维旋转公式:

(x′y′)=(cos⁡α−sin⁡αsin⁡αcos⁡α)(xy)\begin{pmatrix} x' \\ y' \end{pmatrix} = \begin{pmatrix} \cos\alpha & -\sin\alpha \\ \sin\alpha & \cos\alpha \end{pmatrix} \begin{pmatrix} x \\ y \end{pmatrix}

以"爱"(位置1)的第0对为例,原始值 (1.0, 0.5)(1.0,\ 0.5),旋转角度 α=1.0\alpha = 1.0 弧度:

x′=1.0×cos⁡(1.0)−0.5×sin⁡(1.0)=1.0×0.540−0.5×0.841=0.540−0.421=0.120x' = 1.0 \times \cos(1.0) - 0.5 \times \sin(1.0) = 1.0 \times 0.540 - 0.5 \times 0.841 = 0.540 - 0.421 = 0.120

y′=1.0×sin⁡(1.0)+0.5×cos⁡(1.0)=1.0×0.841+0.5×0.540=0.841+0.270=1.111y' = 1.0 \times \sin(1.0) + 0.5 \times \cos(1.0) = 1.0 \times 0.841 + 0.5 \times 0.540 = 0.841 + 0.270 = 1.111

原来是 (1.0, 0.5)(1.0,\ 0.5),旋转后变成 (0.120, 1.111)(0.120,\ 1.111)。位置 0 的"我"不旋转(角度都是 0,cos⁡(0)=1, sin⁡(0)=0\cos(0)=1,\ \sin(0)=0),Q 值不变。位置 1 的"爱"和位置 2 的"猫"被旋转了不同角度。

**关键:K 也做完全相同的旋转。**Q 和 K 都被各自位置的角度旋转了。当位置 mm 的 Q 和位置 nn 的 K 做点积时,两个旋转角度相减:

⟨R(mθ)⋅q, R(nθ)⋅k⟩=⟨R((m−n)θ)⋅q, k⟩\langle R(m\theta)\cdot q,\ R(n\theta)\cdot k \rangle = \langle R((m-n)\theta)\cdot q,\ k \rangle

结果只取决于 m−nm - n(相对距离),不取决于 mm 或 nn 的绝对值。这是 RoPE 最核心的性质——注意力分数天然只反映相对位置。

和前两种位置编码的对比:Sinusoidal 和 Learnable 都是把位置信息加到 token embedding 上——位置编码和语义信息混在一起。RoPE 不加任何东西,而是对 Q 和 K 做旋转变换——位置信息通过旋转角度注入,直接影响注意力分数的计算,不污染原始的语义表示。而且旋转后的点积天然只反映相对距离,不需要模型自己去学这个关系。

为什么这比前两代好?

  • 不需要额外参数:旋转角度由公式确定,和 Sinusoidal 一样是无参的
  • 天然编码相对位置:不需要模型自己去"推断"相对关系,数学上就保证了
  • 有一定的长度外推能力:虽然不是完美的,但比 Learnable 好得多。配合 NTK-aware scaling、YaRN 等技术,可以从 4K 训练长度扩展到 128K+

4.2 为什么旋转不作用在 V 上?#

回忆注意力的计算流程:

output=softmax ⁣(QKTdk)V\text{output} = \text{softmax}\!\left(\frac{QK^T}{\sqrt{d_k}}\right) V

分两个阶段理解:

QKTQK^T 阶段

决定"注意力怎么分配"——哪些 token 重要、哪些不重要。这个决策需要位置信息,因为"离我近的词可能更相关"。所以 Q 和 K 需要被旋转注入位置信息。

乘以 V 阶段

决定"传递什么内容"——把重要 token 的信息加权求和。传递的内容应该是纯粹的语义信息,不需要被位置"污染"。

**打个比方:**你在图书馆找书。找书的过程(Q 和 K 匹配)需要知道位置——"这本书在第三排第五列"。但你拿到书之后读的内容(V)和书放在哪个架子上没关系——《哈利波特》的内容不会因为放在第一排还是第五排而改变。

⚠️ 如果 V 也被旋转了会怎样?

那同一个 token 在不同位置传递的语义内容就不一样了。这没有道理——"猫"这个词的语义不应该因为它在句子第 3 个位置还是第 100 个位置而改变。RoPE 只旋转 Q 和 K,V 保持原始语义,这是设计上的刻意选择。

4.3 优缺点总结#

✅ 优点

  • **天然编码相对位置。**Q·K 点积时旋转角度相减,位置旋转因子只依赖相对距离 m−nm-n,完整分数仍取决于 Q/K 内容。这不是模型"学出来的",是数学上保证的——Sinusoidal 理论上有但模型用不好,Learnable 根本没有,RoPE 直接在公式层面强制了。
  • **零参数。**旋转角度由位置和频率公式确定,不需要像 Learnable 那样维护一个 Lmax⁡×dL_{\max} \times d 的可训练矩阵。
  • **不污染原始语义表示。**Sinusoidal / Learnable 把位置向量加到 token embedding 上,位置和语义混在一起。RoPE 只做旋转——向量长度(信息量)不变,只有方向改变,语义信息不被干扰。
  • **有一定的长度外推能力。**编码的是相对距离而非绝对位置,相对位置结构并不保证长度外推,未见过的距离与频率组合仍可能退化。配合 NTK-aware scaling、YaRN 等技术,可从 4K 扩展到 128K+。
  • **计算高效。**旋转操作只是每对维度做一次 sin/cos 乘加,不需要额外矩阵乘法,开销几乎可以忽略。

❌ 缺点

  • **长度外推不是完美的。**训练时见过的最大相对距离有限,超出范围后旋转角度对应的 sin/cos 值是模型没见过的区域,注意力行为可能异常。NTK-aware scaling、YaRN 这些辅助技术的本质,就是调整频率参数让远距离旋转角度不变化太剧烈。
  • **V 没有位置信息。**RoPE 只旋转 Q 和 K,V 不做任何位置相关变换。"注意力怎么分配"考虑了位置,"传递什么内容"没有。大多数场景下不是问题,但在某些需要 V 直接感知位置的任务上可能有局限。
  • **实现比前两种略复杂。**Sinusoidal 加固定向量,Learnable 查表加上去,RoPE 需要对 Q / K 的每对维度做旋转运算,代码需要额外处理维度配对和旋转矩阵构造。

**一句话总结:**RoPE 是目前位置编码的最优解——零参数、天然相对位置、不污染语义、有外推能力。缺点很小(外推需要辅助技术、V 没有位置信息、实现略复杂),远远被优势盖过。这就是为什么 LLaMA、Qwen、Mistral 等所有主流 LLM 都选了它。

4.4 RoPE 长度外推技术:从 PI 到 NTK-aware 到 YaRN#

RoPE 本身有一定的外推能力,但直接在超出训练长度的位置上使用仍会导致性能下降。社区为此发展出一系列逐步改进的外推技术:

1. 位置插值(Position Interpolation, PI)

最简单的做法:把位置索引线性缩放,让超长序列的位置"挤"进训练时见过的范围。比如训练 4K 想推理 16K,就把位置 pospos 除以 4:

RoPEPI(q,pos)=RoPE(q,pos/s),s=Ltarget/Ltrain\text{RoPE}_{\text{PI}}(q, pos) = \text{RoPE}(q, pos / s), \quad s = L_{\text{target}} / L_{\text{train}}

s=4s=4 时,位置 16000 被映射到 4000,落入训练范围

**问题:**所有频率的旋转角都被等比缩小了。高频维度(编码局部精细位置)本来在训练范围内运转良好,被缩小后分辨率下降——相邻 token 的角度差变小,模型分不清近处的位置。这就像把一张高清照片缩小了 4 倍,全局看得更远了,但局部细节模糊了。需要少量微调来适应。

2. NTK-aware Scaling

核心观察:高频维度不需要被缩放(它们周期短、训练时已见过足够多的完整周期),真正需要缩放的是低频维度(周期长、训练时只见过不到一圈)。

NTK-aware 的做法:不缩放位置,而是调大 base θ\theta。把 θ\theta 从 10000 调大到 θ′=θ⋅sd/(d−2)\theta' = \theta \cdot s^{d/(d-2)},这等效于对不同频率做非均匀缩放——低频维度被大幅放慢(避免外推到训练时没见过的旋转角),高频维度几乎不变(保留局部精细分辨率)。

θ′=θ⋅sd/(d−2)\theta' = \theta \cdot s^{d/(d-2)}

等效于对频率做非均匀缩放:低频缩放多、高频缩放少

**具体示例:**以 LLaMA 为例,d=128d=128(head dimension = hidden_dim / num_heads = 4096/32),s=4s=4(4K→16K)。RoPE 共有 d/2=64d/2=64 对维度,每对的旋转频率为 ωi=1/100002i/128\omega_i = 1/10000^{2i/128}。NTK 把 base 调大为 θ′=10000×4128/126≈40890\theta' = 10000 \times 4^{128/126} \approx 40890,对第 ii 对维度的等效缩放倍数为 42i/1264^{2i/126}:

维度对 ii 频率高低 原始角度差 PI 后(÷4) NTK 后 NTK 等效缩放
0 最高频 1 rad 0.25 1 1× 不动
10 高频 0.0398 0.01 0.0319 1.25×
32 中频 0.01 0.0025 0.00495 2×
63 最低频 1.16e-4 2.9e-5 2.9e-5 4× 全缩

对比 PI(所有维度一刀切除以 4),NTK 实现了"高频不动 → 中频缩一半 → 低频全缩"的平滑过渡。高频维度负责区分相邻 token,保持不动就保住了局部分辨率;低频维度负责远距离关系,全缩后避免外推到没见过的角度。

**优势:**不需要微调即可获得不错的外推效果("free lunch"),是 Code Llama 等模型的做法。

3. YaRN(Yet another RoPE extensioN)

YaRN 结合了前两者的优点,并加入了一个温度缩放因子:

  • **频率分区:**把维度对分成三类——高频(不缩放)、低频(做 PI 线性插值)、中频(在两者之间平滑过渡,用 ramp 函数混合)
  • **温度校正:**缩放后注意力分数的分布会变化(entropy 增大),YaRN 加入一个温度因子来补偿

**具体示例:**同样 d=128d=128, s=4s=4(4K→16K)。YaRN 的核心是对每个维度对 ii 计算一个"训练时见过多少个完整旋转周期"的比值:

ri=Ltrainλi=Ltrain2π⋅100002i/dr_i = \frac{L_{\text{train}}}{\lambda_i} = \frac{L_{\text{train}}}{2\pi \cdot 10000^{2i/d}}

rir_i 大 → 训练时见过很多圈(高频,不需要缩放);rir_i 小 → 训练时连一圈都没见完(低频,必须缩放)

然后用 ramp 函数(参数 α=1,β=32\alpha=1, \beta=32)把维度分成三个区:

γi=clamp ⁣(ri−αβ−α,  0,  1)\gamma_i = \text{clamp}\!\left(\frac{r_i - \alpha}{\beta - \alpha},\; 0,\; 1\right)

γ=1\gamma=1:高频,不缩放;γ=0\gamma=0:低频,全 PI 缩放;中间:平滑过渡

每个维度的等效缩放倍数为 si=1+(1−γi)(s−1)s_i = 1 + (1 - \gamma_i)(s - 1):

维度对 ii rir_i(见过几圈) γi\gamma_i 区域 等效缩放 sis_i
0 652 1 高频 → 不缩放 1×
20 36.7 1 高频 → 不缩放 1×
26 15.5 0.47 过渡区中部 2.6×
32 6.5 0.18 过渡区下部 3.5×
45 1.0 0 低频 → 全 PI 缩放 4×
63 0.075 0 低频 → 全 PI 缩放 4×

对比三种方法对 i=26i=26(中频维度)的处理:PI 直接 4× 全缩,NTK 约 1.8× 轻缩,YaRN 2.6× 适度缩放。YaRN 在过渡区的处理比 NTK 更激进(更接近 PI),因为 r=15.5r=15.5 意味着训练时只见过 15 圈,YaRN 认为这还不够安全,需要一定程度的缩放。

**温度校正:**缩放降低了旋转频率,使远处 token 的旋转角变小、cos⁡\cos 更接近 1,导致远近 token 的注意力 logits(即 QKT/dkQK^T/\sqrt{d_k},softmax 之前的原始分数)差距缩小,softmax 后的注意力分布变平(entropy 增大)。YaRN 对 logits 额外乘一个温度因子 1/st1/\sqrt{s_t}(st=0.1ln⁡(s)+1s_t = 0.1\ln(s)+1,s=4s=4 时 st≈1.14s_t \approx 1.14)来收紧分布,使 softmax 输出重新变尖锐、与原始模型保持一致。

**效果:**YaRN 只需约 400 步微调即可将 LLaMA-2 从 4K 外推到 128K,是目前效果最好的 RoPE 外推方案之一。

**三种技术的区别一句话:**PI 对所有频率等比缩放(简单但损精度),NTK-aware 通过调大 θ\theta 实现非均匀缩放(不需要微调),YaRN 分区处理 + 温度校正(效果最好但需少量微调)。

5. 另一条路线:ALiBi(Attention with Linear Biases)(2022,Press et al. → MPT / BLOOM / Falcon)#

设计动机:RoPE 需要对 Q/K 做旋转运算,能不能更简单?能不能完全不对输入加位置编码,而是在 attention score 上做手脚?

5.1 核心思想#

ALiBi 的做法极其直接:不给 token 加任何位置向量,也不做旋转,而是在计算 attention score 时,加一个与距离成正比的负偏置——距离越远,惩罚越大:

Attention(Q,K)=softmax ⁣(QKTdk+m⋅bias)\text{Attention}(Q, K) = \text{softmax}\!\left(\frac{QK^T}{\sqrt{d_k}} + m \cdot \text{bias}\right)

mm 是每个 head 不同的斜率(slope),bias 矩阵只取决于 token 间距离

bias 矩阵的定义非常简单:

bias[i][j]=−∣i−j∣\text{bias}[i][j] = -|i - j|

距离越远,bias 越负,softmax 后注意力权重越小

每个 head 有一个不同的斜率 mm,按几何级数预设:

m=2−8/n,  2−16/n,  …m = 2^{-8/n},\; 2^{-16/n},\; \ldots

nn 为 head 数。不同 head 的 mm 不同:mm 大的 head 关注近处,mm 小的 head 关注远处

5.2 具体数值示例(4 个 head,序列长度 5)#

第一步:确定每个 head 的斜率

n=4n=4 个 head,斜率为 2−8/4=2−2=0.252^{-8/4}=2^{-2}=0.25, 2−16/4=2−4=0.06252^{-16/4}=2^{-4}=0.0625, 2−24/4=2−6=0.0156252^{-24/4}=2^{-6}=0.015625, 2−32/4=2−8=0.003906252^{-32/4}=2^{-8}=0.00390625。简化示例取 m=[0.5,0.25,0.125,0.0625]m = [0.5, 0.25, 0.125, 0.0625]:

head 0 : m = 0.5    (衰减快 → 关注近处)
head 1 : m = 0.25
head 2 : m = 0.125
head 3 : m = 0.0625  (衰减慢 → 关注远处)

第二步:构造 bias 矩阵(所有 head 共用)

bias[i][j] = -|i - j|

[[ 0, -1, -2, -3, -4],
 [-1, 0, -1, -2, -3],
 [-2, -1, 0, -1, -2],
 [-3, -2, -1, 0, -1],
 [-4, -3, -2, -1, 0]]

第三步:乘以斜率得到每个 head 的实际偏置

head 0(m=0.5m=0.5,衰减快 → 关注近处)

[[ 0.0, -0.5, -1.0, -1.5, -2.0],
 [-0.5, 0.0, -0.5, -1.0, -1.5],
 [-1.0, -0.5, 0.0, -0.5, -1.0],
 [-1.5, -1.0, -0.5, 0.0, -0.5],
 [-2.0, -1.5, -1.0, -0.5, 0.0]]

head 2(m=0.125m=0.125,衰减慢 → 关注远处)

[[ 0.0, -0.125, -0.25, -0.375, -0.5],
 [-0.125, 0.0, -0.125, -0.25, -0.375],
 [-0.25, -0.125, 0.0, -0.125, -0.25],
 [-0.375, -0.25, -0.125, 0.0, -0.125],
 [-0.5, -0.375, -0.25, -0.125, 0.0]]

对比加粗的角落值:距离=4 时,head 0 的惩罚是 −2.0-2.0,head 2 只有 −0.5-0.5——head 2 对远处 token 的惩罚轻得多,可以"看得更远"。

5.3 为什么有效#

  • **直觉:**attention score 本身就包含了"哪些 token 重要"的信息,距离偏置只是温和地偏好近处——像一个可调的"近视眼镜",不同 head 度数不同。
  • 零额外参数:mm 是按公式预设的,不可学习,bias 矩阵按距离公式算出来,不需要训练。
  • **长度外推:**训练时用短序列(比如 2K),推理时可以直接外推到更长序列(8K+),因为 bias 只依赖 token 间距离,不依赖绝对位置——没见过的位置没关系,只要距离的偏置值合理就行。

5.4 优缺点总结#

✅ 优点

  • **零额外参数。**斜率 mm 预设,bias 按距离计算,不增加任何可训练参数。
  • **长度外推能力强。**训练 2K,推理可到 8K+。在 Press et al. 的实验中,ALiBi 的外推效果优于 Sinusoidal 和 Learnable。
  • **实现极简。**几行代码——构造距离矩阵,乘以斜率,加到 attention score 上,完成。

❌ 缺点

  • **线性距离衰减过于简化。**真实语言中,"重要性"不一定随距离单调递减(比如段落首句可能很重要但距离很远),ALiBi 的位置 bias 本身单调,但内容点积仍能表达非单调的重要性。
  • **外推不如 RoPE + NTK。**虽然好于 Sinusoidal/Learnable,但 RoPE 配合 NTK-aware 插值 / YaRN 的外推效果已经追上甚至超过 ALiBi。
  • **未成为主流。**在 BLOOM、MPT、Falcon 上验证可行,但 LLaMA、Qwen、Mistral 等主流 LLM 最终选择了 RoPE。

💡 为什么主流选了 RoPE 而不是 ALiBi?

  • RoPE 保留了相对位置信息的同时兼容绝对位置,表达能力更强。
  • RoPE + NTK-aware 插值 / YaRN 的外推效果已经追上甚至超过 ALiBi。
  • RoPE 在多模态场景(2D 图像、3D 视频的空间位置编码)中更容易扩展,ALiBi 的一维距离偏置不好推广到高维。

**一句话总结:**ALiBi 是一种极简的位置编码方案——不加位置向量,只在 attention score 上加距离惩罚。零参数、外推好、实现简单,但线性衰减过于粗糙,在 RoPE + 外推技术面前没有决定性优势,最终没有成为主流 LLM 的首选。

6. 总结对比#

方法 年份 核心思路 是否学习 绝对/相对 长度外推 代表模型
Sinusoidal 2017 固定的多频率正弦函数 否 绝对 差 原始 Transformer
Learnable 2018 每个位置学一个向量 是 绝对 不能 BERT, GPT-2, ViT
RoPE 2021 用位置做旋转变换 否 相对 较好 LLaMA, Qwen, Mistral
ALiBi 2022 attention score 加距离负偏置 否(零参数) 相对 强 BLOOM, MPT, Falcon

6.1 主流模型使用情况#

模型 年份 位置编码 说明
Transformer(原始) 2017 Sinusoidal 固定 sin/cos 公式,不需要学习
BERT 2018 Learnable 最大长度 512,可训练参数
GPT-2 2019 Learnable 最大长度 1024
ViT 2020 Learnable 图像 patch 序列长度固定,Learnable 够用
CLIP(视觉侧) 2021 Learnable 同 ViT
GPT-NeoX 2022 RoPE 开源模型中较早采用 RoPE,无外推扩展
BLOOM 2022 ALiBi BigScience 大模型,选择 ALiBi 做位置编码
MPT 2023 ALiBi MosaicML 出品,ALiBi 代表模型
Falcon 2023 ALiBi TII 出品,也采用 ALiBi
LLaMA 1 2023 RoPE 原始 RoPE,上下文 2K,无外推
LLaMA 2 2023 RoPE 上下文 4K;社区用 YaRN/NTK 扩展到 128K+
Code LLaMA 2023 RoPE NTK-aware 外推,16K 上下文
LLaMA 3 2024 RoPE 直接调大 base θ\theta 到 500K(NTK 思路),原生 128K
Qwen 全系列 2023–24 RoPE YaRN 外推,Qwen2 支持 128K
Mistral / Mixtral 2023–24 RoPE NTK-aware 外推,结合 Sliding Window Attention
DeepSeek 2024 RoPE YaRN 外推,DeepSeek-V2 支持 128K
DiT 2023 adaLN-Zero 不用传统 PE,位置信息通过 adaLN 注入
Stable Diffusion 3 2024 RoPE 2D 图像的高度和宽度两个方向分别做旋转
CogVideoX 2024 RoPE 3D 时间 + 高度 + 宽度三个方向分别旋转
HunyuanVideo 2024 RoPE 3D 同 CogVideoX,视频生成需要 3D 位置编码

**趋势:**Sinusoidal 已退出历史 → Learnable 在固定长度场景仍在用 → ALiBi 在部分模型(BLOOM/MPT/Falcon)中验证可行 → RoPE 最终胜出,成为 LLM 和视频生成的标配 → 扩散模型从 adaLN 向 RoPE 演进

🔥 面试怎么答"你知道哪些位置编码"

说四种,按时间线讲演进逻辑:Sinusoidal 是第一代,固定公式不需要学习,但相对位置利用不充分;Learnable 是第二代,简单有效但长度固定;RoPE 是第三代,通过旋转操作天然编码相对位置,不需要参数,有外推能力,是现在主流 LLM 的标配。还有 ALiBi,思路不同——不加位置编码,而是在 attention score 上加距离惩罚,零参数且外推能力强,BLOOM/MPT/Falcon 用了它,但最终 RoPE 因为表达能力更强、多模态扩展更好成为主流。

相关阅读路线

理解 Transformer 与架构变体 ↗