人工智能实践(语言智能)
第2讲:Transformer

2.4 位置编码

Sinusoidal、Learned、RoPE、ALiBi 四种位置编码的数学形式、长度外推能力与实践取舍

为什么需要位置编码

Self-Attention 有一个容易被忽视的特性:对输入的排列对称(permutation-equivariant)。交换序列中任意两个 token,输出结果只是对应位置也发生交换——模型完全不知道谁在前谁在后。

对语言来说这是灾难性的:

小明打了小红 vs. 小红打了小明

两句话词完全相同,但意思相反。如果模型丢失了位置信息,这两句话的表示会被压成同一个。

**位置编码(Positional Encoding, PE)**的任务就是:把"谁在第几个位置"的信息显式注入进模型。历史上有四种主流方案,我们按时间线依次看。

方案一:Sinusoidal PE(Vaswani 2017 原式)

原论文提出了一种无参数的位置编码,用正弦/余弦函数按频率编码位置:

PE(pos,2i)=sin(pos100002i/dmodel)\text{PE}_{(\text{pos}, 2i)} = \sin\left(\frac{\text{pos}}{10000^{2i/d_{\text{model}}}}\right) PE(pos,2i+1)=cos(pos100002i/dmodel)\text{PE}_{(\text{pos}, 2i+1)} = \cos\left(\frac{\text{pos}}{10000^{2i/d_{\text{model}}}}\right)

其中 pos\text{pos} 是 token 在序列中的位置,ii 是隐维度的索引(0i<dmodel/20 \le i < d_{\text{model}}/2)。

核心性质:对任意固定偏移 kkPEpos+k\text{PE}_{\text{pos}+k} 可以表示为 PEpos\text{PE}_{\text{pos}}线性变换。这保证了模型在学习"相对位置"关系时不会被绝对位置卡住。

使用方式:加在词嵌入上

h0=TokenEmbedding(x)+PE(pos)h_0 = \text{TokenEmbedding}(x) + \text{PE}(\text{pos})

Sinusoidal PE 的优势是无需训练、对超出训练长度的序列有一定外推能力。劣势是注入方式是加法,和词嵌入共享同一向量空间,表达能力受限。

方案二:Learned PE(BERT / GPT-2 / GPT-3)

最朴素的方案——把位置本身当成 token,查一个可学习的嵌入表:

self.pos_embedding = nn.Embedding(max_seq_len, d_model)

h0 = token_embed(x) + self.pos_embedding(torch.arange(n))

BERT、GPT-2、GPT-3 都采用这种方案。

优势:实现极简单,效果好。

致命劣势max_seq_len硬上限。训练时 n=512n = 512,推理时就完全不能处理更长序列——查表会越界。GPT-3 的 2048 上下文窗口就是这个原因。

方案三:RoPE(旋转位置编码)

Rotary Position Embedding(RoPE)(Su et al., 2021)是目前大模型的事实标准,被 LLaMA、Qwen、ChatGLM、DeepSeek 等一致采用。

核心思想

不再把位置信息加到 embedding 上,而是把位置直接"旋转"进 Q 和 K。在计算 Attention 之前,对 Query 和 Key 按位置做2D 旋转

dd 维向量两两配对成复数 q=[q(1),q(2),,q(d/2)]q = [q^{(1)}, q^{(2)}, \ldots, q^{(d/2)}],对第 ii 个复数旋转角度 mθim \theta_imm 是 token 位置):

RoPE(q,m)(i)=q(i)eimθi,θi=100002i/d\text{RoPE}(q, m)^{(i)} = q^{(i)} \cdot e^{i m \theta_i}, \quad \theta_i = 10000^{-2i/d}

用实数矩阵写,对每一对坐标 (q2i,q2i+1)(q_{2i}, q_{2i+1}) 做旋转:

(q2iq2i+1)=(cosmθisinmθisinmθicosmθi)(q2iq2i+1)\begin{pmatrix} q'_{2i} \\ q'_{2i+1} \end{pmatrix} = \begin{pmatrix} \cos m\theta_i & -\sin m\theta_i \\ \sin m\theta_i & \cos m\theta_i \end{pmatrix} \begin{pmatrix} q_{2i} \\ q_{2i+1} \end{pmatrix}

关键性质:点积只依赖相对位置

神奇的是,经 RoPE 旋转后的 qmknq_m \cdot k_n 只依赖相对位置 mnm - n,与绝对位置无关:

qmkn=q~R(mn)k~q_m^\top k_n = \tilde{q}^\top R(m - n) \tilde{k}

这一性质让 RoPE 兼具绝对位置的编码方式相对位置的比较语义,是它成功的关键。

外推与 NTK 缩放

RoPE 的另一大优势是可外推:训练时 n=2048n = 2048,推理时 n=8192n = 8192 时,只要调整频率基(从 1000010000 改大),模型不需要重训也能处理更长序列。这一技巧被称作 NTK-aware RoPE,是 LLaMA 2 → LLaMA 3 支持 128K 上下文的关键工具。

# 极简 RoPE 实现(LLaMA 风格)
def rotate_half(x):
    x1, x2 = x.chunk(2, dim=-1)
    return torch.cat([-x2, x1], dim=-1)

def apply_rope(q, k, cos, sin):
    # cos / sin 形状 (seq_len, d_head)
    q_rot = q * cos + rotate_half(q) * sin
    k_rot = k * cos + rotate_half(k) * sin
    return q_rot, k_rot

方案四:ALiBi(Attention with Linear Biases)

ALiBi(Press et al., ICLR 2022)的思路更激进——完全不加位置编码,而是在注意力分数上直接加一个线性偏置:

scoreij=qikjmij\text{score}_{ij} = q_i k_j^\top - m \cdot |i - j|

其中 mm 是每个头固定的斜率(不同头用不同的 mm)。距离越远,惩罚越大;距离越近,几乎没有惩罚。

特点

  • 实现极简,几乎不增加参数
  • 外推能力最强——天然支持任意长度
  • 缺点:对结构化位置信息的捕捉弱于 RoPE

ALiBi 在 BLOOM、MPT 等模型中使用,但主流大模型(LLaMA 系)仍选 RoPE。

四种方案对比

方案代表模型实现方式外推能力参数
SinusoidalTransformer 原版加在 embedding 上0
LearnedBERT / GPT-2 / GPT-3可学习查表无(硬上限)nmaxdn_{\max} \cdot d
RoPELLaMA / Qwen / DeepSeek旋转 Q / K强(配合 NTK)0
ALiBiBLOOM / MPT在 score 上加线性偏置最强hh(每个头一个斜率)

长上下文:位置编码的现代战场

LLM 的上下文窗口从 2K(GPT-3)→ 4K(LLaMA 1)→ 8K / 32K(LLaMA 2 / Qwen 2)→ 128K / 200K(LLaMA 3 / Claude)→ 1M(Gemini 1.5)的跨越,很大一部分工作都压在位置编码上。

主要手段:

  • NTK-aware RoPE / YaRN:通过调整 RoPE 的频率基,让模型在不重训的情况下支持更长上下文
  • Position Interpolation(PI):把长序列的位置"压缩"到训练长度范围内
  • ALiBi / RoPE + 指数衰减:用衰减项压制过远距离的注意力

实践建议:除非做基础研究,直接用 RoPE + YaRN 是 2024–2026 年的默认选择。对长文档任务,先把模型切换到 128K 以上版本(Qwen2.5-7B-128K、LLaMA-3.1-128K),再用 RAG / 文档切片做工程上的补充。

本节小结

要点内容
为什么需要 PESelf-Attention 对位置排列对称,必须显式注入位置
Sinusoidal无参数、能外推;注入方式受限(加法)
Learned简单有效;硬上限(不能外推)
RoPE旋转 Q/K;相对位置天然;当前事实标准
ALiBi注意力分数上的线性偏置;外推最强
长上下文NTK-aware RoPE / YaRN 是关键工具

下一节我们从"单个 Block"放大到"整个模型"——看看同样的 Transformer 可以怎样被拼装成 BERT、GPT 和 T5 三种形态。