Transformer中的Self-Attention和Multi-Head Attention

2024-06-18 03:04

本文主要是介绍Transformer中的Self-Attention和Multi-Head Attention,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

2017 Google 在Computation and Language发表

当时主要针对于自然语言处理(之前的RNN模型记忆长度有限且无法并行化,只有计算完ti时刻后的数据才能计算ti+1时刻的数据,但Transformer都可以做到)

文章提出Self-Attention概念,在此基础上提出Multi-Head Atterntion

下面借鉴霹雳吧啦博主的视频进行学习:


Self-Attention

假设输入的序列长度为2,输入就两个节点x1,x2,然后通过Input Embedding也就是图中的f(x)将输入映射到a1,a2。紧接着分别将a1,a2分别通过三个变换矩阵Wq,Wk,Wv(这三个参数是可训练的,是共享的)得到对应的q^{i},k^{i},v^{i}(直接使用全连接层实现)。

其中:

q代表query,后续会去和每一个k进行匹配

k代表key,后续会被每个q匹配

v代表从a中提取得到的信息

后续q和k匹配的过程可以理解成计算两者的相关性,相关性越大对应v的权重也越大。

假设a_{1}=(1,1),a_{2}=(1,0),W^{q}=\begin{pmatrix} 1,&1 \\ 0,&1 \end{pmatrix}

那么q^{1}=(1,1)\begin{pmatrix} 1, &1 \\ 0, & 1 \end{pmatrix}=(1,2), q^{2}=(1,0)\begin{pmatrix} 1, &1 \\ 0, & 1 \end{pmatrix}=(1,1)

因为Transformer是并行化的,可以直接写成:

\begin{pmatrix} q^{1}\\ q^{2} \end{pmatrix}=\begin{pmatrix} 1, &1 \\ 1, &0 \end{pmatrix}\begin{pmatrix} 1, &1 \\ 0, &1 \end{pmatrix}=\begin{pmatrix} 1, &2 \\ 1, &1 \end{pmatrix}

同理可以得到\begin{pmatrix} k^{1}\\ k^{2} \end{pmatrix}\begin{pmatrix} v^{1}\\ v^{2} \end{pmatrix},那么求得的\begin{pmatrix} q^{1}\\ q^{2} \end{pmatrix}就是原论文中的Q,\begin{pmatrix} k^{1}\\ k^{2} \end{pmatrix}是K,\begin{pmatrix} v^{1}\\ v^{2} \end{pmatrix}是V。接着q^{1}和每个k进行match,点乘操作,接着除以\sqrt{d}得到对应的\alpha,其中d代表向量k^{i}的长度,除以\sqrt{d}的原因是在论文中的解释“进行点乘后数值很大,导致通过softmax后梯度变得很小”,所以通过\sqrt{d}进行缩放。

\alpha _{1,1}=\frac{q^{1}\cdot k^{1}}{\sqrt{d}}=\frac{1*1+2*0}{\sqrt{2}}=0.71\\ \alpha _{1,2}=\frac{q^{1}\cdot k^{2}}{\sqrt{d}}=\frac{1*0+2*1}{\sqrt{2}}=1.41

同理q^{2}去匹配所有的k能得到\alpha _{2,i},统一写成乘法矩阵形式:

\begin{pmatrix} \alpha _{1,1} & \alpha _{1,2} \\ \alpha _{2,1} & \alpha _{2,2} \end{pmatrix}=\frac{\begin{pmatrix} q^{1}\\ q^{2} \end{pmatrix}\begin{pmatrix} k^{1}\\ k^{2} \end{pmatrix}^{T}}{\sqrt{d}}

接着对每一行即(\alpha _{1,1},\alpha _{1,2}),(\alpha _{2,1},\alpha _{2,2})分别进行softmax处理得到(\widehat{\alpha} _{1,1},\widehat{\alpha} _{1,2}),(\widehat{\alpha} _{2,1},\widehat{\alpha} _{2,2}),这里的\widehat{\alpha }相当于计算得到针对每个v的权重。到这里完成了Attention(Q,K,V)公式中的softmax(\frac{QK^{T}}{\sqrt{d_{k}}})部分。

上面已经计算得到\alpha,即针对每个v的权重,接着进行加权得到最终结果

b_{1}=\widehat{\alpha }_{1,1}\times v^{1}+\widehat{\alpha }_{1,2}\times v^{2}=(0.33,0.67)\\ b_{2}=\widehat{\alpha }_{2,1}\times v^{1}+\widehat{\alpha }_{2,2}\times v^{2}=(0.50,0.50)

统一写成矩阵乘法形式:

\begin{pmatrix} b_{1}\\ b_{2} \end{pmatrix}=\begin{pmatrix} \widehat{\alpha }_{1,1} & \widehat{\alpha }_{1,2}\\ \widehat{\alpha }_{2,1}& \widehat{\alpha }_{2,2} \end{pmatrix}\begin{pmatrix} v^{1}\\ v^{2} \end{pmatrix}

Self-Attention的内容就结束了,总结下来就是论文中一个公式:

 Attention(Q,K,V)=softmax(\frac{QK^{T}}{\sqrt{d_{k}}})V


Multi-Head Attention

多头注意力机制能联合来自不同head部分学习到的信息。

首先还是和Self-Attention模块一样将a_{i}分别通过W^{q},W^{k},W^{v}得到对应的q^{i},k^{i},v^{i},然后再根据使用的head的数目h进一步把得到的q^{i},k^{i},v^{i}均分成h份。比如下图中假设的h=2然后q^{1}拆分成q^{1,1},q^{1,2},那么q^{1,1}就属于head1,q^{1,2}属于head2。

论文中写的通过W_{i}^{Q},W_{i}^{K},W_{i}^{V}映射得到每个head的Q_{i},K_{i},V_{i}:

head_{i}=Attention(QW_{i}^{Q},KW_{i}^{K},VW_{i}^{V})

其实简单的均分也可以将W_{i}^{Q},W_{i}^{K},W_{i}^{V}设置成对应值来实现均分,比如下图中的Q通过W_{1}^{Q}就能得到均分后的Q_{1}

通过上述方法就能得到每个headi对应的Q_{i},K_{i},V_{i}参数,接下来针对每个head使用Self-Atttention中相同的方法即可得到对应的结果。

Attention(Q_{i},K_{i},V_{i})=softmax(\frac{Q_{i}K_{i}^{T}}{\sqrt{d_{k}}})V_{i}

接着将每个head得到的结果进行concat拼接,比如下图中b1,1(head1得到的b1)和b1,2(head2得到的b1)拼接在一起,b2,1(head得到的b2)和b2,2(head得到的b2)拼接在一起。

接着将拼接后的结果通过W^{O}(可学习的参数)进行融合,如下图,融合后得到最终的结果b1,b2

到这,总结下来就是论文中的两个公式:

MultiHead(Q,K,V)=Concat(head_{1},...,heah_{h})W^{O}\\ where head_{i}=Attention(QW_{i}^{Q},KW_{i}^{K},VW_{i}^{V})

import torch
from fvcore.nn import FlopCountAnalysisdef main():#Self-Attentiona1 = torch.nn.MultiheadAttention(embed_dim=512, num_heads=1)a1.proj = torch.nn.Identity() #removr Wo#Multi-Head Attentiona2 = torch.nn.MultiheadAttention(embed_dim=512, num_heads=8)#[batch_szie,num_tokens,total_embed_dim]t = torch.rand(32, 1024, 512)flops1 = FlopCountAnalysis(a1, t)print("Self-Attention FLOPs:", flops1.total())flops2 = FlopCountAnalysis(a2, t)print("Multi-Head Attention FLOPs:",flops2.total())if __name__ == '__main__':main()
Self-Attention FLOPs: 60129542144
Multi-Head Attention FLOPs: 68719476736

其实两者FLOPs的差异只是在最后的W^{O}上,如果把Multi-Head Attentio的W^{O}也删除(即把a2的proj也设置成Identity),可以看出两者FLOPs是一样的:

Self-Attention FLOPs: 60129542144
Multi-Head Attention FLOPs: 60129542144

Positional Encoding

刚才计算是没有考虑到位置信息的。假设在Self-Attention模块中,输入a1,a2,a3得到b1,b2,b3。对于a1而言,a2和a3离它都是一样近且没有先后顺序。假设将输入的顺序改为a1,a2,a3,对结果b1是没有任何影响的。下面是Pytorch的实验,首先使用nn.MultiheadAttention创建一个Self-Attention模块(num_heads=1),注意这里在正向传播过程中直接传入QKV,接着创建两个顺序不同的QKV变量t1和t2(主要是将q2,k2,v2和q3,k3,v3的顺序换了下),分别将这两个变量输入Self-Attention模块进行正向传播。

import torch
import torch.nn as nnm = nn.MultiheadAttention(embed_dim=2, num_heads=1)t1 = [[[1., 2.], #q1,k1,v1[2., 3.], #q2,k2,v2[3., 4.]]] #q3,k3,v3t2 = [[[1., 2.], #q1,k1,v1[3., 4.], #q3,k3,v3[2., 3.]]] #q2,k2,v2q, k, v  = torch.as_tensor(t1), torch.as_tensor(t1), torch.as_tensor(t1)
print("result:\n", m(q, k, v))q, k, v = torch.as_tensor(t2), torch.as_tensor(t2), torch.as_tensor(t2)
print("result2:\n", m(q, k , v))

即使调换了qkv顺序,但对b1是没有影响的。

为了引入位置信息,原论文引入了位置编码positional encoding。如下图所示,位置编码是直接加在输入的a={a1,...,an}中的,即pe={pe1,...,pen}和a={a1,...,an}拥有相同维度大小。关于位置编码在原论文有提出两种方案,一种是原论文中使用的固定编码,即论文中给出的sine and cosine funtions方法,按照该方法可计算出位置编码;另一种是可训练的位置编码。ViT论文中使用的是可训练的位置编码。positional encoding


超参对比

关于Transformer中的一些超参数的实验对比可以参考原论文,其中:

N表示重复堆叠的Transformer Block的次数

dmodel表示Multi-Head Self-Attention输入输出的token维度(向量长度)

dff表示在MLP(feed forward)中隐层的节点个数

h表示Multi-Head Self-Attention中的head的个数

dk,dv表示Multi-Head Self-Attention 中每个head的key(K)以及query(Q)的维度

Pdrop表示dropout层的drop_rate

这篇关于Transformer中的Self-Attention和Multi-Head Attention的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1071130

相关文章

2014 Multi-University Training Contest 8小记

1002 计算几何 最大的速度才可能拥有无限的面积。 最大的速度的点 求凸包, 凸包上的点( 注意不是端点 ) 才拥有无限的面积 注意 :  凸包上如果有重点则不满足。 另外最大的速度为0也不行的。 int cmp(double x){if(fabs(x) < 1e-8) return 0 ;if(x > 0) return 1 ;return -1 ;}struct poin

2014 Multi-University Training Contest 7小记

1003   数学 , 先暴力再解方程。 在b进制下是个2 , 3 位数的 大概是10000进制以上 。这部分解方程 2-10000 直接暴力 typedef long long LL ;LL n ;int ok(int b){LL m = n ;int c ;while(m){c = m % b ;if(c == 3 || c == 4 || c == 5 ||

2014 Multi-University Training Contest 6小记

1003  贪心 对于111...10....000 这样的序列,  a 为1的个数,b为0的个数,易得当 x= a / (a + b) 时 f最小。 讲串分成若干段  1..10..0   ,  1..10..0 ,  要满足x非递减 。  对于 xi > xi+1  这样的合并 即可。 const int maxn = 100008 ;struct Node{int

什么是 Flash Attention

Flash Attention 是 由 Tri Dao 和 Dan Fu 等人在2022年的论文 FlashAttention: Fast and Memory-Efficient Exact Attention with IO-Awareness 中 提出的, 论文可以从 https://arxiv.org/abs/2205.14135 页面下载,点击 View PDF 就可以下载。 下面我

跟我一起玩《linux内核设计的艺术》第1章(四)——from setup.s to head.s,这回一定让main滚出来!(已解封)

看到书上1.3的大标题,以为马上就要见着main了,其实啊,还早着呢,光看setup.s和head.s的代码量就知道,跟bootsect.s没有可比性,真多……这确实需要包括我在内的大家多一些耐心,相信见着main后,大家的信心和干劲会上一个台阶,加油! 既然上篇已经玩转gdb,接下来的讲解肯定是边调试边分析书上的内容,纯理论讲解其实我并不在行。 setup.s: 目标:争取把setup.

图神经网络框架DGL实现Graph Attention Network (GAT)笔记

参考列表: [1]深入理解图注意力机制 [2]DGL官方学习教程一 ——基础操作&消息传递 [3]Cora数据集介绍+python读取 一、DGL实现GAT分类机器学习论文 程序摘自[1],该程序实现了利用图神经网络框架——DGL,实现图注意网络(GAT)。应用demo为对机器学习论文数据集——Cora,对论文所属类别进行分类。(下图摘自[3]) 1. 程序 Ubuntu:18.04

ElasticSearch 6.1.1 通过Head插件,新建索引,添加文档,及其查询数据

ElasticSearch 6.1.1 通过Head插件,新建索引,添加文档,及其查询; 一、首先启动相关服务: 二、新建一个film索引: 三、建立映射: 1、通过Head插件: POST http://192.168.1.111:9200/film/_mapping/dongzuo/ {"properties": {"title": {"type":

Windows环境下ElasticSearch6.1.1版本安装Head插件

安装Head插件步骤如下: 1、下载node.js ,网址:https://nodejs.org/en/ 安装node到D盘。如D:\nodejs。 把NODE_HOME设置到环境变量里(安装包也可以自动加入PATH环境变量)。测试一下node是否生效: 2、安装grunt grunt是一个很方便的构建工具,可以进行打包压缩、测试、执行等等的工作,5.0里的head插件就是通过grunt

Transformer从零详细解读

Transformer从零详细解读 一、从全局角度概况Transformer ​ 我们把TRM想象为一个黑盒,我们的任务是一个翻译任务,那么我们的输入是中文的“我爱你”,输入经过TRM得到的结果为英文的“I LOVE YOU” ​ 接下来我们对TRM进行细化,我们将TRM分为两个部分,分别为Encoders(编码器)和Decoders(解码器) ​ 在此基础上我们再进一步细化TRM的

LLM模型:代码讲解Transformer运行原理

视频讲解、获取源码:LLM模型:代码讲解Transformer运行原理(1)_哔哩哔哩_bilibili 1 训练保存模型文件 2 模型推理 3 推理代码 import torchimport tiktokenfrom wutenglan_model import WutenglanModelimport pyttsx3# 设置设备为CUDA(如果可用),否则使用CPU#