注意力机制练习 Attention

 

 1 import torch
 2 import torch.nn.functional as F
 3 
 4 # 一个形状为 (batch_size, seq_len, feature_dim) 的张量(矩阵) x
 5 # 两个样本, 每个样本3 个词语长度,每个词语编码为4维
 6 x = torch.randn(2, 3, 4)  # (batch_size, seq_len, feature_dim)
 7 
 8 # 定义头数和每个头的维度
 9 num_heads = 2
10 head_dim = 2
11 
12 # feature_dim 必须是 num_heads * head_dim 的整数倍
13 assert x.size(-1) == num_heads * head_dim
14 
15 # 定义线性层用于将 x 转换为 Q, K, V 向量
16 # Wq Wk Wv
17 linear_q = torch.nn.Linear(4, 4) # 每次创建全链接层,随机参数
18 linear_k = torch.nn.Linear(4, 4)
19 linear_v = torch.nn.Linear(4, 4)
20 
21 # 通过线性层计算 Q, K, V
22 Q = linear_q(x)  # (batch_size, seq_len, feature_dim)
23 K = linear_k(x)  # (batch_size, seq_len, feature_dim)
24 V = linear_v(x)  # (batch_size, seq_len, feature_dim)
25 
26 
27 # 将 Q, K, V 分割成 num_heads 个头
28 def split_heads(tensor, num_heads):
29     # (batch_size, seq_len, feature_dim)  -》 (batch_size, num_heads, seq_len, feature_dim)
30     batch_size, seq_len, feature_dim = tensor.size()
31     head_dim = feature_dim // num_heads
32     output = tensor.view(batch_size, seq_len, num_heads, head_dim).transpose(1, 2)
33     # view 维度转换
34     # transpose 维度交换
35     # (batch_size, num_heads, seq_len, feature_dim)
36     return output
37 
38 
39 Q = split_heads(Q, num_heads)  # (batch_size, num_heads, seq_len, head_dim)
40 K = split_heads(K, num_heads)  # (batch_size, num_heads, seq_len, head_dim)
41 V = split_heads(V, num_heads)  # (batch_size, num_heads, seq_len, head_dim)
42 
43 # 计算 Q 和 K 的点积,作为相似度分数 , 也就是自注意力原始权重
44 # 第i行第j列:第i个词对第j个词的关注程度
45 raw_weights = torch.matmul(Q, K.transpose(-2, -1))  # (batch_size, num_heads, seq_len, seq_len)
46 
47 # transpose(-2, -1) -》 (batch_size, num_heads, head_dim, seq_len)
48 
49 # 对自注意力原始权重进行缩放, 防止梯度爆炸
50 scale_factor = K.size(-1) ** 0.5 # 根号 head_dim
51 
52 scaled_weights = raw_weights / scale_factor  # (batch_size, num_heads, seq_len, seq_len)
53 
54 # 对缩放后的权重进行 softmax 归一化,得到注意力权重
55 # 归一化操作 / 激活函数
56 attn_weights = F.softmax(scaled_weights, dim=-1)  # (batch_size, num_heads, seq_len, seq_len)
57 
58 # 将注意力权重应用于 V 向量,计算加权和,得到加权信息
59 # 每个词的输出 = 该词对所有Value的加权平均
60 attn_outputs = torch.matmul(attn_weights, V)  # (batch_size, num_heads, seq_len, head_dim)
61 
62 
63 def combine_heads(tensor, num_heads):
64     batch_size, num_heads, seq_len, head_dim = tensor.size()
65     feature_dim = num_heads * head_dim
66     output = tensor.transpose(1, 2).contiguous().view(batch_size, seq_len, feature_dim)
67     return output  # (batch_size, seq_len, feature_dim)
68 
69 
70 attn_outputs = combine_heads(attn_outputs, num_heads)  # (batch_size, seq_len, feature_dim)
71 
72 # 对拼接后的结果进行线性变换
73 linear_out = torch.nn.Linear(4, 4)
74 attn_outputs = linear_out(attn_outputs)  # (batch_size, seq_len, feature_dim)
75 print(" 加权信息 :", attn_outputs)

 

posted @ 2026-07-22 00:22  Marksion  阅读(2)  评论(0)    收藏  举报