Transformer 的核心机制就是 Self-Attention,它赋予模型强大的“理解上下文”能力。本文从零开始,详细解析 Self-Attention 的原理、Q/K/V 向量的含义、举例说明并用 PyTorch 代码实现,助你彻底搞懂这项技术!
什么是 Self-Attention?
Self-Attention(自注意力)是一种机制,它让模型在处理某个词时,能够“感知”到句子中其它词,并根据它们的重要程度加权组合信息。
在传统的 RNN 中,信息只能通过固定顺序传播;而在 Transformer 中,Self-Attention 允许每个词同时访问整个序列,从而极大提升模型的表现力与并行性。
Q / K / V 是什么?(关键点)
在 Self-Attention 中,每个词的向量表示会被映射为 3 个不同的向量:
Query(Q):我想找什么内容?
Key(K):你提供了哪些“关键词”?
Value(V):你具体包含了哪些信息?
类比解释:
想象你在搜索文档内容:
你有一个查找目标(Query)
每篇文章有它的关键词标签(Key)
每篇文章本身的内容就是 Value
你计算目标和标签(Q 和 K)之间的匹配程度(比如用点积),然后根据匹配度加权文章内容(V)来生成你最终关注的结果。
数学表达:
输入词向量:
假设每个词的维度是 d_model = 512
,我们会训练三个参数矩阵:
WQ ∈ ℝ512×64
WK ∈ ℝ512×64
WV ∈ ℝ512×64
每个词向量 X(shape 为 [batch, seq_len, d_model]
) 乘以这三个矩阵得到:
Q = X @ W_Q
K = X @ W_K
V = X @ W_V
生成的 Q、K、V 都是 [batch, seq_len, d_k]
维度。
当然可以!下面是一篇面向开发者社区(比如 CSDN、知乎、掘金、微信公众号)的技术文章草稿,清晰介绍 Self-Attention 原理 + 例子讲解,适合发布在论坛或博客平台上:
Self-Attention 原理
Self-Attention 的计算过程大致分为以下几步:
1. 输入表示(嵌入向量)
假设我们有一句话:"The cat sat"
,它被转成 embedding 向量后,shape 是 [seq_len, d_model]
。假设每个词的向量为 4 维:
The: [1, 0, 1, 0]
cat: [0, 2, 0, 2]
sat: [1, 1, 1, 1]
2. 生成 Q / K / V 向量
我们定义三个训练得到的权重矩阵:WQ、WK、WV(常设为 4×2,输出向量维度为 2):
W_Q = [[1, 0],
[0, 1],
[1, 0],
[0, 1]]
然后用它们乘以嵌入向量,生成每个 token 的 Query、Key、Value 向量:
Q = X @ W_Q
K = X @ W_K
V = X @ W_V
3. 计算打分矩阵
通过 Q × K^T
得到每个 token 对其它 token 的相关性打分(注意力权重前的 raw score):
scores = Q @ K.transpose(-2, -1) # shape: [seq_len, seq_len]
这一步的输出 shape 是 [seq_len, seq_len]
,表示每个词和其它词之间的关系强弱。
4. softmax 归一化
为了得到每个词应该“关注”其它词的程度,我们对每一行做 softmax:
p_attn = softmax(scores, dim=-1)
它的结果是一个概率分布,越大的表示当前词越关注对应位置的词。
5. 加权求和得到输出
最后我们将 Value 向量按权重加权求和:
output = p_attn @ V
这样就得到了每个词的新表示,它融合了上下文中的相关信息。
举个具体例子(简单演示)
假设有一组 Query、Key 向量如下:
Q = [[1, 0],
[0, 1],
[1, 1]]
K = [[1, 0],
[0, 1],
[1, 1]]
转置 K 得到:
K^T = [[1, 0, 1],
[0, 1, 1]]
执行打分:
scores = Q × K^T = [
[1, 0, 1], # token 1 对 3 个 token 的打分
[0, 1, 1], # token 2
[1, 1, 2] # token 3
]
对每一行做 softmax:
softmax([1, 0, 1]) ≈ [0.42, 0.15, 0.42]
softmax([0, 1, 1]) ≈ [0.21, 0.39, 0.39]
softmax([1, 1, 2]) ≈ [0.21, 0.21, 0.58]
最后再用这些权重去加权 Value 向量,得到新的输出。
PyTorch 实现一把
import torch
import torch.nn.functional as F
# 模拟 batch=2, seq_len=5, dim=64
Q = torch.randn(2, 5, 64)
K = torch.randn(2, 5, 64)
V = torch.randn(2, 5, 64)
# 打分
scores = torch.bmm(Q, K.transpose(1, 2)) # shape: [2, 5, 5]
# softmax 归一化
p_attn = F.softmax(scores, dim=-1)
# 加权求和
output = torch.bmm(p_attn, V) # shape: [2, 5, 64]
总结
Self-Attention 的关键步骤:
生成 Q/K/V
用 Q × Kᵀ 计算相关性打分
用 softmax 转为注意力分布
用这个分布去加权 V 得到输出
通过这个机制,模型可以动态调整每个词关注的信息范围,从而更好地理解上下文。