Advertisement

【PyTorch][chapter 26][李宏毅深度学习][attention-2]

阅读量:

前言:

Multi-Head Attention 的主要作用是:将 Q、K、V 向量按不同头分割为多个子语义空间


目录:

  1. attention 机制
  2. Multi-Head Attention

一 attention 注意力

Self-Attention(自注意力机制):该机制使输入序列中的每个元素都能够关注并赋予权重整个序列中的其他元素,在生成新的输出表示的同时不受外部信息或历史状态的影响。

将查询Query,键Key,值Value 映射 到输出。

查询Query,键Key, 值Value 都是向量.

其输出为 值的加权求和。

1.1 mask 作用

1.2 scale 作用

复制代码
 # -*- coding: utf-8 -*-

    
 """
    
 Created on Tue Jul 16 11:21:33 2024
    
   5. @author: chengxf2
    
 """
    
 import torch
    
 import math
    
  
    
 def attention(query,key ,value, mask=None):
    
     #[batchSize, seq_num, query_dim]
    
     d_k = query.size(-1)
    
     print(d_k)
    
     attentionMatrix = torch.matmul(query, key.transpose(-2,-1))
    
     
    
     scores = attentionMatrix/math.sqrt(d_k)
    
     
    
     if mask is not None:
    
     scores = scores.mask_fill(mask==0, -1e9)
    
  
    
     p_attn = torch.softmax(scores, dim=-1)
    
     out = torch.matmul(p_attn, value)
    
     return out
    
     
    
  
    
 seq_len = 5
    
 hid_dim = 10
    
 out_len =3
    
  
    
 query = torch.rand((seq_len,hid_dim))
    
 key =  torch.rand_like(query)
    
 value = torch.rand((seq_len, out_len))
    
  
    
 attention(query, key, value)

二 Multi-Head Attention

多头注意力机制的主要理论依据是信息在不同维度上的多样化表示这一核心理论。通过将输入向量在多个子空间中进行映射,在各个子空间独立地进行自注意力计算后汇总结果的方式下实现特征交互作用的建模,并且这种设计使得模型能够更全面地捕捉和表达复杂的特征关系

2,1 第一步:查询Q、键K 和值V 矩阵的 生成

输入:

张量A

shape: [batch, seq_len, input_dim]

输出:

Q,K,V

shape:[batch,seq_len, query_dim]


(下面以输入seq_len=2 ,为例)

Q=AW_Q
K=AW_K
V=AW_V

其中下面三个矩阵是需要学习的矩阵:

W_Q,W_K,W_V

的shape 为【input_dim, query_dim]

2.2 第二步:子空间投影

Q,K V 乘以对应的Head 矩阵,得到对应的mulite-head Q,K,V

以 Query张量为例: 实现的时候先乘以Head 矩阵

O=QW_H

,然后再通过View 功能

分割成子空间。

第三步: 对不同Head 的Q,K,V

做self-attention,得到不同Head 的

b^i

第四步: concate

导入 torch 库

从 torch.nn 导入神经网络模块

我们假设有一个包含查询、键和值的张量集合

query = torch.rand(10, 8, 64) # (batch_size, n_query, d_model)
key = value = query # 为了简化计算,在本示例中使用相同的张量作为键和值

创建一个四头注意力机制实例,并指定嵌入维度为64

multihead_attn = nn.MultiheadAttention(embed_dim=64, num_heads=4)

通过多头注意力机制处理输入张量序列

output, attention_weights = multihead_attn(query, key, value)

输出结果信息

print("输出形状: ", output.shape) # 输出: torch.Size([10, 8, 64])
print("注意力权重形状: ", attention_weights.shape) # 输出: torch.Size([10, 4, 8, 8])

复制代码
 # -*- coding: utf-8 -*-

    
 """
    
 Created on Wed Jul 17 09:46:40 2024
    
   5. @author: chengxf2
    
 """
    
  
    
 import torch
    
 import torch.nn as nn
    
 import copy
    
 import math
    
 from torchsummary import summary 
    
 import netron
    
 def clones(module, N):
    
     
    
     "生成N 个 相同的层"
    
     
    
     layers = nn.ModuleList(
    
     
    
     [copy.deepcopy(module)  for _ in range(N)]
    
     )
    
     
    
     return layers
    
  
    
 def attention(query, key ,value):
    
     
    
      #输出[batch, head_num, seq_len,query_dim ]
    
   
    
      seq_num = query.size(-1)
    
      
    
      scores = torch.matmul(query, key.transpose(-2,-1))
    
      
    
      scores = scores/math.sqrt(seq_num)
    
      
    
      p_attn = torch.softmax(scores, dim=-1)
    
      
    
      out = torch.matmul(p_attn, value)
    
      print("\n out.shape",out.shape)
    
      return out, p_attn
    
  
    
 class  MultiHeadedAttention(nn.Module):
    
     
    
     def __init__(self, head_num, query_dim):
    
     
    
     super(MultiHeadedAttention, self).__init__()
    
     self.head_num = head_num
    
     self.sub_query_dim = query_dim//head_num
    
    
    
     self.linears = clones(nn.Linear(query_dim,query_dim), 4)
    
     self.attn = None
    
     
    
     
    
     def forward(self, query, key, value):
    
     #query.shape [batch, seq_num,query_dim]
    
     
    
     batchSz = query.size(0)
    
     #[batchsz, seq_num, head_num, query_dim]
    
     query, key, value = \
    
         [net(x).view(batchSz, -1, self.head_num, self.sub_query_dim).transpose(1, 2)
    
          for net, x in zip(self.linears, (query, key, value))]
    
    
    
     #输出[batch, head_num, seq_len,sub_query_dim ]
    
    
    
     x, self.attn = attention(query, key, value)
    
     print("\n attn ",self.attn)
    
     
    
     x = x.transpose(1,2).contiguous().view(batchSz,-1,self.head_num*self.sub_query_dim)
    
     
    
     out = self.linears[-1](x)
    
     
    
     print(out.shape)
    
     return out
    
     
    
 if __name__ == "__main__":
    
     batchSz=1
    
     seq_num =2
    
     out_dim=query_dim =9
    
  
    
     head_num =3
    
     #下面这三个矩阵是需要学习的矩阵
    
     query = torch.randn((batchSz, seq_num, query_dim))
    
     key =  torch.rand_like(query)
    
     value =torch.randn((batchSz, seq_num, out_dim))
    
     
    
     
    
     model = MultiHeadedAttention(head_num,query_dim)
    
  
    
     model(query,key,value)
    
     
    
     print("\n 模型参数 \n ")
    
    
    
     input_size = (seq_num, query_dim)
    
     summary(model,[input_size,input_size,input_size])
    
     # 创建一个输入样本
    
     input_dict = {"x1": query, "x2": key, "x3":value}
    
  
    
     # 导出模型为ONNX格式
    
     torch.onnx.export(model,               # 模型实例
    
               (query,key,value),                   # 模型输入
    
               "model.onnx")
    
  
    
     netron.start('model.onnx') 

https://zhuanlan.zhihu.com/p/626820422

The Annotated Transformer

The Annotated Transformer

全部评论 (0)

还没有任何评论哟~