Skip to main content

位置编码

如何理解LLM sin cos位置编码中,依据三角函数的基本性质,可以得知pos+kpos+k个位置编码是第pospos个位置编码的线性组合,这就意味着位置编码中蕴涵着单词之间的距离信息

理解这个问题的关键在于三角函数的和角公式。让我们一步步拆解:

1. 三角函数位置编码公式​

对于 Transformer 中的位置编码,第 pos 个位置、第 i 个维度的编码为:

PE(pos,2i)=sin⁡(pos100002i/d)PE(pos, 2i) = \sin\left(\frac{pos}{10000^{2i/d}}\right) PE(pos,2i+1)=cos⁡(pos100002i/d)PE(pos, 2i+1) = \cos\left(\frac{pos}{10000^{2i/d}}\right)

其中 d 是模型维度。

2. 核心数学性质:和角公式​

三角函数的关键性质:

sin⁡(α+β)=sin⁡αcos⁡β+cos⁡αsin⁡β\sin(\alpha + \beta) = \sin\alpha\cos\beta + \cos\alpha\sin\beta cos⁡(α+β)=cos⁡αcos⁡β−sin⁡αsin⁡β\cos(\alpha + \beta) = \cos\alpha\cos\beta - \sin\alpha\sin\beta

3. 推导线性组合关系​

令:

  • α = pos / 10000^{2i/d}
  • β = k / 10000^{2i/d}

那么:

PE(pos+k,2i)=sin⁡(α+β)=sin⁡αcos⁡β+cos⁡αsin⁡β=PE(pos,2i)⋅cos⁡β+PE(pos,2i+1)⋅sin⁡βPE(pos+k, 2i) = \sin(\alpha + \beta) = \sin\alpha\cos\beta + \cos\alpha\sin\beta = PE(pos, 2i) \cdot \cos\beta + PE(pos, 2i+1) \cdot \sin\beta PE(pos+k,2i+1)=cos⁡(α+β)=cos⁡αcos⁡β−sin⁡αsin⁡β=PE(pos,2i+1)⋅cos⁡β−PE(pos,2i)⋅sin⁡βPE(pos+k, 2i+1) = \cos(\alpha + \beta) = \cos\alpha\cos\beta - \sin\alpha\sin\beta = PE(pos, 2i+1) \cdot \cos\beta - PE(pos, 2i) \cdot \sin\beta

4. 矩阵形式表示​

将这两个公式写成矩阵形式:

[PE(pos+k,2i)PE(pos+k,2i+1)]=[cos⁡βsin⁡β−sin⁡βcos⁡β]⋅[PE(pos,2i)PE(pos,2i+1)]\begin{bmatrix} PE(pos+k, 2i) \\ PE(pos+k, 2i+1) \end{bmatrix} = \begin{bmatrix} \cos\beta & \sin\beta \\ -\sin\beta & \cos\beta \end{bmatrix} \cdot \begin{bmatrix} PE(pos, 2i) \\ PE(pos, 2i+1) \end{bmatrix}

这就是一个旋转矩阵!

5. 物理意义解读​

5.1 距离信息的编码​

  • β 只依赖于 相对位置 k 和 维度 i
  • pos+k 的位置编码可以由 pos 的位置编码线性变换得到
  • 变换矩阵的系数 (cosβ, sinβ) 只与相对距离 k 有关

这意味着:模型可以学习到相对位置关系,而不仅仅是绝对位置。

5.2 实际例子​

假设我们想计算位置 10 和位置 13 之间的关系:

  • 相对距离 k = 3
  • 对于每个维度 i,都有一个旋转角度 βi=3/100002i/dβ_i = 3 / 10000^{2i/d}
  • 位置 13 的编码 = 旋转矩阵 βiβ_i × 位置 10 的编码

5.3 为什么这是"线性组合"​

因为:

# pos+k 的编码可以由 pos 的编码线性表示
PE_pos_k = a * PE_pos_even + b * PE_pos_odd

其中 a, b 是常数(对固定 k 和 i 是固定的)。

6. 可视化理解​

对于固定的维度 i:​

  • 每个位置编码是单位圆上的一个点
  • 位置 pos→(sin(ω⋅pos),cos(ω⋅pos))pos → (sin(ω·pos), cos(ω·pos)),其中 ω=1/100002i/dω = 1/10000^{2i/d}
  • 相对距离 k 对应旋转角度 ω⋅kω·k
  • 所有位置都在同一个圆上,只是角度不同

不同维度的不同"频率":​

# 低频维度(i 小)
ω_small = 1/10000^{2*0/512} ≈ 1.0 # 缓慢变化

# 高频维度(i 大)
ω_large = 1/10000^{2*255/512} ≈ 1/10000 ≈ 0.0001 # 快速振荡

7. 在注意力机制中的作用​

在注意力计算中,Q⋅KTQ·K^T会包含位置编码的信息:

Qpos⋅Kpos+kT=(ContentVector+PosEncodepos)⋅(ContentVector+PosEncodepos+k)TQ_{pos}·K_{pos+k}^T = ( ContentVector + PosEncode_{pos})·(ContentVector + PosEncode_{pos+k})^T

由于 位置编码 pos+k_{pos+k} 是 位置编码 pos_{pos}的线性函数,模型可以学会:

  1. 相对位置模式:如"动词后面常跟名词"(距离1)
  2. 句法结构:如主谓一致(固定距离关系)
  3. 局部依赖:相邻词有强关联

8. 与可学习位置编码的对比​

特性三角函数编码可学习编码
外推性✅ 好(可计算任意位置)❌ 差(只训练过固定长度)
相对位置✅ 内置(三角公式)❌ 需要显式学习
距离信息✅ 明确编码❌ 隐含在参数中
长序列✅ 支持(周期性)❌ 可能过拟合

9. 现代变体:RoPE(旋转位置编码)​

RoPE 直接将这个思想扩展到复数域:

qpos=q⋅eiωposkpos=k⋅eiωposq_{pos} = q \cdot e^{i\omega pos} k_{pos} = k \cdot e^{i\omega pos}

这样 Q·K 内积自然包含相对位置信息:

qpos⋅kpos+k=(q⋅k)⋅eiωkq_{pos}·k_{pos+k} = (q·k) \cdot e^{i\omega k}

相对位置 k 只影响相位,不改变模长。

10. 实际验证代码​

import numpy as np

def sinusoidal_position_encoding(pos, d_model=512):
"""计算sinusoidal位置编码"""
position = np.arange(pos)[:, np.newaxis]
div_term = np.exp(np.arange(0, d_model, 2) * -(np.log(10000.0) / d_model))

pe = np.zeros((pos, d_model))
pe[:, 0::2] = np.sin(position * div_term) # 偶数维度
pe[:, 1::2] = np.cos(position * div_term) # 奇数维度
return pe

# 验证线性关系
d_model = 512
pos = 10
k = 3
i = 10 # 看第10个维度对(实际是第20、21维)

pe = sinusoidal_position_encoding(pos + k + 1, d_model)

# 提取两个维度
dim_even = 2*i
dim_odd = 2*i + 1

# 计算β
div_term = np.exp(np.arange(0, d_model, 2) * -(np.log(10000.0) / d_model))
beta = k * div_term[i]

# 验证公式
pe_pos_even = pe[pos, dim_even]
pe_pos_odd = pe[pos, dim_odd]
pe_pos_k_even = pe[pos + k, dim_even]
pe_pos_k_odd = pe[pos + k, dim_odd]

# 根据公式计算
calc_even = pe_pos_even * np.cos(beta) + pe_pos_odd * np.sin(beta)
calc_odd = pe_pos_odd * np.cos(beta) - pe_pos_even * np.sin(beta)

print(f"实际值: [{pe_pos_k_even:.6f}, {pe_pos_k_odd:.6f}]")
print(f"计算值: [{calc_even:.6f}, {calc_odd:.6f}]")
print(f"误差: [{abs(pe_pos_k_even - calc_even):.6f}, {abs(pe_pos_k_odd - calc_odd):.6f}]")

总结​

核心洞见:三角函数位置编码通过和角公式,使得相对位置关系被编码为线性变换。这意味着:

  1. 位置 pos+k 的编码 = 线性矩阵 × 位置 pos 的编码
  2. 变换矩阵只依赖于相对距离 k,与绝对位置 pos 无关
  3. 模型可以学习到"距离为k的两个词之间的关系"
  4. 这种编码具有外推性,可以处理比训练时更长的序列

这正是为什么原始 Transformer 论文说这种编码可以让模型"轻松学习到相对位置信息"。后续的 RoPE、ALiBi 等位置编码方法都是基于类似的洞见发展而来。