位置编码Positional Encoding
内容全来自于网络总结。
1.Transformers中的PE
公式是初中生都看的懂,
- d m o d e l d_{model} dmodel表示输入的维度,
- p o s pos pos表示单词的索引,
- i i i表示向量中索引,
- 用 s i n sin sin, c o s cos cos计算出对应值,
但是为什么可以这样加到input上达到位置编码的效果呢?这时候看看bert就是非常直观的绝对位置动态编码,就直观很多,每个位置就是固定的embedding:
原文作者解释的:
对于任何偏移量k,对pos+k的编码都可以是pos编码线形变换.先来看看可视化结果:
值得注意的是,每个向量第0和第1的位置,第0的位置对应于PE公式的sin式,第1的位置对应于PE公式的cos式子,但是他们的2i都是0,所以会有下式:
所以每个输入向量的第0个和第1个位置的位置编码只和向量所处的pos有关.但是第3个位置后就受d_model影响了,一旦d_model变小,sin/cos函数就会有“拉伸”感,如下图所示:
对于长度为20的input,维度是50,可以画出一下PE值:
越小的pos受影响的i就越少, i i i如果很大,PE值就会在0和1进行变换.从上图中,我们看到30~50列值基本没有变化.为啥上图这种编码就能学到位置信息?其实有种非常直观的解释方式,比如让你对数字进行编码,最直观的想法就是二进制编码,如下图所示:
PE方法就可以简单的理解为上述版本的float编码.
2.什么是Transformer位置编码
在以前的模型中,NLP的每个Sequence都是一个token一个token的输入到模型当中。比如有一句话是“我喜欢吃洋葱”,那么输入模型的顺序就是“我”,“喜”,“欢“,”吃“,”洋“,”葱”,一个字一个字的。
上面的输入方式其实就引入了一个问题。一个模型每次只吃了一个字,那么模型只能学习到前后两个字的信息,无法知道整句话讲了什么。为了解决这个问题,Transformer模型引用了Self-attention来解决这个问题。Self-attention的输入方式如下:
可以看到,对于Self-attention结果而言,它可以一次性的将所有的字都当做输入。但是NLP的输入是有特点的,其特点是输入的文本要按照一定的顺序才可以。因为,文本的顺序是带有一部分语义关系的。比如下面两句话,不同的语序就有不同的语义。
- 句子1:我喜欢吃洋葱
- 句子2:洋葱喜欢吃我
所以,对于Transformer结构而言,为了更好的发挥并行输入的特点,首先要解决的问题就是要让输入的内容具有一定的位置信息。在原论文中,为了引入位置信息,加入了Position机制。
对于Transformer而言,Position机制看似简单,其实不容易理解。这篇文章通过梳理位置信息的引入方式,然后详细讲解在Transformer中是如何做的。最后将通过数学来证明为什么这种编码方式可以引入相对的位置信息。
位置编码分类:总的来说,位置编码分为两个类型:函数型和表格型
-
函数型:通过输入token位置信息,得到相应的位置编码
-
表格型:建立一个长度为L的词表,按词表的长度来分配位置id
2.1.表格型
- 方法一:使用[0,1]范围分配
这个方法的分配方式是,将0-1这个范围的,将第一个token分配0,最后一个token分配去1,其余的token按照文章的长度平均分配。具体形式如下:
- 我喜欢吃洋葱 【0 0.16 0.32.....1】
- 我真的不喜欢吃洋葱【0 0.125 0.25.....1】
问题:可以看到,如果句子长度不同,那么位置编码是不一样,所以无法表示句子之间有什么相似性。
- 方法二:1-n正整数范围分配
这个方法比较直观,就是按照输入的顺序,一次分配给token所在的索引位置。具体形式如下:
- 我喜欢吃洋葱 【1,2,3,4,5,6】
- 我真的不喜欢吃洋葱【1,2,3,4,5,6,7】
问题:往往句子越长,后面的值越大,数字越大说明这个位置占的权重也越大,这样的方式无法凸显每个位置的真实的权重。
总结:过去的方法总有这样或者那样的不好,所以Transformer对于位置信息的编码做了改进。
2.2.相对位置的关系-函数型
相对位置编码的特点,关注一个token与另一个token距离的相对位置(距离差几个token)。位置1和位置2的距离比位置3和位置10的距离更近,位置1和位置2与位置3和位置4都只相差1。
还是按照上面"我喜欢吃洋葱"中的“我”为例,看看相对位置关系是什么样子的:
可以看到,使用相对位置的方法,可以清晰的知道单词之间的距离远近的关系。
Transformer的Position
类型:首先给一个定义:Transformer的位置信息是函数型的。在GPT-3论文中给出的公式如下:
细节:首先需要注意的是,上个公式给出的每一个Token的位置信息编码不是一个数字,而是一个不同频率分割出来,和文本一样维度的向量。向量如下:
不同频率是通过
w
n
w_n
wn 来表示的。得到位置向量P之后,将和模型的embedding向量相加,得到进入Transformer模型的最终表示。
① 关于
w
i
w_i
wi :
w
i
w_i
wi 是频率
② 关于 $ t$:这里的 $ t$ 就是每个token的位置,比如说是位置1,位置2,以及位置 n
3.为什么可以表示相对距离?
上文说过,这样的位置信息表示方法可以表示不同距离token的相对关系。这里我们通过数学来证明。
回顾下中学的三角函数正余弦公式:
-
已知某一个token的位置是 $pos $ ,如果某一个token表示为 p o s + k pos+k pos+k ,那就表明这个位置距上一个token为 k k k 。
-
如果这时需要看看一个位置 $ pos$ 和 $ pos+k$ 这两个字符的关系。按照位置编码的的公式,可以计算 p o s + k pos+k pos+k
的位置编码,其结果如下:
可以看看上面公式中,有一部分是似曾相识的:
根据上面的公式可以看出,似曾相识的部分带入
P
E
p
o
s
+
k
PE_{pos+k}
PEpos+k 的公式中,带入之后的结果如下:
可以知道,距离K是一个常数,所有上面公式中 sin() 和 cos() 的计算值也是常数,可以表示为:
这样,就可以将 P E p o s + k PE_{pos+k} PEpos+k 写成一个矩阵的乘法。
可以从上面的矩阵乘法角度看到,位置 pos 的编码与位置 pos+k 的编码是线性关系。
那么问题来了,上面的操作也只可以看到线性关系,怎么可以更直白地知道每个token的距离关系?
为了解答上面的问题,将 P E p o s PE_{pos} PEpos 和 P E p o s + k PE_{pos+k} PEpos+k 相乘 (两个向量相乘),可以得到如下结果:
发现相乘后的结果为一个余弦的加和。这里影响值的因素就是 k 。如果两个token的距离越大,也就是K越大,根据余弦函数的性质可以知道,两个位置的 PE 相乘结果越小。这样的关系可以得到,如果两个token距离越远则乘积的结果越小。
其他
这样的方式虽说可以表示出相对的距离关系,但是也是有局限的。其中一个比较大的问题是:只能的到相对关系,无法得到方向关系。所谓的方向关系就是,对于两个token谁在谁的前面,或者谁在谁的后面是无法判断的。数学表示如下:
4.其他参考
为什么这么做有用:
- pos+K=5,在计算第 5 个单词的位置编码的时候
- pos=1,k=4
- pos=2,k=3