上一篇我们介绍了 T5 的主干逻辑,实际上,T5 的核心理念可以概括为"统一、简化 " 。
那么问题来了:
一个追求统一和简洁的框架,会选择什么样的位置编码?
最终,T5 没有走 Transformer-XL 的四项重构路线,也没有沿用原始的加法型 RPE,而是提出了一种极简的方案:偏置型 RPE 。
它第一次把相对编码做成了一个极其稳定、极其工程友好的标准模块,可以说达到了范式层级的设计,从而广泛传播和应用。
1. 偏置型 RPE:一个标量就够了
T5 的 RPE 做法可以说简单到令人怀疑:
\[Attention = softmax\left(\frac{QK^T}{\sqrt d} + B\right)V \]
这里多出来的 \(B\) 是一个 偏置矩阵 ,\(B_{ij}\) 表示位置 \(i\) 和 \(j\) 之间的标量偏置 。
再展开注意力分数部分就是:
\[\text{score}{ij} = \frac{Q_i \cdot K_j}{\sqrt d} + b{i-j} \]
这里的 \(b_{i-j}\) 是一个可学习的标量,它只依赖于相对距离 \(i - j\)。
公式本身非常简单,但这极简的设计下却有很多细节,我们分点展开一下:
1.1 为什么一个标量就够?
一个首当其冲的问题是:
一个标量偏置,真的能提供多少位置信息?
这里需要理解的是,注意力机制的最终产物是权重分布,而权重分布本身就是一些标量值。所以从根本上说:
我们最终需要的,就是在每个 Query-Key 对上打个"位置标签",告诉模型这个距离应该怎么影响注意力权重。
而 T5 的想法是:
我不再去重构你的过程,只要让不同的位置对最终的权重有不同的影响就够了。
就像这样:
| 相对距离 | Token 对 | 语义分数 | 偏置 | 最终分数 |
|---|---|---|---|---|
| 近 | ("我", "爱") | 0.5 | +0.3 | 0.8 |
| 远 | ("我", "它") | 0.5 | -0.2 | 0.3 |
为一种相对位置提供一个可学习的标量,它同样可以在反向传播中学到相应的语义,影响最终的权重分布。
同时,这种偏置型 RPE 继承了 Transformer-XL 删去 V 的 RPE 的逻辑,其想法也是一样的:位置只需要指导"关注谁",不需要修改"传递什么"。
1.2 如何改善可学习编码的外推能力?
再回到最开始说的: \(b_{i-j}\) 是可学习的标量。
展开这部分,我们需要简单回顾一下之前的两组 RPE 的逻辑:
首先,Shaw 的加法型 RPE 是可学习向量 ,它要分别去适配 Q 和 V 的维度,同时又要保证可更新,因此,我们最终为其额外建立了两张 PRE 向量表。
然后,Transformer-XL 为实现跨窗口的能力,将可学习编码改为正余弦固定编码来获得外推能力,同时提出了注意力的四项重构式来增加交互。
通过二者的逻辑,我们可以总结出一对互斥选择:
希望更加自适应,就要让编码可学习,但代价是建表空间、计算量以及外推能力;而希望获得更好的外推能力,就要使用相对来说更死板的固定编码。
而 T5 选择了可学习的标量,其实本身就是在说:
它不相信"固定公式"能适应所有任务,所以把相对位置偏置改成了可学习参数。
这种设置拥有自适应能力,而且对每个注意力头只需要维护一行向量 即可。
但只要是可学习编码,就逃不开外推能力的限制:
每个不同的相对距离都学一个独立的标量,训练时最大长度之外的相对距离完全没见过,增加最大长度的计算成本又高,如何取舍?
T5 的解决方案是分桶策略。
2. 分桶策略(Bucketing)
2.1 分桶思想
可以用我们的生活例子来理解分桶思想:
我们对面有两个人,一个人在面前 1 米处,另一个人在 2 米处,我们能清晰感觉出"1米近、2米远"的区别。
但如果一位在 100 米外,一位在 101 米外,我们根本不会在意它们之间的距离差异。
而注意力也有类似的规律:
一个 token 对邻近 token 的"相对距离"极其敏感,但对远处的 token,大概方向上的"远近"就够了。
T5 根据这个规律,把相对距离分成了两个区间:
| 区间 | 描述 | 分桶方式 |
|---|---|---|
| 近距离 | 需要精确区分 | 每个距离独享一桶 |
| 远距离 | 只需要模糊感知 | 对数压缩,多距离共享一桶 |
这就是分桶策略的核心思想:近精细,远模糊。
2.2 具体的分桶计算
在实际中,分桶逻辑如下:
首先,先计算绝对相对距离(在实际应用中,这其实是解码器的逻辑,在下面就会展开说):
\[r = |i - j| \]
第二步,我们要判断距离落在哪个区间:
- 如果 \(r < N\) :即近距离区间,直接使用第 \(r\) 个桶。
- 如果 \(r \geq N\):进入对数压缩区间,映射为:
\[\text{bucket} = N + \left\lfloor \frac{\log(r / N)}{\log(D_{max} / N)} \times (num_{buckets} - N - 1) \right\rfloor \]
其中 \(N\) 是精确分桶的边界(默认一般取 8),\(D_{max}\) 是最大距离阈值(默认 128),它控制着分桶的粒度。
我们用一个详细的例子来理解,假设 \(N = 8\),桶数 \(num_{buckets} = 16\),\(D_{max}=128\) ,来看看不同距离对应的桶:
| 桶编号 | 对应距离范围 \(r\) | 所属阶段 | 典型计算 |
|---|---|---|---|
| 0 | 0 | 精确区间 | \(r<8\),直接映射到桶 0 |
| 1 | 1 | 精确区间 | \(r<8\),直接映射到桶 1 |
| 2 | 2 | 精确区间 | \(r<8\),直接映射到桶 2 |
| 3 | 3 | 精确区间 | \(r<8\),直接映射到桶 3 |
| 4 | 4 | 精确区间 | \(r<8\),直接映射到桶 4 |
| 5 | 5 | 精确区间 | \(r<8\),直接映射到桶 5 |
| 6 | 6 | 精确区间 | \(r<8\),直接映射到桶 6 |
| 7 | 7 | 精确区间 | \(r<8\),直接映射到桶 7 |
| 8 | \(8 \sim 9\) | 对数区间 | \(8+\left\lfloor \frac{\log(r/8)}{\log16}\times7 \right\rfloor=8\) |
| 9 | \(10 \sim 15\) | 对数区间 | \(8+\left\lfloor \frac{\log(r/8)}{\log16}\times7 \right\rfloor=9\) |
| 10 | \(16 \sim 22\) | 对数区间 | 对数压缩后落入桶 10 |
| 11 | \(23 \sim 31\) | 对数区间 | 对数压缩后落入桶 11 |
| 12 | \(32 \sim 45\) | 对数区间 | 对数压缩后落入桶 12 |
| 13 | \(46 \sim 63\) | 对数区间 | 对数压缩后落入桶 13 |
| 14 | \(64 \sim 90\) | 对数区间 | 对数压缩后落入桶 14 |
| 15 | \(\ge 91\) | 最大桶/截断区间 | 超过后统一映射到最后桶 |
其实说到底,这还是一个粒度问题,对数空间的特性让极远的距离被自然压缩,模型只需要学习"极远的都差不多"就足够了。原本我们为每种相对距离都单独维护对应编码,代价就是参数量大,增加表长的代价高。
而现在,我们用分桶算法把距离划分为了几个不同大小的区间,极大降低了可学习编码的外推成本,实现了能力和成本的均衡,而且更加符合实际认知。
3. 双向注意力与单向注意力下的分桶差异
T5 的偏置型 RPE 还有一个非常关键的细节: 分桶逻辑会随着注意力掩码的方向性发生变化。
这是因为:编码器是双向注意力,解码器是单向因果注意力。两者对"相对位置方向"的需求并不相同。
我们具体展开来说:
3.1 编码器中的双向分桶
在编码器(Encoder)中,注意力是双向的,任意两个 token 都能互相看到。因此,相对位置既可能为正,也可能为负:
\[i-j \in (-\infty,+\infty) \]
例如:
- \(i-j=+3\):表示目标 token 位于当前位置左侧。
- \(i-j=-3\):表示目标 token 位于当前位置右侧。
因此,T5 在编码器中会:
先区分方向,再分别进行分桶。
就像这样,假设 \(num_{buckets}=32\) ,那么桶通常会被均分为:
| 方向 | bucket 范围 |
|---|---|
| 负方向(右侧) | 0~15 |
| 正方向(左侧) | 16~31 |
随后,每个方向内部再独立使用上面的近距离精确分桶。远距离对数压缩,大概就像这样:
| 相对距离 \(i-j\) | 方向 | 对应 bucket | 说明 |
|---|---|---|---|
| \(-3\) | 右侧方向 | 3 | 右侧近距离精确分桶 |
| \(-1\) | 右侧方向 | 1 | 右侧最近 token |
| \(-8\) | 右侧方向 | 8 | 进入右侧对数压缩区 |
| \(-32\) | 右侧方向 | 11 | 右侧远距离共享桶 |
| \(-128\) | 右侧方向 | 15 | 右侧最大距离桶 |
| \(+1\) | 左侧方向 | 17 | 左侧最近 token |
| \(+3\) | 左侧方向 | 19 | 左侧近距离精确分桶 |
| \(+8\) | 左侧方向 | 24 | 左侧进入对数压缩区 |
| \(+32\) | 左侧方向 | 27 | 左侧远距离共享桶 |
| \(+128\) | 左侧方向 | 31 | 左侧最大距离桶 |
也就是说: T5 并不会把"左边 3 个 token"和"右边 3 个 token"视为同一种关系。
因为在自然语言中,左边通常是历史上下文,右边通常是后续补充信息,两者语义作用并不对称,这是一种很合理的设计。
3.2 解码器中的单向分桶
而在解码器(Decoder)中,由于因果掩码的存在:当前 token 只能看到自己之前的 token。
因此一定满足:
\[j \le i \]
即:
\[i-j \ge 0 \]
这意味着解码器中根本不存在负方向的位置关系。
所以,T5 在 Decoder 中不会再为负方向预留 bucket,而是:
将全部 bucket 都用于表示"过去方向"的距离。
例如同样:\(num_{buckets}=32\),现在的使用就像我们第二部分的例子一样了:
| 模式 | bucket 使用方式 |
|---|---|
| Encoder | 正负方向各占 16 个 |
| Decoder | 全部 32 个都用于过去方向 |
这样做的结果是:Decoder 的距离分辨率会明显更高。
这一点非常符合自回归生成的需求。
在文本生成中,最近几个 token 通常对下一 token 的预测影响最大。因此,Decoder 比 Encoder 更需要精细的近距离位置建模。
这也是 T5 会针对单向注意力专门调整 bucket 分配逻辑。
这便是 T5 的偏置型 RPE 的完整逻辑。
4.总结
总结来看,T5 的偏置型 RPE 本质上是在"归本溯源":
不再复杂地重构 Attention,而是直接用一个可学习偏置去影响最终注意力分数。
相比之前的几种方案,T5 直接退回到了最核心的问题:
位置真正影响的,其实只是"应该关注谁"。
因此,它只使用一个标量偏置就完成了相对位置信息的注入。
但真正让 T5 工程化的,其实是后面的两件事:
- 分桶策略:解决可学习位置编码难以外推的问题。
- 方向感知的双向/单向分桶:不只是关注"距离多远",还关注"方向在哪里"。
整体来看,T5 的 RPE 可以说是:用极低的复杂度,实现了极高的工程实用性。
到这里,NLP 的位置编码问题就可以短暂小结,我们之后就会再回到 CV 中,看看 RPE 在二维数据中又要如何应用。