多头注意力

http://zh.d2l.ai/chapter_attention-mechanisms/multihead-attention.html

代码里不同注意力头的 W_q, W_k, W_v 似乎是一样的,注意力机制用的也是同一个,那么每个注意力头产生的输出应该也是一样的,是不是有问题啊?

我也认为有问题。这是单头注意力机制。英文版的讨论里认为这是一个巨大的单头注意力(多个头的参数concat到一起变成一个单头),然后并行计算(相当于多头)。这里的代码实在应该再优化一下。

代码实现没问题哈,为了加速代码所以用了并行的写法。如果没看懂的话可以看李沐的这个讲解 68 Transformer【动手学深度学习v2】_哔哩哔哩_bilibili


每个注意力头的这三个参数是一样的还是不一样的呢???

这里的确有点难懂, 这里其实是把所有注意力头里面的参数拼起来, 变成了一个大的全连接层

我做了一个图来帮助理解, 希望也能帮到大家


话说这一节的代码真的很难懂… :melting_face:

3 Likes

这张图梳理的维度变换过程很清楚,感谢。这节的代码注释里要是有这些维度变换信息就好懂多了。

每个注意力头的这三个W都是不一样的,所以公式里的W有下标编号i。只是代码实现里的self.W_xx是把全部注意力头拼接到一起的,如果分开看的话实际上是num_heads个头,每个头的输出维度是num_hiddens/num_heads,拼接到一起就是num_hiddens的维度。

太优秀了!这张图确实恨清楚,配合代码看,一下就理解了

研究了半天,谈谈我的理解:
一开始query的shape是(2,4,100),应该是(2,4,20)复制了5份然后拼在一起的,实际每个batch的query的shape就是(2,4,20)

num_hiddens=100其实也是将5个head的全连接层放到一起初始化了;

transpose_qkv做的事情其实是将拼在一起的query拆开,每个query的shape是变成(4,20),然后将2个5头query共10个query摊开一起算,所以最后送到attention的shape是(10,4,20)

不知道这样理解对不对,最后附上我研究transpose_qkv的草稿:

这边多头注意力在transpose_qkv那边做的交换维度的操作主要目的是将计算中可并行的多个head“化作batch_size”和batch_size那个维度放在一起,使输入attention的维度变成(batch_sizehead,num_of_QKV,num_of_hiddens),放入d2l.DotProductAttention(dropout)(缩放点积注意力的实现)中去计算。点积注意力计算过程中是没有参数需要学习,所以可以将多个head需要做的计算当作数量为head的多个batch拆出来和原来的beath拼在一起计算,使得batch数量从原batch_size->batch_sizehead