核心要点

  • Transformer 无循环/卷积结构,需显式注入位置信息。

  • 公式:PE(pos,2i)=sin(pos/10000^(2i/d)),PE(pos,2i+1)=cos(同一频率)。

  • 不同维度对应不同波长(频率几何衰减),便于模型表达相对位置。

  • 易错点:分母指数用 2i/d 且偶/奇维共享同一频率;用对数形式计算避免数值溢出。

标准回答

Transformer 本身对输入顺序不敏感,需要位置编码为每个位置注入唯一的位置信号,再与词嵌入相加。正弦位置编码对偶数维用 sin、奇数维用 cos,且同一对 (2i, 2i+1) 共享频率 1/10000^(2i/d);随着维度增大波长变长、频率几何衰减,使不同维度刻画从高频到低频的位置变化,模型可由此线性表达相对位置。计算分母时用 exp(−log(10000)·2i/d) 的对数形式更数值稳定。下面用 NumPy 实现:

python
import numpy as np

def positional_encoding(seq_len, d_model):
    # 返回 (seq_len, d_model) 的正弦位置编码矩阵
    pos = np.arange(seq_len)[:, None]          # (L, 1)
    i = np.arange(0, d_model, 2)               # 偶数维索引 0,2,4,...
    # 用对数-指数形式计算频率,数值更稳定
    div = np.exp(-np.log(10000.0) * i / d_model)  # 1/10000^(2i/d)
    pe = np.zeros((seq_len, d_model))
    pe[:, 0::2] = np.sin(pos * div)            # 偶数维用 sin
    pe[:, 1::2] = np.cos(pos * div)            # 奇数维用 cos(同一频率)
    return pe

if __name__ == '__main__':
    pe = positional_encoding(seq_len=10, d_model=16)
    print(pe.shape)                            # (10, 16)
    print(pe[0, :4].round(3))                  # pos=0: sin=0, cos=1 交替

常见误区

⚠️ 常见踩坑

分母指数容易误写成 i/d(应为 2i/d,对应偶数维索引);偶/奇维须共用同一频率而非各算各的;直接对 10000^(2i/d) 取幂在大 d 下可能精度差,推荐对数形式。

追问

追问 1正弦位置编码相比可学习位置编码有什么优势?

正弦编码无需参数、可外推到训练时未见过的更长序列(因为是确定性函数),且其线性性质便于模型表达相对位移;可学习位置编码表达力更强但受限于最大长度、难外推。实际中两者效果相近,长文本场景更倾向用可外推的方案。

追问 2RoPE 与正弦绝对位置编码有何不同?

RoPE(旋转位置编码)不把位置信息加到嵌入上,而是在注意力计算中对 Q、K 按位置做旋转,使点积自然依赖相对位置差。它兼具相对位置的优良性质和较好的长度外推能力,配合插值/NTK 缩放可扩展上下文,已成为 LLaMA、Qwen 等主流大模型的标配。

延伸学习

与本题相关的知识库文章、术语、工具与行业资讯。