从一条直线到大模型输出一个token(六):QKV 三剑客
从一条直线到大模型输出一个token(六):QKV 三剑客
建议先看:从一条直线到大模型输出一个token(五):Transformer Block 全景与层归一化
上一篇把 Block 的结构图和 LayerNorm 讲完了。这一篇进入 Block 里最核心的部件——多头自注意力的第一步:Q、K、V 三个矩阵是怎么算出来的,各自代表什么。
从一条直线到大模型输出一个token(六):QKV 三剑客
1. 一个比喻:图书馆式的分工
先把 QKV 的角色用一句话锚定,如图 6-1 所示。

图6-1 QKV 三剑客:图书馆式的分工(查询单 / 书脊名片 / 书的内容)
想象你在图书馆找资料,会发生三件事:
- 你心里有个问题(“西安是不是个地名?”),填一张查询单——这是 Q(Query,查询):我要找什么信息
- 每本书的书脊上印着名片(类别、关键词),供你比对——这是 K(Key,键):我有什么信息
- 名片对上了,你把书抽出来读具体内容——这是 V(Value,值):我的具体内容
一句话里的每个 token 都要同时扮演这三个角色:「西安」发查询单(Q),「天气」亮名片(K),名片对上后「天气」交付内容(V)。注意力的本质就是这三步:Q 找 K 配对、按配对度取 V——配对打分是下一篇的内容,本篇先把三个角色"孵化"出来。
2. Q 的诞生:X 乘一个权重矩阵
2.1 计算方式:一次矩阵乘法
上一篇讲过,进注意力之前矩阵先过了第①步层归一化。那份归一化后的 X(6×4096,含「西安」行 [ − 1.446 , 0.463 , 1.257 , − 0.485 ] [-1.446,\ 0.463,\ 1.257,\ -0.485] [−1.446, 0.463, 1.257, −0.485] 等),就是 QKV 的共同原料。
Q 由一次矩阵乘法得到:
Q = X ⋅ W Q \mathbf{Q} = \mathbf{X} \cdot \mathbf{W}_Q Q=X⋅WQ
W Q \mathbf{W}_Q WQ 是一个 4096×4096 的权重矩阵——还记得第一篇说的吗?大模型的本质就是权重和偏置,这里的 W Q \mathbf{W}_Q WQ 是训练学出来的(约 1678 万个参数)。整个过程如图 6-2 所示,图中每个矩阵每行的最大值用红色标出(含义见 2.3 节)。

图6-2 Q 的诞生:X 乘权重矩阵 W_Q(红色 = 每行最大值)
2.2 贯穿案例手算
用演示规模(d=4)实际算一遍。「西安」行乘 W Q \mathbf{W}_Q WQ 的第 1 列:
( − 1.446 ) × 0.5 + 0.463 × 0 + 1.257 × 1 + ( − 0.485 ) × 0 = − 0.723 + 1.257 = 0.534 (-1.446) \times 0.5 + 0.463 \times 0 + 1.257 \times 1 + (-0.485) \times 0 = -0.723 + 1.257 = 0.534 (−1.446)×0.5+0.463×0+1.257×1+(−0.485)×0=−0.723+1.257=0.534
这就是 Q 矩阵第 2 行第 1 个数——一行乘一列出一个数,第一篇练过的矩阵乘法直接上场。X 的 6 行各自乘完 W Q \mathbf{W}_Q WQ 的 4 列,得到完整的 Q(6×4,红色 = 每行最大值):
Q = [ 1.508 − 0.470 1.178 − 1.252 0.534 − 0.253 − 0.818 0.221 0.990 − 0.456 − 0.418 − 0.208 0.332 0.757 0.721 − 0.636 − 0.958 1.685 − 0.379 0.439 1.049 − 1.558 1.473 − 0.651 ] \mathbf{Q} = \begin{bmatrix} \textcolor{red}{1.508} & -0.470 & 1.178 & -1.252 \\ \textcolor{red}{0.534} & -0.253 & -0.818 & 0.221 \\ \textcolor{red}{0.990} & -0.456 & -0.418 & -0.208 \\ 0.332 & \textcolor{red}{0.757} & 0.721 & -0.636 \\ -0.958 & \textcolor{red}{1.685} & -0.379 & 0.439 \\ \textcolor{red}{1.049} & -1.558 & 1.473 & -0.651 \end{bmatrix} Q= 1.5080.5340.9900.332−0.9581.049−0.470−0.253−0.4560.7571.685−1.5581.178−0.818−0.4180.721−0.3791.473−1.2520.221−0.208−0.6360.439−0.651
2.3 数值怎么读:大小和正负的含义
Q 的每一行是对应 token 的"查询单"。以「西安」的查询单 [ 0.534 , − 0.253 , − 0.818 , 0.221 ] [0.534, -0.253, -0.818, 0.221] [0.534,−0.253,−0.818,0.221] 为例,怎么理解这四个数?
- 正数 = 我在找这个特征: + 0.534 +0.534 +0.534 表示「西安」的查询在 d₁ 方向"寻找"正值特征——演示语义空间里假设 d₁ 编码"地点属性",正数代表它在找地点类信息
- 负数 = 我在避开这个特征: − 0.818 -0.818 −0.818 表示「西安」在 d₃ 方向强烈"排斥"——假设 d₃ 编码"疑问语气",一个地点名词不需要语气特征,所以查询发出强负值
- 绝对值越大,态度越强: ∣ − 0.818 ∣ > ∣ 0.534 ∣ |{-0.818}| > |{0.534}| ∣−0.818∣>∣0.534∣,说明「西安」对"避开疑问语气"的诉求比对"寻找地点属性"更强烈
- 行内最大值(红色)= 最强烈的诉求:Q 第 2 行红色的是 0.534 0.534 0.534——「西安」最强烈的诉求是"找地点信息"
六个 token 的查询单逐行解读,如图 6-3 所示。

图6-3 Q 矩阵完整解读:每行的最大值与含义(红色标注)
从图 6-3 能看出节奏差异:「西安」的最大值只有 0.534——六个词里最含蓄的查询;「怎么样」(1.685)和「?」(1.473)最强烈——疑问词急着找答案所指。
注意:d₁~d₄ 的"语义假设"是演示用的设定。真实的 4096 维里每个维度对应什么语义,没有人规定——它们是训练自己长出来的,且往往是多个语义的混合。但"正数=寻找、负数=避开、绝对值=强度"的读法是通用的。
3. K 的诞生:换一个矩阵再乘一次
3.1 计算:X × W_K
K 的诞生方式与 Q 完全一样,只是换权重矩阵:
K = X ⋅ W K \mathbf{K} = \mathbf{X} \cdot \mathbf{W}_K K=X⋅WK
W K \mathbf{W}_K WK 是另一个独立的 4096×4096 权重矩阵(约 1678 万参数)。计算过程如图 6-4 所示。

图6-4 K 的诞生:X 乘权重矩阵 W_K(红色 = 每行最大值)
「西安」行乘 W K \mathbf{W}_K WK 第 1 列:
( − 1.446 ) × 0.8 + 0.463 × 0.2 + 1.257 × 0 + ( − 0.485 ) × 0 = − 1.157 + 0.093 = − 1.064 (-1.446) \times 0.8 + 0.463 \times 0.2 + 1.257 \times 0 + (-0.485) \times 0 = -1.157 + 0.093 = -1.064 (−1.446)×0.8+0.463×0.2+1.257×0+(−0.485)×0=−1.157+0.093=−1.064
完整的 K(6×4,红色 = 每行最大值):
K = [ 0.181 − 0.972 1.022 0.412 − 1.064 0.081 0.909 − 0.137 − 0.969 − 0.223 1.185 − 0.055 0.321 − 0.934 0.256 1.139 − 0.001 − 0.405 − 0.429 1.359 1.046 0.389 0.005 − 1.231 ] \mathbf{K} = \begin{bmatrix} 0.181 & -0.972 & \textcolor{red}{1.022} & 0.412 \\ -1.064 & 0.081 & \textcolor{red}{0.909} & -0.137 \\ -0.969 & -0.223 & \textcolor{red}{1.185} & -0.055 \\ 0.321 & -0.934 & 0.256 & \textcolor{red}{1.139} \\ -0.001 & -0.405 & -0.429 & \textcolor{red}{1.359} \\ \textcolor{red}{1.046} & 0.389 & 0.005 & -1.231 \end{bmatrix} K= 0.181−1.064−0.9690.321−0.0011.046−0.9720.081−0.223−0.934−0.4050.3891.0220.9091.1850.256−0.4290.0050.412−0.137−0.0551.1391.359−1.231
3.2 数值怎么读:名片上的"招牌特征"
K 的每一行是对应 token 的"名片"。看「天气」的名片 [ 0.321 , − 0.934 , 0.256 , 1.139 ] [0.321, -0.934, 0.256, 1.139] [0.321,−0.934,0.256,1.139]:
- 数值大小 = 这个维度特征的"招牌程度":名片上一格的值衡量"我在这个维度上突出到什么程度"
- 1.139 1.139 1.139(红色,本行最大)在 d₄ 上是强招牌——假设 d₄ 编码"气象属性",说明「天气」的名片在气象维度上高高挂起
- − 0.934 -0.934 −0.934 在 d₂ 上是强负值——「天气」在"结构词"维度(d₂ 假设编码虚词属性)明确表示"我不是结构词"
- 行内对比:「天气」的招牌集中在 d₄(1.139),「西安」的招牌集中在 d₃(0.909)——不同词的"最强名片"落在不同维度上,这正是下一步 Q·Kᵀ 能打出差异分的基础
六张名片的逐行解读,如图 6-5 所示。

图6-5 K 矩阵完整解读:每张名片的招牌特征(红色标注)
一句话总结读法:Q 是"我要什么"(正=找、负=避),K 是"我有什么"(绝对值=招牌强度)。查询要找的和名片挂的如果对上(同维度同符号、数值都大),点积就高。
4. V 的诞生:交付内容的"包装"
4.1 计算:X × W_V
V = X ⋅ W V \mathbf{V} = \mathbf{X} \cdot \mathbf{W}_V V=X⋅WV
W V \mathbf{W}_V WV 又是一个独立的权重矩阵。计算过程如图 6-6 所示。

图6-6 V 的诞生:X 乘权重矩阵 W_V(红色 = 每行最大值)
「西安」行乘 W V \mathbf{W}_V WV 第 1 列:
( − 1.446 ) × 0.9 + 0.463 × 0 + 1.257 × 0 + ( − 0.485 ) × 0 = − 1.301 (-1.446) \times 0.9 + 0.463 \times 0 + 1.257 \times 0 + (-0.485) \times 0 = -1.301 (−1.446)×0.9+0.463×0+1.257×0+(−0.485)×0=−1.301
完整的 V(6×4,红色 = 每行最大值):
V = [ 0.508 − 1.220 1.103 0.187 − 1.301 0.417 1.131 − 0.436 − 1.096 0.023 1.439 − 0.422 0.666 − 1.218 − 0.034 1.290 0.120 − 0.485 − 0.922 1.760 1.138 0.153 0.375 − 1.479 ] \mathbf{V} = \begin{bmatrix} 0.508 & -1.220 & \textcolor{red}{1.103} & 0.187 \\ -1.301 & 0.417 & \textcolor{red}{1.131} & -0.436 \\ -1.096 & 0.023 & \textcolor{red}{1.439} & -0.422 \\ 0.666 & -1.218 & -0.034 & \textcolor{red}{1.290} \\ 0.120 & -0.485 & -0.922 & \textcolor{red}{1.760} \\ \textcolor{red}{1.138} & 0.153 & 0.375 & -1.479 \end{bmatrix} V= 0.508−1.301−1.0960.6660.1201.138−1.2200.4170.023−1.218−0.4850.1531.1031.1311.439−0.034−0.9220.3750.187−0.436−0.4221.2901.760−1.479
V 的读法:它是名片对上之后实际交付的货物。下一篇文章会看到:注意力的最终输出是"按分数加权混合各词的 V"——所以 V 的数值代表"我贡献给别人的内容是什么"。逐行解读如图 6-7 所示,红色的行内最大值(如「怎么样」的 1.760 在 d₄,全场最大)就是这个词最突出的"输出资本"。

图6-7 V 矩阵完整解读:每个词的交付内容(红色标注)
用代码描述三个矩阵的诞生(大模型实现细节,跳过不影响理解):
class SelfAttention:
def __init__(self, d_model=4096):
# 三个独立的权重矩阵,训练前随机初始化
self.W_Q = random_init(d_model, d_model) # 4096×4096
self.W_K = random_init(d_model, d_model)
self.W_V = random_init(d_model, d_model)
def forward(self, x): # x: 归一化后的 (6, 4096)
Q = x @ self.W_Q # 查询单:我要找什么
K = x @ self.W_K # 名片:我有什么
V = x @ self.W_V # 内容:我交付什么
return Q, K, V # 三个 (6, 4096)
三个矩阵的总览如图 6-8 所示。

图6-8 三剑客总览:X 的三次「换视角」(红色 = 每行最大值)
需要澄清一个容易误会的说法:Q、K、V 并不"来自 X"本身。准确的说法是:X 乘以训练好的 W Q \mathbf{W}_Q WQ 得到 Q,X 乘以训练好的 W K \mathbf{W}_K WK 得到 K,X 乘以训练好的 W V \mathbf{W}_V WV 得到 V——X 只是原料,三个权重矩阵才是"翻译官",把同一份原料投影到三个不同的语义空间。
5. 预告篇7:Q 和 K 的第一次配对
三个矩阵都备齐了,先睹为快——把 Q 的每一行和 K 的每一行做点积(这正是下一篇的第一步 Q K T \mathbf{Q}\mathbf{K}^{\mathrm{T}} QKT),得到的 6×6 分数矩阵画成热力图,如图 6-9 所示。

图6-9 Q·Kᵀ 注意力分数热力图:6 个词的两两配对打分(贯穿案例实算)
这张图怎么读(对照图右侧的图例):
- 行 = 发问者,列 = 被查者:第 i 行第 j 列的格子 = 第 i 个词的查询单(Q 第 i 行)和第 j 个词的名片(K 第 j 行)的点积。比如第 1 行第 6 列的 2.94 = 「今天」的 Q · 「?」的 K
- 绿色 = 吸引,红色 = 排斥,颜色越深越强烈:正分说明查询要找的特征恰是名片上挂的(同维度同号且都大);负分说明查询要的特征恰是名片缺的。2.94 深绿是强烈吸引,-2.02 深红是强烈排斥
- 深色边框 = 每行最大值:这个词"最关注"的对象
几个一眼可见的看点:
- 「今天 ↔ ?」互相打出全场最高分 2.94——问句的首尾呼应:问号强烈关注主语(问号在问"今天怎么样"),主语也和句尾问号关联(今天在等一个回答)
- 「今天」强烈排斥「怎么样」(-2.02):时间名词的查询里带着"避开疑问语气"的诉求(还记得 2.3 节西安的读法吗),「怎么样」的名片恰好挂满疑问特征——查询要避开的和名片最强的撞了个正着,打出深红负分
- 「西安 ↔ 怎么样」互相 0.75——地点和疑问词联动:“怎么样"在问"西安的天气怎么样”,两者天然关联
- 对角线(自己和自己)普遍不高:「西安」和自己的名片打分只有 -1.36,反而和「怎么样」最高——因为 Q 和 K 是两个不同空间:自己发问用的特征(Q)和自己名片挂的特征(K)不一定是同一批。自注意力的"自"指"句子内部",不是"只关注自己"
这张图是未缩放、未 Softmax 的原始分。为什么还要除以 d k \sqrt{d_k} dk、为什么还要过 Softmax?这正是第 7 篇要讲的内容。
6. 主流大模型的 W_Q/W_K/W_V 现状
本篇的演示里三个权重矩阵是满规格的(4096×4096)。真实的大模型在"省显存"的路上一路演进,QKV 权重的形态已经分了三代:
表6-1 主流大模型 QKV 权重形态演进
| 方案 | 代表模型 | W_K/W_V 形态 | KV 显存 |
|---|---|---|---|
| MHA(多头注意力) | BERT、GPT-2、原始 Transformer | 满规格,和 W_Q 一样 | 100%(基准) |
| MQA(多查询注意力) | PaLM、Gemini 早期 | W_K/W_V 全部头共享一份 | 约 1/32 |
| GQA(分组查询注意力) | LLaMA-3、Qwen2.5、GLM-4、Mistral | 若干 Q 头共享一组 KV 头 | 约 1/4~1/8 |
| MLA(多头潜在注意力) | DeepSeek-V3/V4 | KV 压缩到低秩潜空间再还原 | 约 1/10 |
- MHA → GQA:32 个注意力头(第 7 篇讲多头),原本每头都要独立的 K、V。GQA 让比如 8 个 Q 头共享 1 组 KV 头——精度几乎不损失,KV 显存直接降到 1/8。LLaMA-3-8B 用 32 Q 头 + 8 KV 头,就是 GQA
- MLA(DeepSeek 独门):更激进的思路——把 KV 先压缩到一个低维"潜在空间"存起来,用时再解压还原。KV Cache 能压到 MHA 的约 1/10,代价是计算路径复杂一些
- 现状一句话:开源新模型几乎全是 GQA 或 MLA,满规格 MHA 在大模型里已经基本退出(只在 encoder 类模型如 BERT 里还在用)
这些机制直接决定第 10 篇 KV-Cache 的显存账单,到时候会回来对表。
7. 为什么是三个不同的 W
最后一个问题:Q、K、V 的原料都是同一个 X,为什么不干脆用 X 本身,或者只用一个 W?
如果 Q=K=V=X:注意力打分变成"自己和自己的点积"——每个词最像自己,其次像谁完全没规律,词际信息交换直接废掉。就像图书馆里,查询单、名片、书内容是同一张纸——你的问题就是你的答案,检索没有意义。
三个独立的 W 的意义在于分工,如图 6-10 所示。

图6-10 为什么三个不同的 W:提问、亮牌、交货是三种不同的表达
「发问的我」≠「亮牌的我」≠「交付货的我」——同一个人在不同交互环节,展示的侧面不同。体现在数学上: W Q \mathbf{W}_Q WQ 把 X 投影到"提问空间", W K \mathbf{W}_K WK 投影到"被检索空间", W V \mathbf{W}_V WV 投影到"内容交付空间",三个空间各自独立地学。
而且这个设计不是人拍脑袋定的,是训练学出来的:三个 W 初始化为随机值,训练中如果"提问和亮牌用同一套表达"效果更好,梯度会把它们推向相同;事实是训练出来的三个 W 差异很大——模型自己发现了分工的价值。
顺带回答"参数量":一个 MHA 注意力子层的 QKV 权重共 3 × 4096 × 4096 ≈ 5000 3 \times 4096 \times 4096 \approx 5000 3×4096×4096≈5000 万参数;GQA 下(32Q+8KV)约 4096 2 × ( 1 + 1 / 4 × 2 ) ≈ 2100 4096^2 \times (1 + 1/4 \times 2) \approx 2100 40962×(1+1/4×2)≈2100 万。
8. 讨论:QKV 之外,还能拆更多维度吗
写到这里不妨跳出来想一个问题:Q、K、V 本质上是什么?
回头看第 2~4 节:X 是每个 token 的完整向量,Q/K/V 是它乘三个不同权重矩阵得到的三个"投影"。换句话说,QKV 并不是三种新信息,而是同一份 4096 维信息的三个"视角拆分"——查询视角、被检索视角、内容视角。注意力机制就是建立在这三个视角的配合上。
那么一个自然的脑洞:能不能拆出第四个、第五个视角?比如:
- T(Time,时间视角): T = X ⋅ W T \mathbf{T} = \mathbf{X} \cdot \mathbf{W}_T T=X⋅WT——专门表达"这个词的时间属性"(时态、先后、时长),让"昨天/今天/明天"的推理有专门的通道
- E(Event,因果/事件视角): E = X ⋅ W E \mathbf{E} = \mathbf{X} \cdot \mathbf{W}_E E=X⋅WE——专门表达"这个词参与的事件角色"(原因、结果、施事、受事),让因果推理有独立的表达空间
理论上完全可以:再加两个 4096×4096 的权重矩阵,训练时一起学。但为什么主流大模型停留在 QKV 三个?
一,必要性。三个视角是"检索"这个动作的最小完备集:发起(Q)、应答(K)、交付(V)——少一个检索不成立,多一个(比如 T)检索本身不需要它。时间、因果这些信息,已经能被编码在 Q、K、V 的 4096 维里(比如 d₁₇₈ 恰好响应时间语义),不需要独立通道。
二,成本。每加一个视角,权重多 1678 万参数、每层多一次 6×4096 × 4096×4096 的矩阵乘法。收益不成比例——实验上没有证据表明独立的时间/因果视角能带来稳定的增益。
三,多头已经承担了这个角色。下一篇会讲:大模型把 4096 维拆成 32 个头并行做注意力,每个头可以各自关注不同侧面——有的头盯语法、有的头盯指代、有的头盯语义关联。"多视角"的需求,实践中是用"多头"而不是"多 QKV"来满足的——加头只要加相对便宜的 W(而且头之间共享输入),比加整套 QKV 流水线划算得多。
顺带一提,学界确实探索过类似方向的扩展:有的工作把注意力拆成"内容注意力 + 位置注意力"两条路(Decoupled Attention 一族),可以看作"给 QKV 加视角"的轻量版本;但四元组、五元组(QKVT、QKVTE)这种完整扩容,至今没有成为主流——三个视角 + 多头,就是工程和效果的平衡点。
这个讨论也反过来加深了对 QKV 的理解:它不是什么神秘的三件套,就是"一次检索需要的三种表达"这个朴素需求,落在矩阵运算上的样子。
小结
这一篇,Block ②的原料备齐了:
- QKV 三角色:Q=查询单(我要找什么)、K=名片(我有什么)、V=内容(我交付什么)
- 诞生方式:X 分别乘三个独立的训练权重矩阵 W Q \mathbf{W}_Q WQ、 W K \mathbf{W}_K WK、 W V \mathbf{W}_V WV——X 是原料,W 是翻译官
- 数值读法:Q 正数=寻找、负数=避开、绝对值=强度;K 的绝对值=招牌程度;V=待交付内容;每行最大值(红色)= 最强烈诉求/最强招牌/最大输出资本
- 贯穿案例:「西安」×三个 W 的手算全程可验证;Q/K/V 三个 6×4 矩阵全部实算并逐行解读
- 热力图预告:「今天↔?」2.94 首尾呼应、「今天↔怎么样」-2.02 强排斥、对角线不高——Q·Kᵀ 已能看出注意力的雏形
- 现状:主流大模型 QKV 权重已从 MHA 演进到 GQA(LLaMA-3/Qwen/GLM)和 MLA(DeepSeek-V3)
下一篇预告
Q(查询单)、K(名片)、V(内容)都备齐了,下一篇正式打分:Q 和 K 怎么配对、怎么算"相关度"。
剧透一下主角公式:
Attention ( Q , K , V ) = Softmax ( Q K T d k ) V \text{Attention}(\mathbf{Q}, \mathbf{K}, \mathbf{V}) = \text{Softmax}\left(\frac{\mathbf{Q}\mathbf{K}^{\mathrm{T}}}{\sqrt{d_k}}\right)\mathbf{V} Attention(Q,K,V)=Softmax(dkQKT)V
本篇热力图已经算出了 Q K T \mathbf{Q}\mathbf{K}^{\mathrm{T}} QKT 的原始分——为什么还要除以 d k \sqrt{d_k} dk(不除会发生什么)?Softmax 又怎么把分数变成"分配比例"?分数有了之后怎么加权混合 V 得到最终输出?另外还有多头的谜题:大模型为什么要 32 个头并行做这件事?都在第 7 篇。
系列目录:
- 从一条直线到高维空间
- 分词与 token 表
- 隐藏层与嵌入
- 位置编码 RoPE
- Transformer Block 全景与层归一化
- QKV 三剑客(当前篇)
- 注意力权重与多头机制
- 残差连接与前馈网络
- 输出矩阵与多层堆叠
- 首 token 诞生与 KV-Cache
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
更多推荐
所有评论(0)