注意力机制的数学直觉-QKV矩阵在做什么
> **[进阶选读]** 本文适合想深入理解 LLM 内部机制的读者。深入理解 Q/K/V 矩阵计算的具体过程,适合想从数学角度理解自注意力的读者。路径 A 的读者可以跳过。
注意力机制的数学直觉:Q/K/V 矩阵在做什么
[进阶选读] 本文适合想深入理解 LLM 内部机制的读者。深入理解 Q/K/V 矩阵计算的具体过程,适合想从数学角度理解自注意力的读者。路径 A 的读者可以跳过。
[进阶选读] 本篇从数学直觉角度深入解析注意力机制的计算过程,适合想彻底理解 Transformer 内部原理的读者。如果你的目标是应用开发(路径 A),可以跳过本篇,不影响后续学习。
第 04 篇用图书馆类比解释了自注意力的直觉:Query 在问,Key 在介绍,Value 在给答案。但有一个关键问题被跳过了——Query 和 Key "匹配"这件事,具体是怎么计算的?"相似度分数"从哪里来?为什么要除以一个奇怪的系数?为什么需要多个头?
本篇从数学直觉出发,逐层拆解这些问题。目标不是推导公式,而是让每一步计算都有直觉支撑。
1.1 先把类比建清楚
把图书馆检索系统的类比精确化:
图 6.20:Q/K/V 注意力计算完整流程图——三个矩阵的角色与计算步骤
假设你走进一家图书馆,想找一本讲 Python 入门的书。你在搜索框输入:"适合零基础学习的 Python 编程入门书"。这就是你的 Query(查询词)。
图书馆里每本书都有一套标签卡片——"Python、编程、入门、零基础"。这就是那本书的 Key(索引键)。
你的查询词和每本书的标签进行匹配,得出一个相关度分数。相关度高的书排在前面。
当你真正打开这本书,看到里面的知识内容时,读到的才是 Value(内容值)。
Q、K、V 为什么需要是三个不同的矩阵变换?
一个词在句子中可以同时扮演不同的角色。以"苹果"为例:当它作为搜索者(Query)时,它在问"我周围有什么相关信息?";当它作为被搜索对象(Key)时,它在说"我是一个食物/品牌名词,在这些语境下与我相关";当它作为信息提供者(Value)时,它在说"关于我,你可以知道这些语义内容"。
把这三个角色用三个不同的投影矩阵分开,让模型有最大的灵活性:每个角色可以强调词的不同语义方面。W_Q 让词形成最有效的"查询意图",W_K 让词形成最有效的"可检索标签",W_V 让词提供最有用的"实际内容"。
整个注意力计算的过程就是:
- 用 Query 和所有书的 Key 做匹配,得到每本书的相关度分数
- 把相关度分数归一化成"从这本书取多少信息"的权重
- 按权重从每本书的 Value 里取信息,加权混合,得到最终结果
在 Transformer 里,这里的"书"是句子里的每一个词。处理当前词时,它的 Query 去和序列里所有词的 Key 做匹配,权重决定"从哪些词借鉴多少信息",最后从 Value 里加权提取,得到当前词的新表示。
1.2 向量点积:相似度的计算方式
1.2.1 几何直觉:方向相似意味着语义相关
在向量空间中,"方向"是一个有意义的概念。如果把两个词的向量想象成从原点出发的箭头,方向相似意味着这两个词在语义上有关联。
为什么点积能衡量方向相似度?点积 = |A| × |B| × cos(θ),其中 θ 是两个向量的夹角。两个向量方向完全相同时 cos(θ) = 1,完全相反时 cos(θ) = -1,垂直时 cos(θ) = 0。
这意味着:Query 向量和 Key 向量的方向越接近,它们的点积越大,说明这个词对当前词提供的信息越相关——这正是注意力权重应该表达的含义。
Query 和 Key 都是向量(Vector)——可以理解为一串数字,比如 [0.8, 0.3, 0.9, 0.1],用于表示词语的语义特征。
两个向量的相似度,用点积(Dot Product)来衡量。点积的计算方式:把两个向量对应位置的数字两两相乘,再把所有乘积加起来。
不需要记住这个计算过程,只需要理解点积的直觉含义:
两个向量方向越相近,点积越大。
用人的类比来说:假设每个人的兴趣爱好可以用一个数字向量表示,喜欢编程的人对应 [1.0, 0.0],喜欢音乐的人对应 [0.0, 1.0],两者都感兴趣的人对应 [0.7, 0.7]。兴趣相似的两个人做点积,得到一个大数;兴趣差异大的两个人做点积,得到一个小数甚至负数。这个大数或小数,就是"相似度分数"。
在注意力机制里,Query 向量代表"我在寻找什么类型的信息",Key 向量代表"我提供什么类型的信息"。Q 和 K 点积越大,说明这个词提供的信息正是当前词需要的,注意力权重就越高。
1.3 Softmax:把分数变成权重
点积计算之后,得到一组原始分数,比如:
- "animal" 对当前词的分数:3.2
- "street" 对当前词的分数:0.4
- "tired" 对当前词的分数:1.8
- 其余词的分数:各种数值
这些分数的问题是:它们是原始数字,有正有负,量级不一。需要把它们转换成"权重"——每个权重在 0 到 1 之间,并且所有权重加起来等于 1。这样才能用来做加权平均。
Softmax(软最大化)就是做这件事的函数。
Softmax 的直觉:先对每个分数取指数(e 的该数次方),让大的数变得更大、小的数变得更小,然后除以所有指数的总和做归一化。
以上面的分数为例(简化示意):
| 词 | 原始分数 | 经过 Softmax 后的权重 |
|---|---|---|
| animal | 3.2 | 0.72 |
| tired | 1.8 | 0.22 |
| street | 0.4 | 0.06 |
| 其余词 | 更低 | 约 0.00 |
权重之和 = 0.72 + 0.22 + 0.06 + ... = 1.0
Softmax 有一个重要特性:大的分数会被放大,小的分数会被压缩。原始分数差距不大时,Softmax 后的权重差距会被拉大,模型的注意力会更聚焦于最相关的词。
1.4 缩放因子:为什么要除以 √d_k
注意力公式里有一步常常被初学者跳过:在做 Softmax 之前,先把点积除以一个数——√d_k,其中 d_k 是 Key 向量的维度(维度可以理解为向量的长度,即向量里数字的个数)。
为什么需要这个除法?
随着向量维度 d_k 变大,点积的值也会随之变大。比如维度是 4 时,点积最大可能是几;维度是 512 时,点积可能高达几百。
点积非常大时,Softmax 会进入一个危险区域:极大的值经过 Softmax 之后,概率几乎全部集中在最大的那一项(接近 1.0),其余全部接近 0。这种极端的概率分布会导致梯度消失(Vanishing Gradient)——梯度消失指的是训练时的学习信号变得极弱,模型停止更新。
把点积除以 √d_k,是一种简单的归一化手段,把点积的数值范围控制在合理区间,让 Softmax 的输出不那么极端,梯度保持健康。
这个除法本身不复杂,但缺少它,注意力机制在大维度下会严重失效。
1.5 完整的 Q/K/V 计算流程
把前面所有步骤串起来:
这幅图对应的就是注意力机制的标准公式:
Attention(Q, K, V) = Softmax(Q × K^T ÷ √d_k) × V
不需要记住公式,理解每一步在做什么就够了:Q 和 K 算相似度 → 除以 √d_k 缩放 → Softmax 归一化 → 加权提取 V。
1.6 Q/K/V 矩阵从哪里来
一个细节值得关注:Q、K、V 并不是输入向量本身,而是输入向量分别乘以三个不同的权重矩阵(W_Q、W_K、W_V)之后得到的。
这三个矩阵是训练中学习到的参数。为什么要做这个变换?
因为同一个词,在不同的上下文里,应该提供不同的"查询意图"(Q)和不同的"信息标签"(K)。通过三个可学习的矩阵,模型能把同一个词的原始向量投影到三个不同的语义空间里,分别扮演好 Query、Key、Value 三个角色。
类比:同一个人(输入向量),在图书馆里作为读者(扮演 Query 角色)时说的话,和作为图书管理员(扮演 Key 角色)时说的话,内容完全不同。W_Q、W_K、W_V 就是"角色切换"的变换矩阵。
1.7 多头注意力:为什么需要多个头
理解了单头注意力之后,多头注意力(Multi-Head Attention)就很直观了。
核心问题:一组 Q/K/V 只能学到一种类型的关联关系。但自然语言里,词与词之间的关系是多维度的:
- 语法关系:"猫"和"追"(主谓关系)
- 语义关系:"猫"和"喵喵叫"(语义相关)
- 指代关系:"它"和"猫"(指代同一对象)
- 位置关系:相邻词之间的局部依赖
一个注意力头,一次只能关注一种关系。如果只有一个头,它必须在这些关系之间做妥协,所有关系的学习效果都会打折扣。
解决方案:并行使用多组 Q/K/V,每组独立地学习一类关系,最后把所有头的结果拼接起来。
多头注意力 vs 单头注意力的对比:
| 维度 | 单头注意力 | 多头注意力 |
|---|---|---|
| 关系类型 | 学习一种综合关系 | 每个头学习一种关系类型 |
| 表达能力 | 有限,关系之间相互竞争 | 强,各类关系并行学习 |
| 计算量 | 较低 | 每个头维度缩小,总计算量相近 |
| 可解释性 | 难以分析学了什么 | 不同头可分析出不同关注模式 |
| 典型应用 | 简化实验场景 | 所有主流 Transformer 模型 |
GPT-3 使用 96 个注意力头,每个头的维度是 128。这 96 个头并行工作,分别关注语言的不同维度,最终拼接成一个维度为 12288 的向量。这是 GPT-3 强大理解能力的结构基础之一。
1.8 代码示例:NumPy(Python科学计算基础库,提供高效的多维数组运算)实现简化版注意力
以下为代码示例,非程序员可跳过代码,重点看文字说明。
代码展示了从输入向量到注意力输出的完整计算过程,步骤和前面讲的完全对应:
import numpy as np
def softmax(x):
"""
Softmax 函数:把一组数字转换为概率分布。
先减去最大值(防止数值溢出),再做指数归一化。
"""
# axis=-1 表示沿最后一个维度做 softmax(对每行做归一化)
e_x = np.exp(x - np.max(x, axis=-1, keepdims=True))
return e_x / e_x.sum(axis=-1, keepdims=True)
def scaled_dot_product_attention(Q, K, V):
"""
缩放点积注意力(Scaled Dot-Product Attention)
参数:
Q: Query 矩阵,形状 (序列长度, d_k)
K: Key 矩阵,形状 (序列长度, d_k)
V: Value 矩阵,形状 (序列长度, d_v)
返回:
output: 注意力输出,形状 (序列长度, d_v)
attention_weights: 注意力权重矩阵,用于可视化
"""
d_k = Q.shape[-1] # Key 向量的维度
# 步骤 1:计算 Q 和 K 的点积
# (seq_len, d_k) × (d_k, seq_len) → (seq_len, seq_len)
# 结果矩阵的 [i][j] 表示第 i 个词对第 j 个词的原始相似度分数
scores = np.matmul(Q, K.T)
# 步骤 2:缩放——除以 √d_k,防止点积过大导致梯度消失
scores = scores / np.sqrt(d_k)
# 步骤 3:Softmax——把分数转换为注意力权重(每行加和=1)
attention_weights = softmax(scores)
# 步骤 4:用注意力权重对 Value 矩阵加权求和
# (seq_len, seq_len) × (seq_len, d_v) → (seq_len, d_v)
output = np.matmul(attention_weights, V)
return output, attention_weights
# ---- 示例演示 ----
# 假设句子有 4 个词,每个词的向量维度是 8
np.random.seed(42)
seq_len = 4 # 序列长度(词的数量)
d_model = 8 # 词向量维度
d_k = 4 # Q 和 K 的投影维度
# 模拟输入词向量(实际来自词嵌入层)
X = np.random.randn(seq_len, d_model)
# 三个可训练的投影矩阵(实际通过梯度下降学习,这里随机初始化)
W_Q = np.random.randn(d_model, d_k)
W_K = np.random.randn(d_model, d_k)
W_V = np.random.randn(d_model, d_k)
# 计算 Q、K、V 矩阵
Q = X @ W_Q # (4, 8) × (8, 4) → (4, 4)
K = X @ W_K
V = X @ W_V
# 执行注意力计算
output, weights = scaled_dot_product_attention(Q, K, V)
print("输入序列形状:", X.shape) # (4, 8)
print("Q/K/V 形状:", Q.shape) # (4, 4)
print("注意力权重矩阵:\n", np.round(weights, 3))
# 每行代表一个词对所有词的注意力分布,每行加和等于 1
print("输出形状:", output.shape) # (4, 4)
# 验证:注意力权重每行加和 = 1
print("每行权重之和:", weights.sum(axis=1)) # 全部约等于 1.0
文字说明:
scores = Q @ K.T这一行就是"Query 和 Key 做点积",得到每个词对其他所有词的原始相似度分数/ np.sqrt(d_k)就是"除以 √d_k",缩放防止梯度消失softmax(scores)就是把分数转换为权重,每行加和等于 1weights @ V就是"加权提取 Value",得到每个词融合了上下文信息的新表示
实际的 Transformer 里,还会有掩码(Mask)操作——在解码阶段,第 i 个词不应该看到第 i+1 及之后的词(因为那些词还没有生成),通过把对应位置的分数设置为负无穷,Softmax 之后权重就变成 0,实现了屏蔽效果。
1.9 从直觉到理解的完整路径
把本篇的内容串起来,形成一条完整的理解链:
- Q/K/V 从哪来:输入向量分别经过三个可训练矩阵(W_Q、W_K、W_V)投影得到
- Q 和 K 怎么匹配:做点积,得到相似度分数,方向越相近分数越大
- 为什么要缩放:防止维度大时点积过大,导致 Softmax 极化,梯度消失
- Softmax 做什么:把相似度分数变成加和为 1 的注意力权重
- 权重怎么用:对 V 矩阵做加权求和,提取每个词应该借鉴的信息
- 为什么多头:不同头并行学习不同类型的关系(语法、语义、指代……),拼接后表达能力更强
这些就是注意力机制的数学直觉全貌。没有遗漏任何重要概念,也没有真正用到超出初中数学的知识——所有"数学"最后都归结为"越相似点积越大"这一条直觉。
下一篇讲 Transformer 里另一个核心组件的工作原理:MoE(混合专家架构),解释 DeepSeek 为什么又快又便宜。