如果你把「猫吃鱼」的三个 token 打乱顺序变成「鱼吃猫」,嵌入层查出来的向量集合是一样的——因为嵌入层只看 token ID,不看位置。注意力机制计算点积时也不区分位置——它只看两个向量的方向是否一致,不管它们相隔多远。
但语言是有顺序的。「猫吃鱼」和「鱼吃猫」的含义完全不同。模型必须有一种方式知道每个 token 在序列中的位置。
这就是位置编码(positional encoding)要解决的问题。
绝对位置编码
最直接的方法:给每个位置分配一个固定的向量,加到 token 的嵌入向量上。
位置 0 → [0.0, 1.0, 0.0, 1.0, ...]
位置 1 → [0.84, 0.54, 0.84, 0.54, ...]
位置 2 → [0.91, -0.42, 0.91, -0.42, ...]
...
原始 Transformer(2017)使用正弦余弦函数生成这些向量。也有的模型让位置向量作为可学习参数(跟嵌入表一样在训练中学)。
不管哪种方式,嵌入层的输出变成:
token 向量 = 嵌入(token ID) + 位置编码(位置)
加了位置编码之后,同一个词在不同位置会有不同的向量——因为加上了不同的位置向量。这样注意力计算就能区分位置了。
但绝对位置编码有一个根本的问题:它把位置编码进了向量本身,无法泛化到训练时没有见过的长度。如果训练时最长的序列是 4,096 个 token,推理时遇到第 4,097 个 token 就没有对应的位置编码了。
RoPE:旋转位置编码
RoPE(Rotary Position Embedding)用了一个更巧妙的方法:不把位置加到向量上,而是在计算注意力的 Q 和 K 时,根据位置旋转向量。
想象二维平面上的一个向量。你可以把它旋转一个角度——角度的大小取决于这个 token 的位置。位置 0 不旋转,位置 1 旋转一个小角度 θ,位置 2 旋转 2θ……
当两个 token 计算点积时,它们的旋转角度之差就编码了两者之间的距离。点积的结果只取决于相对距离(角度之差),而不是绝对位置——这让模型有可能泛化到训练时没有见过的长度。
RoPE 被 LLaMA、Qwen、Mistral 等大多数主流模型采用,是目前最常见的位置编码方案。
ALiBi:注意力偏置
ALiBi(Attention with Linear Biases)完全不修改向量,而是在注意力分数上加一个偏置:距离越远的 token 对,偏置越负——相当于给远处的 token 一个惩罚。
分数(i, j) = Q_i · K_j − m × |i − j|
m 是一个超参数。|i − j| 是两个 token 之间的距离。距离越大,减去的值越大,注意力越低。
ALiBi 的好处是极其简单,且能较好地泛化到训练长度之外。缺点是它假设了「越远越不重要」——这在大多数情况下成立,但并非总是如此。
NoPE:Sophia 的选择
Sophia 使用了一种出人意料的方案:不使用任何显式的位置编码。
这个方案叫 NoPE(No Positional Encoding)。它不往嵌入里加位置向量,不旋转 Q 和 K,也不给注意力分数加偏置。
那 Sophia 怎么知道 token 的位置?
答案是:因果掩码本身就提供了位置信息。
回忆第 13 章节:因果掩码让每个 token 只能看到它前面的 token。位置 0 只能看到自己,位置 1 能看到两个 token,位置 2 能看到三个……
这意味着每个位置的注意力模式天然不同:位置 0 的注意力分布只有一个非零值,位置 1 有两个,位置 100 有 101 个。模型可以通过注意力模式的形状来推断位置——虽然它没有被显式告知「你是第几个 token」,但它能从可见范围的大小中感知到相对位置。
NoPE 的优势是简洁——不引入额外的参数或计算。缺点是位置信息是隐式的、间接的,理论上不如显式编码那么精确。
但 Sophia 的实验表明,在她的架构和训练设定下,NoPE 的效果与 RoPE 没有显著差异。再加上 Sophia 的大部分层使用线性注意力(KDA),而 RoPE 在线性注意力中的应用没有像在标准注意力中那么成熟,NoPE 成了更自然的选择。
为什么这个决定重要
位置编码的选择影响两件事:
一是长度外推能力——模型能否处理训练时没有见过的更长序列。RoPE 通过旋转角度外推,ALiBi 通过线性衰减外推,NoPE 依赖因果掩码的隐式推断。
二是训练效率——位置编码是否引入额外的计算。NoPE 不引入任何额外计算,RoPE 需要旋转操作(计算量不大但需要实现),ALiBi 需要维护偏置矩阵。
对 Sophia 来说,NoPE 在简洁性和实际效果之间找到了平衡。
下一章节来看 Sophia 每四层中第四层使用的注意力变体——MLA:怎么通过压缩 KV 来减少显存占用。