Skip to content
🔗 分享本题
查看我的学习进度 →

Sin Cos 位置编码动漫知识图:多组不同频率正弦余弦波为位置提供坐标,相位差表达相对位移,公式可生成更长位置但有效能力仍需验证

🧠 图解记忆:多频率给位置坐标,相位差携带相对距离;点击图片可查看原图。

💡 答案要点

位置编码 = 让模型知道token的位置信息

为什么需要位置编码?

问题:不含位置编码的 Self-Attention 对输入置换是等变的,无法单独区分词序

python
# 改变输入顺序会相应改变输出位置,但不会自动知道“第几个 token”的语义
input1 = ["狗", "咬", "人"]
input2 = ["人", "咬", "狗"]

# 若忽略输出位置的同样置换,计算结构本身不含绝对顺序信息

解决: 加入位置信息

python
embedding_with_pos = word_embedding + positional_encoding

Sin/Cos位置编码公式

python
PE(pos, 2i) = sin(pos / 10000^(2i/d_model))
PE(pos, 2i+1) = cos(pos / 10000^(2i/d_model))

其中:
- pos: 位置(0, 1, 2, ...)
- i: 维度索引(0 到 d_model/2)
- d_model: embedding维度(如512)

具体计算示例:

python
import numpy as np

def get_positional_encoding(max_len, d_model):
    pe = np.zeros((max_len, d_model))

    for pos in range(max_len):
        for i in range(0, d_model, 2):
            # 偶数维度: sin
            pe[pos, i] = np.sin(pos / (10000 ** (i/d_model)))

            # 奇数维度: cos
            if i+1 < d_model:
                pe[pos, i+1] = np.cos(pos / (10000 ** (i/d_model)))

    return pe

# 示例: max_len=100, d_model=512
pe = get_positional_encoding(100, 512)

# 位置0的编码
print(pe[0])  # [sin(0/1), cos(0/1), sin(0/464), cos(0/464), ...]

# 位置1的编码
print(pe[1])  # [sin(1/1), cos(1/1), sin(1/464), cos(1/464), ...]

为什么选sin/cos?

优势1: 表示相对位置

python
# 数学性质: sin/cos的线性组合
sin(α + β) = sin(α)cos(β) + cos(α)sin(β)
cos(α + β) = cos(α)cos(β) - sin(α)sin(β)

# 意味着: PE(pos+k)可由PE(pos)线性变换得到
# 模型容易学习相对位置关系

优势2: 泛化到未见过的长度

python
# 训练: max_len=512
# 推理: len=1024  # 超出训练长度

# sin/cos是连续函数,可以外推
pe_1024 = get_positional_encoding(1024, 512)  # 依然有效!

优势3: 不同频率捕捉不同范围

python
# 低频(i接近0): 变化慢,捕捉长距离关系
PE(pos, 0) = sin(pos / 1)  # 周期短,变化快

# 高频(i接近d_model): 变化快,捕捉近距离关系
PE(pos, 511) = sin(pos / 10000)  # 周期长,变化慢

可视化:

Position 0: [0.00, 1.00, 0.00, 1.00, 0.00, 1.00, ...]
Position 1: [0.84, 0.54, 0.01, 1.00, 0.00, 1.00, ...]
Position 2: [0.91,-0.42, 0.02, 1.00, 0.00, 1.00, ...]
           ↑ 快变化  ↑ 慢变化

其他位置编码方法

方法原理优缺点应用
Sin/Cos固定公式✅泛化好 ❌不可学习原始Transformer
Learned PE可学习embedding✅适应任务 ❌不泛化BERT
RoPE旋转位置编码✅长文本好LLaMA
ALiBi注意力偏置✅超长文本MPT

RoPE简介(LLaMA使用):

python
# 不是加法,而是旋转
# Q和K乘以旋转矩阵
Q_rot = rotate(Q, position)
K_rot = rotate(K, position)

# 优势: 相对位置信息更明确
# LLaMA-2可处理4K→32K上下文

面试话术:

"Sin/Cos编码的巧妙之处在于:1)不同频率捕捉不同距离 2)可外推到训练时未见长度 3)相对位置可线性表示。现代LLM如LLaMA改用RoPE,在超长文本上表现更好。我们项目用ALiBi,32K上下文零成本扩展。"