1333 字
7 分钟
位置编码
位置编码 (Positional Encoding)
1. 为什么需要位置编码?
类比:Self-Attention 就像一群人围坐圆桌讨论——每个人都能听到所有人说话,但没人知道座位顺序。位置编码就是给每把椅子贴上座位号,让模型知道”谁先说、谁后说”。
RNN 天然按时间步处理序列,位置信息隐含在计算顺序中。但 Transformer 的 Self-Attention 对输入做的是集合运算——打乱词序,注意力得分完全不变:
这意味着 “我爱你” 和 “你爱我” 对模型来说是一样的——显然不行。必须在输入中显式注入位置信息。
2. 正弦位置编码(原论文方案)
原论文使用固定的正弦/余弦函数生成位置编码:
其中:
- :词在序列中的位置(0, 1, 2, …)
- :维度索引(0, 1, …, )
- :嵌入维度
2.1 直觉理解
类比:想象一排不同频率的钟摆。低频钟摆(大 )转动很慢,区分远距离位置;高频钟摆(小 )转动很快,区分相邻位置。每个位置对应一组唯一的钟摆角度组合——就像二进制计数器的各个位。
2.2 为什么选正弦函数?
三个关键优势:
- 唯一性:不同位置的编码向量不同
- 有界性:值域固定在 ,不会因位置增大而爆炸
- 相对位置可线性表达: 可以表示为 的线性变换——模型可以学会关注”相隔 步”的关系
这是一个旋转矩阵位置 的编码 = 位置 的编码做了一个角度为 的旋转。这个性质让模型很容易学会”两个词相隔多远”。
3. 位置编码如何融入模型
位置编码与 Token Embedding 逐元素相加(不是拼接):
为什么是加法不是拼接?拼接会使维度翻倍,增加后续所有层的计算量。加法保持维度不变,实验证明效果相当。原论文中 Token Embedding 乘以 正是为了让语义信号和位置信号处于相近的数量级。
4. 代码实现
import subprocesssubprocess.check_call(["pip", "install", "numpy"])import numpy as np
def sinusoidal_position_encoding(max_len, d_model): """生成正弦位置编码矩阵
Args: max_len: 最大序列长度 d_model: 模型维度(必须是偶数)
Returns: PE 矩阵, shape: (max_len, d_model) """ pe = np.zeros((max_len, d_model)) position = np.arange(max_len)[:, np.newaxis] # (max_len, 1) div_term = 10000 ** (np.arange(0, d_model, 2) / d_model) # (d_model/2,)
pe[:, 0::2] = np.sin(position / div_term) # 偶数维度用 sin pe[:, 1::2] = np.cos(position / div_term) # 奇数维度用 cos
return pe
# ========== 生成并观察 ==========pe = sinusoidal_position_encoding(max_len=50, d_model=512)print(f"位置编码矩阵形状: {pe.shape}")print(f"\n位置 0 的前 8 维: {pe[0, :8].round(4)}")print(f"位置 1 的前 8 维: {pe[1, :8].round(4)}")print(f"位置 49 的前 8 维: {pe[49, :8].round(4)}")
# ========== 验证:不同位置的编码确实不同 ==========# 计算位置 0 和位置 1 的余弦相似度cos_sim_01 = np.dot(pe[0], pe[1]) / (np.linalg.norm(pe[0]) * np.linalg.norm(pe[1]))cos_sim_049 = np.dot(pe[0], pe[49]) / (np.linalg.norm(pe[0]) * np.linalg.norm(pe[49]))print(f"\n位置 0 vs 1 余弦相似度: {cos_sim_01:.4f}(相邻,较高)")print(f"位置 0 vs 49 余弦相似度: {cos_sim_049:.4f}(远距离,较低)")5. 现代位置编码方案
原论文的正弦编码是”绝对位置编码”。近年来的研究发展出了更强的方案:
5.1 可学习位置编码 (Learned PE)
直接将位置编码作为可训练参数:
- 优点:模型自己学习最优编码
- 缺点:无法泛化到训练时未见过的长度
- 使用者:GPT-2、BERT
5.2 RoPE (Rotary Position Embedding)1
将位置信息编码为旋转角度,直接作用在 Q、K 向量上:
注意力分数 天然只依赖相对位置 。
- 优点:优雅地编码相对位置,可外推到更长序列
- 使用者:LLaMA、Qwen、ChatGLM
5.3 ALiBi (Attention with Linear Biases)2
不修改 Embedding,而是在注意力分数上直接减去一个与距离成正比的偏置:
- 优点:实现极简,长度外推能力强
- 使用者:BLOOM、MPT
5.4 方案对比
| 方案 | 类型 | 长度外推 | 实现复杂度 |
|---|---|---|---|
| 正弦编码 | 绝对,固定 | 理论可以,实际有限 | 低 |
| 可学习 PE | 绝对,可训练 | 不能 | 低 |
| RoPE | 相对,嵌入旋转 | 较好 | 中 |
| ALiBi | 相对,注意力偏置 | 好 | 低 |
相关笔记
- Token Embedding — 上一篇:分词与词嵌入
- 理解 Self Attention — 下一篇:位置编码注入后的核心计算