正弦/余弦位置编码 用不同频率的波浪给每个位置打独特的时间戳让Transformer既能知道绝对位置又能通过数学运算推导出相对距离。一句话理解位置编码 给每个座位位置发一个独特的波形密码让模型知道谁坐在第几排。为什么需要位置编码Transformer没有循环结构不像RNN逐个处理它是一次性看完全部token。所以它天生是瞎子——不知道顺序输入对Transformer来说“小猫在打滚”一堆向量不知道谁在前谁在后“滚打在小猫”也是一堆向量完全一样对待位置编码就是给每个位置贴一个座位号让模型能区分顺序。正弦/余弦是什么直觉理解想象一个弹簧或波浪位置0: 波浪起点sin0, cos1 位置1: 波浪往前一点sin0.84, cos0.54 位置2: 再往前sin0.91, cos-0.42 位置3: 更前面sin0.14, cos-0.99每个位置对应波浪上的一个不同点所以每个位置的编码独一无二。具体公式拆解PE(pos,2i)sin⁡(pos100002i/d)PE_{(pos, 2i)} \sin\left(\frac{pos}{10000^{2i/d}}\right)PE(pos,2i)​sin(100002i/dpos​)PE(pos,2i1)cos⁡(pos100002i/d)PE_{(pos, 2i1)} \cos\left(\frac{pos}{10000^{2i/d}}\right)PE(pos,2i1)​cos(100002i/dpos​)参数含义符号含义示例postoken的位置第几个字0, 1, 2, 3, 4i向量的维度索引0, 1, 2, 3d总维度这里442i偶数维度0, 2用sin2i1奇数维度1, 3用cos以小猫在打滚为例手算位置编码假设d44维向量计算每个位置的编码位置0“小”维度0 (i0): sin(0 / 10000^(0/4)) sin(0) 0 维度1 (i0): cos(0 / 10000^(0/4)) cos(0) 1 维度2 (i1): sin(0 / 10000^(2/4)) sin(0) 0 维度3 (i1): cos(0 / 10000^(2/4)) cos(0) 1位置0编码 [0, 1, 0, 1]位置1“猫”维度0: sin(1 / 10000^0) sin(1) 0.84 维度1: cos(1 / 10000^0) cos(1) 0.54 维度2: sin(1 / 10000^0.5) sin(1/100) sin(0.01) 0.01 维度3: cos(1 / 10000^0.5) cos(0.01) 1.00位置1编码 [0.84, 0.54, 0.01, 1.00]位置2“在”维度0: sin(2) 0.91 维度1: cos(2) -0.42 维度2: sin(0.02) 0.02 维度3: cos(0.02) 1.00位置2编码 [0.91, -0.42, 0.02, 1.00]完整位置编码表位置token维度0 (sin)维度1 (cos)维度2 (sin)维度3 (cos)0小0.001.000.001.001猫0.840.540.011.002在0.91-0.420.021.003打0.14-0.990.031.004滚-0.76-0.650.041.00关键特性1. 每个位置编码独一无二位置0: [0, 1, 0, 1] 位置1: [0.84, 0.54, 0.01, 1] 位置2: [0.91, -0.42, 0.02, 1]没有两个位置是一样的2. 相对位置可以计算神奇之处模型可以通过编码相减知道两个token相距多远位置1 - 位置0 的某种组合 → 距离是1 位置3 - 位置1 的某种组合 → 距离是2这是因为正弦/余弦的周期性和线性组合性质。3. 值域固定 [-1, 1]不管句子多长位置编码的值永远在-1到1之间不会爆炸。直观比喻想象5个人站成一排每个人手里拿一个不同颜色的灯位置0: 红灯最左边 位置1: 橙灯 位置2: 黄灯 位置3: 绿灯 位置4: 蓝灯最右边Transformer通过灯的颜色就知道谁站在哪里。正弦/余弦就是生成这些颜色的数学方法。为什么不用简单的 0,1,2,3,4方法问题直接用位置数字[0,1,2,3,4]句子长了数字太大模型不稳定用one-hot[1,0,0,0,0]维度爆炸5000个位置要5000维正弦/余弦✅ 维度固定值域稳定能表达相对位置最终操作和词嵌入相加词嵌入(小) [0.2, -0.5, 0.8, 0.3] 位置编码(0) [0, 1, 0, 1 ] ───────────────────────────────────── 最终输入 [0.2, 0.5, 0.8, 1.3]模型看到的不是单纯的小而是坐在第0个位置的小