Transformer架构原理的菜鸟学习之路02——位置编码(Positional encoding)
位置编码的应用随处可见,例如我们常用的11位手机号码,看似没有什么规律可循,其实是由3位网号(移动、电信等)+4位HLR号(归属位置寄存器)+4位的个人代码共同组成,尽管现在已经可以携号转网,但依然可以通过权威网站追溯到号码属地信息。
在日常生活场景中,基本上都是以姓名来区分不同的人,但只有身份证号等关键信息才是可以真正区分不同地区居民的编码。前六位一般遵循如下的编码标准:
第1~2位表示省级 行政区代码;
第3~4位表示地 市级行政区代码;
第5~6位表示县级 行政区代码。
在计算机系统以及机器学习算法当中,位置编码同样不可或缺。不管是一句话切分成的词元(token),还是一幅图像切分的像素块,最终都会被转换成统一格式的向量集合;
而集合有一个典型的排列等变性(随机性)特征,如果不给这些词嵌入向量加上位置编码,词元之间的很多重要关系将无从理解和确定。
一、傅里叶变换
刚开始读到“通过将这些不同频率的正弦/余弦波叠加,Transformer 为每个位置生成了一个独一无二的“指纹”,既包含了局部信息,也包含了全局信息”这句话时,我是百思不得其解。
过往的经验教训告诉我,当一个问题实在无法得到有效解答之时,很可能需要回溯一下这个问题,这就是我要简单谈一谈傅里叶变换的原因。
我们每时每刻看到的世界都在不断变化,就像是看一部电影,每一帧都不太相同,故事会随时间的流动而徐徐展开,我们想当然地认为这个世界永远不会静止下来,这就是动态的、流逝的“时域”视角。
其实,我们还可以用另一种静态的、永恒的“频域”视角来看世界,把电影拆分成一组有特定规律、永远不变的“颜色频率”和“声音频率”,世界不再是“不断流逝的眼前”,而是“永恒震荡的节奏”。
傅里叶变换的核心:任何复杂的信号(时域),都可以分解为一系列不同频率的正弦波和余弦波的叠加(频域)。Transformer 的位置编码设计思想,本质上是傅里叶变换(正变换:时域→频域;逆变换:频域→时域)思想的一种具体应用。
为了更好地理解这种傅里叶变换过程,我尝试使用了“请使用HTML语言编写网页,模拟多个正余弦函数叠加成不同图像的过程”的提示词,生成了一个可以直观体验变换过程的网页,有兴趣的朋友不妨一试,以加深对概念的直观理解。
二、正余弦位置编码
经典Transformer架构的设计者巧妙地借用了傅里叶变换的智慧,用一组正交的正弦/余弦基函数编码(Sinusoidal),将一个离散的、绝对的位置索引,映射到了一个连续的、包含丰富相对关系的高维词嵌入向量空间中。
很多人读到这里,可能也会和我有一样的疑问,为什么要设计如此复杂的编码而不是直接使用数字编码?
容易理解的浅层原因是简单的数字编码表征长序列(比如10000,100000等)时,位置数制会比较大,不利于模型权重的有效训练,而正余弦函数的值域固定在[-1,1]之间,便于稳定训练。
更深刻原因则是纯数字编码无法进行相对位置编码的线性变换,这里又不得不出现了一个新词。如果对线性变换的概念一无所知,显然无助于理解正余弦函数值编码的意义与价值,这也是一直在困扰我们小组成员的学习边界问题,一个问题可能与一连串的问题紧密相关,拓展学习又谈何容易!
所以我们不断地求助于AI老师,希望能够找到一种便于初学者理解“线性变换”概念的简约方式。我们可以用图像来做一个简单的列表,缩放、旋转、翻转等都类似于线性变换,因为线条还是线条,边角还是边角,并且不同状态之间可以来回转换,而对图像的随意擦除操作就不是线性变换,因为不能从一种擦除状态推导出另一种擦除状态。
再举一个时针转动的例子,3点钟的时针顺时针旋转90°就是6点钟,6点钟顺时针旋转90°就是9点钟,如果从数值本身,6是3的2倍,而9是6的1.5倍,显然不符合线性变换的典型特征。
如果我们从旋转90角度描述这种操作,就是典型的线性变换。我们可以使用一种极简的矩阵乘法来直观演示这种有趣的线性变换方式:
已知:
验证1:
验证2:
每次乘同一个旋转矩阵 R3,位置就 +3:3→6→9,两次验证全部正确,全程只有矩阵乘法,是标准线性变换。
我们可以把sin (x) 和 cos (x)看成单位圆上一个点的两条边:sin(x) = 高度,cos(x) = 水平长度,由于sin (x) 和 cos (x) 永远满足如下等量关系:
一个相对较大的值负责区分近的位置(相邻词),另一个相对较小的值负责区分远的位置(长句子)。
正是有了这种此消彼长、永远互补的相对关系,彼此之间才能有目的、有计划地进行不同形式的线性变换。如果对矩阵乘法还是云里雾里的朋友,请先往下看。
三、矩阵乘法与线性变换
为什么矩阵相乘就能实现位置编码向量的旋转、缩放等线性变换操作,这里很有必要回顾一下矩阵的四种不同视角。
例如对于一个2*2的矩阵,既可以看作是4个有序的数字abcd,也可以看做是两个列向量或者两个行向量,还可以看做对向量(x,y)进行的一种线性变换,可以根据需要进行选择或设计。
矩阵相乘的维度规则:(A×B)×(B×C)=A×C,中间的 B 必须相同,结果由前后维度决定。例如:(3行×2列)×(2行×2列)=3行×2列
利用一些特殊矩阵可以轻松实现原来矩阵的缩放、旋转、升维、降维、裁剪过滤等线性与非线性变换操作。
1、缩放
用 2×2 对角矩阵点乘一个点 (1,1)
(1,1) → (2,2),对角线上的数字就是缩放倍数。
2、旋转
用 2×2 旋转矩阵点乘点 (1,0),
(1,0) → (0,1),确实旋转了 90°
3、从低维升到高维
矩阵形状:2×3,向量形状:2×1
输入:2 维点 (x,y) 输出:3 维点 (x, y, x+y)
维度从 2 → 3,直观理解:把平面上的点,抬到三维空间里,不再局限在平面,这就是升维
4、从高维“压扁”到低维
矩阵:3×2, 向量:3×1, 3 维 → 2 维,
直接丢掉 z 轴,3D 点 → 拍扁成 2D 点,
这就是降维 / 投影。Transformer 里的降维的基本逻辑:用一个窄矩阵把高维向量压扁。
5、裁剪/过滤信息
用一个只保留部分维度的矩阵,比如 3×3 矩阵,但第三行全 0,z 信息直接被清零,相当于裁剪、丢弃、掩码,Transformer 的 Mask 就类似这种逻辑。
正是由于矩阵乘法与向量运算的多元互动与巧妙变换的关系,Transformer经典架构的设计师方才选择适合通过矩阵乘法进行进行线性变换的正余弦编码,而自注意力机制本身就包含了海量的矩阵乘法计算。
这当然不是“去简就繁”的随机性巧合,而是“化繁为简”创造性的设计,从而让“国王-男人+女人=女王”的两次向量计算与“国王-女王”之间的语义联系共享了相似的底层逻辑。
四、“国王-男人+女人=女王”
假设我们已经通过海量语料库训练好了词向量(Word2Vec)模型,词语被赋予了数学坐标,语义关系变成了几何关系。
我们可以把这个过程想象成在一张巨大的“语义地图”上进行导航。为了便于理解,我们将词向量的维度简化设定为 4维(实际上维度更高)。
1、准备工作:词语的“基因”编码
首先,每个词语都被表示为一个向量(一个包含多个数字的数组)。这些数字捕捉了词语的“语义特征”。
国王 可能表示为:[1.0, 0.8, -0.2, 0.5] (代表权力、男性、统治等特征)
男人 可能表示为:[0.3, 0.9, -0.1, 0.0] (代表性别、雄性特征)
女人 可能表示为:[-0.3, 0.8, 0.1, 0.0] (代表性别、雌性特征)
女王 可能表示为:[0.4, 0.7, -0.1, 0.5] (代表权力、女性、统治等特征)
2、计算过程:在语义空间中“走步子”
第一步:国王 - 男人(剥离“男性”特征)
这一步就像是在“国王”的概念中,减去“男人”的特征向量。我们逐元素相减:
结果A=国王−男人=[0.7,−0.1,−0.1,0.5]
语义解释:我们从“国王”中拿走了“男性”的属性。剩下的 [0.7, -0.1, -0.1, 0.5] 代表什么?它代表的是“拥有王权的非特定性别的人”或者说是“统治者的角色本身”,保留了权力(0.7)和地位(0.5),但去掉了强烈的男性偏向(从0.8降到了-0.1)。
第二步:结果A + 女人(注入“女性”特征)
这一步是将“女人”的特征向量加到上一步得到的“统治者角色”上。我们逐元素相加: =结果A+女人=[0.4,0.7,0.0,0.5]
语义解释:我们将“女性”的属性注入到“统治者角色”中。现在,我们有了一个拥有权力(0.4)、具有女性特征(0.7)、地位显赫(0.5)的实体。
3、结果验证:寻找最近的邻居
接下来,需要在语义向量库中,寻找哪个已有的词语向量与 [0.4, 0.7, 0.0, 0.5]向量最“相似”。
我们发现,“女王” 的向量是
[0.4, 0.7, -0.1, 0.5]
我们的计算结果
[0.4, 0.7, 0.0, 0.5]
这两个向量在数值上极其接近(仅在第三个维度上有微小差异)。在高维空间中,这意味着它们的方向几乎一致,距离非常近。
向量平移:国王-男人+女人,相当于进行了两次语义向量平移(线性变换的一种基本形式)。
类比关系:“从国王到男人的距离,应该等于从女王到女人的距离”。通过数学运算,我们成功地在语义地图上找到了对应的位置,像人一样的机器学习、深度学习就悄然发生了。
五、RoPE旋转位置编码
随着技术的更新迭代,正余弦函数形成的绝对位置编码的缺点(直接加在词向量上正余弦函数位置编码只能表示绝对位置,序列变长后编码差异模糊,外推能力弱且稳定性差)。
我们都知道,默认坐标系里有两个最基础的向量:
向右 1 步:i = (1, 0),横向基向量
向上 1 步:j = (0, 1),纵向基向量
所有点(新向量)都能靠这两个箭头(基向量)组合而成,这两个箭头一拉,就是单位正方形网格。
使用水平剪切矩阵
乘以横向基向量 (1,0),横向基向量(1,0)未变
再使用水平剪切矩阵乘以纵向基向量(0,1),纵向基向量则变成了(1,1) ,向右发生了倾斜。
通过矩阵乘法线性变换之后的横向基向量(1,0)未变,纵向基向量从(0,1)变成了(1,1)。
通过使用旋转矩阵重新定义基向量,让位置向量跟着旋转,将单位正方形变成了单位平行四边形,但是网格本身不弯曲、不扭曲,这就是RoPE旋转编码的基本思想。
RoPE 旋转位置编码不关心绝对位置,只关注“谁和谁近,谁和谁远”的相对位置关系(这也是自注意力机制的核心意蕴),在注意力计算时,让 Q、K 各自旋转。
假设位置 m 的 Q/K 旋转角度为θ·m,位置 n 的 Q/K 旋转角度为θ·n,两者的角度差就是:θ⋅m−θ⋅n=θ⋅(m−n), 只和 (m−n) 有关,和 m、n 本身无关,根据转角差判断距离,最终点积只跟相对距离有关。
关于RoPE旋转编码的深入探讨,已经超过本文的写作边界和能力范围,希望能在以后关于QKV矩阵乘法与向量归一化、点积等相关知识的学习过程中慢慢学习和深刻体会。
转自:https://mp.weixin.qq.com/s/eCW2Q_E0Es0FYjeRJ1ZWvA
