注意力机制是深度学习领域中广泛应用的技术,特别是在自然语言处理和计算机视觉任务中。它使模型能够有选择地关注输入数据的特定部分,以此提升模型的性能。
想象一下,当你读到 “The cat sat on the mat” 这句话时,人类可以立即理解单词之间的关系,可以知道 “sat” 与 “cat” 的关系比与“mat”的关系更密切。
注意力机制使机器能够捕捉类似的关系,帮助它们专注于输入数据的特定部分。
Transformer 中的注意力机制
在 Transformer 模型中,注意力机制是其核心组件,它使得模型可以在处理输入序列的过程中关注到最重要的信息,从而大幅提高了模型在长序列中的表现。
自注意力机制
在自注意力机制中,每个输入向量可以“关注”同一序列中的其他向量,这使得模型能够灵活地关注整个序列的不同部分。
图片
下面,我们一起来看一下如何使用代码来实现上述过程。
import numpy as np
word_embeddings = {
'she': np.array([0.2, 0.9, 0.1, 0.5]),
'likes': np.array([0.8, 0.3, 0.7, 0.2]),
'coffee': np.array([0.4, 0.6, 0.3, 0.9])
}
X = np.vstack([word_embeddings['she'],
word_embeddings['likes'],
word_embeddings['coffee']])
W_q = np.array([[0.9, 0.1, 0.1, 0.1],
[0.1, 0.9, 0.1, 0.1],
[0.1, 0.1, 0.9, 0.1],
[0.1, 0.1, 0.1, 0.9]])
W_k = np.array([[0.9, 0.1, 0.1, 0.1],
[0.1, 0.9, 0.1, 0.1],
[0.1, 0.1, 0.9, 0.1],
[0.1, 0.1, 0.1, 0.9]])
W_v = np.array([[0.8, 0.2, 0.1, 0.1],
[0.2, 0.8, 0.2, 0.1],
[0.1, 0.2, 0.8, 0.1],
[0.1, 0.1, 0.1, 0.9]])
Q = np.dot(X, W_q)
K = np.dot(X, W_k)
V = np.dot(X, W_v)
scores = np.dot(Q, K.T)
d_k = K.shape[1]
scaled_scores = scores / np.sqrt(d_k)
exp_scores = np.exp(scaled_scores)
attention_weights = exp_scores / exp_scores.sum(axis=1, keepdims=True)
output = np.dot(attention_weights, V)
print(output)
多头注意力机制(Multi-Head Attention)
多头注意力机制进一步扩展了自注意力的表达能力。
通过设置多个注意力头(head),每个头从不同的子空间中获取信息,最后将各头的结果拼接起来并进行线性变换。
这样模型可以更好地捕捉多维度的依赖关系,使其在复杂任务中表现更为优异。
图片
多头注意力的计算流程
多头注意力机制增加了模型的灵活性,能让模型从不同角度学习到序列中词汇间的关系。
class MultiHeadAttention(nn.Module):
def __init__(self, d_model, num_heads):
super(MultiHeadAttention, self).__init__()
# Ensure that the model dimension (d_model) is divisible by the number of heads
assert d_model % num_heads == 0
# Initialize dimensions
self.d_model = d_model # Model's dimension
self.num_heads = num_heads # Number of attention heads
self.d_k = d_model // num_heads # Dimension of each head's key, query, and value
# Linear layers for transforming inputs
self.W_q = nn.Linear(d_model, d_model) # Query transformation
self.W_k = nn.Linear(d_model, d_model) # Key transformation
self.W_v = nn.Linear(d_model, d_model) # Value transformation
self.W_o = nn.Linear(d_model, d_model) # Output transformation
# 缩放点积注意力机制
def scaled_dot_product_attention(self, Q, K, V, mask=None):
# Calculate attention scores
attn_scores = torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(self.d_k)
# Apply mask if provided (useful for preventing attention to certain parts like padding)
if mask is not None:
attn_scores = attn_scores.masked_fill(mask == 0, -1e9)
# Softmax is applied to obtain attention probabilities
attn_probs = torch.softmax(attn_scores, dim=-1)
# Multiply by values to obtain the final output
output = torch.matmul(attn_probs, V)
return output
def split_heads(self, x):
# Reshape the input to have num_heads for multi-head attention
batch_size, seq_length, d_model = x.size()
return x.view(batch_size, seq_length, self.num_heads, self.d_k).transpose(1, 2)
def combine_heads(self, x):
# Combine the multiple heads back to original shape
batch_size, _, seq_length, d_k = x.size()
return x.transpose(1, 2).contiguous().view(batch_size, seq_length, self.d_model)
def forward(self, Q, K, V, mask=None):
# Apply linear transformations and split heads
Q = self.split_heads(self.W_q(Q))
K = self.split_heads(self.W_k(K))
V = self.split_heads(self.W_v(V))
# Perform scaled dot-product attention
attn_output = self.scaled_dot_product_attention(Q, K, V, mask)
# Combine heads and apply output transformation
output = self.W_o(self.combine_heads(attn_output))
return output