图解Positional Encoding:用20行Python代码实现Transformer位置编码

图解Positional Encoding:用20行Python代码实现Transformer位置编码

最近在复现一个Transformer模型时,我又一次被那个看似简单却至关重要的模块——位置编码(Positional Encoding)——给“绊”了一下。很多教程会直接甩出那个著名的正弦余弦公式,告诉你“照着做就行”,但如果你和我一样,不亲手画出来、不跑通代码,心里总感觉隔着一层纱。为什么非要用三角函数?为什么是奇偶位置分开处理?它到底是怎么让模型“感知”到词语顺序的?这篇文章,我就想和你一起,抛开复杂的数学推导,用最直观的图解和不到20行的核心Python代码,把Transformer位置编码的里里外外彻底搞明白。无论你是刚入门Transformer的开发者,还是想巩固底层细节的实践者,我们都能从零开始,构建起清晰的理解。

1. 为什么Transformer必须“记住”位置?

在自然语言处理的世界里,词语的顺序几乎决定了句子的全部意义。“猫追老鼠”和“老鼠追猫”描述的是截然不同的场景。对于循环神经网络(RNN)这类模型来说,它们按顺序逐个处理词语,词语的位置信息在时间步中自然得以保留。但Transformer的自注意力机制(Self-Attention) 带来了革命性的并行计算能力,也带来了一个根本性问题:它一次性“看到”整个句子,词语之间失去了天然的先后顺序。

想象一下,如果没有位置信息,Transformer眼中的“我爱人工智能”和“人工智能爱我”这两个句子,其词袋表示可能完全相同,模型将无法区分。因此,我们必须显式地将位置信息注入到模型的输入中。这就是位置编码(Positional Encoding, PE)诞生的初衷:它是一个与词嵌入(Word Embedding)维度相同的向量,专门用来表示一个词在序列中的绝对或相对位置。

那么,如何设计这个位置编码呢?一个朴素的想法是直接用整数序列 [0, 1, 2, 3, ...]。但这会带来几个问题:

  • 数值范围不可控:序列长度可能从几十到上千,编码值差异巨大,容易干扰模型训练。
  • 泛化能力差:训练时见过的最大位置是100,模型可能难以理解第101个位置。
  • 无法体现相对位置:位置3和位置4的差是1,位置100和位置101的差也是1,但模型可能无法从这种简单的线性关系中捕捉到“相邻”的语义。

我们需要一种编码方案,它必须满足几个关键性质:

  1. 唯一性:每个位置都有一个独一无二的编码。
  2. 有界性:编码值应落在稳定的、有界的范围内(如[-1, 1])。
  3. 可泛化:能够处理比训练时更长的序列。
  4. 能表征相对位置:模型能轻易地从编码中推导出“位置i和位置j相距多远”。

Transformer论文给出的答案,出人意料地优雅:使用一组不同频率的正弦和余弦函数。

2. 正弦与余弦:位置编码的“密码本”

让我们直接看向Transformer论文中那个经典的公式:

对于位置 pos 和维度索引 i(其中 i 从0到 d_model-1d_model 是词向量的维度):

[ PE_{(pos, 2i)} = \sin\left(\frac{pos}{10000^{2i/d_{model}}}\right) ] [ PE_{(pos, 2i+1)} = \cos\left(\frac{pos}{10000^{2i/d_{model}}}\right) ]

初看可能有些令人费解。我们一步步拆解:

  • pos:词语在句子中的绝对位置(从0开始计数)。
  • i:词向量中维度的索引。
  • d_model:词向量的总维度(例如512或768)。
  • 10000^{2i/d_{model}}:这个项决定了频率。随着维度索引 i 的增大,分母变得巨大,使得频率降低。

核心思想是:将位置 pos 编码成一个 d_model 维的向量。这个向量的每一个维度都是一个正弦或余弦波,但它们的波长(频率)各不相同。 偶数维度(2i)使用正弦函数,奇数维度(2i+1)使用余弦函数。

为什么这样设计有效?我们可以从两个角度理解:

1. 二进制表示的类比 想象用二进制表示数字:最低位(最右边)在0和1之间快速交替(每1个数变一次),次低位每2个数变一次,再次位每4个数变一次。高位比特变化非常缓慢,承载着“粗粒度”信息;低位比特变化迅速,承载着“细粒度”信息。正弦余弦函数在这里扮演了类似的角色。低维度索引 i 对应的频率高(波长短),变化快,像二进制低位;高维度索引 i 对应的频率低(波长长),变化慢,像二进制高位。这种多频率的组合,确保了每个位置都能获得一个独一无二的高维编码。

2. 相对位置的可推导性 这是正弦余弦函数搭配使用的精妙之处。根据三角函数的和角公式: [ \sin(\alpha

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值