从零看懂 Transformer:Q、K、V 与注意力机制
从零看懂 Transformer:Q、K、V 与注意力机制
YYT很多人第一次看到 Transformer 的 Q、K、V,都会被一串矩阵和公式劝退。其实先记住一个直觉就够了:每个 Token 都会生成一份“我想找什么”(Q)、一份“我有什么特征”(K),以及一份“我能提供什么内容”(V)。
模型用 Q 和其他 Token 的 K 计算相关程度,再按照这个相关程度汇总它们的 V。下面就沿着“文字 → 向量 → QKV → 注意力 → 新表示”这条路,把它一步步拆开。
一、先用一个例子理解 Q、K、V
想象你在公司遇到一个问题:“谁能帮我优化数据库查询?”
- Q(Query,查询):你当前想寻找的信息,也就是“我需要数据库优化方面的帮助”。
- K(Key,键):每位同事身上便于匹配的特征,例如“熟悉数据库”“擅长前端”。
- V(Value,值):同事真正能提供的经验和内容。
你用问题去匹配每个人的特征,匹配度越高,就越多地参考对方的经验。注意力机制做的事情很像这样:对一个 Token 来说,它会查看当前允许关注的其他 Token,并根据匹配分数混合它们的信息。
这个类比帮助理解 Q、K、V 的分工,但不要把它们当成模型能读懂的中文标签。真实的 Q、K、V 是向量,含义由训练过程逐渐塑造,通常无法把某一个维度直接翻译成一句人类语言。
二、从文字得到向量:Token、Embedding 与位置信息
1. 先把文字切成 Token
模型收到句子后,分词器会把它转换成 Token。Token 不一定等于一个汉字或一个完整单词;具体怎么切,取决于分词器和词表。英文单词可能被拆成子词,中文里一个 Token 也可能对应一个字、多个字或其他子词片段。
比如,下面只是一个便于理解的示意:
1 | “小猫追球,因为它很兴奋” |
真实模型的切分结果未必与这个例子相同。模型随后会把每个 Token ID 映射成一个向量,这一步叫 Embedding:
1 | “小猫” → [0.21, -0.53, 0.77, ...] |
一个 Token 的向量可能有数百或数千个维度。维度里的数字不是词典释义,而是模型计算时使用的特征表示。
2. 还要让模型知道顺序
如果只把所有 Token 的向量交给标准自注意力层,模型本身没有直接的顺序概念。“猫追狗”和“狗追猫”包含同一批 Token,却表达了不同关系,所以模型还需要获得位置信息。
经典 Transformer 使用正弦、余弦函数构造位置编码,再与 Token Embedding 相加:
1 | Token Embedding + Position Encoding → 输入表示 x |
早期的一些模型采用可学习的绝对位置向量。许多现代大语言模型则使用旋转位置编码(RoPE)等方案,把位置信息融入注意力计算中的 Q、K 表示。它们实现方式不同,目标都是让模型利用序列顺序。
采用“位置向量与 Embedding 相加”方案时,第一层接收的 x 同时包含 Token 表示和位置信息;使用 RoPE 时,第一层输入通常仍从 Token Embedding 开始,位置信息会在注意力计算中融入 Q、K。进入后续层后,每个 Token 的 x 则是上一层生成的上下文表示,并随着网络层数不断更新。
三、Q、K、V 是怎么得到的?
每个 Token 的输入表示会经过三组不同的可学习线性变换:
1 | Q = x W_Q |
如果一次处理整段序列,可以把所有 Token 的向量排成矩阵 X:
1 | Q = X W_Q |
若序列长度是 n、模型隐藏维度是 d_model,那么 X 可以看成 n × d_model 的矩阵。投影后,Q Kᵀ 会得到一个 n × n 的分数矩阵:每一行对应一个查询位置,每一列对应一个可供关注的位置。
这里讲的是自注意力,因此 Q、K、V 都由同一个输入序列投影得到。在交叉注意力中,Q 可以来自一段序列,而 K、V 来自另一段序列,例如解码器根据编码器输出查询信息。
W_Q、W_K、W_V 就是模型参数。它们通常从随机值开始,在训练中根据目标和误差通过反向传播不断调整。以 GPT 一类模型为例,训练目标通常包含预测下一个 Token;BERT 一类模型则使用过遮盖 Token 预测等目标。经过训练后,这些变换会学出适合当前任务的表示方式。
同一层、同一个注意力头里,所有位置会共享这组投影矩阵;不同层或不同注意力头使用各自的参数。工程实现中,三组投影有时会合并成一个大矩阵一次计算,但概念上仍然是三种不同的变换。
可以把它们先记成:
| 向量 | 直观理解 | 在注意力中的作用 |
|---|---|---|
| Q | 我现在要找什么 | 发起查询,与其他位置的 K 比较 |
| K | 我有什么特征 | 与 Q 匹配,产生注意力分数 |
| V | 我能提供什么 | 按注意力权重汇总,形成新信息 |
这里的“查询”“特征”“内容”是帮助理解的说法,并不意味着模型内部真的存着这些文字标签。
四、注意力的核心:打分、归一化、汇总
现在假设句子里有三个 Token:“小猫”“很”“兴奋”。我们只看模型在处理“兴奋”这个位置时,如何从其他位置收集信息。
第一步:用 Q 和 K 打分
取“兴奋”的 Q,分别与三个 Token 的 K 做点积。下面的数字是虚构的示意分数:
为了单独看清后面的 Softmax 和加权汇总,这里暂时省略缩放因子和掩码。
1 | Q(兴奋) · K(小猫) = 5.2 |
点积可以暂时理解为两个向量的匹配分数。分数越高,表示在这一次注意力计算里,模型越倾向于让“兴奋”参考对应位置的信息。具体分数由学到的参数和当前上下文共同决定,不是固定的词语关联表。
第二步:用 Softmax 把分数变成权重
注意力分数可以为正也可以为负,因此需要把它们变成一组非负且总和为 1 的权重。Softmax 的定义是:
1 | softmax(z_i) = exp(z_i) / Σ_j exp(z_j) |
将刚才的分数代入,近似得到:
1 | exp(5.2) ≈ 181.27 |
这表示在这个简化示例中,“兴奋”位置的大部分注意力权重落在“小猫”上。Softmax 通过指数函数保留分数的相对大小,并把它们变成便于加权汇总的比例;它不保证每次都出现“赢家通吃”,结果取决于分数之间的差距。
第三步:按权重汇总 V
最后用这些权重对各个位置的 V 做加权求和:
1 | 新表示(兴奋) |
输出仍然是一个向量,但它已经融合了当前注意力范围内的信息。模型会在后续层继续加工它。
这也有助于理解代词和上下文:处理“它”时,模型可以把上下文里与当前计算有关的信息聚合到“它”的表示中。不过,不同注意力头和不同层可能捕捉到不同关系,不能据此断言某个头始终专门负责“指代消解”。
把整段序列写成矩阵形式,缩放点积注意力是:
1 | Attention(Q, K, V) |
其中 Q Kᵀ 一次计算出各个查询位置与各个键位置之间的分数;Softmax 通常沿着每个查询对应的键位置归一化;M 是可选的掩码。忽略因果掩码和其他位置限制时,可以把 M 理解为全零。
五、为什么要除以 √d_k?
向量维度较高时,点积是很多维度乘积的累加。假设 Q、K 的各维近似独立、均值为 0、方差为 1,那么未缩放点积的方差会随维度 d_k 增长,标准差大约是 √d_k。
分数的尺度太大时,Softmax 容易变得非常尖锐,例如:
1 | [2.0, 1.0] → [0.73, 0.27] |
后一种情况下,注意力权重几乎都压在一个位置上,Softmax 对分数变化的响应会变小,训练时相关梯度也可能变弱。除以 √d_k 可以在常见的初始化假设下把点积的尺度控制住,让 Softmax 更容易处于有效工作区间。
这不是说训练过程中所有分数都会严格保持方差为 1;它是一种针对高维点积尺度的稳定化设计。这个缩放因子来自经典 Transformer 论文提出的 Scaled Dot-Product Attention。
六、多头注意力:从不同表示子空间并行观察
单个注意力头只使用一组 Q、K、V 投影。多头注意力会并行计算多个头:每个头有各自的投影参数,可以从不同的表示子空间生成注意力结果,然后把结果拼接起来,再经过一次线性变换:
1 | 头 1:Attention(Q₁, K₁, V₁) ─┐ |
对应的简写公式是:
1 | MultiHead(Q, K, V) = Concat(head₁, …, headₕ) W_O |
其中每个 head 都独立完成一次注意力计算,W_O 再把拼接结果投影回模型需要的维度。
可以把多头理解为“让模型并行地从多个角度收集信息”。有些头可能呈现出明显的局部或关系模式,但这些模式不是人为指定的标签,也不保证每个头都能被简单解释成一种语言学功能。
七、GPT 为什么要遮住未来位置?
在 GPT 逐 Token 生成文本时,预测当前位置只能依据当前位置及之前的 Token。如果计算注意力时允许它看到后面的真实答案,训练目标就会发生信息泄漏。
因此,GPT 使用因果掩码(causal mask):把未来位置的注意力分数设成负无穷。经过 Softmax 后,这些位置的权重就是 0:
1 | 可关注:当前 Token 以及它之前的位置 |
需要区分两件事:**掩码规定某些位置不能被关注,注意力权重决定其余位置各自有多重要。**编码器、自回归解码器和交叉注意力会使用不同的注意力范围。
八、注意力之后,一个 Transformer 层还做什么?
注意力子层生成新的上下文表示后,通常还会经过前馈网络(Feed-Forward Network)。这个网络对每个位置分别进行非线性变换,再通过残差连接和 LayerNorm 等结构帮助信息传递与训练稳定。
常见的前馈网络由两层线性变换和中间的非线性激活组成;同一层通常对每个位置使用相同的网络参数,但各位置分别计算。
可以把常见的 Pre-LayerNorm 结构简化写成:
1 | h = x + SelfAttention(LayerNorm(x)) |
这是许多现代 Transformer 使用的一类写法,用来突出“子层结果加回输入”的残差结构。原始 Transformer 使用的 LayerNorm 放置顺序与这种简写不同,不同模型也会有额外变体;共同点是注意力负责跨位置交换信息,前馈网络负责逐位置变换特征,残差连接则保留并传递原有表示。
在 GPT 这样的解码器模型中,这些层会重复堆叠,最终的上下文表示再用于预测下一个 Token。完整链路可以概括为:
1 | 文本 |
九、最后用一句话记住 Q、K、V
Q 决定当前要寻找什么,K 决定各位置如何与这个查询匹配,V 则提供最终按权重汇总的信息。
自注意力的核心就是:让每个位置根据 Q 与各个 K 的匹配分数,选择性地汇总 V。位置表示告诉模型顺序,多头让模型并行学习不同的表示关系,因果掩码限制 GPT 不能偷看未来;它们一起组成了 Transformer 中强大的信息交互机制。
想看原始结构,可以继续读 Vaswani 等人的论文:Attention Is All You Need。