从一条直线到大模型输出一个token(四):位置编码 RoPE

从一条直线到大模型输出一个token(四):位置编码 RoPE

建议先看:从一条直线到大模型输出一个token(三):隐藏层与嵌入

上一篇留下两个坑:嵌入矩阵不知道顺序、不知道上下文。这一篇填第一个坑——矩阵怎么"知道"每个词排在第几位。

1. 排列等变性:注意力天生是"位置盲"

先看一个反直觉的事实。

上一篇说过,后续所有层对矩阵的处理都是"逐行计算"——第 1 行算第 1 行的,第 3 行算第 3 行的。现在把"我吃苹果"和"苹果吃我"这两句话分别送进模型,如图 4-1 所示。

排列等变性

图4-1 排列等变性:注意力是「位置盲」——这是必须补位置的根因

两句话的嵌入矩阵里,「我」的向量内容一模一样,只是行位置不同(一个在第 1 行,一个在第 3 行)。而后续的自注意力机制(第 7 篇会看到它怎么算)对每一行的处理方式完全一样——行与行怎么排列,它根本不关心。

这个性质在数学上叫排列等变性(permutation equivariance):输入行序打乱,输出行序跟着打乱,但内容不变。对"我吃苹果"和"苹果吃我",注意力算出的结果几乎相同——但这两句话的意思天差地别。

所以必须在矩阵进 Transformer 之前,把位置信息"揉"进向量里。这就是位置编码(Position Encoding)干的事。

2. 位置编码的设计要求

不是随便塞个数字就行。位置编码要满足三条设计要求:

  1. 每个位置有唯一编码——位置 0 和位置 5 的编码必须不同,否则等于没加
  2. 能表达相对距离——理想情况下,"位置 3 和位置 5 的关系"应该能从编码里算出来,因为语言里远近距离很重要("今天"和"天气"相邻 vs 隔了 10 个词,相关性不同)
  3. 不受句子长度限制——训练时见过 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 时代风光无限。但三个硬伤逐渐暴露:

  1. 外推死穴:表只刻到 8192 行,第 8193 个 token 直接没有编码,上下文长度被表的大小焊死
  2. 参数冗余:8192×4096 ≈ 3300 万参数,只干"编码位置"这一件事
  3. 没有结构:位置 100 和位置 101 的两个向量之间的距离,跟位置 1 和位置 2 之间的距离没有任何规律关系——"相邻"这个概念在表里没有被表达

5. 第三代:RoPE 旋转位置编码(事实标准)

5.1 核心思想:不加数,转角度

RoPE(Rotary Position Embedding,2021 年 RoFormer 论文提出)换了个思路:不往向量里加任何数字,而是把向量按自己的位置旋转一个角度,如图 4-5 所示。

RoPE旋转直觉

图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=100002i/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=Rmnq, k

左边是"各自按绝对位置旋转后点积",右边是"只按相对位置 ( m − n ) (m-n) (mn) 旋转一次"。这个恒等式是三角函数和角公式 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((mn)θ) 的矩阵版。

真实算一组数验证(演示向量 [ 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)50.0964

表4-1 RoPE 相对性质验证:同距离点积相同

绝对位置不同、相对距离相同 → 点积分毫不差。位置信息就这样悄悄融进了后续所有点积运算(第 7 篇会看到,注意力分数恰恰就是点积)。

5.3 为什么它成了事实标准

三条设计要求逐条对答案:

  1. 唯一编码:每个位置的旋转角组合唯一 ✓
  2. 相对距离:点积天然只依赖位置差(表 4-1 实证),比前两代都直接 ✓
  3. 外推性:任意位置 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=100000.50.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=100002046/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 所示。

RoPE手算

图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.58cos10.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.010.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 后再点积

「天气」的位置 k012345678
点积-1.571-0.8760.4961.2770.745-0.617-1.562-1.2270.076

点积随距离剧烈变化,曲线如图 4-7 所示。

有无RoPE对比

图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无结构死穴(表上限)33MGPT-2 / BERT
RoPE2021天然(点积=位置差)天然支持0LLaMA/Qwen/GLM/DeepSeek 全系

下一篇预告

位置补完了,第二个坑还在:矩阵里还没有"上下文"。举个例子——

“我今天吃了一个苹果” 和 “苹果今天发布了一款新手机”

两句话里的「苹果」是同一个 token(id 相同),嵌入向量一模一样。但一句是水果、一家是公司,含义天差地别——这个"含义",只能由旁边的词决定。而现在的矩阵里,「苹果」的向量是死的:旁边站着「吃」还是「发布」,它自己不会有任何变化。

让每个词的向量"吸收"周围词的信息、活起来,靠的就是注意力机制。下一篇正式进入 Transformer 大厦内部:先看 Block 的整体结构(层归一化 → 注意力 → 残差 → 层归一化 → 前馈网络 → 残差),再拆第一块砖:层归一化(LayerNorm)——为什么每层计算前都要把数值"拉回同一起跑线"。

系列目录:

  1. 从一条直线到高维空间
  2. 分词与 token 表
  3. 隐藏层与嵌入
  4. 位置编码 RoPE(当前篇)
  5. Transformer Block 全景与层归一化
  6. QKV 三剑客
  7. 注意力权重与多头机制
  8. 残差连接与前馈网络
  9. 输出矩阵与多层堆叠
  10. 首 token 诞生与 KV-Cache

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

a18792721831

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值