注意力机制 - 测试代码
1 课程概览
本课讲解注意力机制的测试代码。实例化 MyAttention 模块,创建随机 Q、K、V 张量,前向传播,输出注意力结果表示和权重分布。测试结果:output 形状为 [1, 1, 64],attn_weights 形状为 [1, 1, 32]。
2 核心概念与定义
- 测试代码:实例化模块,创建输入,前向传播,输出结果。
- output:注意力结果表示,形状 [1, 1, 64]。
- attn_weights:注意力权重分布,形状 [1, 1, 32]。
3 模型与算法详解
测试流程
1. 实例化参数设置
2. 创建随机输入张量(Q、K、V)
3. 实例化注意力机制模块并测试
4. 输出结果
参数设置
| 参数 | 值 | 说明 |
|---|---|---|
| query_size | 32 | 查询张量维度 |
| key_size | 32 | 键张量维度 |
| value_size | 64 | 值张量维度 |
| output_size | 32 | 输出维度 |
输入张量
| 张量 | 形状 | 说明 |
|---|---|---|
| Q | [1, 1, 32] | 查询张量(批次、序列、特征) |
| K | [1, 32, 32] | 键张量(批次、单词数、特征) |
| V | [1, 32, 64] | 值张量(批次、单词数、词向量维度) |
输出结果
| 输出 | 形状 | 说明 |
|---|---|---|
| output | [1, 1, 32] | 注意力结果表示 |
| attn_weights | [1, 1, 32] | 注意力权重分布 |
权重分布
32 个单词的权重和为 1。
$$\sum_{i=1}^{32} \text{attn_weights}_i = 1$$
4 数学原理与推导
注意力计算
$$\text{attn_weights} = \text{softmax}(\text{Q} \cdot \text{K}^T)$$
$$\text{attention_q} = \text{bmm}(\text{attn_weights}, \text{V})$$
$$\text{output} = \text{Linear}(\text{attention_q})$$
5 代码示例
import torch
import torch.nn as nn
import torch.nn.functional as F
class MyAttention(nn.Module):
"""自定义注意力机制模块"""
def __init__(self, query_size, key_size, value_size, output_size):
super(MyAttention, self).__init__()
self.query_layer = nn.Linear(query_size, key_size)
self.attn_weights = None
self.output_layer = nn.Linear(value_size, output_size)
def forward(self, Q, K, V):
# 1. 计算注意力权重分布
Q = self.query_layer(Q)
attn_weights = F.softmax(torch.matmul(Q, K.transpose(-2, -1)), dim=-1)
self.attn_weights = attn_weights
# 2. 用 bmm() 计算注意力结果表示
attention_q = torch.bmm(attn_weights, V)
# 3. 按指定维度输出
output = self.output_layer(attention_q)
return output, attn_weights
def test_attention():
"""测试注意力机制"""
print("=== 注意力机制 - 测试代码 ===")
# 1. 实例化参数设置
query_size = 32
key_size = 32
value_size = 64
output_size = 32
# 2. 创建随机输入张量
Q = torch.randn(1, 1, query_size) # 查询张量 [批次, 序列, 特征]
K = torch.randn(1, 32, key_size) # 键张量 [批次, 单词数, 特征]
V = torch.randn(1, 32, value_size) # 值张量 [批次, 单词数, 词向量维度]
print(f"Q 形状: {Q.shape}")
print(f"K 形状: {K.shape}")
print(f"V 形状: {V.shape}")
# 3. 实例化注意力机制模块并测试
my_attn = MyAttention(query_size, key_size, value_size, output_size)
output, attn_weights = my_attn(Q, K, V)
# 4. 输出结果
print("\n" + "=" * 50)
print(f"查询张量 Q 的注意力结果表示:")
print(f" output 形状: {output.shape}") # [1, 1, 32]
print(f" output 内容: {output}")
print(f"\n查询张量 Q 的注意力权重分布:")
print(f" attn_weights 形状: {attn_weights.shape}") # [1, 1, 32]
print(f" attn_weights 内容: {attn_weights}")
print(f" 权重和: {attn_weights.sum().item():.4f}") # 应该接近 1
# 测试
if __name__ == "__main__":
test_attention()
代码说明
| 代码 | 说明 |
|---|---|
torch.randn(1, 1, 32) | 创建随机 Q 张量 |
torch.randn(1, 32, 32) | 创建随机 K 张量 |
torch.randn(1, 32, 64) | 创建随机 V 张量 |
my_attn(Q, K, V) | 前向传播 |
attn_weights.sum() | 权重和(应该接近 1) |
6 重难点与易错提醒
- ❗重点:output 形状为 [1, 1, 32],attn_weights 形状为 [1, 1, 32]。
- ❗重点:attn_weights 的 32 个权重和为 1。
- ❗重点:Q 的形状是 [批次, 序列, 特征],K 和 V 的形状是 [批次, 单词数, 特征]。
7 课堂问答精选
Q1:测试结果中 output 和 attn_weights 的形状是什么?
A:output 形状为 [1, 1, 32](注意力结果表示),attn_weights 形状为 [1, 1, 32](注意力权重分布)。
Q2:为什么 attn_weights 的形状是 [1, 1, 32]?
A:因为有 32 个单词,每个单词都有一个权重,所以权重分布是 [1, 1, 32]。
Q3:attn_weights 的和是多少?
A:attn_weights 的和应该接近 1,因为经过了 softmax 归一化。
8 本课小结
- 测试流程:实例化参数 → 创建输入张量 → 前向传播 → 输出结果。
- output 形状为 [1, 1, 32],attn_weights 形状为 [1, 1, 32]。
- attn_weights 的和接近 1。
9 延伸思考
- 注意力机制的参数如何解释?
- 如何区分一般注意力和自注意力?