北海市网站建设_网站建设公司_Redis_seo优化
2025/12/30 4:34:38 网站建设 项目流程

Transformers位置编码详解:绝对与相对机制比较

在现代自然语言处理系统中,一个看似简单却至关重要的问题长期存在:如何让完全并行的神经网络理解“顺序”?

Transformer 模型自 2017 年问世以来,凭借其强大的注意力机制取代了传统的 RNN 和 CNN 结构,成为 NLP 领域的基石。但正因为它摒弃了递归结构,也就失去了对输入序列天然的“时序感知”。如果不对位置信息进行建模,“猫追狗”和“狗追猫”在模型眼里可能并无区别。

为解决这一根本性问题,位置编码(Positional Encoding)应运而生——它虽不显眼,却是 Transformer 能够真正“读懂句子”的关键所在。从最初的正弦函数到如今复杂的相对偏置设计,位置编码的演进折射出我们对语言结构理解的深化。


绝对位置编码:赋予每个位置唯一身份

最早的解决方案很直观:既然模型不知道词的位置,那就直接告诉它每个 token 在第几位。这就是绝对位置编码的核心思想。

原始 Transformer 使用了一种基于正弦和余弦函数的固定编码方式:

$$
PE_{(pos, 2i)} = \sin\left(\frac{pos}{10000^{\frac{2i}{d_{\text{model}}}}}\right), \quad
PE_{(pos, 2i+1)} = \cos\left(\frac{pos}{10000^{\frac{2i}{d_{\text{model}}}}}\right)
$$

这个公式乍看复杂,实则巧妙。通过将不同频率的三角波叠加,使得每个位置都获得一个独一无二的向量表示。低频部分覆盖长距离变化,高频捕捉局部细节,整体呈现出平滑且可外推的特性。

更重要的是,这种编码是无参数的。相比于后来常见的可学习嵌入表(learned positional embedding),它不需要占用额外的模型容量,也避免了过拟合特定长度训练数据的风险。即使面对比训练时更长的序列,也能通过函数计算生成新的编码,具备良好的泛化能力。

实际实现中,通常会预先生成一个最大长度的位置编码矩阵,并作为常量缓冲区注册到模型中:

import torch import torch.nn as nn import math class AbsolutePositionalEncoding(nn.Module): def __init__(self, d_model: int, max_len: int = 5000): super().__init__() pe = torch.zeros(max_len, d_model) position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1) div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model)) pe[:, 0::2] = torch.sin(position * div_term) pe[:, 1::2] = torch.cos(position * div_term) pe = pe.unsqueeze(0) # shape: [1, max_len, d_model] self.register_buffer('pe', pe) def forward(self, x): # x shape: [batch_size, seq_len, d_model] x = x + self.pe[:, :x.size(1)] return x

这段代码中的div_term控制着频率衰减的速度,确保高维通道变化缓慢,形成多尺度的时间表征。而register_buffer的使用则保证该张量随模型一起被移动至 GPU,但不会参与梯度更新,提升推理效率。

不过,绝对编码也有明显短板。例如,当整个句子发生平移(如从位置 1–10 移动到 101–110),尽管语义关系未变,模型仍需重新学习这些“新位置”的含义。此外,在超长文本任务中,固定周期性的正弦编码可能无法有效区分遥远位置。

这些问题促使研究者转向另一种更贴近人类认知的方式——相对位置建模


相对位置编码:关注“你离我有多远”

人类理解语言时,往往并不依赖绝对坐标,而是关注词语之间的相对距离。“因为……所以……”这类逻辑连接词的有效性,与其相隔多少个词有关,而非它们出现在句首还是句尾。

相对位置编码正是基于这一洞察。它不再为每个位置分配独立向量,而是在注意力计算过程中动态引入两个 token 之间的偏移信息。

以经典的 additive 方法为例,注意力得分不再只是 $ q_i^\top k_j $,而是增加一个依赖于相对距离 $ i-j $ 的偏置项:

$$
A_{ij} = \frac{q_i^\top k_j}{\sqrt{d_k}} + b_{i-j}
$$

这里的 $ b_{i-j} $ 是一个可学习的向量,代表从位置ji的影响强度。由于只涉及有限范围内的相对偏移(如 ±16),参数量远小于完整的绝对位置嵌入表。

这种设计带来了几个显著优势:

  • 平移不变性更强:无论上下文整体位于序列何处,只要相对关系一致,注意力行为就保持稳定;
  • 更适合长序列建模:配合循环机制(如 Transformer-XL 中的 segment 循环),可以跨越多个片段捕捉长期依赖;
  • 内存更高效:只需维护一个小规模的偏置查找表,尤其适合移动端或低资源场景。

下面是其实现示例:

import torch import torch.nn as nn class RelativePositionBias(nn.Module): def __init__(self, num_heads: int, max_relative_position: int): super().__init__() self.num_heads = num_heads self.max_relative_position = max_relative_position self.relative_attention_bias = nn.Embedding(2 * max_relative_position + 1, num_heads) def forward(self, length_q, length_k): range_q = torch.arange(length_q) range_k = torch.arange(length_k) distance = range_q[:, None] - range_k[None, :] # [Lq, Lk] distance = torch.clamp(distance, -self.max_relative_position, self.max_relative_position) distance += self.max_relative_position # 映射到非负索引 bias = self.relative_attention_bias(distance) # [Lq, Lk, H] return bias.permute(2, 0, 1) # [H, Lq, Lk]

在这个模块中,distance矩阵记录了所有 query 和 key 之间的相对位置差,经过截断和偏移后用于查表。最终得到的偏置会被加到原始注意力分数上,从而引导模型关注特定距离范围内的交互。

值得注意的是,相对编码并不会改变输入表示本身,而是深度集成在注意力机制内部。这意味着它的作用更加精细、灵活,但也增加了实现复杂度——必须修改标准注意力的计算流程。


实际应用中的权衡与选择

在真实系统架构中,位置编码的选择直接影响模型的整体行为。以下是一个典型的处理流程对比:

使用绝对编码的流程(如 BERT)

Input Tokens → Token Embedding → + Positional Encoding → LayerNorm → Multi-Head Attention

在这种模式下,位置信息从一开始就与词义融合在一起。模型需要通过自注意力间接推断出“I”和“learning”之间相隔两个词的事实。这种方式简单通用,适用于大多数标准 NLP 任务,但在处理文档级文本或代码等超长序列时表现受限。

使用相对编码的流程(如 Transformer-XL)

Q, K, V from previous layer → Compute QK^T → Retrieve Relative Bias based on position offset → Add bias to attention scores → Softmax + Dropout → Output

这里的位置信息是动态注入的。更重要的是,结合缓存机制,模型能够感知跨 segment 的相对距离(如当前词与 512 步前的词之间的关系)。这使得它在语言建模、代码补全等需要长期记忆的任务中表现出色。

工程实践中的常见考量

问题设计建议
是否应使用可学习编码?对于领域特定任务(如源代码、DNA 序列),可学习编码往往优于固定函数;但对于通用语言模型,正弦式编码更具外推优势。
最大长度如何设置?若采用可学习编码,需预设最大长度。超过时可通过线性插值扩展位置索引(如 LLaMA 系列的做法)。
如何优化显存使用?将位置编码注册为 buffer 存放于 GPU 显存,避免重复创建;对于相对偏置,限制最大偏移范围可大幅减少内存占用。
是否可以混合使用?是的。Swin Transformer 等视觉模型采用“相对位置偏差”而非向量加法,进一步解耦位置与内容信息,值得借鉴。

实际上,近年来的趋势正逐步从“编码”转向“偏差”——即不再将位置信息当作输入的一部分,而是作为注意力机制的调节因子。这种方式不仅提升了灵活性,也增强了模型对局部结构的敏感性。


写在最后:位置编码的未来方向

回顾位置编码的发展历程,我们可以看到一条清晰的技术演进路径:
从静态赋值 → 动态建模 → 偏置调控

早期的绝对编码解决了“有没有顺序”的问题,而相对编码则深入到了“关系有多近”的层面。今天,已有越来越多的工作尝试更细粒度的位置感知方式,例如:

  • 旋转位置编码(RoPE):通过旋转向量隐式编码相对位置,已被 LLaMA、ChatGLM 等主流大模型广泛采用;
  • ALiBi(Attention with Linear Biases):不使用任何显式位置编码,而是根据相对距离施加线性惩罚,实现无限外推;
  • XPos:在 RoPE 基础上引入位置缩放,进一步提升长序列建模能力。

这些创新表明,位置建模已不再是简单的附加组件,而是深刻影响模型归纳偏置的核心机制之一。

在工程层面,借助 PyTorch-CUDA 这类高度集成的深度学习环境,开发者可以快速验证不同位置编码方案的效果。无论是通过 Jupyter Notebook 可视化编码向量分布,还是在多卡集群上测试相对编码在长文本任务中的性能增益,现代工具链都极大降低了实验门槛。

可以说,位置编码虽小,却承载着我们对语言本质的理解。它的每一次进化,都在推动 Transformer 向更智能、更鲁棒的方向迈进。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询