学习注意力机制【1】

目录

注意力机制介绍:

自注意力机制三个步骤:

(1)计算注意力分数:(Attention Scores):

(2)计算注意力权重(Attention Weights):

(3)得到加权和(Weighted Sum):

自注意力机制Q K V


注意力机制介绍:

Attention机制,便是聚焦于局部信息的机制

注意力机制(Attention Mechanism)是机器学习中的一种数据处理方法,广泛应用在自然语言处理(NLP)、图像处理(CV)及语音识别等各种不同类型的机器学习任务中。根据注意力机制应用于域的不同,即注意力权重施加的方式和位置不同,将注意力机制分为空间域、通道域和混合域三种

在自注意力机制中,每个元素(例如句子中的每个单词)都有一个向量表示,其中每个向量都与其他向量进行相似度比较。这个相似度可以用点积、加权点积等方式来计算。然后,根据这些相似度得分,计算每个元素与其他元素的“注意力权重”,即每个元素要关注的其他元素的重要性。最后,对每个元素,用它与其他元素的注意力权重进行加权平均,得到一个新的向量表示,其较高的维度捕获了与输入序列中其他元素的“有益关注”。

自注意力机制三个步骤:

(1)计算注意力分数:(Attention Scores):

对于每个元素(例如句子中的单词),都会计算它与所有其他元素之间的相似度。这个相似度可以使用向量点积、加权点积等方式来计算,并将计算结果标准化后得到注意力分数。

(2)计算注意力权重(Attention Weights):

对于每个元素,将它与其他元素的注意力分数进行加权平均,来计算它与其他元素之间的注意力权重。这个过程可以通过将注意力分数和其他元素的向量进行点积、计算加权均值等方式来实现。

(3)得到加权和(Weighted Sum):

对于每个元素,将其与其他元素的注意力权重进行加权平均,得到一个新的向量表示。这个新的向量表示被认为是原始向量表示的一个加权和,其中重要的元素得到更高的权重。

需要注意的是,自注意力机制通常会将输入序列分为多个头(或多个通道),每个头(或通道)都计算注意力分数、注意力权重和加权和。这种多头机制有助于让神经网络同时关注不同方面的信息,从而更好地理解输入序列。

自注意力机制Q K V

注意力机制中的"Q"通常代表查询向量(query vector),该向量用于计算注意力分数并确定注意力权重。

在自注意力机制中,查询向量Q表示将要进行关注的元素。对于一组输入向量(例如文本中的单词向量),Q可以作为一个参考向量,用于计算与其他向量之间的相似度。这些相似度进一步用于计算每个元素与其他元素的注意力权重,以及最终的加权和向量表示。

在注意力机制的实现中,查询向量通常与其他两个向量一起使用,即键向量(K)和值向量(V)。键向量K用于计算注意力分数,值向量V用于计算加权和。这三个向量通常都是通过神经网络学习得到的。

query(查询)、key(键)和value(值)

在自然语言处理中,q、k、v通常被看作是从输入数据中提取出的三个不同的表示形式。比如,我们想从一段文本中提取出其中的关键词,那么可以将文本中的每个单词分别作为原始数据的value,然后对每个value生成查询(query)和键(key)。这样,在进行注意力计算时,q将与k进行匹配,通过计算q和k之间的相似度,可以在输入数据中找到最相关的value,从而更好地提取数据中的信息。

具体来说,在注意力机制中,输入数据中的每个元素都会被表示为一个向量,其中value是输入数据中的原始向量,而query和key则是用来计算注意力分数的向量。在计算注意力分数时,通过比较query与key的相似度来决定value的权重分配,最终根据这些权重加权求和得到注意力机制的输出。

因此,q、k、v在注意力机制中扮演着不同的角色,同时也是计算注意力权重和输出的关键因素。

注意力机制代码:

基础代码

import torch
import torch.nn as nn

class SelfAttention(nn.Module):
    def __init__(self, input_size, hidden_size):
        super(SelfAttention, self).__init__()
        self.input_size = input_size
        self.hidden_size = hidden_size
        self.q_layer = nn.Linear(input_size, hidden_size)
        self.k_layer = nn.Linear(input_size, hidden_size)
        self.v_layer = nn.Linear(input_size, hidden_size)

    def forward(self, input):
        # input shape: (batch_size, seq_len, input_size)
        q = self.q_layer(input)  # shape: (batch_size, seq_len, hidden_size)
        k = self.k_layer(input)  # shape: (batch_size, seq_len, hidden_size)
        v = self.v_layer(input)  # shape: (batch_size, seq_len, hidden_size)

        # calculate attention scores
        attention_scores = torch.bmm(q, k.transpose(1, 2)) / np.sqrt(self.hidden_size)  
        # shape: (batch_size, seq_len, seq_len)

        # calculate attention weights
        attention_weights = nn.functional.softmax(attention_scores, dim=-1)
        # shape: (batch_size, seq_len, seq_len)

        # calculate weighted sum
        weighted_sum = torch.bmm(attention_weights, v)
        # shape: (batch_size, seq_len, hidden_size)

        return weighted_sum

定义了一个名为“SelfAttention”的PyTorch模块,其中包含了自注意力机制的基本操作。在这个模块中,输入序列先分别经过查询向量(q)、键向量(k)和值向量(v)的网络层,产生对应的向量表示,然后根据这些向量表示计算注意力分数,再计算注意力权重,并最终计算出加权和向量表示。

具体来说,对于输入张量input,首先通过线性层q_layer、k_layer和v_layer分别转换为查询向量q、键向量k和值向量v。然后,计算注意力分数,使用矩阵乘法和缩放的技巧。接着,计算注意力权重,使用softmax函数将注意力分数标准化得到。最后,计算加权和,使用矩阵乘法将注意力权重与值向量相乘,并将结果返回。

当使用这个模块对输入序列进行处理时,可以直接调用forward方法即可。例如,可以将输入序列表示为一个(batch_size, seq_len, input_size)的张量,并传入模块中进行处理:

input_seq = torch.randn(batch_size, seq_len, input_size)
attention = SelfAttention(input_size, hidden_size)
output = attention(input_seq)

这将返回一个(batch_size, seq_len, hidden_size)的张量作为输出。

多头注意力机制代码 

import torch
import torch.nn as nn

class MultiHeadAttention(nn.Module):
    def __init__(self, n_heads, input_dim, hidden_dim):
        super(MultiHeadAttention, self).__init__()
        self.n_heads = n_heads
        self.input_dim = input_dim
        self.hidden_dim = hidden_dim
        
        self.query_layer = nn.Linear(input_dim, hidden_dim)
        self.key_layer = nn.Linear(input_dim, hidden_dim)
        self.value_layer = nn.Linear(input_dim, hidden_dim)
        
        self.output_layer = nn.Linear(hidden_dim, input_dim)
        
    def forward(self, x):
        # Split input into multi heads
        x = x.view(x.size(0), -1, self.n_heads, self.hidden_dim)
        x = x.permute(0, 2, 1, 3)
        
        # Multi head attention
        query = self.query_layer(x)
        key = self.key_layer(x)
        value = self.value_layer(x)
        
        scores = torch.matmul(query, key.transpose(-2, -1))
        scores = scores / (self.hidden_dim ** 0.5)
        attention_weights = nn.functional.softmax(scores, dim=-1)
        
        output = torch.matmul(attention_weights, value)
        output = output.permute(0, 2, 1, 3).contiguous()
        output = output.view(output.size(0), -1, self.hidden_dim * self.n_heads)
        
        # Output layer
        output = self.output_layer(output)
        
        return output

这个代码实现了一个拥有多头注意力机制的自注意力层
n_heads表示头的数量,input_dim和hidden_dim分别是输入和隐藏层的维度
在forward方法中,首先将输入进行切分,然后计算多头注意力,最后将多头输出拼接起来,并通过一个线性层进行输出。

tensorflow 多头注意力机制代码 

import tensorflow as tf

# 定义多头注意力机制函数
def multihead_attention(queries, keys, values, num_heads, dropout_rate):
    # 获取embedding维度大小
    d_model = queries.get_shape().as_list()[-1]
    
    # 建立权重矩阵,其中q、k、v均建立num_heads个权重矩阵
    wq = tf.keras.layers.Dense(d_model)(queries)
    wk = tf.keras.layers.Dense(d_model)(keys)
    wv = tf.keras.layers.Dense(d_model)(values)
    
    # 将权重矩阵分割成num_heads个小矩阵
    wq_heads = tf.concat(tf.split(wq, num_heads, axis=2), axis=0)
    wk_heads = tf.concat(tf.split(wk, num_heads, axis=2), axis=0)
    wv_heads = tf.concat(tf.split(wv, num_heads, axis=2), axis=0)
    
    # 计算scaled dot-product attention
    scaled_dot_attn = tf.matmul(wq_heads, tf.transpose(wk_heads, [0, 2, 1]))
    scaled_dot_attn = scaled_dot_attn / tf.sqrt(tf.cast(d_model, tf.float32))
    scaled_dot_attn = tf.nn.softmax(scaled_dot_attn, axis=-1)
    scaled_dot_attn = tf.keras.layers.Dropout(rate=dropout_rate)(scaled_dot_attn)
    attn_output = tf.matmul(scaled_dot_attn, wv_heads)
    
    # 将多头注意力的输出拼接在一起
    attn_output = tf.concat(tf.split(attn_output, num_heads, axis=0), axis=2)
    
    # 添加线性变换和dropout操作
    attn_output = tf.squeeze(tf.keras.layers.Dense(d_model)(attn_output), axis=0)
    attn_output = tf.keras.layers.Dropout(rate=dropout_rate)(attn_output)
    
    # 返回多头注意力输出
    return attn_output
    
# 定义输入变量
queries = tf.placeholder(tf.float32, shape=[None, None, d_model])
keys = tf.placeholder(tf.float32, shape=[None, None, d_model])
values = tf.placeholder(tf.float32, shape=[None, None, d_model])
num_heads = 4
dropout_rate = 0.2

# 调用多头注意力机制函数
attn_output = multihead_attention(queries, keys, values, num_heads, dropout_rate)

这段代码实现了基于多头注意力机制的蛋白质特征提取模型。其中,输入变量queries、keys、values分别表示输入的查询、键和值,num_heads表示所采用的attention头数,dropout_rate表示dropout的概率。在函数中,首先用Dense层建立权重矩阵,然后将权重矩阵分割成多个小矩阵,对每个小矩阵进行scaled dot-product attention计算,然后将结果拼接在一起,再进行线性变换和dropout操作得到输出。通过调用该函数,即可获取蛋白质特征的多头注意力表示形式。

猜你喜欢

转载自blog.csdn.net/weixin_63016274/article/details/129564032