RoPE (Rotary Position Embedding) 是大语言模型中广泛使用的位置编码方法,被 LLaMA、ChatGLM、Mistral 等主流模型采用。
本教程通过代码帮助你深入理解 RoPE 的原理和实现。
rope/
├── README.md # 本文件 - 快速入门
├── requirements.txt # 依赖包
├── rope_tutorial.py # 完整的 Python 教程(可运行)
├── rope_deep_dive.md # 🔥 深度原理解析(为什么这样设计)
└── *.png # 生成的可视化图片(运行后生成)
pip install -r requirements.txtpython rope_tutorial.py运行后会生成可视化图片,并在终端输出详细的讲解。
Transformer 的自注意力机制是位置无关的——它只看 token 之间的相似度,不知道它们的顺序。
例如:"我爱你" 和 "你爱我" 如果没有位置信息,模型会认为是一样的!
🌟 用「旋转」来表示位置!
想象一个 2D 向量,通过旋转不同角度来表示不同位置:
- 位置 0:旋转 0°
- 位置 1:旋转 θ°
- 位置 2:旋转 2θ°
- ...
对于 d 维的嵌入向量:
-
分组:将向量分成 d/2 组,每组 2 个元素
-
设置频率:第 i 组的基础频率是:
θᵢ = 1 / (10000^(2i/d)) -
旋转:位置 m 的向量,第 i 组旋转角度是
m × θᵢ -
旋转公式:
x'₂ᵢ = x₂ᵢ × cos(m×θᵢ) - x₂ᵢ₊₁ × sin(m×θᵢ) x'₂ᵢ₊₁ = x₂ᵢ₊₁ × cos(m×θᵢ) + x₂ᵢ × sin(m×θᵢ)
以 1024 维 的 embedding 向量为例:
原始向量: x = [x₀, x₁, x₂, x₃, x₄, x₅, ..., x₁₀₂₂, x₁₀₂₃]
拆分为 512 个维度对:
├── 维度对 0: (x₀, x₁) → 用 θ₀ = 1.0 旋转 (高频,变化快)
├── 维度对 1: (x₂, x₃) → 用 θ₁ 旋转
├── 维度对 2: (x₄, x₅) → 用 θ₂ 旋转
├── ...
└── 维度对 511: (x₁₀₂₂, x₁₀₂₃) → 用 θ₅₁₁ = 0.0001 旋转 (低频,变化慢)
为什么这样设计?
| 维度对位置 | 频率 | 作用 | 类比 |
|---|---|---|---|
| 前面(0, 1, 2...) | 高频 | 捕捉短距离位置关系 | 秒针 |
| 后面(509, 510, 511...) | 低频 | 捕捉长距离位置关系 | 时针 |
这就像钟表:秒针转得快用来区分相近的时间,时针转得慢用来区分相隔很远的时间。
RoPE 最重要的性质是:
Query 和 Key 的点积只取决于它们的相对位置,而不是绝对位置!
这意味着:
- 位置 (3, 5) 和 位置 (100, 102) 的点积是相同的
- 因为它们的相对位置都是 2
| 特性 | 绝对位置编码 | RoPE |
|---|---|---|
| 编码方式 | 加法 | 旋转(乘法) |
| 相对位置 | 隐式学习 | 显式编码 |
| 外推能力 | 差 | 好 |
| 是否需要训练 | 是 | 否 |
MIT License