注意力机制 - 参数解释
1 课程概览
本课解释注意力机制的参数。通过 Seq2Seq 架构图,解释 Q、K、V 的来源和形状变化。解码器端的注意力机制包括:矩阵乘法、缩放(可选)、掩码(可选)、softmax、与 V 相乘。
2 核心概念与定义
- Q(Query):查询张量,decoder 的输入。
- K(Key):键张量,encoder 的输出。
- V(Value):值张量,encoder 的输出(词向量矩阵)。
- 缩放(Scale):可选操作,防止点积结果过大。
- 掩码(Mask):可选操作,防止偷看答案。
3 模型与算法详解
注意力分类
| 类型 | 条件 | 计算规则 |
|---|---|---|
| 一般注意力 | Q、K、V 不相等 | 规则 1、2 |
| 自注意力 | Q = K = V | 规则 3(scaled dot-product) |
解码器端注意力机制
计算流程。
1. Q · K^T → 匹配分(矩阵乘法)
2. 缩放(可选)
3. 掩码(可选)
4. softmax → 概率分布
5. 概率分布 · V → attention_q(中间语义张量 C)
各步骤说明
| 步骤 | 操作 | 说明 |
|---|---|---|
| 1 | matrix multiply | 矩阵乘法,Q · K^T |
| 2 | scale | 缩放(可选),除以 √d_k |
| 3 | mask | 掩码(可选),防止偷看答案 |
| 4 | softmax | 转概率 |
| 5 | · V | 与词向量矩阵相乘 |
掩码(Mask)
防止偷看答案。
- 生成第 3 个词时,把第 3 个词及后面的词盖住
- 类似于电力负荷预测中,预测 10 点的负荷,只看 9 点及以前的负荷
Seq2Seq 架构
句子到句子结构。
Encoder → K, V
Decoder → Q
Attention → attention_q
4 数学原理与推导
注意力计算
$$\text{attn_weights} = \text{softmax}\left(\frac{\text{Q} \cdot \text{K}^T}{\sqrt{d_k}}\right)$$
$$\text{attention_q} = \text{attn_weights} \cdot \text{V}$$
其中:
- $\text{Q}$ 是查询张量
- $\text{K}$ 是键张量
- $\text{V}$ 是值张量
- $d_k$ 是 K 的维度
- $\sqrt{d_k}$ 是缩放因子(可选)
三种计算规则
规则 1:拼接 + Linear + softmax
$$\text{attention_q} = \text{softmax}(\text{Linear}(\text{Q} \oplus \text{K})) \cdot \text{V}$$
规则 2:Linear + tanh + softmax
$$\text{attention_q} = \text{softmax}(\tanh(\text{Linear}(\text{Q}))) \cdot \text{V}$$
规则 3:scaled dot-product
$$\text{attention_q} = \text{softmax}\left(\frac{\text{Q} \cdot \text{K}^T}{\sqrt{d_k}}\right) \cdot \text{V}$$
5 代码示例
import torch
import torch.nn.functional as F
def attention_explain():
"""解释注意力机制的参数"""
print("=== 注意力机制 - 参数解释 ===")
# 1. 参数设置
batch_size = 1
seq_len = 32 # 32 个单词
d_k = 64 # K 的维度
d_v = 64 # V 的维度
# 2. 创建 Q、K、V
Q = torch.randn(batch_size, 1, d_k) # 查询张量
K = torch.randn(batch_size, seq_len, d_k) # 键张量
V = torch.randn(batch_size, seq_len, d_v) # 值张量
print(f"Q 形状: {Q.shape} (批次, 序列, 特征)")
print(f"K 形状: {K.shape} (批次, 单词数, 特征)")
print(f"V 形状: {V.shape} (批次, 单词数, 词向量维度)")
# 3. 注意力计算流程
print("\n--- 注意力计算流程 ---")
# 步骤 1:矩阵乘法(Q · K^T)
scores = torch.matmul(Q, K.transpose(-2, -1))
print(f"步骤 1 - 匹配分: {scores.shape}")
# 步骤 2:缩放(可选)
scaled_scores = scores / torch.sqrt(torch.tensor(d_k, dtype=torch.float32))
print(f"步骤 2 - 缩放: {scaled_scores.shape}")
# 步骤 3:掩码(可选,这里不实现)
print(f"步骤 3 - 掩码: (可选)")
# 步骤 4:softmax 转概率
attn_weights = F.softmax(scaled_scores, dim=-1)
print(f"步骤 4 - 概率分布: {attn_weights.shape}")
print(f" 权重和: {attn_weights.sum().item():.4f}")
# 步骤 5:与 V 相乘
attention_q = torch.matmul(attn_weights, V)
print(f"步骤 5 - attention_q: {attention_q.shape}")
# 4. 判断注意力类型
print("\n--- 注意力类型 ---")
if torch.equal(Q, K) and torch.equal(K, V):
print("类型: 自注意力(Q = K = V)")
else:
print("类型: 一般注意力(Q、K、V 不相等)")
# 测试
if __name__ == "__main__":
attention_explain()
代码说明
| 代码 | 说明 |
|---|---|
torch.matmul(Q, K.transpose(-2, -1)) | Q · K^T |
/ torch.sqrt(...) | 缩放 |
F.softmax(..., dim=-1) | 转概率 |
torch.matmul(attn_weights, V) | 与 V 相乘 |
6 重难点与易错提醒
- ❗重点:Q、K、V 的来源:Q 来自 decoder,K、V 来自 encoder。
- ❗重点:缩放和掩码是可选操作。
- ❗重点:Q = K = V 时为自注意力。
- 💡技巧:掩码用于防止偷看答案。
7 课堂问答精选
Q1:Q、K、V 分别来自哪里?
A:Q 来自 decoder 的输入,K 和 V 来自 encoder 的输出。
Q2:缩放和掩码的作用是什么?
A:缩放用于防止点积结果过大;掩码用于防止偷看答案(如生成第 3 个词时,盖住第 3 个词及后面的词)。
Q3:如何区分一般注意力和自注意力?
A:当 Q = K = V 时为自注意力;当 Q、K、V 不相等时为一般注意力。
8 本课小结
- Q 来自 decoder,K、V 来自 encoder。
- 解码器端注意力机制:矩阵乘法 → 缩放(可选)→ 掩码(可选)→ softmax → 与 V 相乘。
- 缩放和掩码是可选操作。
- Q = K = V 时为自注意力。
9 延伸思考
- 如何在英译法案例中应用注意力机制?
- 如何构建基于 GRU 的编码器?