写在前面
在前两篇文章中,我们分别拆解了 LLM 的整体架构,又专门深挖了 Tokenizer。现在,我们已经知道如何把一段人类语言变成一串数字 ID,也知道了 Tokenizer 如何决定“切在哪里”。
但紧接着就来了一个问题:这些 ID 本身只是“编号”,没有语义,更没有顺序感。模型怎么知道“苹果”和“水果”是一类东西?怎么知道“我爱你”和“你爱我”不是一回事?
这就是今天我们要深入探讨的两个核心组件——Embedding(词嵌入) 和 RoPE(旋转位置编码) 。一个负责把词语变成带有语义坐标的向量,另一个负责告诉模型“谁在前、谁在后”。
如果说 Tokenizer 是 LLM 的“翻译官”,那 Embedding 就是它的“语义词典”,而 RoPE 则是它的“时序导航仪”。
一、Embedding:给每个词发一张“特征身份证”
1.1 为什么 Token ID 不够用?
经过 Tokenizer,每个词或子词都被分配了一个数字 ID。但问题来了:ID 只是标签。假设词表里“猫”是 9246 号,“狗”是 9703 号,“手机”是 11399 号,你问模型“9246 和 9703 像吗?”,模型根本无从判断——两个数字之间没有任何语义关系。
这就像用身份证号来判断两个人是不是亲戚:110101 和 110102 号只是办证的先后顺序而已,不代表任何血缘关系。所以,Token ID 只是模型的“输入凭证”,真正要让模型“理解”词语,还需要把它们变成能够进行数学运算的“坐标”。
1.2 Embedding 做了什么:把词“画”进高维空间
Embedding 的核心思想非常朴素:不再用孤立的编号,而是给每个词分配一组“特征分数”,形成一个向量。
想象一下,如果我们只用两个维度来描述一个词——“萌度”和“机械感”:
- 猫:[0.9, 0.1] —— 很萌,不机械
- 狗:[0.8, 0.2] —— 也很萌,不机械
- 手机:[0.1, 0.9] —— 不萌,很机械
把这些分数画在二维坐标纸上,“猫”和“狗”会自然地聚在一起,“手机”则离它们很远。距离本身就能反映语义关系——不需要人工标注“猫和狗相似”,坐标的远近就说明了一切。
真实的大模型做的事情完全一样,只不过维度远不止 2 个——而是 768 个(BERT)、4096 个(LLaMA-7B),甚至更多。每个维度不再是人类能命名的“萌度”“机械感”,而是模型在海量语料中自己学出来的抽象特征。
“Embedding”这个词翻译成“嵌入”,本身就很形象:把一个孤立的符号,塞进一个充满逻辑关系的空间里。就像拼图——每个词是一块拼图,Embedding 帮它找到在世界(高维空间)中最合适的位置。
1.3 数学本质:一张巨大的“查表”
从工程实现的角度看,Embedding 层本质上就是一张巨大的“查表”(Look-up Table):一张尺寸为 [词汇表大小 V × 向量维度 d] 的矩阵。
当模型拿到一个 Token ID 时,Embedding 层做的事情极其简单:
- 用 Token ID 作为行索引,从矩阵中取出对应的那一行
- 这一行向量(长度为 d)就是这个 Token 的 Embedding
比如,假设词表大小是 32000,Embedding 维度是 4096,那么这张表的尺寸就是 32000 × 4096,总参数量约为 1.31 亿——在 LLaMA-7B(约 70 亿参数)中,光 Embedding 层就占了近 20% 的参数!
💡 那这些向量是固定的吗? 不。Embedding 层的权重是可训练的。在预训练阶段,模型通过反向传播不断更新这张表里的数值,让语义相近的词逐渐在向量空间中靠近。最终得到的 Embedding 矩阵,就是模型学到的“语义地图”。
1.4 静态 Embedding vs 上下文 Embedding:一个词只能有一个向量吗?
传统的 Word2Vec 或 GloVe 产生的 Embedding 是“静态”的:无论上下文怎么变,“苹果”这个词的向量始终是同一个。这在处理多义词时会出现问题——比如“苹果手机”里的“苹果”和“吃苹果”里的“苹果”,语义完全不同,却共用同一个向量。
现代 LLM 解决这个问题的方式是:Embedding 层产生的仍然是一个静态的初始向量,但这个向量会在后续的每一层 Transformer 中被不断“加工”,融合上下文信息,最终变成动态的、依赖上下文的表示。
所以,LLM 中的 Embedding 只是起点——它给每个词一个初始的“身份特征”,然后让 Transformer 层去根据上下文不断调整和丰富这个特征。这也是为什么 LLM 能精准区分“苹果公司”和“水果苹果”——不是因为 Embedding 层有多聪明,而是因为后面的 Attention 机制做了大量的上下文感知工作。
1.5 参数计算:Embedding 层的成本
Embedding 层的参数量往往相当可观。计算公式很简单:
Embedding 参数量 = 词汇表大小(V)× Embedding 维度(d)
以 LLaMA-7B 为例:词表大小 32000,维度 4096,Embedding 层参数量为 32000 × 4096 ≈ 1.31 亿。再加上输出层(通常与输入 Embedding 共享权重,或者单独一个同样大小的矩阵),光输入输出两层就占了约 2.6 亿参数,接近整个 7B 模型的 4%。这也就是为什么在推理时,减少 Embedding 维度可以显著压缩显存占用——OpenAI 的 text-embedding-3-large 模型甚至允许用户在调用时通过参数动态缩短嵌入向量的维度,从默认的 3072 维压缩到 1024 维甚至 256 维,在保持检索质量的同时大幅降低存储成本。
二、RoPE 登场:当向量学会了“旋转”
2.1 为什么需要位置编码?——一个“盲人摸象”的难题
Attention 机制有一个天生的“盲区”:它对输入序列的顺序完全无感。
如果你把“我爱你”和“你爱我”中的词打乱顺序,然后分别计算它们的 Embedding 集合,模型看到的是完全相同的三个向量,只是顺序不同。但 Attention 本身的公式——只对 Q、K、V 做点积和加权求和——并没有内置“顺序”的概念。因此,如果不加处理,模型会把这两个句子当成同样的东西来处理。
这就是为什么必须给 Embedding 注入位置信息。 只有告诉模型每个词在句子中的位置,它才能区分“狗追猫”和“猫追狗”是两个完全不同的故事。
2.2 绝对位置编码的困境:为什么被抛弃?
早期 Transformer 解决这个问题的方式很直接——绝对位置编码。
所谓“绝对”,就是给每个位置(第 0 位、第 1 位、第 2 位……)分配一个独一无二的向量,然后直接加到 Embedding 上。这又分为两种方式:
- 可学习位置编码:把位置向量当作可训练参数,让模型自己学
- Sinusoidal 位置编码:用正弦和余弦函数生成固定模式的位置向量,不需要训练
绝对位置编码简单直观,但有一个致命的缺陷:模型只能处理训练时见过的最长长度。如果你训练时最大长度是 2048,那模型就永远无法理解第 2049 个位置——因为它的位置编码表里根本没有这一行。而重新训练或微调一个更长上下文的模型,成本极高。
更关键的是,语言的本质决定了:相对位置往往比绝对位置更重要。在大多数语言现象中,词与词之间的距离关系(比如主语和谓语相隔多远,代词指代的名词在前面几个词的位置),远比某个词是“第 42 个位置”这种信息有意义得多。
于是,研究重心逐渐从“绝对位置”转向了“相对位置编码”——让模型天然地捕捉词与词之间的距离,而不是死记硬背绝对位置的序号。
2.3 RoPE 的核心洞察:用“旋转”来编码相对位置
RoPE(Rotary Position Embedding,旋转位置编码) 是这一转变中最重要的突破。
它的核心思想极其优雅:通过对 Query 和 Key 向量施加一个与位置相关的旋转操作,使得两个向量的点积结果天然包含它们的相对位置信息。
具体来说,RoPE 将每个 Token 的向量看作复数(或配对的特征),然后根据它在序列中的位置,将其旋转一定的角度。位置越靠后,旋转的角度越大。
用数学来表达(尽量简化):
- 把向量变成复数:对于 d 维向量,两两配对,每一对看作一个复数:
x₁ + i·x₂ - 按位置旋转:对于位置 m,将复数乘以
e^(i·m·θ)(相当于旋转 m·θ 角度) - 计算 Attention:旋转后的 Query 和 Key 做内积
关键来了——经过这一通旋转,两个位置 m 和 n 的 Query 和 Key 的内积结果,只依赖于它们的相对位置差 (m – n),而不依赖于各自的绝对位置:
旋转后的 Q(m) · 旋转后的 K(n) = 原 Q · 旋转后的 K(n - m)
这个性质让 RoPE 天然地编码了相对位置。模型不需要去记住“位置 42”应该长什么样——它只需要知道两个词之间“隔了多少步”。
2.4 为什么“旋转”这个操作刚刚好?
为什么偏偏是旋转?为什么不是平移、缩放或者其他操作?
答案在于复数乘法的性质:两个复数相乘,相当于模长相乘、角度相加。当我们对向量施加旋转(即乘上 e^(i·m·θ))后,两个旋转后的复数做内积,它们的旋转角度会“相减”——而相减的结果恰好是相对位置差。
用几何来理解:如果把向量看作空间中的一个箭头,旋转操作完美地“保护”了向量的长度(模长不变),只改变了它的方向。这意味着 RoPE 不会改变 Embedding 本身的语义强度——它只是在“语义方向”的基础上,叠加了一个“位置方向”。两者互不干扰,却在 Attention 的计算中自然地融合在一起。
这也是为什么 RoPE 被认为是“最硬核、影响最深远的数学创新”之一——它用简单的旋转操作,把相对位置信息无缝地织入了 Attention 的骨架。
2.5 工程实现:如何高效地“旋转”?
理论说完了,实际代码怎么写?现代 LLM 通常用预计算的 sin/cos 表来高效实现 RoPE。核心逻辑如下:
def apply_rope(x, cos, sin):
"""
对输入向量 x 应用旋转位置编码。
x: [batch, heads, seq_len, head_dim]
cos, sin: 预计算好的三角函数值
"""
# 将特征维度拆成两半,配对旋转
half_dim = x.shape[-1] // 2
x1, x2 = x[..., :half_dim], x[..., half_dim:]
# 旋转:把 (x1, x2) 变成 (-x2, x1) 再乘上 sin/cos
rotated = torch.cat((-x2, x1), dim=-1)
return (x * cos) + (rotated * sin)
这段代码的精髓在于:(-x2, x1) 这一步就是复数旋转的实数版本。乘以 cos 和 sin 后,相当于在每一对特征维度上施加了旋转角度。
在实际的 LLM 推理中,cos 和 sin 是预先计算好并缓存的,所以每次 Attention 计算时只需要做一次元素乘法和加法——计算开销非常小。
2.6 对比视角:RoPE vs 其他位置编码
为了让你对 RoPE 的价值有更直观的理解,我们把它和其他主流方案放在一起对比:
| 方法 | 类型 | 外推能力 | 计算效率 | 代表模型 | 核心特点 |
|---|---|---|---|---|---|
| 可学习位置编码 | 绝对 | 差 | 高 | 早期 GPT | 简单,但长度固定 |
| Sinusoidal | 绝对 | 中 | 高 | 原始 Transformer | 无需训练,但外推有限 |
| RoPE | 相对 | 好 | 中 | LLaMA, Qwen, ChatGLM | 旋转操作,天然编码相对位置 |
| ALiBi | 相对 | 极好 | 高 | BLOOM, MPT | 直接在 Attention 分数上加线性偏置 |
RoPE 不是唯一的选择。ALiBi(Attention with Linear Biases) 是另一种非常有趣的方法——它不在 Embedding 层面做任何处理,而是直接在 Attention 分数矩阵上加上一个与距离成正比的惩罚项:距离越远,Attention 分数扣得越多。这种方式计算极其高效,且外推能力甚至比 RoPE 更强。不过 RoPE 在捕捉复杂位置模式上通常表现更好,因此在需要更强位置感知能力的生成模型中更受欢迎。
为什么现代 LLM 纷纷从可学习绝对位置编码转向 RoPE? 原因很清晰:
- 更好地捕捉相对距离:语言理解更多依赖“两个词相隔多远”,而非它们的绝对位置序号
- 更好的长上下文表现:RoPE 可以更自然地扩展到训练时未见过的长度
- 更优雅地与 Attention 集成:位置信息被注入到了 Attention 最核心的 Q·K 计算中,而非简单地加在输入上
2.7 LLaMA 中的 RoPE:一个小细节
LLaMA 系列对 RoPE 做了一处细节优化:只对 Query 和 Key 应用旋转,Value 保持不变。这是因为相对位置信息只在计算 Attention 分数(Q·K)时才需要——Value 向量只负责承载实际的语义内容,不参与位置判断。此外,LLaMA 还采用了RMSNorm + Pre-Norm 的组合来稳定深层网络的训练,与 RoPE 搭配使用,让模型在处理长序列时更加稳健。
三、前沿探索:RoPE 之后,位置编码走向何方?
RoPE 虽然好用,但并非完美。随着 LLM 的上下文窗口从 4K 一路飙到 1M、2M,RoPE 的局限性也逐渐暴露。当前的位置编码研究主要沿着以下几个方向推进。
3.1 RoPE 的“天花板”:为什么超长上下文会失效?
RoPE 的旋转频率是由一组预设的基频(通常为 10000)决定的。当序列长度远远超过训练时的长度,高频的旋转会变得过于密集,低频的旋转则会变得过于稀疏,导致模型对长距离位置的感知能力下降。近年来,研究者提出了多种频率缩放(Frequency Scaling) 技术来缓解这个问题,比如 YaRN、NTK 缩放等,但它们本质上还是在 RoPE 的框架内“修修补补”。
一篇 2025 年的研究提出了 HoPE(Hyperbolic Rotary Positional Encoding) ,从数学上重新设计了旋转的几何空间(从欧氏空间切换到双曲空间),试图从根本上解决 RoPE 在超长距离上的振荡和不稳定问题。
3.2 最激进的想法:位置编码也许根本不需要?
一个让人重新思考 RoPE 根本作用的新方法是 DroPE(Drop Positional Embeddings) ,由 Sakana AI 团队提出。
他们的核心洞察是:RoPE 在训练阶段对于收敛至关重要,但在推理时却成了长度外推的瓶颈。实验证明,没有显式位置编码的 Transformer(NoPE)在理论上拥有更好的长度泛化能力,但训练极不稳定,难以收敛。
DroPE 的策略是“过河拆桥”:训练时正常使用 RoPE 保证收敛,训练结束后,用不到原始预训练 1% 的计算量进行一次轻量“重校准”,然后直接丢弃位置编码。在 LongBench 等长文本基准上,这种简单粗暴的方法甚至超越了专门为长文本设计的复杂架构。
这背后的深层含义在于:位置编码可能只是帮助模型在早期学会关注距离关系的“训练辅助轮”,而非模型理解顺序的永久必需品。 一旦模型学会了如何利用 Attention 的内在结构来感知顺序,这些显式编码就可以“功成身退”。
3.3 更高阶的数学:用李群和李代数统一 RoPE
一篇 2025 年的理论研究《Rethinking RoPE: A Mathematical Blueprint for N-dimensional Positional Embedding》指出:现有的 RoPE 变体缺乏统一的理论基础,尤其是在高维空间中的推广。研究者基于李群和李代数理论,为 RoPE 建立了一套系统的数学框架,使其能够自然地推广到任意维度,并在理论上证明了一些现有 RoPE 变体(如 2D RoPE)的局限性。
这项工作虽然理论色彩浓厚,但它传递了一个重要信号:RoPE 正在从经验性的工程创新,逐步演变为有坚实数学根基的理论体系。这对未来设计更强大、更可控的位置编码至关重要。
3.4 四元数 RoPE:把旋转从 2D 扩展到 3D
既然 RoPE 的核心是“旋转”,那能不能用更强大的数学工具来表示旋转?QuatRo(Quaternion Rotary Embeddings) 尝试用四元数来替代传统的 2D 旋转——四元数是表示 3D 旋转的标准工具,在计算机图形学中广泛使用。这个方向的探索还在早期,但它暗示了位置编码可能不限于一维序列——未来或许会看到为视频(时间+空间)、3D 模型等设计的多维位置编码方案。
3.5 位置编码的理论化:为什么有些方法更好?
2025 年 6 月,一篇重要的理论论文系统分析了各类位置编码(Sinusoidal、可学习、相对、ALiBi 等)对 Transformer 表达能力、泛化能力和长度外推能力 的影响。研究者使用 Rademacher 复杂度分析等工具,首次给出了不同编码方案在泛化误差上的理论界限,并提出了一些基于正交函数族(如小波、勒让德多项式)的新型位置编码方案。这类工作正在填补 Transformer 理论中的一块重要空白——我们不再只是“试出来”哪种位置编码好用,而是开始真正“理解”它们为什么好用。
3.6 多模态中的位置编码新战场
随着多模态大模型的兴起,位置编码也面临新的挑战。2D RoPE 被用于视觉 Transformer 中,帮助模型理解图像块之间的空间位置关系。如何在同一个模型中统一处理文本的 1D 序列位置、图像的 2D 空间位置、视频的时空位置,是多模态位置编码研究的前沿课题。未来,我们可能会看到位置编码从“语言专属”走向“通用位置感知”,为视觉、语音、3D 等多模态理解提供统一的位置表示框架。
四、总结与展望
4.1 Embedding 与 RoPE:一张“语义地图”和一支“时序导航仪”
让我们回顾一下 Embedding 和 RoPE 各自扮演的角色:
- Embedding:把每个 Token 变成一个高维向量。这个向量是 Token 在“语义空间”中的坐标——语义相近的词,坐标也相近。它是模型理解语言的基础地图。
- RoPE:给每个向量加上“位置方向”。通过对向量进行旋转,让 Attention 计算时天然包含相对位置信息。它是模型的时序导航仪,让模型知道词语之间的先后顺序。
两者配合在一起,才能让模型既知道“词是什么意思”,又知道“词在哪里”——缺了任何一个,模型都会变成“有语义但乱序”或者“有顺序但不懂词”的半成品。
4.2 数据流回顾
结合我们前面三篇文章的内容,完整的数据流是这样的:
- Tokenizer → 把原始文本切成 Token,映射为数字 ID
- Embedding → 把每个 ID 转成一个高维向量(语义坐标)
- RoPE → 对 Query 和 Key 向量施加旋转操作,注入相对位置信息
- Transformer 层 → Attention(让词之间“交流”)+ FFN(存储和加工知识)
- 输出层 → 预测下一个 Token,如此循环
4.3 关键公式速查
| 概念 | 公式/核心思想 |
|---|---|
| Embedding 参数量 | V × d(词表大小 × 维度) |
| RoPE 旋转 | 将 (x₁, x₂) 变为 (cos·x₁ – sin·x₂, sin·x₁ + cos·x₂) |
| RoPE 核心性质 | 旋转后 Q·K 的结果只依赖于相对位置差 |
| LLaMA 使用方式 | 只对 Q 和 K 应用 RoPE,V 保持不变 |
| RoPE 基频 | 通常为 10000,决定旋转的角度步长 |