news 2026/6/4 6:44:30

08 位置编码详解:Sinusoidal、RoPE、ALiBi 为什么重要?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
08 位置编码详解:Sinusoidal、RoPE、ALiBi 为什么重要?

在前面的文章中,我们已经讲过 Transformer 的整体结构、Self-Attention、Encoder、Decoder。

但是这里还有一个非常关键的问题:

Transformer 是怎么知道 token 顺序的?

例如下面两个句子:

我 喜欢 你 你 喜欢 我

它们包含的 token 很相似,但语义完全不同。如果模型不知道顺序,那么它很难区分:

谁喜欢谁? 哪个词在前? 哪个词在后? 两个 token 相隔多远?

RNN 天然按时间步读取序列,因此顺序信息隐含在递归结构里。CNN 通过卷积窗口和局部结构感知相邻关系。但是 Transformer 的 Self-Attention 是并行计算的。

Self-Attention 本身只看 token 之间的相关性:

这里的计算的是 token 与 token 之间的匹配分数,但它并不知道第几个 token 在前、第几个 token 在后。

所以 Transformer 必须额外引入位置信息。这就是Positional Encoding,也就是位置编码。本文重点讲三种重要位置编码方式:

Sinusoidal Positional Encoding RoPE:Rotary Position Embedding ALiBi:Attention with Linear Biases

它们分别代表了三种不同思路:

Sinusoidal:把位置编码加到 token embedding 上 RoPE:把位置通过旋转注入到 Q 和 K 中 ALiBi:不加位置向量,而是在 attention score 上加距离惩罚

一、为什么 Transformer 必须要位置编码?

Self-Attention 的核心计算是:

它比较的是 token 表示之间的相似度。假设有三个 token:

x1, x2, x3

Self-Attention 会让每个 token 和其他 token 计算注意力权重:

x1 关注 x1, x2, x3 x2 关注 x1, x2, x3 x3 关注 x1, x2, x3

但是,如果不加入位置编码,模型看到的只是一个 token 集合,而不是有顺序的序列。例如:

我 喜欢 你

和:

你 喜欢 我

如果只看 token 集合,它们都包含:

我 喜欢 你

但顺序不同,语义完全不同。所以 Transformer 需要额外告诉模型:

这个 token 是什么? 这个 token 在哪里? 这个 token 和其他 token 相隔多远?

其中:

token embedding 负责告诉模型:这个 token 是什么 position encoding 负责告诉模型:这个 token 在哪里

最终输入 Transformer 的通常是:

这就是位置编码最基础的作用。


二、绝对位置和相对位置

在讲具体方法前,我们先区分两个概念:

绝对位置 相对位置

1. 绝对位置

绝对位置关注的是:

当前 token 是第几个 token?

例如:

我 喜欢 机器 学习

可以给每个 token 一个位置编号:

我:位置 0 喜欢:位置 1 机器:位置 2 学习:位置 3

Sinusoidal Positional Encoding 和 learned positional embedding 都属于绝对位置编码思路。

它们会给每个位置分配一个位置向量,然后加到 token embedding 上。

2. 相对位置

相对位置关注的是:

两个 token 之间相隔多远?

例如:

第 5 个 token 和第 7 个 token 相距 2 第 5 个 token 和第 100 个 token 相距 95

很多语言关系更依赖相对距离,而不是绝对编号。

例如:

形容词通常修饰附近的名词 代词可能指向前面某个名词 括号、引号、代码块存在局部或层级关系

RoPE 和 ALiBi 都更强调相对位置关系。这也是为什么它们在现代大语言模型中非常重要。


三、Sinusoidal Positional Encoding:原始 Transformer 的位置编码

原始 Transformer 使用的是 Sinusoidal Positional Encoding,也就是正弦余弦位置编码。它不是可训练参数,而是通过固定公式生成。

公式如下:

其中:

  • pos:token 在序列中的位置;

  • i:维度索引;

  • :模型隐藏维度;

  • 偶数维使用

  • 奇数维使用

例如,如果,那么位置编码的维度可以理解为:

第 0 维:sin 第 1 维:cos 第 2 维:sin 第 3 维:cos 第 4 维:sin 第 5 维:cos 第 6 维:sin 第 7 维:cos

不同维度使用不同频率的正弦余弦函数。低维度变化更快,高维度变化更慢。这样,每个位置都会得到一个独特的位置向量。


四、为什么 Sinusoidal 要用不同频率?

如果只用一个频率,模型只能在一个尺度上感知位置。但是语言中的位置关系有不同尺度。

例如:

相邻 token 的关系 短语内部的关系 句子内部的关系 段落内部的关系 长文档中的远距离关系

所以位置编码需要同时包含高频和低频信息。高频维度变化快,更适合区分相邻位置。

低频维度变化慢,更适合表示较长距离的位置关系。这就是 Sinusoidal Positional Encoding 使用多频率 sin / cos 的原因。

可以直观理解为:

不同维度相当于不同尺度的位置尺子,模型可以根据任务需要选择使用哪种尺度的位置关系。


五、Sinusoidal Positional Encoding 代码实现

下面是一个 PyTorch 实现。

import torch import torch.nn as nn import math class SinusoidalPositionalEncoding(nn.Module): def __init__(self, d_model: int, dropout: float = 0.1, max_len: int = 5000): super().__init__() self.dropout = nn.Dropout(dropout) # pe: [max_len, d_model] pe = torch.zeros(max_len, d_model) # position: [max_len, 1] position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1) # div_term: [d_model / 2] div_term = torch.exp( torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model) ) # 偶数维使用 sin pe[:, 0::2] = torch.sin(position * div_term) # 奇数维使用 cos pe[:, 1::2] = torch.cos(position * div_term) # 增加 batch 维度:[1, max_len, d_model] pe = pe.unsqueeze(0) # pe 不是可训练参数,但要随模型保存、加载和移动设备 self.register_buffer("pe", pe) def forward(self, x: torch.Tensor) -> torch.Tensor: """ x: [batch_size, seq_len, d_model] """ seq_len = x.size(1) # 取出当前序列长度对应的位置编码 x = x + self.pe[:, :seq_len] return self.dropout(x) if __name__ == "__main__": batch_size = 2 seq_len = 4 d_model = 8 x = torch.zeros(batch_size, seq_len, d_model) pe_layer = SinusoidalPositionalEncoding(d_model=d_model, dropout=0.0) out = pe_layer(x) print("output shape:", out.shape) print(out[0])

输出形状是:

[batch_size, seq_len, d_model]

也就是:

[2, 4, 8]

位置编码不会改变输入形状,只是在 token embedding 上加了位置信息。


六、Sinusoidal 的优点和局限

Sinusoidal Positional Encoding 的优点是:

不需要训练 实现简单 可以为任意位置生成编码 和原始 Transformer 结构一致

但是它也有一些局限。第一,它是绝对位置编码。也就是说,它更直接告诉模型:

这个 token 是第几个位置

但很多语言关系其实更依赖相对距离:

两个 token 相隔多远 谁在谁前面 是否是附近 token

第二,它是加到 token embedding 上的。输入一开始就把语义信息和位置信息混合在一起。

后续 attention 只能从混合后的表示中自己学习位置关系。第三,对于长上下文外推,Sinusoidal 虽然可以生成训练长度之外的位置编码,但模型是否能稳定利用这些新位置,并不是天然保证的。

这也是后来 RoPE、ALiBi 等方法出现的重要原因。


七、RoPE:把位置编码变成旋转

RoPE 的全称是:

Rotary Position Embedding

中文通常叫:

旋转位置编码

它和 Sinusoidal 最大的不同是:

RoPE 不把位置编码直接加到 token embedding 上,而是把位置信息注入到 Query 和 Key 中。

在 Self-Attention 中,注意力分数来自:

其中:

  • :第 i 个 token 的 Query;

  • :第 j 个 token 的 Key。

RoPE 的做法是:根据 token 的位置,对做旋转变换。

可以写成:

其中:

  • :第 i个位置对应的旋转矩阵;

  • :第 j个位置对应的旋转矩阵;

  • :加入位置信息后的 Query 和 Key。

然后 attention score 变成:

这个设计非常关键,因为旋转矩阵有一个重要性质:

可以转化成与相对距离 j-i有关的形式。

也就是说:

RoPE 虽然使用了绝对位置的旋转角度,但在 attention score 中自然体现出相对位置信息。

这就是 RoPE 的核心价值。


八、RoPE 的二维旋转直观理解

为了理解 RoPE,可以先看二维向量。

假设一个二维向量是:

旋转角度为,旋转矩阵是:

旋转后的向量是:

RoPE 会把高维向量拆成很多二维对:

第 0、1 维作为一组 第 2、3 维作为一组 第 4、5 维作为一组 ...

然后对每一组二维向量按照当前位置进行旋转。不同维度组使用不同频率。这和 Sinusoidal 一样,也有多尺度位置建模能力。


九、RoPE 为什么适合大语言模型?

RoPE 的优势主要有三点。

1. 它直接作用在 Attention 里

Sinusoidal 是:

token embedding + position encoding

RoPE 是:

Q 和 K 根据位置旋转

也就是说,RoPE 直接影响 attention score。由于 Self-Attention 本质上就是通过计算 token 之间的关系,所以把位置注入 Q 和 K 非常自然。

2. 它天然包含相对位置信息

RoPE 通过旋转性质,让两个 token 的 attention score 和相对距离有关。这对于语言建模非常重要。因为在文本中,很多关系不是取决于绝对位置,而是取决于相对距离。例如:

当前词和前一个词 当前词和前一句中的主语 当前括号和对应的左括号 当前代码缩进和上文结构

这些都更依赖相对位置。

3. 它适合自回归语言模型

GPT 类模型每次生成下一个 token,需要持续扩展上下文。RoPE 不需要为每个最大长度学习一个固定位置表,而是可以按公式生成不同位置的旋转角度。因此它在现代 Decoder-only 大语言模型中非常常见。


十、RoPE 代码实现

下面给出一个简化版 RoPE 实现。

输入一般是 attention 中的 q 和 k。

形状为:

[batch_size, heads, seq_len, head_dim]

代码如下:

import torch def rotate_half(x): """ 把最后一维两两分组,做二维旋转中的 (-x2, x1) 操作。 x: [..., dim] """ x_even = x[..., 0::2] x_odd = x[..., 1::2] # [-x_odd, x_even] x_rotated = torch.stack((-x_odd, x_even), dim=-1) return x_rotated.flatten(-2) def apply_rope(q, k, base=10000): """ q, k: [batch_size, heads, seq_len, head_dim] """ batch_size, heads, seq_len, head_dim = q.shape device = q.device # 每两个维度一组,所以取 0,2,4,... dim_idx = torch.arange(0, head_dim, 2, device=device).float() # 频率项 inv_freq = 1.0 / (base ** (dim_idx / head_dim)) # 位置编号 positions = torch.arange(seq_len, device=device).float() # angles: [seq_len, head_dim/2] angles = torch.einsum("i,j->ij", positions, inv_freq) # 扩展成 [seq_len, head_dim] angles = torch.repeat_interleave(angles, repeats=2, dim=-1) # [1, 1, seq_len, head_dim] cos = torch.cos(angles).unsqueeze(0).unsqueeze(0) sin = torch.sin(angles).unsqueeze(0).unsqueeze(0) q_rope = q * cos + rotate_half(q) * sin k_rope = k * cos + rotate_half(k) * sin return q_rope, k_rope if __name__ == "__main__": batch_size = 1 heads = 2 seq_len = 4 head_dim = 8 q = torch.randn(batch_size, heads, seq_len, head_dim) k = torch.randn(batch_size, heads, seq_len, head_dim) q_rope, k_rope = apply_rope(q, k) print("q shape:", q.shape) print("q_rope shape:", q_rope.shape) print("k_rope shape:", k_rope.shape)

输出:

q shape: torch.Size([1, 2, 4, 8]) q_rope shape: torch.Size([1, 2, 4, 8]) k_rope shape: torch.Size([1, 2, 4, 8])

可以看到,RoPE 不改变张量形状。它只是根据位置对 Q 和 K 做旋转。


十一、RoPE 在 Attention 中放在哪里?

普通 Multi-Head Attention 是:

输入 x ↓ 线性层生成 Q, K, V ↓ 计算 QK^T ↓ Softmax ↓ 加权求和 V

加入 RoPE 后变成:

输入 x ↓ 线性层生成 Q, K, V ↓ 对 Q, K 应用 RoPE ↓ 计算 Q_rope K_rope^T ↓ Softmax ↓ 加权求和 V

注意:

RoPE 通常作用在 Q 和 K 上,不作用在 V 上。

因为 Q 和 K 决定 attention score,也就是决定“谁关注谁”。V 表示被聚合的内容信息,一般不需要旋转位置。代码结构大概是:

Q = self.W_q(x) K = self.W_k(x) V = self.W_v(x) Q = split_heads(Q) K = split_heads(K) V = split_heads(V) Q, K = apply_rope(Q, K) scores = torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(d_k) attn = torch.softmax(scores, dim=-1) out = torch.matmul(attn, V)

这就是 RoPE 和普通 attention 的主要区别。


十二、ALiBi:不加位置向量,而是给 Attention 分数加偏置

ALiBi 的全称是:

Attention with Linear Biases

它的思路和 Sinusoidal、RoPE 都不同。Sinusoidal 是:

把位置向量加到 token embedding 上

RoPE 是:

把位置通过旋转注入 Q 和 K

ALiBi 则是:

直接在 attention score 上加入一个和距离有关的线性偏置

普通 attention score 是:

ALiBi 修改为:

这里以 causal language model 为例,假设

其中:

  • i:当前 query 位置;

  • j:被关注的 key 位置;

  • :两个 token 的距离;

  • :第 h个 attention head 的斜率;

  • 距离越远,惩罚越大。

也就是说,ALiBi 会鼓励模型更关注近处 token,同时仍然允许模型关注远处 token。


十三、ALiBi 的直观理解

假设当前 token 是第 5 个位置,它可以关注前面的 token:

位置 0, 1, 2, 3, 4, 5

距离分别是:

5, 4, 3, 2, 1, 0

ALiBi 会给更远的位置加更大的负偏置:

距离 0:惩罚最小 距离 1:轻微惩罚 距离 2:更大惩罚 距离 5:最大惩罚

这样 attention score 会倾向于:

近处 token 更容易被关注 远处 token 仍然可以被关注,但需要自身 QK 匹配分数足够高

这是一种非常简单但有效的位置归纳偏置。


十四、ALiBi 为什么有利于长度外推?

ALiBi 的一个重要优势是:

它不依赖固定长度的位置 embedding 表。

如果使用 learned absolute position embedding,模型通常只学习训练长度以内的位置。例如训练时最大长度是 1024,那么模型只学习了:

位置 0 到位置 1023

如果测试时输入长度变成 2048,后面的位置 embedding 没有训练过,就容易出现外推问题。Sinusoidal 可以生成更长位置的编码,但模型是否能稳定利用仍然不一定。ALiBi 不需要位置向量表。它只根据距离计算线性偏置。无论序列长度是 1024、2048,还是更长,只要能计算距离,就能生成偏置。所以 ALiBi 在长上下文外推上具有天然优势。


十五、ALiBi 代码实现

下面给出一个简化版 ALiBi bias 构造代码。

import torch def get_alibi_slopes(n_heads): """ 简化版 head slope 生成方式。 实际论文和开源实现中会使用更细致的 slope 设置。 这里用于教学理解。 """ return torch.tensor([1.0 / (2 ** i) for i in range(n_heads)]) def build_alibi_bias(batch_size, n_heads, seq_len, device="cpu"): """ 构造 ALiBi bias。 返回形状: [batch_size, n_heads, seq_len, seq_len] """ slopes = get_alibi_slopes(n_heads).to(device) # [heads] positions = torch.arange(seq_len, device=device) # distance[i, j] = i - j distance = positions.unsqueeze(1) - positions.unsqueeze(0) # causal 情况下,只关注 j <= i,未来位置之后会由 causal mask 屏蔽 distance = distance.clamp(min=0).float() # bias: [heads, seq_len, seq_len] bias = -slopes.view(n_heads, 1, 1) * distance.unsqueeze(0) # [batch_size, heads, seq_len, seq_len] bias = bias.unsqueeze(0).expand(batch_size, -1, -1, -1) return bias if __name__ == "__main__": batch_size = 1 n_heads = 4 seq_len = 5 alibi_bias = build_alibi_bias(batch_size, n_heads, seq_len) print("ALiBi bias shape:", alibi_bias.shape) print("Head 0 bias:") print(alibi_bias[0, 0])

输出类似:

ALiBi bias shape: torch.Size([1, 4, 5, 5]) Head 0 bias: tensor([[-0., -0., -0., -0., -0.], [-1., -0., -0., -0., -0.], [-2., -1., -0., -0., -0.], [-3., -2., -1., -0., -0.], [-4., -3., -2., -1., -0.]])

注意,未来位置还需要配合 causal mask 屏蔽。ALiBi 只是提供距离偏置,不替代 causal mask。


十六、ALiBi 在 Attention 中怎么用?

普通 attention score 是:

scores = torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(d_k)

加入 ALiBi 后:

scores = scores + alibi_bias

完整简化代码如下:

import torch import torch.nn.functional as F import math def attention_with_alibi(Q, K, V, alibi_bias, causal_mask=None): """ Q, K, V: [batch_size, heads, seq_len, head_dim] alibi_bias: [batch_size, heads, seq_len, seq_len] """ d_k = Q.size(-1) scores = torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(d_k) # 加入 ALiBi 位置偏置 scores = scores + alibi_bias # 仍然需要 causal mask 屏蔽未来位置 if causal_mask is not None: scores = scores.masked_fill(causal_mask == 0, -1e9) attn = F.softmax(scores, dim=-1) out = torch.matmul(attn, V) return out, attn

这就是 ALiBi 的核心实现。它不改变 embedding,不旋转 Q/K,只是在 attention score 上加了一个距离相关的 bias。


十七、Sinusoidal、RoPE、ALiBi 的核心区别

现在我们把三者放在一起对比。

方法注入位置位置类型是否可训练核心思想代表特点
SinusoidalToken Embedding绝对位置用 sin/cos 生成位置向量,加到 embedding 上原始 Transformer,简单直观
RoPEQuery / Key相对位置效果根据位置旋转 Q/K,使 attention score 体现相对距离适合自回归 LLM,常用于现代大模型
ALiBiAttention Score相对距离偏置在 attention 分数上加距离惩罚简单高效,有利于长度外推

可以这样理解:

Sinusoidal:告诉模型每个 token 在第几个位置 RoPE:让 Q 和 K 的匹配天然包含相对距离 ALiBi:直接告诉 attention,距离越远应该有越大惩罚

十八、为什么现代大模型更偏爱 RoPE 或 ALiBi?

现代大模型通常面对更长上下文、更复杂任务和更强泛化需求。因此,位置编码需要满足几个要求:

能表达 token 顺序 能表达相对距离 能适应长上下文 训练和推理成本不能太高 实现要稳定

Sinusoidal 适合作为 Transformer 入门方法,也适合讲清楚位置编码的基本思想。但是在大语言模型中,仅仅使用绝对位置往往不够。RoPE 和 ALiBi 更强调相对位置关系,因此更适合长文本和自回归语言建模。

RoPE 的优势是:

直接作用于 Q/K 相对位置性质自然 和 attention 机制结合紧密 在现代 Decoder-only 模型中非常常见

ALiBi 的优势是:

实现简单 不需要位置 embedding 表 直接支持更长序列 对长度外推友好

不过它们也不是没有局限。RoPE 在很长上下文扩展时,可能需要额外的缩放或插值策略。ALiBi 的线性距离偏置很简单,但表达能力也相对受限。所以今天的大模型位置编码还在不断发展。


十九、位置编码和长上下文有什么关系?

长上下文是大语言模型中的重要问题。如果模型训练时只见过 2048 token,但推理时要处理 8192、32768 甚至更长上下文,就会遇到位置外推问题。位置编码会直接影响模型能否处理更长文本。如果位置编码依赖固定长度表,超过训练长度后就很麻烦。如果位置编码可以通过公式生成,或者只依赖相对距离,就更容易扩展。这也是 RoPE 和 ALiBi 重要的原因。它们都不是简单地给每个位置学习一个固定向量,而是通过更结构化的方式表达位置关系。可以简单理解为:

短上下文时代:只要模型知道 token 大概在第几个位置即可 长上下文时代:模型更需要稳定理解相对距离和远距离依赖

所以,位置编码不只是一个小组件,而是长上下文能力的重要基础。


版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/4 6:41:14

SRAM加速LLM推理:LUT-GEMV算法与硬件架构设计

1. SRAM加速LLM推理的技术背景在大型语言模型(LLM)推理过程中&#xff0c;矩阵向量乘法(GEMV)占据了超过85%的计算开销。传统CPU架构面临两个关键瓶颈&#xff1a;一是内存墙问题&#xff0c;数据在处理器和内存间的频繁搬运消耗了60%以上的能耗&#xff1b;二是随着模型量化精…

作者头像 李华
网站建设 2026/6/4 6:40:27

DPDK硬件兼容性清单:手把手教你选对CPU、网卡和加密卡(附避坑指南)

DPDK硬件选型实战指南&#xff1a;从CPU到加密卡的黄金组合法则在构建高性能网络应用时&#xff0c;硬件选型往往决定了系统90%的性能天花板。DPDK作为数据平面开发的利器&#xff0c;其硬件兼容性直接影响到每秒数据包处理能力、延迟稳定性和系统总吞吐量。但官方支持列表中的…

作者头像 李华
网站建设 2026/6/4 6:40:00

GPT-5.5智能体工作流:从任务分解到过程可审计的范式升级

1. 项目概述&#xff1a;这不是一次常规升级&#xff0c;而是一次工作流范式的迁移“GPT-5.5 开启更强的智能体工作方式”——这个标题里没有堆砌参数&#xff0c;没提上下文长度翻了几倍&#xff0c;也没说训练用了多少GPU年。它直指一个更本质的变化&#xff1a;模型不再只是…

作者头像 李华
网站建设 2026/6/4 6:39:42

新时代的 AI 教育体系 - 全开源:Word Teacher 英语口语训练

AI 时代的教育&#xff0c;应该颠覆传统的老师在台上讲&#xff0c;学生在台下听这一套形式。应该针对每个学生&#xff0c;根据兴趣&#xff0c;都设置不同的课程&#xff0c;每个学生因材施教。过去那套传统的教学方案效率太低。因此&#xff0c;我也开始对这方面进行了一些浅…

作者头像 李华
网站建设 2026/6/4 6:35:54

英特尔COMPUTEX2026发声:Agentic AI时代,CPU、GPU算力配比将重塑!

【导语&#xff1a;过去两年AI硬件核心聚焦于GPU&#xff0c;英伟达股票屡创新高。但在COMPUTEX2026上&#xff0c;英特尔提出AI下一阶段不能只看GPU&#xff0c;智能体将重塑数据中心算力配比&#xff0c;英特尔也推出了一系列应对方案。】Agentic AI重塑算力配比传统AI如同“…

作者头像 李华