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

其中:

Biasij=−∣i−j∣ \text{Bias}ij = -|i - j| Biasij=−∣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辅助下完成。

相关推荐
信马堂2 小时前
WorkBuddy 接入第三方模型 API 全流程:安装与配置实录
人工智能·大模型·token·ai算力·workbuddy
朝朝辞暮i3 小时前
VLA 系统学习第 4 课:一个 Batch 进入神经网络后,模型到底是怎么“学会”的?
人工智能·python·神经网络·vla
IT古董3 小时前
《FDE前沿部署工程师实战教程》33 - Enterprise AI Observability:从Agent Trace到全链路智能运维
数据库·人工智能
xsd202411183 小时前
地网腐蚀AI识别算法全解析:从锈蚀图像到地下腐蚀快速定位
人工智能
oooost3 小时前
pytorch学习笔记2(transformer)
人工智能·机器学习
云杂项4 小时前
Exploring Model Inversion Attacks in the Black-box Setting(个人笔记)
人工智能
还卿一钵无情泪4 小时前
Unsloth 微调 构建自己的大模型 没有GPU也能微调
linux·开发语言·人工智能·python·大模型·nlp·unsloth
冬奇Lab5 小时前
LLM 驱动的自动化测试系列(06):移动端自动化(二)——DroidRun/Mobilerun 的角色级模型拆分
人工智能·测试
冬奇Lab5 小时前
一天一个开源项目(第230篇):HandRaw-Style —— 把 327 种手绘风格、165 种排版、36 种配色编号化,让 AI 画图不再每次都飘
人工智能·开源·资讯
罗西的思考5 小时前
从陶哲轩的访谈看:AI 数学研究方法论 & 给其它行业的启示
人工智能