看完肯定懂,可能会更新
一看位置编码公式,感觉很懵逼
懵逼四点:(或者你还有其他不懂的点)
1、为什么使用正弦余弦公式?不可以使用其他公式?
2、为什么奇数位置使用余弦,偶数位置使用正弦?
3、为什么不单独使用正弦,或者单独使用余弦?
4、正弦余弦公式到底是怎么影响原词向量的?怎么进行计算的?
如果原词向量为下图,你打算怎么给词向量叠加上位置编码呢?(假设词向量只有5位,实际上gpt是几万位)
我来告诉你几种脑子突然出现的想法。
1、给每个词向量的每一个位置都加上位置号码,例如have = [0.1,0.4,0.8 …] …day[4.8, 4.1, 4.4, 4.6, 4.6],发现一个问题,当我们的句子很长例如500个字的时候,后面词语位置编码会很大,本来词向量大部分都是0-1的数字,你这么大,位置编码会严重覆盖掉原有的词向量语义,词向量会丢失原有的语义。
2、等比例缩小行不行,假设100个词语,第1个词汇叠加0,第2个词汇叠加0.01,第3个词汇叠加0.02,第100个词汇叠加0.99,这样确实是可以的,没有问题,但是在实际训练中词与词之间的距离是0.01,数字太小了,位置信息太弱了,实际训练效果不好。假设原词向量大部分维度的数字都在0-1,起码我叠上去的数字也在这个区间吧。
。。。。或者你还想到其他的办法
总结:位置信息太强不行,相邻词之间位置信息太弱也不行
先看三角函数为什么可以,我们看下三角函数的图像
先提一个点:位置信息肯定是唯一的,或者是在很长的文字当中,起码重复度不会太高,x轴代表位置,y轴代表叠加上去的值。
假设只使用一个三角函数sin x,我们将第2和第14两个位置输入到sin x,他们的值很像,在神经网络的训练中,很容易把第2个位置和第14个位置当成是一个位置,不满足我们上面说到的要求位置唯一性。
sin2
sin14
怎么将sin变得具有唯一性呢,原生的sinx函数,周期性较短,很容易出现重复的值,但是我们要求位置信息肯定是唯一的,所以要把sin函数的波长拉长,拉长到10000,下图我拉长到10000,然后将位置x=0,1,2,3…n对应sin(x/10000)叠加到词向量上面,就保证了词与词之间的位置编码具有唯一性。虽然唯一性是保证了,但是相邻词之间的位置编码间隔差值还是太小,不行不行。
所以,重点来了,
原公式在
每个词向量的倒数第1维,使用的是波长为10000的sin公式
在每个词向量的倒数第2维,使用的是波长为5000的sin公式,
维度越靠前,使用的波长越短。
1、单看最后一维,词与词之间的差值非常小,间隔可能在0.00001之间,但是可以保证唯一性,但在神经网络训练中太弱了,位置信息几乎不起作用。
2、根据公式,维度越靠前面波长越短,倒数第2个维度,词与词之间间隔可能在0.0001之间。
3、依次类推,相邻词语不同维度的差值可以大概看作 [0.5, 0.1, 0.05, 0.001 …0.0001,0.00001]。
4、我们发现维度越靠前,不同词语的同等维度数字差距越大,这就能明显的区分出词与词之间的间隔,同时靠后的维度又保证了位置的唯一性。
5、那为什么又要使用cos呢,我的理解是主要还是为了提取更多的位置特征,增加一点复杂性,让位置编码拥有更多的位置特征。
解析下面公式,dmodel 是单个词向量的总维度,i 是单个词向量的某一个维度。
看个例子,不同维度使用的是不同波长的三角函数,下面两个矩阵直接对位相加就可以了
总结:
所以我们设计位置编码必须遵守三个规则
1、位置信息不可比语义信息要强势。
2、位置信息必须有界,防止越到后面位置信息太大覆盖语义信息。
3、文字太长的情况下,相邻字之前的位置信息也不会太弱势。