0基础跟德姆(dom)一起学AI 自然语言处理13-注意力机制介绍2

server/2025/1/16 23:37:13/

1 注意力机制规则

  • 它需要三个指定的输入Q(query), K(key), V(value), 然后通过计算公式得到注意力的结果, 这个结果代表query在key和value作用下的注意力表示. 当输入的Q=K=V时, 称作自注意力计算规则;当Q、K、V不相等时称为一般注意力计算规则

例子:seq2seq架构翻译应用中的Q、K、V解释

  • seq2seq模型架构包括三部分,分别是encoder(编码器)、decoder(解码器)、中间语义张量c。
  • 图中表示的是一个中文到英文的翻译:欢迎 来 北京 → welcome to BeiJing。编码器首先处理中文输入"欢迎 来 北京",通过GRU模型获得每个时间步的输出张量,最后将它们拼接成一个中间语义张量c;接着解码器将使用这个中间语义张量c以及每一个时间步的隐层张量, 逐个生成对应的翻译语言.
  • 在上述机器翻译架构中加入Attention的方式有两种:
  • 第一种tensorflow版本(传统方式),如下图所示:

上图翻译应用中的Q、K、V解释

  • 查询张量Q: 解码器每一步输出或者是当前输入的x
  • 键张量K: 编码部分每个时间步的结果组合而成
  • 值张量V:编码部分每个时间步的结果组合而成
  • 第二种Pytorch版本(改进版),如下图所示:

上图翻译应用中的Q、K、V解释

  • 查询张量Q: 解码器每一步的输出或者是当前输入的x
  • 键张量K: 解码器上一步的隐藏层输出
  • 值张量V:编码部分每个时间步输出结果组合而成
  • 两个版本对比:
  • pytorch版本的是乘型attention,tensorflow版本的是加型attention。pytorch这里直接将与上一个unit隐状态prev_hidden拼接起来✖W得到score,之后将score过softmax得到attenion_weights.
  • 解码过程如下:
  • (1)采用自回归机制,比如:输入“go”来预测“welcome”,输入“welcome”来预测"to",输入“to”来预测“Beijing”。在输入“welcome”来预测"to"解码中,可使用注意力机制
  • (2)查询张量Q:一般可以是“welcome”词嵌入层以后的结果,查询张量Q为生成谁就是谁的查询张量(比如这里为了生成“to”,则查询张量就是“to”的查询张量,请仔细体会这一点)
  • (3) 键向量K:一般可以是上一个时间步的隐藏层输出
  • (4)值向量V:一般可以是编码部分每个时间步的结果组合而成
  • (5)查询张量Q来生成“to”,去检索“to”单词和“欢迎”、“来”、“北京”三个单词的权重分布,注意力结果表示(用权重分布 乘以内容V)

1.3 常见的注意力计算规则

# 如果参数1形状是(b × n × m), 参数2形状是(b × m × p), 则输出为(b × n × p)
>>> input = torch.randn(10, 3, 4)
>>> mat2 = torch.randn(10, 4, 5)
>>> res = torch.bmm(input, mat2)
>>> res.size()
torch.Size([10, 3, 5])

2 什么是深度神经网络注意力机制

  • 注意力机制是注意力计算规则能够应用的深度学习网络的载体, 同时包括一些必要的全连接层以及相关张量处理, 使其与应用网络融为一体. 使用自注意力计算规则的注意力机制称为自注意力机制.

  • 说明: NLP领域中, 当前的注意力机制大多数应用于seq2seq架构, 即编码器和解码器模型.

  • 请思考:为什么要在深度神经网络中引入注意力机制?

    • 1、rnn等循环神经网络,随着时间步的增长,前面单词的特征会遗忘,造成对句子特征提取不充分
    • 2、rnn等循环神经网络是一个时间步一个时间步的提取序列特征,效率低下
    • 3、研究者开始思考,能不能对32个单词(序列)同时提取事物特征,而且还是并行的,所以引入注意力机制!

3 注意力机制的作用

  • 在解码器端的注意力机制: 能够根据模型目标有效的聚焦编码器的输出结果, 当其作为解码器的输入时提升效果. 改善以往编码器输出是单一定长张量, 无法存储过多信息的情况.
  • 在编码器端的注意力机制: 主要解决表征问题, 相当于特征提取过程, 得到输入的注意力表示. 一般使用自注意力(self-attention).

注意力机制在网络中实现的图形表示:

4 注意力机制实现步骤

4.1 步骤

  • 第一步: 根据注意力计算规则, 对Q,K,V进行相应的计算.
  • 第二步: 根据第一步采用的计算方法, 如果是拼接方法,则需要将Q与第二步的计算结果再进行拼接, 如果是转置点积, 一般是自注意力, Q与V相同, 则不需要进行与Q的拼接.
  • 第三步: 最后为了使整个attention机制按照指定尺寸输出, 使用线性层作用在第二步的结果上做一个线性变换, 得到最终对Q的注意力表示.

4.2 代码实现

  • 常见注意力机制的代码分析:
# 任务描述:
# 有QKV:v是内容比如32个单词,每个单词64个特征,k是32个单词的索引,q是查询张量
# 我们的任务:输入查询张量q,通过注意力机制来计算如下信息:
# 1、查询张量q的注意力权重分布:查询张量q和其他32个单词相关性(相识度)
# 2、查询张量q的结果表示:有一个普通的q升级成一个更强大q;用q和v做bmm运算
# 3 注意:查询张量q查询的目标是谁,就是谁的查询张量。
#   eg:比如查询张量q是来查询单词"我",则q就是我的查询张量import torch
import torch.nn as nn
import torch.nn.functional as F# MyAtt类实现思路分析
# 1 init函数 (self, query_size, key_size, value_size1, value_size2, output_size)
# 准备2个线性层 注意力权重分布self.attn 注意力结果表示按照指定维度进行输出层 self.attn_combine
# 2 forward(self, Q, K, V):
# 求查询张量q的注意力权重分布, attn_weights[1,32]
# 求查询张量q的注意力结果表示 bmm运算, attn_applied[1,1,64]
# q 与 attn_applied 融合,再按照指定维度输出 output[1,1,32]
# 返回注意力结果表示output:[1,1,32], 注意力权重分布attn_weights:[1,32]class MyAtt(nn.Module):#                   32          32          32              64      32def __init__(self, query_size, key_size, value_size1, value_size2, output_size):super(MyAtt, self).__init__()self.query_size = query_sizeself.key_size = key_sizeself.value_size1 = value_size1self.value_size2 = value_size2self.output_size = output_size# 线性层1 注意力权重分布self.attn = nn.Linear(self.query_size + self.key_size, self.value_size1)# 线性层2 注意力结果表示按照指定维度输出层 self.attn_combineself.attn_combine = nn.Linear(self.query_size+self.value_size2, output_size)def forward(self, Q, K, V):# 1 求查询张量q的注意力权重分布, attn_weights[1,32]# [1,1,32],[1,1,32]--> [1,32],[1,32]->[1,64]# [1,64] --> [1,32]# tmp1 = torch.cat( (Q[0], K[0]), dim=1)# tmp2 = self.attn(tmp1)# tmp3 = F.softmax(tmp2, dim=1)attn_weights = F.softmax( self.attn(torch.cat( (Q[0], K[0]), dim=-1)), dim=-1)# 2 求查询张量q的结果表示 bmm运算, attn_applied[1,1,64]# [1,1,32] * [1,32,64] ---> [1,1,64]attn_applied =  torch.bmm(attn_weights.unsqueeze(0), V)# 3 q 与 attn_applied 融合,再按照指定维度输出 output[1,1,64]# 3-1 q与结果表示拼接 [1,32],[1,64] ---> [1,96]output = torch.cat((Q[0], attn_applied[0]), dim=-1)# 3-2 shape [1,96] ---> [1,32]output = self.attn_combine(output).unsqueeze(0)# 4 返回注意力结果表示output:[1,1,32], 注意力权重分布attn_weights:[1,32]return output, attn_weights
  • 调用:
if __name__ == '__main__':query_size = 32key_size = 32value_size1 = 32 # 32个单词value_size2 = 64 # 64个特征output_size = 32Q = torch.randn(1, 1, 32)K = torch.randn(1, 1, 32)V = torch.randn(1, 32, 64)# V = torch.randn(1, value_size1, value_size2)# 1 实例化注意力类 对象myattobj = MyAtt(query_size, key_size, value_size1, value_size2, output_size)# 2 把QKV数据扔给注意机制,求查询张量q的注意力结果表示、注意力权重分布output, attn_weights = myattobj(Q, K, V)print('查询张量q的注意力结果表示output--->', output.shape, output)print('查询张量q的注意力权重分布attn_weights--->', attn_weights.shape, attn_weights)
  • 输出效果:
查询张量q的注意力结果表示output---> torch.Size([1, 1, 32]) tensor([[[ 0.3135, -0.0539,  0.0597, -0.0046, -0.3389, -0.1238,  1.0385,0.8896, -0.0268, -0.0705, -0.8409,  0.6547,  0.5909, -0.6048,0.6303, -0.2233,  0.7678, -0.3140,  0.3635, -0.3234, -0.1053,0.5845,  0.1163, -0.2203, -0.0812, -0.0868,  0.0218, -0.0597,0.6923, -0.1848, -0.8266, -0.0614]]], grad_fn=<UnsqueezeBackward0>)
查询张量q的注意力权重分布attn_weights---> torch.Size([1, 32]) tensor([[0.0843, 0.0174, 0.0138, 0.0431, 0.0110, 0.0308, 0.0608, 0.0216, 0.0101,0.0406, 0.0462, 0.0111, 0.0349, 0.0065, 0.0383, 0.0526, 0.0151, 0.0193,0.0294, 0.0632, 0.0322, 0.0072, 0.0294, 0.0388, 0.0135, 0.0443, 0.0594,0.0332, 0.0117, 0.0168, 0.0293, 0.0344]], grad_fn=<SoftmaxBackward0>)

http://www.ppmy.cn/server/158940.html

相关文章

如何清理docker垃圾

使用 Docker 命令清理 清理未使用的容器、网络、镜像和构建缓存&#xff1a; 收起 plaintext docker system prune -a该命令会删除所有未被引用的资源&#xff0c;包括未使用的容器、网络、映像和构建缓存等。如果想要强制删除而不进行提示确认&#xff0c;可以添加-f选项&…

HTML5 滚动动画详解

HTML5 滚动动画详解 滚动动画是一种在用户滚动网页时触发的动态效果&#xff0c;可以增强用户体验并吸引用户注意力。下面将介绍如何使用 HTML5 和 CSS 创建简单的滚动动画。 1. 基本概念 滚动动画通常涉及以下几个要素&#xff1a; 触发条件&#xff1a;用户滚动到特定位置…

征服Windows版nginx(2)

1.配置Nginx 编辑Nginx的配置文件&#xff08;通常是nginx.conf&#xff09;&#xff0c;找到安装Nginx位置&#xff0c;如下路径&#xff1a; D:\nginx-1.26.2\conf 双击打开nginx.CONF编辑&#xff0c;在http块中添加一个新的server块&#xff0c;用于指定Vue项目的静态文件…

49_Lua调试

Lua提供了debug库用于创建自定义调试器,尽管Lua本身没有内置的调试器1。这个库允许开发者在程序运行时检查和控制执行流程,这对于开发过程中的错误查找和修复非常有用。 1.Debug库概述 debug库提供的函数可以分为两类:自省函数(introspection functions)和钩子函数(hoo…

Java并发编程——线程池(基础,使用,拒绝策略,命名,提交方式,状态)

文章目录 线程池&#x1f3ca;线程池的好处&#x1f44d;线程池的创建&#x1f3d7;️线程池(ThreadPoolExecutor)常见参数&#x1f522;处理任务流程&#x1f503;拒绝策略⭐使用数据库任务表来自定义拒绝策略 线程池中两种提交方式线程池命名♂️♀️线程池状态 线程池&#…

IDEA测试报错java.lang.NullPointerException空指针异常解决办法

已知我运行的是测试函数&#xff0c;但是会报错java.lang.NullPointerException空指针异常 这是由于测试使用的包不匹配。 在pom.xml中查看spring boot版本 在SpringBoot 2.2的版本之前 Junit4&#xff1a;org.junit.Test SpringBoot 2.2之后使用的是 Junit5&#xff1a;org.…

计算机网络 (37)TCP的流量控制

前言 计算机网络中的TCP&#xff08;传输控制协议&#xff09;流量控制是一种重要机制&#xff0c;用于确保数据在发送方和接收方之间的传输既高效又稳定。 一、目的 TCP流量控制的主要目的是防止发送方发送数据过快&#xff0c;导致接收方无法及时处理&#xff0c;从而引起数据…

学技术学英语:ELK是什么

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#xff1a; 先看关键单词&#xff0c;再看英文&#xff0c;最后看中文总结&#xff0c;再回头看一遍英文原文&#xff0c;效果更佳&#xff01;&#xff01; 关键词 aggregate 聚合 /ˈɡrɪɡeɪt/ analytics 分析学 /ˌnəˈl…