大模型位置编码最全拆解:绝对位置、相对位置、旋转位置,以及不用位置编码
摘要:Transformer 的 Self-Attention 本身不感知 Token 顺序——把"猫吃鱼"和"鱼吃猫"的 Token 打乱,Attention 输出完全一样。本文系统梳理 Positional Embedding 的完整技术演化:从 Sinusoidal 绝对位置编码的指针类比,到 ALiBi、T5 的相对位置偏置,再到 RoPE 旋转位置编码的数学原理,最后探讨 Train Short Test Long 的一系列扩展方法以及"不用位置编码"的 NoPE/DroPE 思路。
用过 Transformer 的人都学过 Positional Embedding,但你真的理解它解决了什么问题、不同方案之间有什么本质区别吗?本文从最底层的问题出发,一步步拆解位置编码的完整技术树。
Copyright Ownership: Kstheme, Contributors: Kstheme
01 一个基础问题:Transformer 怎么知道 Token 的顺序?
原来的 Transformer 是没有办法考虑输入的顺序的。Transformer 是怎么处理输入 Token 的呢?
输入的 Token 会变成 Embedding,然后这些 Embedding 会变成某一个 Layer 的输入。每个 Layer 里面都会有 Self-Attention,Self-Attention 会输出另外一排 Token。
但是有一个问题:Self-Attention 本身没有考虑 Token 输入的顺序。

假设我把 Token A 跟 Token C 的位置对调,再去算 Self-Attention,你会发现对于 OD 的输出是没有任何影响的。

所以我们必须想办法把位置信息"塞进"Transformer 里,这就是 Positional Embedding 要解决的问题。
本文覆盖的内容如下:
- Absolute Positional Embedding(以 Sinusoidal 为代表)
- Relative Positional Embedding(ALiBi、T5)
- RoPE(Rotary Position Embedding)
- Train Short, Test Long(位置插值、频域方法、YaRN、Dynamic Scaling、LongRoPE)
- No Positional Embedding(NoPE、DroPE)
02 Absolute Positional Embedding
最早的 Positional Embedding 想法很直接:对每一个位置设置一个特别的 Embedding。这个 Embedding 就代表了位置的信息。
我们用 P0 到 P3 代表每一个位置的特别 Embedding,然后把这个特别的 Embedding 加到我们的向量上面去。

这样的话,当 Token 调换顺序之后,它整个的 Embedding 就不一样了,最后算出来的 Self-Attention 的输出也就不一样。

Sinusoidal Positional Embedding
参考文献:https://arxiv.org/abs/1706.03762
这个 Positional Embedding 是在 Transformer 诞生之初就存在的 Embedding。
我们用 d 来代表 Embedding 的长度(d=128 or 256)。

我们可以用 p[i] 来代表它里面的数值。

那 Sinusoidal Position Embedding 是怎么构建所有的 Embedding 的?构建公式如下:
pk[2i]pk[2i+1]=sin(100002i/dk)=cos(100002i/dk)
图像化理解
我们把 p0[0] 到 p49[0] 都拿出来,会发现这个图像是一个 Sin 函数。

接下来我们来看 p0[1] 到 p49[1],这个图像是一个 Cos 函数。

接下来我们来看 p0[10] 到 p49[10],它也是一个 Sin 函数,只不过它的周期比 p0[0] 到 p49[0] 要大。

那如果把全部的 Position Embedding 画出来的话,就会像下图这样:

指针类比:秒针、分针、时针
我们现在用另外的方法来看 Sinusoidal Positional Embedding:它的偶数维度用 Sin 函数表示,奇数维度用 Cos 函数表示。所以我们可以把 2i 和 2i+1 的 Dimension 想象成一个二维的向量(二维平面上的一根指针)。这根指针会随着 k 的数值来进行旋转——当 k 上升时,指针开始往逆时针方向旋转。

旋转的周期如下:
100002i/dk=2π
那么指针走一圈大概需要多少 k 呢?我们只需要把分母下面的数字移到右边,就可以知道 k 等于多少:
k=2π⋅100002i/d
假设 d=128,那么 i=0,...,2d−1=0,...,63。
下面我们看一下 i 的数值不同,它的周期会有怎样的变化:
| i 取值 | k 值 |
|---|---|
| i=0(第 0, 1 维) | 6.3 |
| i=32(第 64, 65 维) | 628.3 |
| i=63(第 126, 127 维) | 54410.1 |
Self-Attention 看到的跟时间有关的信息是这样变化的:这一排向量的最前面两位走的是最快的,大概 6.3 个 Token 就会转一圈。中间 10 到 11 维就转得比较慢。中间 100 到 101 位,如果我们只看前 6 个 Token,那它几乎是没有变化的。
每两个 Dimension 合在一起就是一个指针。转得最快的是秒针,转得稍微慢点的是分针,转得最慢的是时针。接下来会有多少个指针呢?那就看你的 Dimension 有多少。比如我的 Dimension 是 128,那我就有 64 个指针。Transformer 就根据这 64 个指针、每一个指针的位置,来判断每个 Token 具体在哪个位置。

用指针表示位置听起来还是比较合理的,但是应该还有很多其他的方式来表示位置。那为什么当初会用秒针、时针、分针的概念来表示位置呢?这是因为 Transformer 的作者希望 Positional Embedding 可以考虑 Relative Position(相对位置)。
Relative Positioning is Crucial!
Relative Position 就是说,假设有一句话:"猫吃了鱼",猫跟鱼之间间隔了两个 Token。Transformer 在考虑鱼后面要接哪个 Token 的时候,它会往前面考虑猫。鱼对猫的注意力分数是 0.7。

假设我在猫前面塞了大量的 Token,可能猫前面有 1000 个 Token,但是猫跟鱼之间的相对位置没有变,所以我们希望鱼对猫的注意力也不会有所谓改变。哪怕鱼是在 1004 的位置,猫在 1001 的位置,但鱼对猫的注意力分数还是 0.7。

但如果今天鱼跟猫的位置距离非常远,猫在第 1 个 Token,而鱼在第 1004 个 Token,因为距离非常远,所以我们希望鱼对猫的注意力分数要变得比较小。

当时选择了 Sinusoidal Positional Embedding,就是因为它有一些特殊的性质,而这些特殊的性质好像对 Relative Position 有帮助。
pk+r=Mrpk
其中,pk 代表第 k 个位置的 Position,pk+r 代表 k+r 位置的 Position。
而这个公式是跟 k 没有关系的,只跟 k+r 和 k 之间的相对位置有关系。具体如下:
p4p14p104=M3p1=M3p11=M3p101
我们可以具体来看一下 Sinusoidal Positional Embedding 是怎样满足 Relative Position 的条件的。
首先位置 k 的公式为:
pk[2i]pk[2i+1]=sin(100002i/dk)=cos(100002i/dk)
位置 k+r 的公式为:
pk+r[2i]pk+r[2i+1]=sin(100002i/dk+r)=cos(100002i/dk+r)
我们接下来会用到 Sin、Cos 的和角公式:
sin(a+b)cos(a+b)=sin(a)cos(b)+cos(a)sin(b)=cos(a)cos(b)−sin(a)sin(b)
我们可以根据这个和角公式来展开 pk+r 的两项:
pk+r[2i]=sin(100002i/dk+r)=sin(100002i/dk)cos(100002i/dr)+cos(100002i/dk)sin(100002i/dr)
pk+r[2i+1]=cos(100002i/dk+r)=cos(100002i/dk)cos(100002i/dr)−sin(100002i/dk)sin(100002i/dr)
我们把 pk[2i] 和 pk[2i+1] 代入进去得:
pk+r[2i]=sin(100002i/dk+r)=pk[2i]cos(100002i/dr)+pk[2i+1]sin(100002i/dr)
pk+r[2i+1]=cos(100002i/dk+r)=pk[2i+1]cos(100002i/dr)−pk[2i]sin(100002i/dr)
我们现在把 pk+r[2i] 和 pk+r[2i+1] 写成一个矩阵形式:
[pk+r[2i]pk+r[2i+1]]=[cos(100002i/dr)−sin(100002i/dr)sin(100002i/dr)cos(100002i/dr)][pk[2i]pk[2i+1]]
中间这个旋转矩阵,我们用 Mr,i 来进行表示。

那么 Sinusoidal Position Embedding 这种设计对后面去计算 Self Attention 的时候会有什么影响呢?
假设我们把 A 跟 B 的位置用 pn 和 pm 来表示,Attention 分数 a 的计算公式如下:

a=qB⋅kA=(qB)TkA=(Wq(xB+pm))TWk(xA+pn)=(xB+pm)TWqTWk(xA+pn)=xBWqTWkxA+xBTWqTWkpn+pmTWqTWkxA+pmTWqTWkpn
其中,xBWqTWkxA 只跟内容有关,xBTWqTWkpn+pmTWqTWkxA 跟内容、位置的交互影响有关,pmTWqTWkpn 只跟位置有关。
但是 pmTWqTWkpn 显示的是绝对位置,所以我们要把它变成跟相对位置有关的公式:
pmTWqTWkpn=(Mm−npn)TWqTWkpn=(pn)TMm−nWqTWkpn
其中 (pn)TMm−nWqTWkpn 里面的 Mm−n 只跟相对位置有关,但是整体的公式还是会存在绝对位置之间的关联。
03 Relative Positional Embedding
既然用 Absolute Positional Embedding 来做相对位置这么迂回,一个自然的想法是:能不能根据相对位置直接去改 Attention 计算?
ALiBi(Attention with Linear Biases)
参考文献:https://arxiv.org/abs/2108.12409
ALiBi 的做法是:丢掉 Positional Embedding。在没有 Positional Embedding 的情况下先把 Attention 分数算出来,然后减掉 b(m−n)。这个公式就是说减掉 m 和 n 两个位置之间的相对距离。减掉相对距离就会达成一个效果——距离越远 Attention 越小。而常数 b 是你手动设置的数值,你可以给不同的 Attention Head 设置不同的数值。在这篇论文里,并没有设置很复杂的方法来设置 b,就凭直觉来设置。

这个方法听起来很简单,那我们看一下它的效果怎么样。横轴是 Sequence 的长度,纵轴是 Perplexity,困惑度越小证明效果越好。下面的图片表明,在更长的 Sequence 上,ALiBi 的效果会表现得更好,而且 ALiBi 全面碾压 Sinusoidal 方法。

T5 的可学习 Relative Bias
参考文献:https://arxiv.org/abs/1910.10683
讲到这边你可能会想说,这个 b 都是人为设置的,如果直接用 Learn 的方法 会不会更好呢?其实早在 ALiBi 之前,就一定有人想过用 Learn 的方法来确定 b。
对于 Learn 的方法有很多不同的版本,我们这边重点讨论 T5 的方法。它的大概做法就是 A 减掉一个 Bias bm−n,这个 Bias 是跟相对距离 m,n 有关系的,它是一个可以被训练的参数。比如说位置 0~5 是一个数值,5~10 是一个数值,20 之后可能又统一成为其他的数值。
那这个效果怎么样呢?这个效果是要比 ALiBi 还要差的,所以 ALiBi 人手设置的数值,要比当时训练的数值结果还要好。

后来,ALiBi 也消失在了历史的洪流之中,逐渐被更强的 Positional Embedding 方法所取代。但是它给我们的启示就是:Relative Position 真的很重要。
RoPE:Rotary Position Embedding
参考文献:https://arxiv.org/abs/2104.09864
RoPE 是现在最流行的方法之一。它是怎么做的?我们先讲结论:
今天在做 Attention 的 Dot Product 之前,先把 Position 加到 k 上面,但是它加 Position 的方法并不是直接加入一个 Embedding,而是通过旋转 k 和 q 这两个向量的方法来加入 Positional 的信息。我们会得到包含信息位置的 kAn 和 qBm。

然后再用含信息位置的 q 和 k 来算 Attention Weight:
a=(kAn)TqBm=(kA)TRm−nqB
其中,Rm−n 只跟 A、B 之间的相对位置有关,这样的话我们就可以把相对位置矩阵很直接地塞入到 A 跟 B 之间。
这个方法很重要的一点是:它不会影响 Attention 计算的过程。像 ALiBi 的话,它会在做 Attention 过程当中多做一个操作。但是 RoPE 基本上完全没有影响到原来 Attention 的操作,只是 q 跟 k 变得跟原来有些不同而已,而且可以把变换的 K 放到 KV Cache 里面。
那我们现在来看看在 RoPE 这个方法里面是怎么去加 Position 的。
Rotation as Position
我们现在只考虑 k 跟 q 这两个向量的前两位。

把前两位拿出来,它就是一个二维平面上的向量。

当我们把位置信息加进去的时候,其实就是对这个向量做了一个旋转。如果你今天要把位置 n 的信息加进去,那就把原来的 k 前两位旋转 nθ 这个角度,然后就会得到 kAn[0] 和 kAn[1]。


同理,q 也做同样的运算。当我们把位置加进去之后,就相当于旋转 mθ 个角度。

所以对 RoPE 来说,它就是把旋转的角度当做 Position 的信息。
在刚才举例的时候,举例的是前两位,因为只有前两位才可以放到二维平面里面。但是 RoPE 是每两个维度来进行考虑的。

第三、第四个维度,我们就会用另外的角度来进行旋转。我们会把 kA[2] 和 kA[3] 旋转 nθ′ 的角度,得到 kAn[2] 和 kAn[3],q 也同理。
旋转角度怎么设定?
因为每两个维度都会旋转不同的角度 nθi,nθi 的公式如下:
θi=100002i/d1
其中,i=0,1,...,2d−1。

RoPE 的核心性质:相对位置不变性
我们看看 RoPE 可以达到什么样的效果。假如说有一个 k 在 n 的位置,有一个 q 在 m 的位置,我们对它做 Attention。如果我们现在把 k 移到 n+r 的位置,把 q 移到 m+r 的位置,它们之间的相对位置不变,那么 Attention 的数值也是不会改变的。
kAn⋅qBm=kAn+r⋅qBm+r
假设猫的 Position 是 1,鱼的 Position 是 3,我们会把猫的 k 加上 Position 1 的信息,把鱼的 k 加上 Position 3 的信息。鱼这个 Token 得到它的 Query,再把位置加上去得到 qB3,然后通过和猫的 k 进行计算,得到了 Attention a。

现在在猫跟鱼前面加了大量其他的 Token,也不会影响猫跟鱼这两个 Token 算出来的 Embedding。假设猫的 Token 在 101,鱼的 Token 位置在 103,它们两个之间算出来的 Attention 数值,跟猫的 Token 在位置 1、鱼的 Token 在位置 3 算出来的 Attention 数值是一样的。

下面再进一步说明为什么 RoPE 可以达到这个效果。下图中,原来的 k 跟加上位置 n 之后的 k 的对比:

假设 k 又被放到 n+r 的位置,那就相当于把它旋转 (n+r)θ,获得了一个新的位置。

那么 [kAn[0]kAn[1]] 和 [kAn+r[0]kAn+r[1]] 之间的夹角是 rθ,对 qB 来说也是一样的。

所以 [kAn[0]kAn[1]] 和 [qBm[0]qBm[1]] 的内积,与 [kAn+r[0]kAn+r[1]] 和 [qBm+r[0]qBm+r[1]] 是一样的,因为只是把向量做了等量同样角度的旋转,所以不会改变它的内积。
RoPE 的数学推导
接下来我们来探讨一下使用 RoPE 为什么只跟 k 和 q 的相对位置有关。
我们还是只拿前两个维度来举例。不带位置的 k 是如何加上位置的?假设旋转了 nθ 角度,公式如下:
[kAn[0]kAn[1]]=[cos(nθ)sin(nθ)−sin(nθ)cos(nθ)][kA[0]kA[1]]

同理,q 要旋转 mθ 公式如下:
[qBm[0]qBm[1]]=[cos(mθ)sin(mθ)−sin(mθ)cos(mθ)][qB[0]qB[1]]

接下来我们要让 k 跟 q 做 Dot Product:
[kAn[0]kAn[1]]⋅[qBm[0]qBm[1]]=[kAn[0]kAn[1]]T[qBm[0]qBm[1]]=([cos(nθ)sin(nθ)−sin(nθ)cos(nθ)][kA[0]kA[1]])T[cos(mθ)sin(mθ)−sin(mθ)cos(mθ)][qB[0]qB[1]]=[kA[0]kA[1]]T[cos(nθ)sin(nθ)−sin(nθ)cos(nθ)]T[cos(mθ)sin(mθ)−sin(mθ)cos(mθ)][qB[0]qB[1]]=[kA[0]kA[1]]T[cos((m−n)θ)sin((m−n)θ)−sin((m−n)θ)cos((m−n)θ)][qB[0]qB[1]]
其中,[cos(nθ)sin(nθ)−sin(nθ)cos(nθ)]T 代表旋转 −nθ,[cos(mθ)sin(mθ)−sin(mθ)cos(mθ)] 代表旋转 mθ,合起来就是 [cos((m−n)θ)sin((m−n)θ)−sin((m−n)θ)cos((m−n)θ)] 代表旋转 (m−n)θ。
如果是把 kAn 换成 kAn+r,把 qBm 换成 qBm+r,会有什么不同?
[kAn+r[0]kAn+r[1]]⋅[qBm+r[0]qBm+r[1]]=[kA[0]kA[1]]T[cos(((m+r)−(n+r))θ)sin(((m+r)−(n+r))θ)−sin(((m+r)−(n+r))θ)cos(((m+r)−(n+r))θ)][qB[0]qB[1]]
其中,[cos(((m+r)−(n+r))θ)sin(((m+r)−(n+r))θ)−sin(((m+r)−(n+r))θ)cos(((m+r)−(n+r))θ)] 代表旋转 ((m+r)−(n+r))θ=(m−n)θ。
所以结果与没有加 r 时完全相同,验证了相对位置不变性。
RoPE 的实现细节
刚才说 RoPE 采取的方法是,把 k 跟 q 分别做旋转,再去做 Attention。

其实这也等价于把 q 乘上 Rm−n,也就是说 q 自己做旋转,然后再去跟 k 做相乘,相当于只在 q 上做计算。

虽然这两个方法计算起来是等价的,实际上会去采用前一种方式。因为在我们存 KV Cache 的时候,如果用前一种方式,可以把带位置的 k 跟 q 都存下来。但如果我们用后一种方式,那 q 每次和 k 去做 Attention 的时候都需要乘上不同的 Rm−n,效率很低。所以 RoPE 能流行起来的主要原因,就是它可以很好地跟别的方法做搭配。
RoPE vs ALiBi:一个重要的区别
很多人对 RoPE 有一个误解——它可能像 ALiBi 一样,当 k 跟 q 的距离越远,算出来的 Attention Weight 就越小。但事实是:RoPE 并没有保证 q 跟 k 距离越远的话,它们的 Attention Weight 就越小。
但是 RoPE 没有"越远越小"不一定是一件坏事,它可以做到原来 ALiBi 做不到的事情。假设我们现在有一个 Token,它想跳过前一个 Token 直接注意到前面的位置。对于 ALiBi 来说,如果这个 Token 离原来的 Token 越远,注意力就越小。但对于 RoPE 来说,它可以完成一件事:直接忽略中间的 Token,直接注意到前面的 Token。

有的时候,这个方式对于模型理解句子是很有帮助的。比如说"我的猫"和"他的狗"这两个句子——"猫"应该注意到"我"上面,"狗"应该注意到"他"上面,而不是注意到中间的"的"上面。所以 RoPE 可以做到比 ALiBi 更细致的 Attention。
假设 q 跟 k 中间差了 2θ,但是 n+1 位置的 q 跟 n 位置的 k 可能就差了一个 θ,n+2 位置的 q 跟 n 位置的 k 它们的角度可能就是一样的。那么这就恰恰证明了,中间隔了一个 Token,但是注意力分数却可以往上涨,它就可以忽略掉中间的 Token。

04 Train Short, Test Long
参考文献:https://amaarora.github.io/posts/2025-09-21-rope-context-extension.html
我们能不能在训练的时候,虽然 Transformer 在训练阶段只能看见比较短的 Sequence,但是让它在测试的时候看到非常长的 Sequence 也不要坏掉?

因为我们在训练的过程中,可能没办法找到非常长的语料来进行训练。而且在今天的 Agent 当中,我们希望 Agent 可以永无止境地运行下去,所以说它需要吃非常长的 Sequence,要有非常大的 Context Window。所以我们期待有什么样的 Positional Embedding 可以做到 Train Short Test Long。
怎么做 Train Short Test Long?一个很直觉的想法就是,我们训练的时候最多只见过 N 个 Token,我的位置也是 1,2,...,N。


假设测试的时候模型需要处理 LN 个 Token,我们能不能就直接给它我们需要的编号?

RoPE 可以处理这样的状况吗?看样子是不行的。
(下图来自文献:https://arxiv.org/abs/2108.12409)

下图就是测试的时候给模型不同长度的 Sequence,然后看它的 Perplexity 效果如何。假如测试的时候给他们非常长的 Input Sequence:
- 对于 Sinusoidal 来说,只要测试 Sequence 一长,它就直接坏掉。
- 对于 RoPE 来说,它会比 Sinusoidal 稍微好一点点,但是随着 Sequence 越长它也会坏掉。
- 事实上,只有 ALiBi 是能够支撑得住的,因为它不是通过学习得到的参数,而是通过人为设置得到的。看起来这种人为设置是非常 Robust 的,它可以处理比较长的 Sequence。
但是 ALiBi 比较简单,所以后人想的是,能不能通过调整 RoPE,让它能够做到 Train Short Test Long。
为什么 RoPE 在长序列上会失败?
假设我们在训练的时候,旋转最大的角度就是 Nθ,超过这个角度的向量它都没有见过。假如说你在测试的时候给它的角度是 2Nθ。对 RoPE 来说,它从来没有看到过一个向量被转到过这个地步,它就会"发疯",完全不知道要怎么做。

Position Interpolation
参考文献:
那么要怎么办呢?那就是不要给它超过 N 的旋转角度。
比如现在有 LN 个 Token,我们的编号不一定要从 1 到 LN,我们可以让它从 L1 到 N——从来没有规定过 Position 的编号一定要是整数。


这个方法叫做 Position Interpolation(位置插值)。但是使用这个方法之前,模型还是要针对这种非整数的旋转角度进行微调,否则效果还是很差。
不过 Position Interpolation 不一定能够带给我们很好的表现,所以又有各种新方法。
Frequency-Based Approach
有一个新的方法叫做 Frequency-Based Approach。
刚才我们在做 RoPE 的时候,是两个维度两个维度考虑的,而 Position Interpolation 的方法是对不同的维度做同样的处理。Frequency-Based Approach 的想法是:能不能在不同的维度做不同的处理?
比方说,我们在测试的时候要把 N 扩展到 LN,我们能不能乘上一个特别的函数?这个函数一方面跟我们要拓展多少位有关,同时也会跟现在在哪一个维度有关。

那么 Frequency-Based Approach 是怎么设计的呢?它的原则是:θ0 是比较高频的向量,i 的编号越大就代表越低频。对于高频向量,可以不动,不用改它的 Position;对于低频向量,则需要进行压缩。

对于 RoPE 而言,它每两个 Dimension 合起来也是一个指针。这个指针也是在二维的平面上来旋转。对于前两个维度而言,它的指针旋转速度是非常快的。假设 N=128,那么对于 θ0 来说,它可能已经把整个平面上的维度全部看了一遍甚至几遍;而对于 θ32 来说,它可能看了连 1/4 都没有。

所以对于 θ0 来说,你就算给它大于 N 的 Position 也是没有关系的,因为它已经全部看过了。但如果在 θ32 这个维度上面,你如果把 N 提高到 256 的话,那 256 旋转的那个角度它是没有看过的。

NTK-aware Scaling
Frequency-Based Approach 有很多不同的变体,其中比较知名的变体叫 NTK-aware Scaling。
NTK-aware Scaling 的公式如下:
f(L,i)=(L1)d−22i
这个公式的设计是有意义的:
- 假设 i=0,那么 f(L,0)=1,在最高频的 θ0 上面是不需要做任何压缩的。
- 假设 i=2d−1,处在最低频的状态,那么 f(L,2d−1)=L1,它会把最低频的 θ2d−1 压缩到 L1。
不过 NTK-aware Scaling 的方法并没有一篇对应的 Paper,它是出现在 Reddit 的文章里面。

YaRN
另外一种知名的变体叫做 YaRN(Yet another RoPE extensionN method)。
参考文献:https://arxiv.org/abs/2309.00071
YaRN 的思想是:保留一些低频维度的 Scaling 不变,保留一些高频维度的 Scaling 不变,只变中间的。

Dynamic Scaling
还有一种另外的想法叫做 Dynamic Scaling。它的核心思想是:之前的方法可能长的序列都能做,但是对于短的 Sequence 来说,可能它的效果会变得更差。
参考文献:https://www.reddit.com/r/LocalLLaMA/comments/14mrgpr/dynamically_scaled_rope_further_increases/

所以 Dynamic Scaling 的想法就是,对于不同长度的 Sequence 用不同的处理方式。比如我们要输入 5 个 Token,那我们的 Token 数量就要乘 54。但如果 Sequence 小于 Training 的 Sequence,那我们就不需要做任何改动,这样的话你在短序列上的效果也不会差,因为在 Training 的时候见过这些小的 Sequence。

这个想法很简单,但是你会发现它会破坏 KV Cache。
还有一种 Dynamic Scaling 的变体方法:在一定比例的 Sequence 上不做任何 Position 改动,过一定比例后再做 Position 改动,没有必要压缩最前面的 Position。

那 Dynamic Scaling 的方法好不好呢?如果我们使用 Dynamic Scaling 加上 Position Interpolation 或者加上 NTK 方法,它的效果会比不加 Dynamic Scaling 更好。

Frequency-Based + Dynamic:LongRoPE
Frequency-Based 方法是决定后面的压缩函数,Dynamic Scaling 来决定在哪个地方开始压缩。具体要怎么决定呢?有一篇论文叫做 LongRoPE,用了一个 Evolutionary Search 的方法,去找出最好的 Frequency-Based 方法和最好的 Dynamic Scaling 方法。
参考文献:https://arxiv.org/abs/2402.13753

这个方法可以得到一个非常惊人的结果——它可以让模型的输入长度处理到 2048K。

05 No Positional Embedding?!
有一个灵魂的发问:真的需要 Positional Embedding 吗?
Self-Attention 真的没有位置信息吗?
如果我们只考虑第一层的 Self-Attention,那它确实是没有位置信息。但如果我们考虑第二层的 Self-Attention,那结论就不太一样了。
我们看第一层 Attention 可以发现猫跟"吃"的关系,还有鱼跟"吃"的关系。对于下一层的 Attention,它看到第二个位置的时候,会看到一个猫跟吃有关的东西,还有一个鱼跟吃有关的东西。所以"猫吃鱼"和"鱼吃猫"最后得到的 Embedding 是不一样的。所以就算没有 Positional Embedding,Self-Attention 在多层的情况下也是具有 Positional 信息的。

NoPE:没有 Positional Embedding
这篇论文提出了一个方法叫做 NoPE,就是没有 Positional Embedding。
参考文献:https://arxiv.org/pdf/2305.19466
这篇论文训练了一些 Transformer 来做任务,发现其实不加 Position Embedding 也没关系。下图是一些结论,横轴代表做的任务长度,纵轴代表准确率,准确率越高越好。
我们会发现在 Copy 这个任务里面,加上 Positional Embedding 以后,很多模型在 Sequence 长到一定程度时就下降了。可是在没有加 Positional Embedding 的情况下,它的准确率非常高。

如果根据上面的结论,那我们在大模型训练时不应该加 Position Embedding。但为什么现在的大模型都会加 Position Embedding 呢?
有一篇文章有一些相关的讨论。下面这张图比较了 RoPE 跟 NoPE 训练的过程。横轴是训练的 Step(做了几次训练参数的更新),纵轴是 Loss,Loss 越小越好。结论显而易见——NoPE 在训练的时候效果就不如 RoPE 好。
所以我们为什么需要 Positional Embedding?是因为我们在 训练 的时候需要它。

DroPE:训练后期扔掉 Positional Embedding
那我们能不能在训练到一定程度之后就把 Positional Embedding 扔掉呢?现在有一个方法叫做 DroPE。它的想法是:一开始的训练是有 Positional Embedding 的,训练到快结束的时候,把 Positional Embedding 拔掉。Loss 就会突然冲上去,但是很快 Loss 就可以下降下来。在没有 Position Embedding 的情况下,它的训练效果是可以跟 RoPE 一样低的。
那 DroPE 这个方法表现怎么样呢?它是可以比 RoPE + YaRN 表现还要好的。比如我们训练的 Context 是 2K,如果说我们一直在用 Positional Embedding 的话,那当我们在做 Inference 的时候,Context 超过训练的 Context,它的效果就会下降。但是因为我们用 DroPE 的时候会把它的 Positional Embedding 在后面拔掉,它也会在没有 Positional Embedding 的情况下进行学习。那么这个时候,在我们的 Inference Context 超过 Training Context 的时候,它的效果依旧很好。

参考文献:https://arxiv.org/pdf/2512.12167
参考资料
- Sinusoidal Positional Embedding(原始 Transformer)
- ALiBi(Attention with Linear Biases)
- T5(Text-to-Text Transfer Transformer)
- RoPE(Rotary Position Embedding)
- Train Short Test Long(RoPE Context Extension 综述)
- Position Interpolation
- Position Interpolation(Kaiokendev 博客)
- NTK-aware Scaling(Reddit 帖)
- YaRN(Yet another RoPE extensionN method)
- Dynamic Scaling(Reddit 帖)
- LongRoPE
- NoPE(No Positional Embedding)
- DroPE
版权所有
版权归属:Alan Zero
许可证:Kstheme