7 注意力机制介绍2
00 min
2024-4-23
notion image
notion image
自然语言处理基础V4.0
7 注意力机制介绍2
notion image
notion image
notion image
notion image
正在初始化搜索引擎
notion image
notion image
自然语言处理基础V4.0 第一章 自然语言处理入门 第一章 自然语言处理入门
第二章 文本预处理 第二章 文本预处理
第三章 RNN及其变体 第三章 RNN及其变体
7 注意力机制介绍2
目录
第四章 Transformer 第四章 Transformer
第五章 迁移学习 第五章 迁移学习
第六章 Bert系列模型 第六章 Bert系列模型
第七章 Transformer精选问答(拓展资料) 第七章 Transformer精选问答(拓展资料)
目录

7 注意力机制介绍2

学习目标

  • 了解什么是注意力计算规则以及常见的计算规则
  • 了解什么是注意力机制及其作用
  • 掌握注意力机制的实现步骤

1 注意力机制规则

  • 它需要三个指定的输入Q(query), K(key), V(value), 然后通过计算公式得到注意力的结果, 这个结果代表query在key和value作用下的注意力表示. 当输入的Q=K=V时, 称作自注意力计算规则;当Q、K、V不相等时称为一般注意力计算规则
例子:seq2seq架构翻译应用中的Q、K、V解释
notion image
  • seq2seq模型架构包括三部分,分别是encoder(编码器)、decoder(解码器)、中间语义张量c。
  • 图中表示的是一个中文到英文的翻译:欢迎 来 北京 → welcome to BeiJing。编码器首先处理中文输入"欢迎 来 北京",通过GRU模型获得每个时间步的输出张量,最后将它们拼接成一个中间语义张量c;接着解码器将使用这个中间语义张量c以及每一个时间步的隐层张量, 逐个生成对应的翻译语言.
  • 在上述机器翻译架构中加入Attention的方式有两种:
  • 第一种tensorflow版本(传统方式),如下图所示:
notion image
上图翻译应用中的Q、K、V解释
  • 查询张量Q: 解码器每一步输出或者是当前输入的x
  • 键张量K: 编码部分每个时间步的结果组合而成
  • 值张量V:编码部分每个时间步的结果组合而成
  • 第二种Pytorch版本(改进版),如下图所示:
notion image
上图翻译应用中的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 常见的注意力计算规则

  • 将Q,K进行纵轴拼接, 做一次线性变化, 再使用softmax处理获得结果最后与V做张量乘法. $$ Attention(Q,K,V)=Softmax(Linear([Q,K]))\cdot V $$
  • 将Q,K进行纵轴拼接, 做一次线性变化后再使用tanh函数激活, 然后再进行内部求和, 最后使用softmax处理获得结果再与V做张量乘法. $$ Attention(Q,K,V)=Softmax(sum(tanh(Linear([Q,K]))))\cdot V $$
  • 将Q与K的转置做点积运算, 然后除以一个缩放系数, 再使用softmax处理获得结果最后与V做张量乘法. $$ Attention(Q,K,V)=Softmax(\frac{Q\cdot K^T}{\sqrt{d_{k}}})\cdot V $$
  • 说明:当注意力权重矩阵和V都是三维张量且第一维代表为batch条数时, 则做bmm运算.bmm是一种特殊的张量乘法运算.
  • bmm运算演示:
# 如果参数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).
注意力机制在网络中实现的图形表示:
notion image

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 32 def __init__(self, query_size, key_size, value_size1, value_size2, output_size): super(MyAtt, self).__init__() self.query_size = query_size self.key_size = key_size self.value_size1 = value_size1 self.value_size2 = value_size2 self.output_size = output_size # 线性层1 注意力权重分布 self.attn = nn.Linear(self.query_size + self.key_size, self.value_size1) # 线性层2 注意力结果表示按照指定维度输出层 self.attn_combine self.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 = 32 key_size = 32 value_size1 = 32 # 32个单词 value_size2 = 64 # 64个特征 output_size = 32 Q = 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>)
  • 更多有关注意力机制的应用我们将在案例中进行详尽的理解分析.

5 小结

  • 学习了什么是注意力计算规则:
    • 它需要三个指定的输入Q(query), K(key), V(value), 然后通过计算公式得到注意力的结果, 这个结果代表query在key和value作用下的注意力表示. 当输入的Q=K=V时, 称作自注意力计算规则.
  • 常见的注意力计算规则:
    • 将Q,K进行纵轴拼接, 做一次线性变化, 再使用softmax处理获得结果最后与V做张量乘法.
    • 将Q,K进行纵轴拼接, 做一次线性变化后再使用tanh函数激活, 然后再进行内部求和, 最后使用softmax处理获得结果再与V做张量乘法.
    • 将Q与K的转置做点积运算, 然后除以一个缩放系数, 再使用softmax处理获得结果最后与V做张量乘法.
  • 学习了什么是深度学习注意力机制:
    • 注意力机制是注意力计算规则能够应用的深度学习网络的载体, 同时包括一些必要的全连接层以及相关张量处理, 使其与应用网络融为一体. 使自注意力计算规则的注意力机制称为自注意力机制.
  • 注意力机制的作用:
    • 在解码器端的注意力机制: 能够根据模型目标有效的聚焦编码器的输出结果, 当其作为解码器的输入时提升效果. 改善以往编码器输出是单一定长张量, 无法存储过多信息的情况.
    • 在编码器端的注意力机制: 主要解决表征问题, 相当于特征提取过程, 得到输入的注意力表示. 一般使用自注意力(self-attention).
  • 注意力机制实现步骤:
    • 第一步: 根据注意力计算规则, 对Q,K,V进行相应的计算.
    • 第二步: 根据第一步采用的计算方法, 如果是拼接方法,则需要将Q与第二步的计算结果再进行拼接, 如果是转置点积, 一般是自注意力, Q与V相同, 则不需要进行与Q的拼接.
    • 第三步: 最后为了使整个attention机制按照指定尺寸输出, 使用线性层作用在第二步的结果上做一个线性变换, 得到最终对Q的注意力表示.
  • 学习并实现了一种常见的注意力机制的类Attn.
notion image
上一页 6 注意力机制介绍1
下一页 8 RNN案例 seq2seq英译法
notion image