多头注意力
自注意力的意思是,query,key,value都是同一个X。
说明一个词语会咨询所有其他的词元,看其相似度来计算value值。
所以最后演变成下面的结构。
自注意力图
(todo)
与之相比的卷积神经网络图
(todo)
和循环神经网络图
(todo)
可以看出自注意力图能够关联更多信息。
试试看用多头注意力,把q,k,v都设置为同一个输入x。
1 | num_hiddens, num_heads = 100, 5 |
位置编码
当走上了注意力机制来处理词序列的一刻,就已经失去了时间步的概念,也就根本没有把词的位置信息给放进去。
举个例子:
I do not love you, but I do like your hair color.
I do love you, but I do not like your hair color.
两句话用的一模一样的词,但是意思完全不同,搞错这个意思就完蛋了 :),可能与爱情失之交臂。
所以需要引入位置编码。
举个例子:
I do love you, but I do not like your hair color, can you change ?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
最简单的方式就是把这些位置编码信息带入,比如把1转化为二进制0001,变成一个向量(0,0,0,1)
添加到词元的embedding 向量里去,比如 i = (23, 1, 0, 28) + 位置信息 (0,0,0,1) = (23, 1, 0 ,29)。
但是这样做有严重的问题,遇到特别长的句子,数值会变得很大,遇到训练期没见过的超级长句,泛化能力有限。
所以需要找到一个满足一下条件的位置编码方案:
1 给每个时间步有唯一的编码
2 在一个长句和一个短句,两个时间步的距离应该相等
3 句子长度不影响该编码上界值
继续思考下去:
0: 0 0 0 0
1: 0 0 0 1
2: 0 0 1 0
3: 0 0 1 1
4: 0 1 0 0
5: 0 1 0 1
6: 0 1 1 0
7: 0 1 1 1
8: 1 0 0 0
9: 1 0 0 1
10: 1 0 1 0
11: 1 0 1 1
12: 1 1 0 0
13: 1 1 0 1
14: 1 1 1 0
15: 1 1 1 1
发现了规律没有,对于最后一位,1总是每个1位出现一次,对于倒数第二位,1总是隔两位出现两次
对于倒数第三位,1总是每隔4位出现4次,对于倒数第四位,1总是每隔8位出现一次。
也就是遵循这样的规律,最右来回变化频率快,最左来回变化频率慢, 位置编码沿维度频率在变小或者变大。
所以这个跟cos sin函数很像,引入cos,sin函数遵循了位置的规律。
对每个维度引入位置编码:
t为位置
p(t) = sin( wk * t) 当t等于偶数 t=2k
p(t) = cos( wk * t) 当t等于奇数 t=2k+1
wk = 1/pow(1000, 2k/d)
比如
对于一个embeding维度为4句子:I do love you, but I do not like your hair color.
pt = ( sin(t), cos(t), sin(t/100), cos(t/100) )
代入上面函数
i = ( sin(1), cos(1), sin(1/100), cos(1/100) )
1 这样满足的是最右来回频率慢,最左来回频率慢, 满足了位置的频率变化规律
2 在原论文里面,数学家证明了,位置信息不依赖句子总长度。
3 两个位置编码相减也是满足条件的。
这种位置编码方案就是我们想要的。
代码
1 | class PositionalEncoding(nn.Module): |
参考:
https://kazemnejad.com/blog/transformer_architecture_positional_encoding/
https://zhuanlan.zhihu.com/p/106644634
https://zh.d2l.ai/chapter_attention-mechanisms/self-attention-and-positional-encoding.html
https://blog.csdn.net/zhaohongfei_358/article/details/126019181