ALiBi:让大语言模型“免训练“外推到更长序列的位置编码方法

ALiBi:让大语言模型"免训练"外推到更长序列的位置编码方法

一、引言:为什么我们需要 ALiBi?

1.1 位置编码的困境

Transformer 的自注意力机制本身是排列不变 的------它不知道 token 的顺序。因此我们需要某种方式告诉模型"谁在前、谁在后",这就是位置编码(Positional Encoding)

主流的位置编码方案有:

方案 代表模型 核心思路
正弦位置编码 原始 Transformer 用不同频率的 sin/cos 函数
可学习位置编码 GPT-2, BERT 每个位置学一个向量
旋转位置编码 (RoPE) LLaMA, ChatGLM 在 Q、K 上施加旋转
ALiBi BLOOM, MPT 直接在注意力分数上加偏置

前三种方案都面临一个共同问题:长度外推(Length Extrapolation)

1.2 什么是长度外推问题?

假设模型训练时最长序列是 1024 个 token。推理时如果输入 4096 个 token 会怎样?

  • 可学习位置编码:位置 1025~4096 的嵌入向量根本不存在,直接崩溃
  • 正弦位置编码:虽然可以生成任意位置的编码,但效果严重下降
  • RoPE:未经适配时,超出训练长度后性能也会大幅衰减

核心矛盾:训练时见过的最大长度有限,但推理时我们希望处理更长的文本。

ALiBi 就是为了解决这个问题而生的。


二、ALiBi 的核心思想

2.1 论文信息

Train Short, Test Long: Attention with Linear Biases Enables Input Length Extrapolation

Ofir Press, Noah A. Smith, Mike Lewis (2022, ICLR)

论文标题直接点明了核心卖点:训练短序列,测试长序列

2.2 一句话总结

ALiBi 不对输入添加任何位置嵌入,而是在计算注意力分数时,根据 Q 和 K 之间的距离,直接减去一个线性惩罚项。距离越远,惩罚越大。

2.3 数学公式

标准注意力

Attention(Q,K,V)=softmax(QKTdk)V \text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right) V Attention(Q,K,V)=softmax(dk QKT)V

ALiBi 注意力

Attention(Q,K,V)=softmax(QKTdk+m⋅Bias)V \text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}} + m \cdot \text{Bias}\right) V Attention(Q,K,V)=softmax(dk QKT+m⋅Bias)V

其中:

Bias[i][j]=−∣i−j∣ \text{Bias}[i][j] = -|i - j| Bias[i][j]=−∣i−j∣

mmm 是每个注意力头各自的斜率(slope),是一个预设的常数。

2.4 偏置矩阵长什么样?

以序列长度 5 为例,Bias\text{Bias}Bias 矩阵(对于因果注意力,只看下三角):

Bias=(0−10−2−10−3−2−10−4−3−2−10) \text{Bias} = \begin{pmatrix} 0 & & & & \\ -1 & 0 & & & \\ -2 & -1 & 0 & & \\ -3 & -2 & -1 & 0 & \\ -4 & -3 & -2 & -1 & 0 \end{pmatrix} Bias= 0−1−2−3−40−1−2−30−1−20−10

乘以某个头的斜率 mmm 后:

m⋅Bias=(0−m0−2m−m0−3m−2m−m0−4m−3m−2m−m0) m \cdot \text{Bias} = \begin{pmatrix} 0 & & & & \\ -m & 0 & & & \\ -2m & -m & 0 & & \\ -3m & -2m & -m & 0 & \\ -4m & -3m & -2m & -m & 0 \end{pmatrix} m⋅Bias= 0−m−2m−3m−4m0−m−2m−3m0−m−2m0−m0

直觉理解 :每个 token 计算注意力时,越远的 token 被惩罚越多 → 自然倾向于关注近处的内容。


三、斜率 mmm 的设定

3.1 多头注意力中的斜率分配

ALiBi 最巧妙的设计之一:不同的头使用不同的斜率 ,而这些斜率是预设的,不需要学习

对于 nnn 个注意力头,斜率为几何序列:

mi=128n⋅i,i=1,2,...,n m_i = \frac{1}{2^{\frac{8}{n} \cdot i}}, \quad i = 1, 2, \ldots, n mi=2n8⋅i1,i=1,2,...,n

3.2 具体例子

8 个头的情况:

8n=88=1 \frac{8}{n} = \frac{8}{8} = 1 n8=88=1

m1=121=12,m2=122=14,m3=123=18,...,m8=128=1256 m_1 = \frac{1}{2^1} = \frac{1}{2}, \quad m_2 = \frac{1}{2^2} = \frac{1}{4}, \quad m_3 = \frac{1}{2^3} = \frac{1}{8}, \quad \ldots, \quad m_8 = \frac{1}{2^8} = \frac{1}{256} m1=211=21,m2=221=41,m3=231=81,...,m8=281=2561

复制代码
头1: m = 1/2     → 衰减最快,强烈偏好近距离
头2: m = 1/4     → 衰减较快
头3: m = 1/8     → 衰减中等
...
头8: m = 1/256   → 衰减最慢,能"看到"很远的位置

3.3 为什么这样设计?

复制代码
            注意力权重
    ↑
1.0 │ ██
    │ ████
    │ ██████        头8 (m=1/256): 缓慢衰减,关注长距离
    │ ████████████████████████───────────
    │ ██████████████████──────
    │ ██████████────
    │ ████──── 
    │ ──        头1 (m=1/2): 快速衰减,只关注近距离
    └──────────────────────────────→ 距离

不同头承担不同的"感受野"角色:

  • 大斜率头:像局部卷积,捕捉相邻 token 的关系(语法、短语结构)
  • 小斜率头:像全局注意力,捕捉长距离依赖(篇章结构、指代关系)

这种设计使模型天然具备多尺度的位置感知能力。


四、ALiBi 为什么能外推?

4.1 与其他方案的关键区别

复制代码
=== 正弦/可学习/RoPE 位置编码 ===

输入: [token₁, token₂, ..., tokenₙ]
       + PE₁    + PE₂         + PEₙ     ← 位置信息注入到输入中

问题: 位置编码和内容编码混合后,模型很难泛化到未见过的位置编号


=== ALiBi ===

输入: [token₁, token₂, ..., tokenₙ]     ← 不加任何位置编码!
                                           位置信息只在注意力分数中体现

Q·K^T + m·[-|i-j|]                        ← 位置信息作为偏置后加

4.2 外推能力的直觉解释

ALiBi 编码的是"相对距离",而不是"绝对位置"。

训练时模型见过的情况:

  • 距离 0 → 偏置 0
  • 距离 1 → 偏置 −m-m−m
  • 距离 100 → 偏置 −100m-100m−100m
  • 距离 1024 → 偏置 −1024m-1024m−1024m(训练中的最大距离)

推理时遇到更长序列:

  • 距离 2000 → 偏置 −2000m-2000m−2000m
  • 距离 4096 → 偏置 −4096m-4096m−4096m

关键洞察 :偏置是线性函数 f(d)=−mdf(d) = -mdf(d)=−md,线性函数天然具有外推能力!

复制代码
偏置
  0 ┤───╮
    │    ╲
    │     ╲         训练范围
-1024m ┤    ·╲·················
    │       ╲
    │        ╲      外推范围(自然延伸)
-4096m ┤       ╲
    └────────────────→ 距离
         1024  4096

模型在训练时学到了"距离越远,关注越少"的模式。这个模式在更长的距离上自然延续,不会出现任何突变或未定义的行为。

4.3 与 RoPE 外推的对比

复制代码
RoPE 在训练长度外:
  - 旋转角度 mθ 超出训练范围
  - 高频分量出现从未见过的相位
  - 注意力分数剧烈波动
  - 需要额外技术(NTK-aware 插值等)来修复

ALiBi 在训练长度外:
  - 偏置 -md 只是线性函数的自然延伸
  - 远距离 token 的注意力权重平滑地趋近于零
  - 不需要任何修改,天然可外推

五、代码实现

5.1 计算斜率

python 复制代码
import torch
import math

def get_alibi_slopes(num_heads):
    """
    计算每个注意力头的斜率 m
  
    对于 8 个头: [1/2, 1/4, 1/8, 1/16, 1/32, 1/64, 1/128, 1/256]
    """
    # 找到最接近的 2 的幂次
    closest_power_of_2 = 2 ** math.floor(math.log2(num_heads))
  
    # 基础比率
    base = 2 ** (8 / closest_power_of_2)  # 对于 8 头: base = 2^1 = 2
  
    # 生成斜率: 1/base^1, 1/base^2, ..., 1/base^n
    slopes = [1.0 / (base ** i) for i in range(1, closest_power_of_2 + 1)]
  
    # 如果 num_heads 不是 2 的幂次,需要额外处理
    if closest_power_of_2 != num_heads:
        extra_base = 2 ** (8 / (2 * closest_power_of_2))
        extra_slopes = [1.0 / (extra_base ** i) 
                       for i in range(1, 2 * (num_heads - closest_power_of_2) + 1, 2)]
        slopes = extra_slopes + slopes
  
    return torch.tensor(slopes)

# 示例
slopes = get_alibi_slopes(8)
print("8 heads slopes:", slopes)
# tensor([0.5000, 0.2500, 0.1250, 0.0625, 0.0312, 0.0156, 0.0078, 0.0039])

5.2 构建偏置矩阵

python 复制代码
def build_alibi_bias(seq_len, num_heads):
    """
    构建 ALiBi 偏置矩阵
  
    返回 shape: (num_heads, seq_len, seq_len)
    """
    # Step 1: 计算距离矩阵
    # positions[i][j] = -|i - j|
    positions = torch.arange(seq_len)
    # 对于因果注意力(decoder),通常用 i - j(只看过去)
    relative_positions = positions.unsqueeze(0) - positions.unsqueeze(1)
    # 取负的绝对值
    distance_matrix = -torch.abs(relative_positions)  # shape: (seq_len, seq_len)
  
    # Step 2: 获取每个头的斜率
    slopes = get_alibi_slopes(num_heads)  # shape: (num_heads,)
  
    # Step 3: 斜率 × 距离 → 偏置
    # slopes: (num_heads, 1, 1) × distance: (seq_len, seq_len)
    alibi_bias = slopes.unsqueeze(1).unsqueeze(1) * distance_matrix.unsqueeze(0)
  
    return alibi_bias  # shape: (num_heads, seq_len, seq_len)

# 示例: 4 个头,序列长度 5
bias = build_alibi_bias(seq_len=5, num_heads=4)
print(f"Shape: {bias.shape}")
print(f"\n头 0 (slope={get_alibi_slopes(4)[0]:.4f}):")
print(bias[0])

输出:

复制代码
Shape: torch.Size([4, 5, 5])

头 0 (slope=0.0625):
tensor([[ 0.0000, -0.0625, -0.1250, -0.1875, -0.2500],
        [-0.0625,  0.0000, -0.0625, -0.1250, -0.1875],
        [-0.1250, -0.0625,  0.0000, -0.0625, -0.1250],
        [-0.1875, -0.1250, -0.0625,  0.0000, -0.0625],
        [-0.2500, -0.1875, -0.1250, -0.0625,  0.0000]])

5.3 因果注意力的偏置矩阵

在 decoder-only 模型(如 GPT)中,token 只能看到自己和之前的 token:

python 复制代码
def build_alibi_bias_causal(seq_len, num_heads):
    """
    因果(单向)注意力的 ALiBi 偏置
    """
    # 因果注意力:位置 i 只看位置 j ≤ i
    # 距离 = i - j ≥ 0
    positions = torch.arange(seq_len)
    # relative_positions[i][j] = j - i (负数或零)
    relative_positions = positions.unsqueeze(1) - positions.unsqueeze(0)
    # 只保留下三角(j ≤ i 的部分),上三角设为 -inf
    causal_mask = torch.triu(torch.ones(seq_len, seq_len), diagonal=1).bool()
  
    slopes = get_alibi_slopes(num_heads)
  
    # 偏置 = slope × (j - i),其中 j ≤ i,所以 j - i ≤ 0
    alibi_bias = slopes.unsqueeze(1).unsqueeze(1) * relative_positions.unsqueeze(0)
    alibi_bias.masked_fill_(causal_mask.unsqueeze(0), float('-inf'))
  
    return alibi_bias

可视化因果偏置矩阵:

复制代码
头 1 (slope = 1/2):

token:    t₀      t₁       t₂       t₃       t₄
t₀ [  0.00,   -inf,    -inf,    -inf,    -inf  ]
t₁ [ -0.50,   0.00,    -inf,    -inf,    -inf  ]
t₂ [ -1.00,  -0.50,    0.00,    -inf,    -inf  ]
t₃ [ -1.50,  -1.00,   -0.50,    0.00,    -inf  ]
t₄ [ -2.00,  -1.50,   -1.00,   -0.50,    0.00  ]

       ↑ 距离远,惩罚大                ↑ 距离近,惩罚小

5.4 集成到注意力计算中

python 复制代码
class ALiBiAttention(torch.nn.Module):
    def __init__(self, hidden_dim, num_heads):
        super().__init__()
        self.num_heads = num_heads
        self.head_dim = hidden_dim // num_heads
      
        self.W_q = torch.nn.Linear(hidden_dim, hidden_dim, bias=False)
        self.W_k = torch.nn.Linear(hidden_dim, hidden_dim, bias=False)
        self.W_v = torch.nn.Linear(hidden_dim, hidden_dim, bias=False)
        self.W_o = torch.nn.Linear(hidden_dim, hidden_dim, bias=False)
      
        # 注册斜率为 buffer(不参与训练)
        self.register_buffer('slopes', get_alibi_slopes(num_heads))
  
    def forward(self, x, causal_mask=None):
        """
        x: (batch_size, seq_len, hidden_dim)
        """
        B, L, D = x.shape
      
        # === 1. 线性投影(注意:不加任何位置编码!)===
        Q = self.W_q(x).view(B, L, self.num_heads, self.head_dim).transpose(1, 2)
        K = self.W_k(x).view(B, L, self.num_heads, self.head_dim).transpose(1, 2)
        V = self.W_v(x).view(B, L, self.num_heads, self.head_dim).transpose(1, 2)
        # Q, K, V shape: (B, num_heads, L, head_dim)
      
        # === 2. 计算注意力分数 ===
        scale = self.head_dim ** -0.5
        attn_scores = torch.matmul(Q, K.transpose(-2, -1)) * scale
        # attn_scores shape: (B, num_heads, L, L)
      
        # === 3. 加上 ALiBi 偏置(核心!)===
        alibi_bias = self._build_alibi_bias(L)  # (num_heads, L, L)
        attn_scores = attn_scores + alibi_bias.unsqueeze(0)  # 广播到 batch 维度
      
        # === 4. 因果掩码 ===
        if causal_mask is not None:
            attn_scores = attn_scores.masked_fill(causal_mask, float('-inf'))
      
        # === 5. Softmax + 加权求和 ===
        attn_weights = torch.softmax(attn_scores, dim=-1)
        output = torch.matmul(attn_weights, V)
      
        # === 6. 合并多头 + 输出投影 ===
        output = output.transpose(1, 2).contiguous().view(B, L, D)
        output = self.W_o(output)
      
        return output
  
    def _build_alibi_bias(self, seq_len):
        """动态构建偏置矩阵(支持任意长度!)"""
        positions = torch.arange(seq_len, device=self.slopes.device)
        relative_positions = positions.unsqueeze(1) - positions.unsqueeze(0)
        # relative_positions[i][j] = j - i
      
        alibi_bias = self.slopes.unsqueeze(1).unsqueeze(1) * relative_positions.unsqueeze(0)
      
        return alibi_bias

六、ALiBi 的完整工作流程

复制代码
┌─────────────────────────────────────────────────────┐
│                   输入序列                            │
│  "我 喜欢 自然 语言 处理"                              │
│  [t₁, t₂, t₃, t₄, t₅]                              │
└────────────────────┬────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────┐
│              Token Embedding                         │
│                                                      │
│  注意:不加任何位置编码!                                │
│  x = Embedding(tokens)                               │
│                                                      │
│  对比其他方案:                                         │
│  ✗ x = Embedding(tokens) + PosEmbedding(positions)   │
│  ✗ x = Embedding(tokens) + SinCos(positions)         │
└────────────────────┬────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────┐
│          Q, K, V = Linear(x)                         │
│          (纯内容信息,无位置信息)                       │
└────────────────────┬────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────┐
│         注意力分数 = Q·K^T / √d                       │
│                                                      │
│  ┌                              ┐                    │
│  │ q₁k₁  q₁k₂  q₁k₃  q₁k₄  q₁k₅ │    纯内容相似度   │
│  │ q₂k₁  q₂k₂  q₂k₃  q₂k₄  q₂k₅ │                 │
│  │ q₃k₁  q₃k₂  q₃k₃  q₃k₄  q₃k₅ │                 │
│  │ q₄k₁  q₄k₂  q₄k₃  q₄k₄  q₄k₅ │                 │
│  │ q₅k₁  q₅k₂  q₅k₃  q₅k₄  q₅k₅ │                 │
│  └                              ┘                    │
└────────────────────┬────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────┐
│                                                      │
│         +  m × 距离偏置     ← ALiBi 的全部操作!      │
│                                                      │
│  ┌                                          ┐        │
│  │  0    -m    -2m    -3m    -4m            │        │
│  │  -m    0    -m     -2m    -3m            │        │
│  │  -2m   -m    0     -m     -2m            │        │
│  │  -3m   -2m   -m     0     -m             │        │
│  │  -4m   -3m   -2m    -m     0             │        │
│  └                                          ┘        │
│                                                      │
└────────────────────┬────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────┐
│         Softmax → 注意力权重 → 加权求和 V              │
└─────────────────────────────────────────────────────┘

七、实验结果

7.1 外推能力对比

论文中的核心实验:在 1024 长度上训练,测试不同长度的困惑度(PPL):

复制代码
测试长度 →     1024    2048    3072    4096    6144    8192

正弦编码       25.0    >1e3    >1e3    >1e3    >1e3    >1e3
旋转编码       25.0    43.0    >1e3    >1e3    >1e3    >1e3
T5 Bias        25.0    28.0    45.0    >1e3    >1e3    >1e3
ALiBi          25.0    25.5    25.8    26.0    26.5    27.0
                ✓      ✓✓     ✓✓✓    ✓✓✓✓   ✓✓✓✓✓  ✓✓✓✓✓✓

ALiBi 在 8 倍外推时仍保持合理的性能! 其他方案在 2-3 倍时就崩溃了。

7.2 训练速度

由于 ALiBi 不需要计算位置嵌入向量,计算量略有减少:

复制代码
方法          相对训练速度
正弦编码       1.00x
可学习编码     1.00x
RoPE           0.98x(需要额外的旋转操作)
ALiBi          1.01x(只需一次加法)

八、ALiBi 的优缺点

8.1 优点

优点 说明
强外推能力 训练短、测试长,不需要任何额外技术
实现极简 只需在注意力分数上加一个矩阵,几行代码
零额外参数 斜率是预设的,不需要学习
计算高效 不需要像 RoPE 那样修改 Q/K,只需一次加法
与 KV Cache 天然兼容 偏置只依赖相对距离,增量推理不受影响

8.2 缺点

缺点 说明
位置建模能力较弱 线性衰减是一种很强的归纳偏置,可能不够灵活
在训练长度内的性能 同等训练条件下,ALiBi 在训练长度内的 PPL 有时略逊于 RoPE
对注意力模式的约束 强制近距离偏好,可能限制某些需要远距离跳跃注意力的任务
生态不如 RoPE 当前主流开源模型(LLaMA、Qwen 等)多用 RoPE

九、ALiBi vs RoPE:深度对比

维度 ALiBi RoPE
位置信息注入点 注意力分数(加偏置) Q/K 向量(乘旋转矩阵)
编码类型 相对位置 相对位置
需要额外参数?
实现复杂度 极简(一次加法) 中等(旋转操作)
训练长度内性能 略好
原生外推能力 强(线性外推) 弱(需要插值技术)
修改输入嵌入? 不修改 不修改
代表模型 BLOOM, MPT LLaMA, Qwen, Mistral
当前主流程度 较少使用 主流

为什么 RoPE 最终更流行?

虽然 ALiBi 的外推能力更强,但 RoPE 通过一系列扩展技术(YaRN、NTK-aware 插值、动态 NTK 等)弥补了外推的不足,同时在训练长度内的建模能力更强。加上 LLaMA 系列模型的巨大影响力,RoPE 成为了当前大模型的主流选择。


十、使用 ALiBi 的知名模型

模型 发布方 参数量 说明
BLOOM BigScience 176B 最大的开源多语言模型之一
MPT-7B/30B MosaicML 7B/30B 号称可外推到 84k token
BTLM-3B Cerebras 3B 高效小模型

十一、总结

ALiBi 用一个优雅至极的方法解决了位置编码的长度外推问题:

不在输入中编码位置,而在注意力分数中直接加线性距离惩罚。

python 复制代码
# ALiBi 的核心,就这一行:
attn_scores = Q @ K.T / sqrt(d) + slope * distance_bias

它的设计哲学值得深思:

  • 简单就是力量:线性函数的外推能力优于复杂的周期函数
  • 正确的归纳偏置:自然语言中"距离近 = 更相关"几乎总是成立
  • 不需要学的就别学:预设斜率的几何序列就足够好了

虽然在当前大模型生态中 RoPE 占据主导地位,但 ALiBi 的思想------将位置信息与内容信息解耦,用最简单的数学形式编码位置------依然深刻地影响着位置编码的研究方向。

ALiBi 外推能力的深层解释

你的疑问非常好------"线性函数天然具有外推能力"这句话确实太笼统了。让我真正讲清楚为什么 ALiBi 能外推而其他方案不能


一、先搞清楚"外推失败"到底是什么现象

1.1 用一个极简例子说明

训练时最长序列 = 4 个 token,推理时来了 8 个 token。

模型需要算的核心东西 :token iii 对 token jjj 的注意力分数。

复制代码
训练时 (seq_len=4):
token 0 对 token 0: 距离 0  ✓ 见过
token 3 对 token 0: 距离 3  ✓ 见过(最远距离)

推理时 (seq_len=8):
token 7 对 token 0: 距离 7  ✗ 没见过!

外推的本质问题:模型遇到了训练时从未出现过的"距离=7",它该怎么处理?


二、逐个分析各方案为什么失败

2.1 可学习位置编码(GPT-2 风格)

python 复制代码
# 训练时
pos_embedding = nn.Embedding(max_len=4, dim=D)
# 学到了 4 个向量: PE[0], PE[1], PE[2], PE[3]

# 推理时,输入第 5 个 token
pos_embedding(4)  # → 索引越界!直接报错
pos_embedding(7)  # → 不存在!

失败原因:位置 4~7 的嵌入向量根本不存在,这是最硬性的失败。

2.2 正弦位置编码

python 复制代码
# 位置 m 的编码:PE(m) = [sin(mθ₀), cos(mθ₀), sin(mθ₁), cos(mθ₁), ...]

虽然可以算出任意位置的值,但问题在于:

复制代码
训练时:
  输入 = 内容嵌入 + PE(位置)
  模型学到的是:当输入向量"长这样"时,应该如何注意

推理时位置 7:
  PE(7) 这个向量,模型在训练时从未作为输入的一部分见过
  它和内容嵌入相加后,产生的向量落在了训练数据分布之外

失败原因 :位置编码加到了输入里,改变了输入的分布。新位置的 PE 向量让输入变成了分布外(Out-of-Distribution) 的数据。

复制代码
         模型见过的输入分布
         ┌─────────────┐
         │   ●●●●●     │  ← 训练时的输入(内容+PE(0~3))
         │    ●●●●     │
         │             │
         └─────────────┘
                              ★  ← 推理时的输入(内容+PE(7))
                                   落在分布外!

2.3 RoPE

RoPE 不加到输入里,而是旋转 Q 和 K:

score(m,n)=(Rmq)T(Rnk)=qTRm−nTk \text{score}(m, n) = (R_m q)^T (R_n k) = q^T R_{m-n}^T k score(m,n)=(Rmq)T(Rnk)=qTRm−nTk

注意力分数只依赖相对距离 m−nm-nm−n,这比正弦编码好。但问题是:

复制代码
R(Δ) 是一个旋转矩阵,旋转角度 = Δ × θᵢ

训练时见过的角度范围:
  θ₀ = 1.0:       Δ·θ₀ ∈ [0, 3.0]     (Δ最大=3)
  θ₁ = 0.01:      Δ·θ₁ ∈ [0, 0.03]

推理时 Δ=7:
  θ₀ = 1.0:       7·θ₀ = 7.0          ← 超出 [0, 3.0] 的范围!
  θ₁ = 0.01:      7·θ₁ = 0.07         ← 这个还好

高频分量 (大 θi\theta_iθi)的旋转角度超出训练范围后:

复制代码
cos/sin 是周期函数,角度从 3.0 跳到 7.0 时:

cos(3.0) = -0.99        训练时的最远距离
cos(7.0) = +0.75        推理时的距离7

这两个值之间没有平滑过渡!
模型从未学过 cos=0.75 对应"很远的距离"

注意力分数
    ↑
    │    ╱╲     ╱╲         ← RoPE:周期性波动
    │   ╱  ╲   ╱  ╲     
    │  ╱    ╲ ╱    ╲    
    │─╱──────╳──────╲──   ← 不该出现的"复活":远处token获得高分
    │╱    训练范围 │ 外推范围
    └──────────────────→ 距离
              3    7

失败原因 :cos⁡(mθ)\cos(m\theta)cos(mθ) 和 sin⁡(mθ)\sin(m\theta)sin(mθ) 是周期函数 。超出训练范围后,远距离的注意力分数不会单调衰减,反而会出现周期性的"复活"------一个距离很远的 token 可能突然获得很高的注意力分数。


三、ALiBi 为什么能成功

现在回到 ALiBi:

score(i,j)=qiTkjd+m⋅(−(∣i−j∣)) \text{score}(i, j) = \frac{q_i^T k_j}{\sqrt{d}} + m \cdot (-(|i-j|)) score(i,j)=d qiTkj+m⋅(−(∣i−j∣))

3.1 关键洞察:ALiBi 中"什么是模型需要泛化的"

让我们精确地分析模型在训练和推理时分别遇到什么:

复制代码
训练时 (seq_len=4),模型经历过的所有注意力分数:

  score(i,j) = [内容相似度] + [位置偏置]

  距离0: content_score + m×0  = content_score + 0
  距离1: content_score + m×(-1) = content_score - m
  距离2: content_score + m×(-2) = content_score - 2m
  距离3: content_score + m×(-3) = content_score - 3m

训练后 Softmax 学到了什么?

Softmax 接收的输入是一组分数,输出归一化的注意力权重。它学到的核心模式:

"偏置项从 0 开始,每远一步就减少 mmm,越远的 token 分数越低,注意力权重越小。"

3.2 推理时发生了什么

复制代码
推理时 (seq_len=8),对于 token 7:

  距离0: content_score - 0m    ← 见过
  距离1: content_score - 1m    ← 见过
  距离2: content_score - 2m    ← 见过
  距离3: content_score - 3m    ← 见过(训练时的最远距离)
  ──────── 以下是外推 ────────
  距离4: content_score - 4m    ← 没直接见过
  距离5: content_score - 5m    ← 没直接见过
  距离6: content_score - 6m    ← 没直接见过
  距离7: content_score - 7m    ← 没直接见过

但是! 我们来看 Softmax 的输入分布:

复制代码
进入 Softmax 的值:
  [content₀ - 7m,  content₁ - 6m,  content₂ - 5m,  content₃ - 4m,
   content₄ - 3m,  content₅ - 2m,  content₆ - 1m,  content₇ - 0m]

对于 token 7 来说,它附近的 token(距离 0~3)获得的偏置和训练时完全一样

远处的 token(距离 4~7)获得了更大的负偏置 −4m,−5m,−6m,−7m-4m, -5m, -6m, -7m−4m,−5m,−6m,−7m。

3.3 核心问题:Softmax 能处理这些更大的负值吗?

能!这是 ALiBi 成功的真正原因。

复制代码
Softmax 的性质:
  softmax(z)_i = exp(z_i) / Σ exp(z_j)

当某个 z_i 变得很负时:
  exp(-7m) 是一个很小的正数
  这个 token 的注意力权重 ≈ 0

这完全符合模型已经学到的模式:
  "偏置越负 → 权重越小"

让我们用具体数字看(假设 m=0.5m = 0.5m=0.5,忽略内容分数):

复制代码
训练时 Softmax 见过的输入:
  [0, -0.5, -1.0, -1.5]
  → exp: [1.00, 0.61, 0.37, 0.22]
  → softmax: [0.45, 0.28, 0.17, 0.10]

推理时 Softmax 的输入:
  [0, -0.5, -1.0, -1.5, -2.0, -2.5, -3.0, -3.5]
  → exp: [1.00, 0.61, 0.37, 0.22, 0.14, 0.08, 0.05, 0.03]
  → softmax: [0.40, 0.24, 0.15, 0.09, 0.05, 0.03, 0.02, 0.01]

观察:

  • 近距离 token 的权重分布几乎没变(0.45→0.40,0.28→0.24)

  • 远距离 token 自然获得接近 0 的权重

  • 没有任何突变、跳跃或异常

    注意力权重

    0.5 │
    │ █
    0.4 │ █
    │ █ █
    0.3 │ █ █
    │ █ █ █
    0.2 │ █ █ █ █
    │ █ █ █ █ █
    0.1 │ █ █ █ █ █ █
    │ █ █ █ █ █ █ █ █
    0.0 │─█─█─█─█─█─█─█─█───→
    距离 0 1 2 3 4 5 6 7
    ←训练→ ←──外推──→

    复制代码
           平滑衰减,没有任何异常!

3.4 对比:为什么 RoPE 的 Softmax 输入会出问题?

复制代码
RoPE 推理时 Softmax 的输入(示意):

距离:    0     1     2     3  │  4     5     6     7
分数: [+2.0, +1.5, +0.8, +0.1, +1.8, -0.5, +1.6, +0.3]
                              │   ↑           ↑
                              │   周期性"复活"!
                              │   远距离token突然获得高分

→ softmax 后,距离4和距离6的token获得异常高的权重
→ 模型从未学过如何处理这种"远处突然很重要"的模式
→ 生成质量崩溃

四、精确总结

外推成功的三个必要条件

ALiBi 同时满足了这三个条件:

复制代码
条件 1:位置信息不污染输入分布
  ┌─────────────────────────────────────────┐
  │ 正弦/可学习编码:PE 加到输入 → 新位置改变输入分布  │  ✗
  │ RoPE:旋转 Q/K → 不改变输入,但改变注意力计算      │  △
  │ ALiBi:输入完全不含位置信息                        │  ✓
  └─────────────────────────────────────────┘

条件 2:注意力分数随距离单调变化
  ┌─────────────────────────────────────────┐
  │ RoPE:cos/sin 是周期函数 → 远距离分数会震荡       │  ✗
  │ ALiBi:-m|d| 是单调递减函数 → 越远分数越低         │  ✓
  └─────────────────────────────────────────┘

条件 3:外推区域的值在 Softmax 的"舒适区"内
  ┌─────────────────────────────────────────┐
  │ RoPE:外推区域的分数可能突然变大 → Softmax 异常    │  ✗
  │ ALiBi:外推区域的分数更负 → Softmax 自然给更低权重  │  ✓
  │        exp(更负的数) = 更小的正数,完全在正常范围内  │
  └─────────────────────────────────────────┘

一句话解释

ALiBi 外推时,远距离 token 只是获得了更大的负偏置,Softmax 自然地将它们的权重压到接近零。模型不需要"理解"新的距离,它只需要做和训练时一样的事:给负偏置大的 token 低权重。整个过程没有任何训练时未见过的新模式出现。

后记

2026年5月15日于上海,在claude opus 4.6辅助下完成。

相关推荐
极客老王说Agent2 小时前
2026供应链革命:实在Agent货物智能入库智能助理使用方法与库位优化全指南
人工智能·ai
沪漂阿龙2 小时前
面试题:训练-蒸馏详解——知识蒸馏、Teacher-Student、强弱蒸馏、Qwen3 强到弱蒸馏流程全解析
人工智能·深度学习·机器学习
凌波粒2 小时前
什么是 MCP(模型上下文协议)
人工智能·网络协议·aigc
txg6662 小时前
HgtJIT:基于异构图 Transformer 的即时漏洞检测框架
人工智能·深度学习·安全·transformer
IT研究所2 小时前
AI 时代下的知识管理:从 Claude 的“复盘”能力看生成式 AI价值
大数据·运维·数据库·人工智能·科技·低代码·自然语言处理
AI前沿资讯3 小时前
2026 AI 3D工具推荐:V2Fun如何重新定义“一站式角色创作”
人工智能·3d
水上冰石3 小时前
Vibe Coding即氛围编程,直觉编程概念介绍
人工智能
Xxtaoaooo3 小时前
用 JiuwenSwarm 搭建论文写作 Agent 团队:文献检索、大纲生成、语法润色与引用格式避坑
人工智能·论文写作·智能体·jiuwenswarm·agent 团队
云边云科技_云网融合3 小时前
企业出海的 “数字丝绸之路“:SD-WAN 如何重构全球网络竞争力
大数据·运维·网络·人工智能