ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Transformer位置编码全解析:从正弦编码到RoPE与ALiBi

Transformer位置编码全解析:从正弦编码到RoPE与ALiBi 第一次读《Attention is All You Need》时我被一个细节卡了很久模型输入明明是一个并行计算的矩阵GPU一次性看到整句话的所有token那么模型到底怎么知道一个词在句子的开头还是结尾后来才意识到Transformer这一步去掉循环结构换来的代价是所有token在计算初始时是无序的。这个问题就是位置编码要解决的。位置编码这个概念几乎所有做注意力机制的人都接触过但真正能说清楚为什么有这么多种位置编码它们之间是什么关系实际项目里选哪个的人其实不多。我梳理过不少相关方案从Transformer原版的正弦编码、BERT的可学习编码到Transformer-XL的相对位置、DeBERTa的解耦设计再到近几年大模型里几乎标配的RoPE旋转编码和GLM/LLaMA系列偏好的ALiBi踩过不少坑也得出了一些自己的判断。这篇内容不打算写成论文堆砌而是想从注意力机制到底丢失了什么信息这个根源讲起把位置编码的演进脉络和实操选型讲透。1. 为什么注意力机制需要位置编码从并行计算到顺序信息丢失1.1 自注意力的置换不变性到底意味着什么要理解位置编码得先理解自注意力机制的一个缺陷——置换不变性。用大白话说就是你把输入序列中任意两个token互换位置self-attention的输出也仅仅是对应位置互换数值本身几乎不变。因为它的核心计算是Q和K的点积Attention(Q, K, V) softmax(QK^T / sqrt(d_k)) V这个公式里没有任何一项与token在序列中的绝对位置有关。token向量只携带语义信息比如打这个字的embedding不管它出现在句子第一位还是最后一位输入层面的向量是完全一样的。QK^T计算的是两两之间的相似度这个相似度也与它们相隔多远无关。这就带来一个很反直觉的结果对Transformer来说输入序列更像一个无序集合而不是一个有序序列。真实语言显然不是这样我打你和你打我里的词完全一样语义完全相反。如果模型不额外获得顺序信息它根本无法区分这两种输入。1.2 RNN和CNN为什么没有这个问题在Transformer之前RNN/LSTM是按时间步逐个读取token的前一个token的隐藏状态会传给下一个token顺序信息被隐式编码在累计状态里。所以RNN天生知道先后关系。CNN虽然也是并行但它通过卷积核的局部感受野进行滑窗操作不同位置天然有不同的空间关系多层堆叠之后也能捕捉一定的位置模式。Transformer把顺序这个约束彻底释放了换来的是训练并行度和长距离依赖建模能力的大幅提升但也因此必须手动把位置信息喂回模型。可以这么理解RNN是边走边记忆的人CNN是看局部窗口拼接图案的人Transformer是面前摊着所有文字卡片、一次性扫一遍的人——后者没有时间轴概念你只能给每张卡片贴上序号标签。1.3 位置编码应该满足什么要求既然要显式补充顺序信息自然有设计标准。从业界沉淀下来的普遍共识一个好的位置编码方案通常具备这几个特性每个时间步都能获得一个唯一的编码向量用于区分先后。编码之间的距离/差异能反映序列中的相对关系即第5个token和第6个token的距离要能被模型感知。编码应当有界且稳定不能随着序列长度增大而数值爆炸。最好能泛化到训练时未见过的长度也就是长度外推能力。这几个特性在不同方案里各有取舍。绝对位置编码优先满足唯一性相对位置编码优先满足距离感RoPE则在两者间做了更精巧的折中。后面我们逐个拆。2. 绝对位置编码正余弦方案与可学习向量2.1 Transformer原版正弦位置编码的公式拆解Google在Transformer原论文里给出的方案是固定函数生成的位置编码公式长这样PE(pos, 2i) sin(pos / 10000^(2i/d_model)) PE(pos, 2i1) cos(pos / 10000^(2i/d_model))其中pos是token在序列中的绝对位置d_model是embedding维度i是维度下标取值从0到d_model/2。直观来看不同维度对应不同频率的三角函数低维度i小频率高相邻token之间变化明显高维度i大频率低变化平缓。整个位置向量就像一组刻度尺上的读数。很多人没注意到一个关键性质两个不同位置的正弦编码向量做内积结果只与它们的相对位置差有关与绝对位置基本无关。利用三角恒等式可以近似推导出PE(pos)^T · PE(pos k) ≈ Σ cos(k · ω_i)其中ω_i是各维度的角频率。这意味着虽然我们给每个token加的是绝对位置编号但注意力机制在计算QK^T时模型可以自然地读出两个token之间隔了多远。这就是为什么正弦编码常被称为用绝对位置的壳装相对位置的核。2.2 BERT和GPT初代的可学习位置编码BERT没有沿用正弦编码而是把位置编码当做一个可训练的Embedding矩阵维度是[最大序列长度, hidden_size]随机初始化随模型一起训练。它和token embedding相加后送入编码器。可学习位置编码的好处是灵活——模型可以根据任务自适应调整位置信息的使用方式在充分训练后其表达能力通常不输正弦编码甚至在中等长度序列上效果更好。GPT系列初期也采用了类似做法。但它的致命弱点是长度外推能力差训练时只见过512或1024个位置推理时如果输入超过这个长度位置embedding矩阵压根没有对应行只能截断或者插值效果都会打折扣。我自己的经验是用BERT做分类任务时这个短板不明显因为输入基本不超过512但做长文本匹配或文档级任务时直接改最大位置长度重新预训练成本很高效果也不一定稳。所以可学习绝对位置编码适合任务长度可控的场景。2.3 绝对位置编码的短板与常见补救绝对位置编码的共性问题就是位置信息只代表第几个位置没有显式建模相隔多远。虽然正弦编码通过频率差异隐含了相对距离但这种隐含关系在高维空间里会被其他信息干扰模型需要额外学才能充分利用。另一个问题是外推。正弦编码理论上可以外推到任意长度因为函数是连续的可学习编码则完全无法外推。实际操作中常用的补救做法有两种一是位置插值Position Interpolation把超出范围的位置线性映射到已有范围内二是直接加大训练长度。两者各有代价插值会损失位置分辨率加大训练长度成本又高。这也直接推动了后续相对位置编码和RoPE的流行。3. 相对位置编码从第几个座位到我和你隔多远3.1 相对位置编码的出发点绝对位置编码的思路是给每个位置一个身份证号相对位置编码的思路则完全不同它只关心两个token之间隔了几个位置。用公式表示注意力分数不再只计算QK^T而是在其中加入一个依赖相对位置距离的偏置项score(q_i, k_j) q_i · k_j b_{j-i}这里j-i就是相对距离。这么做的好处是显而易见的距离信息是平移不变的不管句子是10个词还是1000个词两个词相邻这种模式都可以用同一个偏置参数表示长度外推能力天然优于绝对位置编码。想象一下绝对位置编码像是告诉模型这是第5排第3座相对位置编码则是告诉模型旁边坐了个人隔了2个座位——后者明显更普适。3.2 Transformer-XL的经典设计相对位置编码的系统化应用是从Transformer-XL开始的。它做了一个关键改动不再把位置编码加到输入embedding上而是在计算QK^T时把注意力分数拆成内容的贡献和位置的贡献两部分。位置部分使用一个可学习的相对位置Embedding并且为了控制参数规模对距离做了截断处理。具体来说Transformer-XL里的相对距离可以取[-K, K]范围内的值超过K的都归到边界桶里。比如K16时位置距离为100和位置距离为50的两个token对使用的偏置会是同一个。这个设计的隐含假设是过于遥远的位置关系难以精确建模不如把容量留给近邻位置。这个分桶思想后来影响了很多模型T5的位置bucketing就是一个直接继承。3.3 T5与DeBERTa的工程化简化T5简化了相对位置编码直接保留一个相对位置偏差表表里有若干桶每个桶对应一段相对距离范围。计算attention logits时查表得到一个标量加进去。T5的桶分配不是线性的而是距离近的地方桶更密、距离远的地方桶更稀疏这也符合语言中近邻依赖更强的直觉。DeBERTa做得更彻底提出了解耦位置编码ECC。它将内容向量和位置向量分开分别计算内容-内容、内容-位置、位置-内容三类注意力分数再按比例融合。核心思想是一个词的语义和它的位置应该是两个独立的信号模型可以同时知道这个词是什么和这个词在哪里且两者在注意力计算中不互相污染。实测中DeBERTa这种解耦设计在GLUE等任务上比同规模的BERT提升明显。4. 旋转位置编码RoPE把位置变成旋转角度4.1 RoPE想解决的三个问题RoPERotary Position Embedding是近两年大模型领域最火的位置编码方案LLaMA、ChatGLM、Qwen等模型都在用。它试图同时满足三个目标像绝对位置编码那样实现简单像相对位置编码那样让注意力分数依赖相对距离同时具备良好的长度外推能力。它的做法非常巧妙。在二维平面上对一个token的Q向量或者K向量做一个旋转旋转角度等于该token的位置pos乘以一个基础角频率θ。记作Rot(Q, pos) Q · [[cos(posθ), -sin(posθ)], [sin(posθ), cos(posθ)]]如果把序列中每个token的Q/K都旋转各自的位置角度那么计算第i个token和第j个token的注意力分数时点积结果里会自然出现与(i-j)相关的相位差。也就是说相对位置信息被编码进了两个向量的夹角里。4.2 高维空间里的分块旋转与实现要点一个token的向量维度远不止2RoPE的做法是把整个向量切成d/2组每组是一个二维平面每组使用不同的角频率θ_i 10000^(-2i/d)这和正弦位置编码的频率设置几乎一样低维转得快、高维转得慢。在高维空间里相当于每个token向量在多个不同角速度的二维平面上同时旋转。实现上不需要真的构造旋转矩阵做矩阵乘法更高效的方式是利用复数运算——把相邻两维看作一个复数乘上对应的e^(i·pos·θ)代码量很短。实际推理时通常预先算好每个位置的cos和sin值缓存到位然后对Q和K分别做旋转。有一个细节很容易踩坑RoPE只加在Q和K上不能加到V上因为位置对语义内容V不应该有影响否则会污染输出表示。很多人一开始会顺手给V也加上损失一下就上来了。4.3 为什么RoPE被看作外推能力强的代表RoPE的外推优势来自它的相位形式。当训练长度与推理长度不一致时绝对位置编码需要面对位置值超出范围的问题RoPE因为是连续旋转任何位置的旋转角度都是良定义的模型虽然没见过那么远的相对距离但至少不会收到完全陌生的输入向量。针对超过训练长度的推理RoPE还有两个好用的外推技巧。一是linear interpolation把所有位置和频率都按比例压缩到训练长度内二是NTK-aware缩放它不改变位置坐标而是把base从10000提高到比如500000让长距离token对的旋转频率变低整体更平滑。我跑过长文本实验NTK方法明显比线性插值稳尤其是2倍长度外推时ppl困惑度上涨更平缓。5. 注意力偏置派ALiBi与线性注意力的位置方案5.1 ALiBi的工作原理不学位置向量直接打折ALiBiAttention with Linear Biases的思路极为直接在注意力分数上给相邻token对加一个很小的负偏置给相距很远的token对加一个较大的负偏置直接压低远处token的注意力权重。公式形式是score(q_i, k_j) q_i · k_j - m_h · |i - j|m_h是每个注意力头单独的斜率参数一般取值为2^(-8/h)的形式h是注意力头的编号。头0的斜率最大对距离最敏感头越靠后斜率越小越倾向于忽略距离信息。这样不同头可以分工——有些头专注近邻有些头负责长距离全局依赖。5.2 ALiBi和RoPE的实践对比我实际测试过两种方案各自的适用场景还挺不一样。ALiBi最大的优点是实现极其简单不需要维护位置编码矩阵也几乎没有额外的显存开销而且外推性能非常好训练长度4096直接推理8192ppl不会像可学习位置编码那样崩掉。但它的代价是引入了一个很强的先验假设距离越远越不重要。这在很多任务上是对的但某些场景——比如一段文档里前后呼应的概念、长范围指代——模型需要记住很远的信息ALiBi的线性惩罚会把这种远距离注意力打得过低。RoPE没有这种简单惩罚它只是把距离编码成相位差模型可以自己决定要不要关注远处灵活性更高。我的倾向是如果做对话模型、或者所有输入长度不太规律、外推压力大的场景ALiBi的性价比很高如果做通用预训练、需要精细控制注意力分布RoPE上限更高。当然现在主流开源大模型多数选了RoPE生态也更丰富。5.3 线性注意力里位置编码的特别之处线性注意力机制如Performer、Linear Transformer把softmax注意力近似为核函数特征映射计算复杂度从O(n²)降到O(n)。但这类方法里很多位置编码的注入方式不再适用——因为位置加在token embedding上在核近似时会被高次特征扭曲。常见的做法是设计可加性位置编码让位置矩阵和内容向量的核映射保持某种线性关系或者在近似空间中引入位置特征。这部分比较进阶但确实提醒我们位置编码和注意力机制的数学形式是强耦合的换注意力就要重新审视位置信息怎么传递。6. 跨模态与多尺度场景中的位置编码6.1 ViT里的位置编码图像patch的顺序视觉Transformer把一幅图切成若干个patch每个patch展开成一维向量后送入Transformer。patch本身没有天然顺序必须手动指定。ViT最初直接沿用BERT的可学习绝对位置编码用一维的0-196位置索引后来又出现了二维位置编码行位置列位置分别编码再拼接和相对位置编码方案。图像位置编码和文本位置编码最明显的区别在于图像的二维空间结构比文本的一维线性顺序更依赖局部性。两个patch相距多远不仅包括欧氏距离还包括方向关系。所以Swin Transformer这类模型干脆采用相对位置偏置在window内部计算相对坐标效果比绝对位置编码更好而且具有平移等变性换不同尺寸输入也不会崩。6.2 FPN结合注意力时的位置编码归一化坐标是关键在CV目标检测任务里FPN特征金字塔输出多个不同尺度的特征图再用注意力机制做特征融合时位置编码很容易踩坑。原因是不同特征图的坐标系统不一样小特征图上的(0,0)和大特征图上的(0,0)对应原图完全不同的区域和尺寸。如果直接用整数绝对坐标加位置编码模型在不同尺度间做attention时位置语义是错乱的。我的做法是先把每个特征图的坐标归一化到[0,1]区间再乘以一个可学习的尺度因子或者直接用归一化坐标做二维相对位置编码。另外由于CNN骨干已经引入了局部空间先验在FPNattention结构里位置编码的权重通常不需要太大否则会覆盖掉CNN提取的天然空间特征。这个平衡点要靠实验调。6.3 通道注意力机制里为什么通常不需要位置编码SESqueeze-and-Excitation、CBAM这类通道/空间注意力机制和Transformer的self-attention不是一回事。SE通过对特征图做全局平均池化得到通道权重再对每个通道缩放——它建模的是哪些通道重要与空间顺序基本无关。CBAM里的空间注意力是按像素位置统计全局信息后生成空间权重图它依赖的也不是序列顺序。所以初学者经常混淆的问题SE、CBAM里需要位置编码吗常规情况下不需要。但如果把注意力机制用到序列任务里比如对视频帧或时序特征做attention就必须考虑位置信息否则模型无法区分帧的先后。理解这一点对不同注意力机制的定位会清晰很多。7. 实战经验位置编码的选型、外推与踩坑记录7.1 用RoPE做长文本微调的几个注意点如果你打算给已有模型加长文本能力RoPE是目前比较稳的选择。但有几个坑值得记下来。第一不要同时叠加多个外推方法。我见过有人既改rope_scaling又直接增大训练长度还顺手把位置embedding max_position改大结果训练崩了。外推优先只选一种要么线性插值、要么NTK、要么动态缩放先跑通一个再说。第二base频率不能随便调。RoPE默认base10000如果想把有效外推长度翻倍可以尝试把base调到500000甚至1e6但过大的base会导致低频部分频次太低模型短序列内的相对距离区分度下降训练前期loss波动会比较明显。这里建议分阶段训练先在2k长度训练稳定再渐进到4k、8k。第三注意Q、K、V三个向量的处理位置。RoPE只旋转Q和KV保持原样。如果框架封装好了一般不用你操心但自实现时必须小心。7.2 位置编码对loss曲线的影响从可学习绝对位置编码切换到RoPE时一个常见现象是前几步loss掉点然后逐步回升。这个阶段不要慌也不要急着回滚方案因为模型需要时间适应新的位置信号分布。我的经验是至少观察500-1000步再下结论。另外可以通过可视化位置编码矩阵来快速诊断问题。用正弦或可学习绝对位置编码时画出位置向量之间的余弦相似度热图正常应该是靠近主对角线区域相似度高、远离则降低。如果热图几乎看不出距离结构说明位置编码的尺度可能设置得不对常见问题是位置编码的数值范围比token embedding大太多或者小太多导致加和后位置信息被淹没。一般经验做法是把位置编码的初始标准差设为0.02左右或者直接遵循原模型的初始化设置。7.3 我的几点结论性经验做了一轮位置编码的梳理和实测之后我最大的体会是没有绝对最好的位置编码只有最适合当前任务的方案。短文本任务里简单的可学习绝对位置编码依然够用、稳定不必迷信相对位置一定更强需要外推和长序列建模时RoPE和ALiBi是更可靠的选择前者上限更高、后者实现更简单在跨模态、多尺度特征融合场景一定要先统一坐标系统再谈位置编码形式。在自实现一个简单注意力模块时我通常会先把位置编码单独拆成一个模块方便随时切换不同方案做对照实验。选型时先明确几个问题最大输入长度是否有硬上限推理时会不会出现训练长度之外的输入任务是否高度依赖远距离依赖把这些想清楚位置编码的选择不会太难。技术演进很快也许过两年还会涌现更好的方案但底层逻辑——如何在不破坏并行计算的前提下把顺序信息以可学习、可泛化的方式注入模型——这始终是注意力机制最核心的问题之一。
返回列表