跳转至

第 6 章 位置表示

6.1 回顾:第 2 章的绝对位置

不带位置、也不带因果掩码的自注意力是置换等变的:若用置换矩阵 \(P\) 重排输入,则

\[ \operatorname{Attention}(PX)=P\,\operatorname{Attention}(X) \]

输出只会跟着重排。第 2 章的对策是查表后加绝对位置:

\[ h^{(0)}_t=E[x_t]+\mathrm{PE}(t) \]

\(\mathrm{PE}\) 可以是正弦公式,也可以是可学习表。小模型因此能分清语序,第一部分的解码器才算齐。因果掩码还会泄露「左边有几个词」,但稳定表达「相隔 3」和「相隔 3000」仍要靠显式位置。

绝对位置的两处限制,在放大后变得扎眼:

  1. 相对距离是间接学的:模型看见的是「我在 17、对方在 20」,要自己悟出「差 3」;\(q^\top k\) 里没有直接出现 \(n-m\)。
  2. 长度绑在训练分布上:可学习表对没见过的下标没有行;正弦能外推,质量也常掉。

要的是:注意力分数里直接出现相对距离,而不是只靠嵌入上的绝对下标让模型自己悟。

6.2 RoPE:把相对位置写进点积

这个例子里 Q、K、V 各是什么

四个位置,每个位置投影之后都有自己的三个向量 \(q_j,k_j,v_j\)(这里假装头维 \(d_h=2\),数字是示意):

下标 \(j\) token \(q_j\)(去提问) \(k_j\)(被提问时的标签) \(v_j\)(被选中时交出的内容)
0 预算 \((1.0,\ 0.2)\) \((0.9,\ 0.1)\) \((0.5,\ 0.5)\)
1 五千 \((0.3,\ 0.8)\) \((1.0,\ 0.0)\) \((2.0,\ 0.0)\)
2 , \((0.1,\ 0.1)\) \((0.2,\ 0.2)\) \((0.0,\ 0.1)\)
3 别太赶 \((1.0,\ 0.0)\) \((0.4,\ 0.6)\) \((0.7,\ 0.3)\)
  • \(q_j\):位置 \(j\) 作为当前格时,用来和序列里各位置做匹配的向量。
  • \(k_j\):位置 \(j\) 被匹配时参与点积的向量。
  • \(v_j\):匹配权重算完后,从位置 \(j\) 取走的内容向量。

当前要算的是位置 3 的输出:用到 \(q_3\),以及 \(k_0,k_1,k_2,k_3\) 和 \(v_0,v_1,v_2,v_3\)。\(q_0,q_1,q_2\) 在这一步不用;它们只在「当前格是 0/1/2」时才会被拿来打分。

转谁

RoPE 只旋转上表里的 \(q\) 和 \(k\),而且按该行自己的下标转:

向量 转不转 转完变成
\(q_3\) 转,用 \(R_3\) \(R_3 q_3\)
\(k_0\) 转,用 \(R_0\) \(R_0 k_0\)
\(k_1\) 转,用 \(R_1\) \(R_1 k_1\)
\(k_2\) 转,用 \(R_2\) \(R_2 k_2\)
\(k_3\) 转,用 \(R_3\) \(R_3 k_3\)
\(v_0,v_1,v_2,v_3\) 不转 仍是表里原来的数
词嵌入 不转 与 RoPE 无关

\(R_j\) 是由下标 \(j\) 决定的 \(2\times 2\) 旋转矩阵(角度 \(j\cdot\omega\))。同一行的 \(q_j\) 与 \(k_j\) 用同一个 \(R_j\);不同行用不同的 \(R_j\)。

转完干什么

位置 3 用转完的 Query 去和每个转完的 Key 打分(再除 \(\sqrt{d_h}\)):

\[ \begin{align*} s_{3,0}&=(R_3 q_3)^\top(R_0 k_0)/\sqrt{2},\\ s_{3,1}&=(R_3 q_3)^\top(R_1 k_1)/\sqrt{2},\\ s_{3,2}&=(R_3 q_3)^\top(R_2 k_2)/\sqrt{2},\\ s_{3,3}&=(R_3 q_3)^\top(R_3 k_3)/\sqrt{2}. \end{align*} \]

四个分数 softmax 得到权重 \(\alpha_{3,0},\ldots,\alpha_{3,3}\),再对没转过的 Value 加权:

\[ o_3=\alpha_{3,0}v_0+\alpha_{3,1}v_1+\alpha_{3,2}v_2+\alpha_{3,3}v_3. \]

整段里 RoPE 只插手「\(s_{3,j}\) 算多大」;取内容时仍用表里原来的 \(v_j\)。

还用上面的数:相对距离怎样进 \(s_{3,1}\)

只看位置 3 对位置 1 这一格分数。表里 \(q_3=(1,0)\),\(k_1=(1,0)\)。为把角度算清楚,这一小节假设每步转 \(\omega=30^\circ\)(真模型里由 rope_theta 算出来的 \(\omega\) 小得多,道理相同)。

不转时。
\(q_3^\top k_1=1\cdot 1+0\cdot 0=1\)。分数只说「这两个内容向量完全同向」。

按例子转完再乘。
\(R_3\) 把向量转 \(3\times 30^\circ=90^\circ\),故 \(R_3 q_3=(0,1)\)。
\(R_1\) 把向量转 \(1\times 30^\circ=30^\circ\),故 \(R_1 k_1=(\cos 30^\circ,\sin 30^\circ)=(\sqrt{3}/2,\ 1/2)\)。
点积变成

\[ (R_3 q_3)^\top(R_1 k_1)=0\cdot\frac{\sqrt{3}}{2}+1\cdot\frac{1}{2}=\frac{1}{2}. \]

同一对内容,分数从 \(1\) 变成 \(1/2\)。差在哪里?两步转角相差 \(90^\circ-30^\circ=60^\circ\),也就是下标差 \(3-1=2\) 步 \(\times 30^\circ\)。写成矩阵就是前面那条恒等式在本例上的样子:

\[ (R_3 q_3)^\top(R_1 k_1)=q_3^\top R_{1-3}k_1=q_3^\top R_{-2}k_1. \]

同一对内容,换一个间隔。 若「五千」的 \(k\) 仍是 \((1,0)\),但挪到下标 2(与 3 只隔 1),则用 \(R_2\)(转 \(60^\circ\)):

\[ R_2 k=(1/2,\ \sqrt{3}/2),\qquad (R_3 q_3)^\top(R_2 k)=0\cdot\frac{1}{2}+1\cdot\frac{\sqrt{3}}{2}=\frac{\sqrt{3}}{2}. \]

\(k\) 的内容没变,只是相对位置 3 的间隔从 2 变成 1,分数从 \(1/2\) 变成 \(\sqrt{3}/2\)。相对距离进的是这一格点积的数值;\(v_1\) 始终还是表里的 \((2,0)\),没有参与旋转。

一般写成 \((R_m q)^\top(R_n k)=q^\top R_{n-m}k\)。二维里 \(R(m\omega)\) 就是

\[ R(m\omega)= \begin{bmatrix} \cos(m\omega)&-\sin(m\omega)\\ \sin(m\omega)&\cos(m\omega) \end{bmatrix}, \]

真模型把 \(d_h\) 切成多对,每对各自一个 \(\omega_i=\theta_{\text{base}}^{-2i/d_{\text{rope}}}\)。不增加参数,输出形状不变。

各维频率由 rope_theta 决定(经典值 10000,长文常更大)。靠前的维对转得快,分辨局部;靠后的转得慢,覆盖长距离。Qwen、Llama 一类 decoder-only 几乎都用 RoPE。ALiBi、相对位置偏置仍有个别模型在用。

与第 2 章对照:绝对位置加在 \(h^{(0)}\) 上;RoPE 在每一层注意力点积前作用在 Q/K 上,嵌入不再加 \(\mathrm{PE}(t)\)。若同时有第 5 章的 QK-Norm,顺序是:投影 → 拆头 → QK-Norm → RoPE → 点积。先旋转再归一化,与先归一化再旋转,形状相同、数值不同。

6.3 超过训练长度时会发生什么

RoPE 的角度 \(m\cdot\omega\) 只在训练见过的 \(m\) 上可靠。推理时若 \(m\) 远大于训练长度,模型面对的是没见过的旋转角,注意力分布会乱,生成质量明显下降。换了 RoPE 也不会自动变成任意长上下文。

2023 年前后,有一批方法在不改结构的前提下改旋转角,好把已训好的模型窗口拉长一点:位置插值(PI)把位置线性压回训练范围;NTK-aware / 调大 rope_theta 让低频维承担扩窗、高频维尽量保住局部;YaRN 再按频率分段并加温度修正。它们常出现在 config 的 rope_scaling 一类字段里。算法名相同不代表各家公式完全一样;权重若没按同一方案训过,格式能跑不代表质量可靠。再配少量长文本继续训练,通常比只改推理侧角度更稳。

今天多数开源模型会直接按目标长度训练,rope_scaling 经常是空的。读 config 时认出这些名字即可。超长之后真正难的是 KV 涨、注意力变贵、中间内容被忽略——第 7 章与第四部分。

6.4 部分层不加 RoPE

因果模型里,每个位置能看见左边多少个 token,本身带一点位置线索。于是有的层干脆不旋转(NoPE),只靠内容做匹配,长度泛化有时更好。常见做法是带 RoPE 的层与 NoPE 层交替;它还没有像 RMSNorm、GQA 那样成为统一标配。

另有一种是部分维度 RoPE:每个头只有一部分维旋转,其余维不转。第 16 章的 QSA(头维 256、RoPE 维 64)属于后者,不是整层 NoPE。

6.5 现代位置表示

开源 config,Qwen、Llama 一类稠密模型默认仍是 RoPE + 目标长度直接训

在新的 Kimi K3 的全局注意力(MLA)层对 Q/K 不加 RoPE,报告里直接写成 NoPE;顺序与近因,改由穿插的线性/递归层(KDA:门控、衰减、短卷积)隐式带着。扩到百万级上下文时,也就不必再调 rope_theta 或套 YaRN。这能成立,靠的是混合注意力骨架;在「纯 decoder + 全注意力」骨架上直接去掉 RoPE,通常撑不住同样的长度。K2 那种全 MLA 路径上,RoPE 仍关键。混合架构在第四、五部分展开;读权重时 RoPE 仍是最常见的选择,但旗舰里已经有人把显式位置编码从注意力里拿掉。

动手:改一处

在第 2 章绝对位置骨架上,去掉嵌入上的 \(\mathrm{PE}\),改接 RoPE。用短序列训练后,直接推到更长的长度,观察困惑度;再与「保留绝对位置、不加 RoPE」对照,看相对距离相关的错误差在哪。


核心问答

Q1:第 2 章已经有位置编码,为什么还要第 6 章? 第 2 章的绝对位置解决「跑起来时能分清先后」。这一章解决「放大、拉长之后,相对距离怎样更干净地进注意力」。RoPE 不是位置的第一次出现,而是绝对位置的主流替换。

Q2:RoPE 是在量 \(q\) 与 \(k\) 之间的距离吗? 分数仍是点积 \(q^\top k\)(再缩放),反映投影后内容是否对齐;欧氏距离不进公式。RoPE 让这个点积额外依赖相对位置差 \(n-m\),于是同一对内容在不同间隔上得分不同。

Q3:RoPE 明明按绝对位置旋转,为什么说它是相对位置编码? 因为 \(R_m^\top R_n=R_{n-m}\),旋转后的点积只通过 \(n-m\) 依赖位置,不依赖绝对下标本身。

Q4:为什么只旋转 Q 和 K,不旋转 V? \(q^\top k\) 决定看谁、看多少;V 是取回来的内容。位置差写进匹配分数即可,不必改写被取用的向量。

Q5:想支持更长上下文,把 rope_theta 直接调大不就行了? 可以,但不是免费的。基频调大等于所有维转得更慢,长距离好分辨了,相邻位置的差别变小。今天更常见的是训练时就开到目标长度;只靠推理侧改角度,质量要另验。

Q6:既然 NoPE 也能工作,为什么不全部去掉位置编码? 纯因果注意力里,隐式线索偏弱,局部语序仍要相对位置撑着,所以常见是多数层 RoPE、少数层 NoPE。整网去掉显式位置编码可以,但通常要有别的模块承担顺序——Kimi K3 靠 KDA 一类递归层(§6.5),不是在第 2 章那套全注意力骨架上直接拔掉 RoPE。