以下是一个简单的 PyTorch 实现多头注意力机制的代码示例,包括注释和变量维度:

import torch
import torch.nn as nn

# 定义一个多头注意力机制的模块
class MultiHeadAttention(nn.Module):
    def __init__(self, d_model, num_heads):
        super(MultiHeadAttention, self).__init__()
        self.d_model = d_model
        self.num_heads = num_heads
        
        assert d_model % num_heads == 0 # 确保能够平均分割
        
        # 定义查询、键、值的线性变换
        self.query_linear = nn.Linear(d_model, d_model)
        self.key_linear = nn.Linear(d_model, d_model)
        self.value_linear = nn.Linear(d_model, d_model)
        
        # 定义输出的线性变换
        self.output_linear = nn.Linear(d_model, d_model)
        
    def forward(self, query, key, value, mask=None):
        batch_size = query.size(0)
        
        # 进行线性变换并分割为多头
        query = self.query_linear(query).view(batch_size, -1, self.num_heads, self.d_model // self.num_heads).transpose(1,2) # shape: (batch_size, num_heads, seq_len, d_model // num_heads)
        key = self.key_linear(key).view(batch_size, -1, self.num_heads, self.d_model // self.num_heads).transpose(1,2) # shape: (batch_size, num_heads, seq_len, d_model // num_heads)
        value = self.value_linear(value).view(batch_size, -1, self.num_heads, self.d_model // self.num_heads).transpose(1,2) # shape: (batch_size, num_heads, seq_len, d_model // num_heads)
        
        # 进行注意力计算
        scores = torch.matmul(query, key.transpose(-2, -1)) / (self.d_model // self.num_heads)**0.5 # shape: (batch_size, num_heads, seq_len, seq_len)
        if mask is not None:
            scores = scores.masked_fill(mask==0, -1e9) # 进行mask操作,避免无效信息的影响
        attn_weights = nn.functional.softmax(scores, dim=-1) # shape: (batch_size, num_heads, seq_len, seq_len)
        attn_output = torch.matmul(attn_weights, value) # shape: (batch_size, num_heads, seq_len, d_model // num_heads)
        
        # 将多头的输出拼接起来,并进行线性变换
        concat_output = attn_output.transpose(1,2).contiguous().view(batch_size, -1, self.num_heads * (self.d_model // self.num_heads)) # shape: (batch_size, seq_len, d_model)
        output = self.output_linear(concat_output) # shape: (batch_size, seq_len, d_model)
        
        return output, attn_weights

变量维度的解释:

  • 'query':查询张量,shape为 '(batch_size, seq_len, d_model)'
  • 'key':键张量,shape为 '(batch_size, seq_len, d_model)'
  • 'value':值张量,shape为 '(batch_size, seq_len, d_model)'
  • 'mask':mask张量,shape为 '(batch_size, seq_len, seq_len)',其中无效信息的位置为0,有效信息的位置为1
  • 'query_linear':查询线性变换的全连接层,输入shape为 '(batch_size, seq_len, d_model)',输出shape为 '(batch_size, seq_len, d_model)'
  • 'key_linear':键线性变换的全连接层,输入shape为 '(batch_size, seq_len, d_model)',输出shape为 '(batch_size, seq_len, d_model)'
  • 'value_linear':值线性变换的全连接层,输入shape为 '(batch_size, seq_len, d_model)',输出shape为 '(batch_size, seq_len, d_model)'
  • 'query'、'key'、'value'的多头分割结果:shape分别为 '(batch_size, num_heads, seq_len, d_model // num_heads)'
  • 'scores':注意力分数张量,shape为 '(batch_size, num_heads, seq_len, seq_len)'
  • 'attn_weights':注意力权重张量,shape为 '(batch_size, num_heads, seq_len, seq_len)'
  • 'attn_output':多头注意力输出张量,shape为 '(batch_size, num_heads, seq_len, d_model // num_heads)'
  • 'concat_output':将多头注意力输出拼接后的张量,shape为 '(batch_size, seq_len, d_model)'
  • 'output_linear':输出线性变换的全连接层,输入shape为 '(batch_size, seq_len, d_model)',输出shape为 '(batch_size, seq_len, d_model)'
  • 'output':多头注意力最终输出张量,shape为 '(batch_size, seq_len, d_model)'
  • 'attn_weights':注意力权重张量,shape为 '(batch_size, num_heads, seq_len, seq_len)'

原文地址: https://www.cveoy.top/t/topic/ocZN 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录