attention中Q,K,V的理解

  • 第一种

1.首先定义三个线性变换矩阵,query,key,value:

class BertSelfAttention(nn.Module):self.query = nn.Linear(config.hidden_size, self.all_head_size) # 输入768, 输出768self.key = nn.Linear(config.hidden_size, self.all_head_size) # 输入768, 输出768self.value = nn.Linear(config.hidden_size, self.all_head_size)

注意,这里的query, key, value只是一种操作(线性变换)的名称,实际的Q/K/V是它们三个的输出

 2.假设三种操作的输入都是同一个矩阵,这里暂且定长度为L的句子,每个token的特征维度是768,那输入就是(L,768),每一行就是一个字,像这样:

乘以上面三种操作就得到了Q、K、V,(L,768)*(768,768)=(L,768),维度其实没变,即此刻的Q、K、V分别为:

代码为:

class BertSelfAttention(nn.Module):def __init__(self, config):self.query = nn.Linear(config.hidden_size, self.all_head_size) # 输入768, 输出768self.key = nn.Linear(config.hidden_size, self.all_head_size) # 输入768, 输出768self.value = nn.Linear(config.hidden_size, self.all_head_size) # 输入768, 输出768def forward(self,hidden_states): # hidden_states 维度是(L, 768)Q = self.query(hidden_states)K = self.key(hidden_states)V = self.value(hidden_states)

3.然后实现这个操作:

① 首先是Q和K矩阵乘,(L, 768)*(L, 768)的转置=(L,L),看图:

首先用Q的第一行,即“我”字的768特征和K中“我”字的768为特征点乘求和,得到输出(0,0)位置的数值,这个数值就代表了“我想吃酸菜鱼”中“我”字对“我”字的注意力权重,然后显而易见输出的第一行就是“我”字对“我想吃酸菜鱼”里面每个字的注意力权重;整个结果自然就是“我想吃酸菜鱼”里面每个字对其它字(包括自己)的注意力权重(就是一个数值)了~

② 然后是除以根号dim,这个dim就是768,至于为什么要除以这个数值?主要是为了缩小点积范围,确保softmax梯度稳定性,具体推导可以看这里:Self-attention中dot-product操作为什么要被缩放

然后就是为什么要softmax,一种解释是为了保证注意力权重的非负性,同时增加非线性,还有一些工作对去掉softmax进行了实验,如PaperWeekly:线性Attention的探索:Attention必须有个Softmax吗?

③ 然后就是刚才的注意力权重V矩阵乘了,如图:

 注意力权重 x VALUE矩阵 = 最终结果

首先是“我”这个字对“我想吃酸菜鱼”这句话里面每个字的注意力权重,和V中“我想吃酸菜鱼”里面每个字的第一维特征进行相乘再求和,这个过程其实就相当于用每个字的权重对每个字的特征进行加权求和,然后再用“我”这个字对对“我想吃酸菜鱼”这句话里面每个字的注意力权重和V中“我想吃酸菜鱼”里面每个字的第二维特征进行相乘再求和,依次类推~最终也就得到了(L,768)的结果矩阵,和输入保持一致~

整个过程在草稿纸上画一画简单的矩阵乘就出来了,一目了然~最后上代码:

class BertSelfAttention(nn.Module):def __init__(self, config):self.query = nn.Linear(config.hidden_size, self.all_head_size) # 输入768, 输出768self.key = nn.Linear(config.hidden_size, self.all_head_size) # 输入768, 输出768self.value = nn.Linear(config.hidden_size, self.all_head_size) # 输入768, 输出768def forward(self,hidden_states): # hidden_states 维度是(L, 768)Q = self.query(hidden_states)K = self.key(hidden_states)V = self.value(hidden_states)attention_scores = torch.matmul(Q, K.transpose(-1, -2))attention_scores = attention_scores / math.sqrt(self.attention_head_size)attention_probs = nn.Softmax(dim=-1)(attention_scores)out = torch.matmul(attention_probs, V)return out

4. 为什么叫注意力网络?因为可以看到Q/K/V都是通过同一句话的输入算出来的,按照上面的流程也就是一句话内每个字对其它字(包括自己)的权重分配;那如果不是自注意力呢?简单来说,Q来自于句A,K、V来自于句B即可~

5. 注意,K/V中,如果同时替换任意两个字的位置,对最终的结果是不会有影响的,至于为什么,可以自己在草稿纸上画一画矩阵乘;也就是说注意力机制是没有位置信息的,不像CNN/RNN/LSTM;这也是为什么要引入位置embeding的原因。

  • 第二种

其实直接用邱锡鹏老师PPT里的一张图就可以直观理解——假设D是输入序列的内容,完全忽略线性变换的话可以近似认为Q=K=V=D(所以叫做Self-Attention,因为这是输入的序列对它自己的注意力),于是序列中的每一个元素经过Self-Attention之后的表示就可以这样展现:

也就是说,The这个词的表示,实际上是整个序列加权求和的结果——权重从哪来?点积之后Softmax得到——这里Softmax(QK)就是求权重的体现。我们知道,向量点积的值可以表征词与词之间的相似性,而此处的“整个序列”包括The这个词自己(再一次强调这是Self-Attention),所以最后输出的词的表示,其“主要成分”就主要地包含它自身和跟它相似的词的表示,其他无关的词的表示对应的权重就会比较低。

  • 第三种

首先附上链接:张俊林:深度学习中的注意力模型(2017版)这个几乎是我读到过的讲解Attention最为透彻的篇章之一了。

Q(Querry)代表查询值,对应Decoder的H(t-1)状态。这里要正确理解H(t-1),想要解码出t时刻的输出,你送入Decoder的必然有前一时刻计算出的隐状态。好了,所谓查询,就是你要拿着这个Decoder中的H(t-1)去和Encoder中各个时刻的隐状态[H(1), H(2), ... , H(T)](也就是各个Key)去比,也就是二者计算相似度(对应于文献中的各种energy函数)。最后算出来的结果用Softmax归一化,这个算出来的权重就是带有注意力机制的权重,其实在翻译任务中,Key和Value是相等的。在Transformer的实现源码中,Key和Value的初始值也是相等的。有了这个权重之后,就可以用这个权重对Value进行加权求和,生成的这个新的向量就是带有注意力机制的语义向量 Context vector,而这个语义向量会权衡Target与Source的token与token的关系,从而实现解码输出时,与Source中“真正有决定意义”的token关联。

姑且画蛇添足的再说几句:
首先,Attention机制是由Encoder-Decoder架构而来,且最初是用于完成NLP领域中的翻译(Translation)任务。那么输入输出就是非常明显的 Source-Target的对应关系,经典的Seq2Seq结构是从Encoder生成出一个语义向量(Context vector)而不再变化,然后将这个语义向量送入Decoder配合解码输出。这种方法的最大问题就是这个语义向量,我们是希望它一成不变好呢?还是它最好能配合Decoder动态调整自己,来使Target中的某些token与Source中的真正“有决定意义”的token关联起来好呢?

这就是为什么会有Attention机制的原因。说到底,Attention机制就是想生成会动态变化的语义向量来配合解码输出。而新贵 Self-Attention则是为了解决Target与Source各自内部token与token的关系。在Transformer中,这两种注意力机制得到了有机的统一,释放出了异常惊人的潜力。  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/234764.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

「Linux」使用C语言制作简易Shell

💻文章目录 📄前言简易shell实现shell的概念系统环境变量shell的结构定义内建命令完整代码 📓总结 📄前言 对于很多学习后端的同学来讲,学习了C语言,发现除了能写出那个经典的“hello world”以外&#xff…

代码随想录算法训练营第一天 | 704. 二分查找 27. 移除元素

class Solution { public:int search(vector<int>& nums, int target) {int l0;int rnums.size()-1;while(l<r){int mid(lr)>>1;if(targetnums[mid]) return mid;if(target>nums[mid]){lmid1;}else{rmid-1;}}return -1;} }; 之前就已经熟悉二分法了&am…

倒计时(JS计时器)

<script>function countDown() {document.body.innerHTML ;//清空页面内容var nowTimer new Date(); //现在时间的毫秒数var valueTimer new Date("2024-1-1 12:00"); //用户输入年份倒计时时间毫秒数var timer (valueTimer - nowTimer) / 1000; //倒计时秒…

量化误差的测量

因为转换的精度有限&#xff0c;所以将模拟值数字化时会不可避免地出现量化误差。量化误差由转换器及其误差、噪声和非线性度决定。当输入信号和计数器时基有区别时就会产生量化误差。根据输入信号的相位和计数器时基的匹配程度&#xff0c;计数器有下列三种可能性&#xff1a;…

JDK 动态代理从入门到掌握

快速入门 本文介绍 JDK 实现的动态代理及其原理&#xff0c;通过 ProxyGenerator 生成的动态代理类字节码文件 环境要求 要求原因JDK 8 及以下在 JDK 9 之后无法使用直接调用 ProxyGenerator 中的方法&#xff0c;不便于将动态代理类对应的字节码文件输出lombok为了使用 Sne…

性能测试:系统架构性能优化

今天谈下业务系统性能问题分析诊断和性能优化方面的内容。这篇文章重点还是谈已经上线的业务系统后续出现性能问题后的问题诊断和优化重点。 系统性能问题分析流程 我们首先来分析下如果一个业务系统上线前没有性能问题&#xff0c;而在上线后出现了比较严重的性能问题&#x…

Android Studio Giraffe版本遇到的问题

背景 上周固态硬盘挂了&#xff0c;恢复数据之后&#xff0c;重新换了新的固态安装了Win11系统&#xff0c;之前安装的是Android Studio 4.x的版本&#xff0c;这次也是趁着新的系统安装新的Android开发工具。 版本如下&#xff1a; 但是打开以前的Android旧项目时&#xff…

vue3 keep-alive页面切换报错:parentComponent.ctx.deactivate is not a function

问题&#xff1a; <router-view v-slot"{ Component }"><keep-alive ><component :is"Component" v-if"$route.meta.keepAlive" /></keep-alive><component :is"Component" v-if"!$route.meta.keepA…

PLC:200smart(13-16章)

PLC&#xff1a;200smart 第十三章2、带参子程序3、将子程序设置成库文件 第十三章 项目ValueValue主程序MAIN一个项目只能有一个&#xff0c;循环扫描子程序SBR_0项目中最多有128个&#xff0c;只有在调用时 才执行&#xff08;子程序可以嵌套其他子程序&#xff0c;最多八层…

STM32 启动文件分析

STM32 启动文件分析 基于STM32F103VET6芯片的 startup_stm32f10x_hd.s 启动文件分析 设置栈&#xff0c;将栈的大小Stack_Size设置为0x00004900&#xff08;18688/102418KB&#xff09;&#xff0c;即局部变量不能大于18KB。&#xff08;EQU等值指令&#xff0c;将0x0000490…

fiddler弱网测试实践

准备工作 1、fiddler安装包 2、一部安卓手机 一、fiddler安装 安装fiddler到电脑上&#xff0c;傻瓜式安装即可 二、fiddler环境配置 三、手机端环境配置 1、获取电脑的IP地址&#xff1a;WindowsR&#xff0c;输入cmd弹出命令窗口&#xff0c;输入命令ipconfig 或者鼠标…

无mac电脑生成uniapp云打包私钥证书的攻略

uniapp顾名思义是一个跨平台的开发工具&#xff0c;大部分uniapp的开发者&#xff0c;其实并没有mac电脑来开发&#xff0c;但是生成ios的证书&#xff0c;官网的教程却是需要mac电脑的&#xff0c;那么有没有办法无需mac电脑即可生成uniapp云打包的私钥证书呢&#xff1f; 下…