从一条直线到大模型输出一个token(四):位置编码 RoPE
建议先看:从一条直线到大模型输出一个token(三):隐藏层与嵌入
上一篇留下两个坑:嵌入矩阵不知道顺序、不知道上下文。这一篇填第一个坑——矩阵怎么"知道"每个词排在第几位。
从一条直线到大模型输出一个token(四):位置编码 RoPE
1. 排列等变性:注意力天生是"位置盲"
先看一个反直觉的事实。
上一篇说过,后续所有层对矩阵的处理都是"逐行计算"——第 1 行算第 1 行的,第 3 行算第 3 行的。现在把"我吃苹果"和"苹果吃我"这两句话分别送进模型,如图 4-1 所示。

图4-1 排列等变性:注意力是「位置盲」——这是必须补位置的根因
两句话的嵌入矩阵里,「我」的向量内容一模一样,只是行位置不同(一个在第 1 行,一个在第 3 行)。而后续的自注意力机制(第 7 篇会看到它怎么算)对每一行的处理方式完全一样——行与行怎么排列,它根本不关心。
这个性质在数学上叫排列等变性(permutation equivariance):输入行序打乱,输出行序跟着打乱,但内容不变。对"我吃苹果"和"苹果吃我",注意力算出的结果几乎相同——但这两句话的意思天差地别。
所以必须在矩阵进 Transformer 之前,把位置信息"揉"进向量里。这就是位置编码(Position Encoding)干的事。
2. 位置编码的设计要求
不是随便塞个数字就行。位置编码要满足三条设计要求:
- 每个位置有唯一编码——位置 0 和位置 5 的编码必须不同,否则等于没加
- 能表达相对距离——理想情况下,"位置 3 和位置 5 的关系"应该能从编码里算出来,因为语言里远近距离很重要("今天"和"天气"相邻 vs 隔了 10 个词,相关性不同)
- 不受句子长度限制——训练时见过 4096 个 token,推理时来了 8192 个,编码最好还能用(外推性)
三代方案对这三条要求的满足程度,决定了各自的命运,演进时间线如图 4-2 所示。

图4-2 位置编码三代演进:从绝对到可学习,再到旋转
3. 第一代:正弦余弦绝对位置编码(2017)
3.1 公式与直觉
原始 Transformer(2017 年《Attention is All You Need》)的做法:给每个位置 m 造一个 4096 维的向量 PE(m),直接加到词向量上:
X p o s = X + P E \mathbf{X}_{pos} = \mathbf{X} + \mathbf{PE} Xpos=X+PE
PE 的每一维用不同频率的正弦/余弦波生成:
P E ( m , 2 i ) = sin ( m 10000 2 i / d ) , P E ( m , 2 i + 1 ) = cos ( m 10000 2 i / d ) PE(m,\ 2i) = \sin\left(\frac{m}{10000^{2i/d}}\right), \qquad PE(m,\ 2i+1) = \cos\left(\frac{m}{10000^{2i/d}}\right) PE(m, 2i)=sin(100002i/dm),PE(m, 2i+1)=cos(100002i/dm)
直觉如图 4-3 上半部分:不同维度用不同频率的波。高频维度(波长短)像尺子的毫米刻度,能分辨相邻位置;低频维度(波长大)像厘米刻度,负责分辨远距离。

图4-3 第一代:不同维度不同频率的波 + 贯穿案例的PE数值
3.2 贯穿案例的 PE 矩阵
用 d=4 演示(两对维度,频率分别为 1 和 1/100),我们 6 个 token 的 PE 矩阵如图 4-3 下半部分。以位置 1 为例: sin ( 1 ) = 0.841 \sin(1) = 0.841 sin(1)=0.841, cos ( 1 ) = 0.540 \cos(1) = 0.540 cos(1)=0.540——图中每个数都能套公式手算验证。
3.3 优缺点(带例子)
优点举例:训练时模型只见过 8192 个位置的 PE 矩阵,推理时来了 10000 个 token 的新闻稿——套公式 sin ( 10000 / 10000 2 i / d ) \sin(10000/10000^{2i/d}) sin(10000/100002i/d) 直接算出来就能用,不用像第二代那样担心"表里没有"。这正是第一代论文里 1 10000 2 i / d \frac{1}{10000^{2i/d}} 100002i/d1 设计成几何级数衰减频率的原因:外推到任意长度都合理。
缺点举例:以「今天」在两个不同位置的对比说明"加法融合"的副作用——
| 情况 | 原始词向量(仅语义) | 加 PE 后 | 含义 |
|---|---|---|---|
| 「今天」在位置 0 | [0.32, -1.07, 0.88, 0.05] | [0.32, -0.07, 0.88, 1.05] | “今天”+0 位置 |
| 「今天」在位置 5 | [0.32, -1.07, 0.88, 0.05] | [-0.64, -0.79, 0.93, 0.75] | “今天”+5 位置 |
同一个词向量加上不同的 PE,得到完全不同的数字;模型要从这个"加好的数字"里反向拆出"词义+位置",要费不少劲。这就是第一代"加法融合"被第二代和第三代逐步抛弃的原因。
至于"相对距离机制绕"——要靠三角恒等式 sin ( m + n ) = sin m cos n + cos m sin n \sin(m+n) = \sin m \cos n + \cos m \sin n sin(m+n)=sinmcosn+cosmsinn 反推两个位置的差,公式推导上不算优雅。
4. 第二代:可学习位置编码(GPT-2 / BERT)
GPT-2 和 BERT 的思路更简单粗暴:位置也当成"词"来学。
给每个位置配一个可训练的 4096 维向量,存成一张表(最大长度 8192 行 × 4096 列),训练时和嵌入表一起自动学出来。使用时位置序号当行号查表,加到词向量上,如图 4-4 所示。

图4-4 第二代:可学习位置编码——把位置也当成词来学
实测效果不输第一代,GPT-2 时代风光无限。但三个硬伤逐渐暴露:
- 外推死穴:表只刻到 8192 行,第 8193 个 token 直接没有编码,上下文长度被表的大小焊死
- 参数冗余:8192×4096 ≈ 3300 万参数,只干"编码位置"这一件事
- 没有结构:位置 100 和位置 101 的两个向量之间的距离,跟位置 1 和位置 2 之间的距离没有任何规律关系——"相邻"这个概念在表里没有被表达
5. 第三代:RoPE 旋转位置编码(事实标准)
5.1 核心思想:不加数,转角度
RoPE(Rotary Position Embedding,2021 年 RoFormer 论文提出)换了个思路:不往向量里加任何数字,而是把向量按自己的位置旋转一个角度,如图 4-5 所示。

图4-5 第三代:RoPE——用旋转角表示位置
规则很简单:
- 位置 0 的向量:不转
- 位置 1 的向量:转 θ \theta θ
- 位置 m 的向量:转 m θ m\theta mθ
4096 维向量被拆成 2048 对二维平面,每一对用不同的频率旋转:
θ i = 10000 − 2 i / d , i = 0 , 1 , … , 2047 \theta_i = 10000^{-2i/d}, \qquad i = 0, 1, \dots, 2047 θi=10000−2i/d,i=0,1,…,2047
频率从 1(第 0 对)递减到 0.0001(第 2047 对)——和第一代正弦余弦的频率设计一脉相承,只是从"加波形"变成了"转角度"。
5.2 数学魔法:绝对旋转,相对信息
RoPE 最漂亮的地方在于:各自旋转后的两个向量做点积,结果只取决于旋转角之差——也就是位置之差。
用旋转矩阵写出来( R m \mathbf{R}_m Rm 表示位置 m 的旋转):
⟨ R m q , R n k ⟩ = ⟨ R m − n q , k ⟩ \langle \mathbf{R}_m \mathbf{q},\ \mathbf{R}_n \mathbf{k} \rangle = \langle \mathbf{R}_{m-n} \mathbf{q},\ \mathbf{k} \rangle ⟨Rmq, Rnk⟩=⟨Rm−nq, k⟩
左边是"各自按绝对位置旋转后点积",右边是"只按相对位置 ( m − n ) (m-n) (m−n) 旋转一次"。这个恒等式是三角函数和角公式 cos ( m θ ) cos ( n θ ) + sin ( m θ ) sin ( n θ ) = cos ( ( m − n ) θ ) \cos(m\theta)\cos(n\theta) + \sin(m\theta)\sin(n\theta) = \cos((m{-}n)\theta) cos(mθ)cos(nθ)+sin(mθ)sin(nθ)=cos((m−n)θ) 的矩阵版。
真实算一组数验证(演示向量 [ 0.5 , − 0.3 ] [0.5, -0.3] [0.5,−0.3], θ = 1 \theta=1 θ=1):
| 位置对 | 相对距离 | 点积 |
|---|---|---|
| (m=1, n=3) | 2 | -0.1415 |
| (m=2, n=4) | 2 | -0.1415 |
| (m=0, n=5) | 5 | 0.0964 |
表4-1 RoPE 相对性质验证:同距离点积相同
绝对位置不同、相对距离相同 → 点积分毫不差。位置信息就这样悄悄融进了后续所有点积运算(第 7 篇会看到,注意力分数恰恰就是点积)。
5.3 为什么它成了事实标准
三条设计要求逐条对答案:
- 唯一编码:每个位置的旋转角组合唯一 ✓
- 相对距离:点积天然只依赖位置差(表 4-1 实证),比前两代都直接 ✓
- 外推性:任意位置 m 都能算 m θ m\theta mθ,没有表的上限 ✓
再加两条工程红利:零参数(不用学,不用存表);不加数(词义信息和位置信息不混在一碗里,位置通过"旋转"作用在整个向量上)。
于是 2023 年之后,LLaMA、Qwen、GLM、DeepSeek、Mistral……所有主流开源大模型全部采用 RoPE。DeepSeek-V3、GLM-4 系列用的还都是它的变体(部分旋转 + 低频外推),根子都是这套旋转思想。
6. 贯穿案例:给 6×4 矩阵做 RoPE
6.1 演示规模设定
最后把整个流程跑一遍。先说清楚手算的设定:
- 维度 d=4,拆成 2 对([d₁,d₂] 一对,[d₃,d₄] 一对)
- 频率 θ 1 = 10000 0 = 1 \theta_1 = 10000^{0} = 1 θ1=100000=1(高维用高频), θ 2 = 10000 − 0.5 ≈ 0.01 \theta_2 = 10000^{-0.5} \approx 0.01 θ2=10000−0.5≈0.01(低维用低频)
- 真实规模:d=4096 时拆 2048 对,频率从 θ 0 = 1 \theta_0=1 θ0=1 递减到 θ 2047 = 10000 − 2046 / 4096 = 0.0001 \theta_{2047}=10000^{-2046/4096}=0.0001 θ2047=10000−2046/4096=0.0001
6.2 为什么是 10000,为什么是递减
这两个问题合并回答:位置 m 转的角度是 m θ m\theta mθ, θ \theta θ 决定"多远的位置才能转一圈"。
- θ = 1 \theta=1 θ=1 表示 m m m 增加 2 π 2\pi 2π(约 6.28)个位置就转一整圈;远距离的位置会"周期重合"——这正是高频维度负责"近距离区分"的原因
- θ = 0.01 \theta=0.01 θ=0.01 表示 m m m 增加 628 628 628 个位置才转一整圈;这就是低频维度,能区分"几公里外"的位置
- 10000 是几何级数的"最大分母",控制整套频率从"高频(转得快)"到"低频(转得极慢)“的跨度——4096 个频率形成多尺度的"时间感”
类比:手表有秒针(转一圈 60 秒,分辨近距离的秒变化)、分针(转一圈 60 分钟)、时针(转一圈 12 小时,跨越大尺度)。多频率组合才能同时辨"近处"和"远处"。
6.3 「西安」行的完整手算
以「西安」(位置 m=1)为例,手算过程如图 4-6 所示。

图4-6 贯穿案例:给6×4矩阵做RoPE(「西安」行完整手算)
第一对 [ − 0.58 , 0.91 ] [-0.58, 0.91] [−0.58,0.91] 旋转 1 × 1 = 1 1 \times 1 = 1 1×1=1 rad:
x ′ = − 0.58 cos 1 − 0.91 sin 1 = − 1.079 , y ′ = − 0.58 sin 1 + 0.91 cos 1 = 0.004 x' = -0.58\cos 1 - 0.91\sin 1 = -1.079, \qquad y' = -0.58\sin 1 + 0.91\cos 1 = 0.004 x′=−0.58cos1−0.91sin1=−1.079,y′=−0.58sin1+0.91cos1=0.004
第二对 [ 0.27 , − 0.72 ] [0.27, -0.72] [0.27,−0.72] 旋转 1 × 0.01 = 0.01 1 \times 0.01 = 0.01 1×0.01=0.01 rad(几乎没转):
x ′ = 0.27 cos 0.01 + 0.72 sin 0.01 = 0.277 , y ′ = 0.27 sin 0.01 − 0.72 cos 0.01 = − 0.717 x' = 0.27\cos 0.01 + 0.72\sin 0.01 = 0.277, \qquad y' = 0.27\sin 0.01 - 0.72\cos 0.01 = -0.717 x′=0.27cos0.01+0.72sin0.01=0.277,y′=0.27sin0.01−0.72cos0.01=−0.717
全部 6 行旋转后的结果也在图 4-6 右侧(每个数都可套公式验证)。真实规模下,就是 4096 维拆 2048 对、6 行各转各的——量变多,原理不变。
到这里,位置信息已经揉进矩阵。但矩阵里每个词还是"各过各的"——「今天」不知道「天气」在旁边,「西安」不知道自己在被提问。让词和词之间产生联系,就要等下一篇的主角登场:Transformer Block 和注意力机制。
7. 有没有 RoPE,差别到底有多大
前面一直在说"点积依赖位置差",听起来很玄乎。做个具体数字实验:拿贯穿案例的「今天」和「天气」两个词向量,固定「今天」在位置 0,让「天气」依次出现在位置 0、1、2……8,分别算点积。
不用 RoPE(直接把两个词向量点积):
X 今天 ⋅ X 天气 = − 1.5708 \mathbf{X}_{今天} \cdot \mathbf{X}_{天气} = -1.5708 X今天⋅X天气=−1.5708
不管「天气」在第几位,这个数死死定在 -1.5708 不动——没有位置信息的向量是"位置盲"的,距离感为零。
用 RoPE 后再点积:
| 「天气」的位置 k | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|---|---|---|---|---|---|---|---|---|---|
| 点积 | -1.571 | -0.876 | 0.496 | 1.277 | 0.745 | -0.617 | -1.562 | -1.227 | 0.076 |
点积随距离剧烈变化,曲线如图 4-7 所示。

图4-7 有无 RoPE 的天壤之别:无 → 一条死水平线;有 → 距离进了点积
红色虚线(无 RoPE)始终是 -1.571 的水平直线;绿色实线(有 RoPE)从 -1.571 出发,在 k=3 时冲到 +1.277(符号都反了!),到 k=6 又回到 -1.562(θ=1 的周期 2π)——点积里塞满了"距离"信息,模型做注意力时自然就有了"远近感"。
再做一个"顺序反转"实验:「今天在天气前」(k=1) vs「天气在今天前」(k=0 但两词互换位置):
| 顺序 | 点积 |
|---|---|
| 「今天」在 m=0,「天气」在 m=1 | -0.8757 |
| 「天气」在 m=0,「今天」在 m=1 | -0.9451 |
点积差 0.07,同一个词对,只是顺序换了,注意力分数就不同——这下"我吃苹果"和"苹果吃我"在注意力眼里不再是同义句。
小结
这一篇,我们填上了"矩阵不知道顺序"的坑:
- 排列等变性:注意力逐行处理、不关心行序,"我吃苹果"和"苹果吃我"它分不清——必须补位置
- 三条设计要求:唯一编码、相对距离、外推性
- 第一代正弦余弦(2017):公式造波形,免训练,但加法融合粗暴
- 第二代可学习(GPT-2):位置当词学,效果好,但外推死穴 + 无结构
- 第三代 RoPE(2021):按位置旋转角度,点积只依赖位置差(同距离点积实测分毫不差),零参数、天然外推
- 贯穿案例:6×4 矩阵逐行旋转,「西安」行完整手算 [ − 0.58 , 0.91 ] → [ − 1.079 , 0.004 ] [-0.58, 0.91] \to [-1.079, 0.004] [−0.58,0.91]→[−1.079,0.004]
表4-2 三代位置编码对比
| 方案 | 年份 | 相对距离 | 外推性 | 参数量 | 代表模型 |
|---|---|---|---|---|---|
| 正弦余弦 | 2017 | 绕(三角恒等式) | 理论可以 | 0 | 原始 Transformer |
| 可学习 | 2019 | 无结构 | 死穴(表上限) | 33M | GPT-2 / BERT |
| RoPE | 2021 | 天然(点积=位置差) | 天然支持 | 0 | LLaMA/Qwen/GLM/DeepSeek 全系 |
下一篇预告
位置补完了,第二个坑还在:矩阵里还没有"上下文"。举个例子——
“我今天吃了一个苹果” 和 “苹果今天发布了一款新手机”
两句话里的「苹果」是同一个 token(id 相同),嵌入向量一模一样。但一句是水果、一家是公司,含义天差地别——这个"含义",只能由旁边的词决定。而现在的矩阵里,「苹果」的向量是死的:旁边站着「吃」还是「发布」,它自己不会有任何变化。
让每个词的向量"吸收"周围词的信息、活起来,靠的就是注意力机制。下一篇正式进入 Transformer 大厦内部:先看 Block 的整体结构(层归一化 → 注意力 → 残差 → 层归一化 → 前馈网络 → 残差),再拆第一块砖:层归一化(LayerNorm)——为什么每层计算前都要把数值"拉回同一起跑线"。
系列目录:
- 从一条直线到高维空间
- 分词与 token 表
- 隐藏层与嵌入
- 位置编码 RoPE(当前篇)
- Transformer Block 全景与层归一化
- QKV 三剑客
- 注意力权重与多头机制
- 残差连接与前馈网络
- 输出矩阵与多层堆叠
- 首 token 诞生与 KV-Cache
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
:位置编码 RoPE&spm=1001.2101.3001.5002&articleId=163951531&d=1&t=3&u=c9f2eb6331d543b08fee0f04cda6ba3c)
354

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



