2、绝对位置编码详解:Sinusoidal位置编码原理、可学习位置编码、绝对位置编码的优缺点

好,咱们正式开始聊位置编码。这一章我打算把「绝对位置编码」讲透。

你想想看,Transformer 的核心是自注意力机制。它本质上是在做「词与词」之间的加权求和。但问题是——它不关心词的先后顺序。

“我爱你”和“你爱我”,词袋是一样的,但意思完全相反。所以,我们必须把位置信息塞进去。

怎么塞?最直接的办法就是:给每个位置分配一个唯一的编码,然后加到词向量上。这就是绝对位置编码。

2.1 Sinusoidal 位置编码原理

这是 Google 在《Attention Is All You Need》里提出的方案。我个人觉得,这是最优雅的数学设计之一。

它的核心思路是:用不同频率的正弦和余弦函数,来生成每个位置的编码向量。

公式长这样:

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, 1, 2, ..., d_model/2 - 1)
  • d_model 是模型的隐藏层维度

说白了,每个位置都有一个独一无二的「频率指纹」。低维度用高频(变化快),高维度用低频(变化慢)。

关键洞察:这种设计让模型可以通过线性变换,轻松学到相对位置关系。因为 sin(a+b) 和 cos(a+b) 都可以用 sin(a), cos(a), sin(b), cos(b) 的线性组合表示。

我在项目中遇到过一个问题:有人问为什么底数要用 10000?其实这不是拍脑袋定的。10000 保证了不同频率的波长覆盖范围足够广——从 2π 到 10000*2π,能适应不同长度的序列。

2.2 可学习位置编码

另一种思路更直接:把位置编码当成可训练的参数,让模型自己学。

BERT 就是这么干的。它初始化一个 [max_seq_len, d_model] 的矩阵,然后随着训练一起更新。

import torch.nn as nn

class LearnablePositionalEncoding(nn.Module):
    def __init__(self, max_len, d_model):
        super().__init__()
        self.pe = nn.Embedding(max_len, d_model)
    
    def forward(self, x):
        # x: [batch, seq_len, d_model]
        seq_len = x.size(1)
        positions = torch.arange(seq_len, device=x.device)
        return x + self.pe(positions)

嗯,这里要注意:可学习编码的 max_len 是固定的。训练时设了 512,推理时就不能处理 513 个 token。这是硬伤。

我的建议:如果你的任务序列长度比较固定(比如分类任务),可学习编码完全够用。但如果你做长文本生成,最好别用。

2.3 绝对位置编码的优缺点

咱们客观地分析一下。我做了这么多年 NLP,两种方案都踩过坑。

维度 Sinusoidal 编码 可学习编码
外推能力 ✅ 理论上可外推(但实际效果有限) ❌ 无法外推,受限于 max_len
参数量 ✅ 0 参数 ❌ 需要 max_len × d_model 参数
表达能力 ❌ 固定模式,无法自适应 ✅ 可针对任务优化
实现复杂度 ✅ 简单,无训练 ✅ 简单,一个 Embedding 层

绝对位置编码的共性缺点也很明显:

  • 位置信息是「加性」的:直接加到词向量上,可能会干扰语义信息。我见过一些实验,位置编码的范数比词向量还大,模型学得很吃力。
  • 缺乏相对位置感知:模型需要自己从绝对位置中「推导」出相对关系。虽然 Sinusoidal 理论上支持,但实际训练中并不总能学到。
  • 长序列退化:序列越长,位置编码之间的区分度越低。尤其是 Sinusoidal 的高频部分,相邻位置的编码几乎一样。

我曾经踩过的坑:在一个长文本分类项目中,我用 Sinusoidal 编码处理 2000+ token 的输入。结果发现模型在长序列上的表现明显下降。后来分析发现,后半段的位置编码几乎「挤在一起」,模型根本分不清 1500 和 1800 的区别。

所以,绝对位置编码虽然简单直接,但天花板也很明显。这也是后来 RoPE、ALiBi 等相对位置编码兴起的原因。

不过话说回来,理解绝对位置编码是基础。你只有知道它哪里不好,才能理解为什么 RoPE 更好。

绝对位置编码知识体系 绝对位置编码 Sinusoidal 编码 正弦/余弦函数生成 0 参数,可外推 可学习位置编码 Embedding 层训练 需固定 max_len 共性缺点 加性干扰语义 | 缺乏相对感知 | 长序列退化

这张图把绝对位置编码的两种方案和它们的优缺点都串起来了。你可以看到,虽然实现方式不同,但最终都落在「加性干扰」和「缺乏相对感知」这两个核心问题上。

下一章我们会深入 RoPE,看看它是怎么优雅地解决这些问题的。


公众号:蓝海资料掘金营,微信deep3321