位置编码是给 Transformer 标注每个词排在第几位的机制。它的存在源于一个先天缺口:注意力计算只看词与词的内容有多相关,本身不知道谁先谁后——没有位置编码,「狗追猫」和「猫追狗」用的词完全一样,在模型眼里就是同一袋词,分不出谁追谁。位置编码就是把「这是第几个词」翻译成模型能参与计算的数字信号,让同一批词因为顺序不同得到不同理解。读模型介绍时看到的 RoPE、rope_theta、最大位置长度,说的都是这套坐标系的不同实现和参数。
注意力只认内容,不认先后
早期循环神经网络是逐词往下读的,读到第几个词,顺序信息自然就带在状态里。Transformer 换了一种做法:把整段文字同时摊开,每个词和其余所有词两两算相关程度,也就是注意力机制在做的事。这种并行算法有个副作用:把输入词序整体打乱,每个词算出的结果也会跟着原样挪位,数值本身不变——换句话说,纯注意力对顺序是「看不见」的。「他欠我三千块」和「我欠他三千块」,词一模一样,意思完全反过来,差别只在顺序。所以必须额外给每个位置发一个标记,模型才有机会利用词序。
第一代做法:把位置变成波形,加进词向量
2017 年提出 Transformer 的原论文用的办法是正弦编码:每个位置生成一串由正弦、余弦算出的数字,不同维度对应不同频率,有的维度变化快,有的维度变化慢,像钟表上秒针、分针、时针的组合——看一眼各指针的角度,就能反推出唯一的时间。某个位置的这串数字,会直接加到这个词的词向量上,一起送进后面的网络。这个设计有三个好处:不用训练,任意长度都能现算;相邻位置的编码平滑过渡;两个位置相差固定距离时,它们的编码之间存在固定的变换关系,模型有机会从中读出相对距离。
同一时期还有一种更直白的做法:可学习位置嵌入。给每个位置准备一个向量,和词向量一样在训练中慢慢学出来,早期 GPT、BERT 用的都是这一路。缺点是位置表有多长,模型最多就只能处理多长:表里只学了 512 个位置,第 513 个词来了,没有现成的向量可用。两种做法标的都是「绝对位置」:每个词站在第几位;至于两个词相隔多远,要靠模型自己换算。
现在的主流是 RoPE:不加向量,转一转查询和键
2021 年的 RoFormer 论文提出了旋转位置编码 RoPE,后来成了 Llama、Qwen、ChatGLM 等主流开源模型的标配。它不在输入端加任何东西,而是在每一层注意力计算时动手:把查询向量和键向量按维度两两配对,每一对按与位置成正比的角度旋转一下,位置越靠后,转得越多。旋转之后,两个词的查询和键算内积,结果只取决于它们的内容和彼此相距多远,不再取决于各自站在第几位——用绝对位置的方式旋转,得到的却是相对距离的效果。这正是它受欢迎的原因:模型真正关心的多半是「这两个词离多远」,RoPE 把这一点直接写进了计算里,还不增加任何要学习的参数。另一条较少见的路线 ALiBi 连向量都不转,直接按距离给注意力分数扣分,BLOOM 等模型用过。
它和词嵌入、上下文窗口不是一回事
位置编码最容易和词嵌入混淆。词嵌入回答的是「这是什么词」,把词变成一串表示含义的数字,具体做法见向量嵌入那篇;位置编码回答的是「这是第几个词」,只管顺序,不管含义。正弦编码时代,两者是直接相加混进同一个向量的;到了 RoPE,位置信息只作用于查询和键,不碰真正被汇总的内容,内容和顺序的界限反而更清楚了。
和上下文窗口的分工也不同:窗口决定一次最多能摆多少词进来,是容量;位置编码决定摆进来的词怎么标号,是坐标系。容量可以标得很大,坐标系却是在训练长度内校准的,超出校准范围,标号就会失真。长文本模型能不能用好标称窗口,一多半看这一关。
三个常见误解
第一个误解是把位置编码想象成给每个词贴一张写着序号的标签,当成文字喂进去。它不在文本层,用户看不见,提示词里也写不出来;它是向量层面的数字变换,只发生在模型内部。
第二个误解是公式能算到任意位置,就等于模型能处理任意长度。正弦和 RoPE 的公式确实对第十万个位置也能算出数值,但训练时没见过的角度组合,对模型来说是没校准过的生坐标,效果会明显变差。把上下文从 4K 扩到 128K,工程上要动位置编码:把角度压缩着用的位置插值、按频率分段处理的 YaRN、调大旋转基数(配置里的 rope_theta,Llama 3 设为 50 万),再配上长文本继续训练,都是在给坐标系重新校准,不是改个数字就完事。
第三个误解是位置编码能帮模型记事实、补知识。它只标记顺序,不携带任何语义内容:词序标得再准,参数里没有的知识还是没有。它能让模型分清「猫追狗」和「狗追猫」,但分不清哪句是真的——真假要靠内容和参数里的知识,位置编码帮不上忙。
以后再看模型配置表,留意三个字段就能对它的位置处理心里有数:用的是哪种位置编码(rope 还是 learned)、旋转基数 rope_theta 是多少、标称的最大位置长度是多少。窗口数字回答「能装多少」,这三个字段回答「装进去之后,顺序还认不认得清」。