注意力机制背后的数学:Q、K 和 V

---
title: "注意力机制背后的数学:Q、K 和 V"
author: "Amit Shekhar (@amitiitbhu)"
source_url: "https://x.com/amitiitbhu/status/2040027305297526811"
published_at: "2026-04-03T11:23:06.000Z"
fetched_at: "2026-06-27T23:39:59Z"
updated_at: "2026-07-23T16:07:01Z"
language: "zh"
review_status: "draft"
---

![](https://pbs.twimg.com/media/HE9orWubgAAbWj1.jpg)

# 注意力机制背后的数学:Q、K 和 V

在这篇文章里,我们会通过一个逐步展开的数值例子,学习注意力机制背后的数学:查询(Query,Q)、键(Key,K)和值(Value,V)。

我们会讲到:

- 注意力公式
- 准备工作:从词到向量
- 创建 Q、K 和 V 矩阵
- 计算注意力分数(Q x K^T)
- 缩放分数
- 应用 softmax
- 计算最终输出(注意力权重 x V)
- 把所有步骤串起来

开始吧。

### 注意力公式

**缩放点积注意力(Scaled Dot-Product Attention)**的核心公式是:

```markdown
Attention(Q, K, V) = softmax(Q x K^T / sqrt(d_k)) x V
```

这里:

- **Q** 是查询矩阵
- **K** 是键矩阵
- **V** 是值矩阵
- **K^T** 是键矩阵的转置
- **d_k** 是键向量的维度
- **sqrt** 表示平方根

如果这个公式看起来复杂,不用担心。我们会用真实数字一步步拆开它。读完这篇文章后,这个公式的每一部分都会变得清楚。

思路很简单:我们把每个词想寻找的内容(**查询**),和其他每个词能提供的内容(**键**)进行比较,再根据比较结果,从最相关的词中收集实际信息(**值**)。

现在,用真实数字来看一遍。

### 准备工作:从词到向量

我们取一个只有 3 个词的简单句子:

**"I love AI"(我爱 AI)**

在 Transformer 里,每个词会先被转换成一个向量(也就是一组数字),称为[嵌入(embedding)](https://www.youtube.com/watch?v=LedXW6xl21s)。为了便于理解,我们会使用非常小的 4 维向量(也就是 **d_emb = 4**)。

```markdown
"I"    → [1.0, 0.0, 1.0, 0.0]
"love" → [0.0, 1.0, 0.0, 1.0]
"AI"   → [1.0, 1.0, 0.0, 0.0]
```

我们把这些向量堆叠成一个形状为 **3 x 4** 的**输入矩阵 X**(3 个词,每个词有 4 个数字):

```markdown
X = | 1.0  0.0  1.0  0.0 |   ← "I"
    | 0.0  1.0  0.0  1.0 |   ← "love"
    | 1.0  1.0  0.0  0.0 |   ← "AI"
```

这里,每一行代表一个词,每一列对应嵌入向量中的一个数字。这就是我们的起点。

### 创建 Q、K 和 V 矩阵

现在,我们需要创建三个单独的矩阵:**Q(查询)**、**K(键)** 和 **V(值)**。

怎么创建它们?我们把输入矩阵 **X** 分别乘以三个不同的**权重矩阵**:**W_Q**、**W_K** 和 **W_V**。这些权重矩阵是在训练过程中学习得到的。

```markdown
Q = X x W_Q
K = X x W_K
V = X x W_V
```

在我们的例子里,假设 **d_k = 3**(也就是我们想让 Q、K、V 向量的大小为 3)。因此,每个权重矩阵的形状都是 **4 x 3**(输入维度 4,输出维度 3)。

为了便于理解,我们使用下面这些权重矩阵:

```markdown
W_Q = | 1  0  1 |
      | 0  1  0 |
      | 1  0  0 |
      | 0  1  1 |

W_K = | 0  1  0 |
      | 1  0  1 |
      | 0  0  1 |
      | 1  1  0 |

W_V = | 1  0  0 |
      | 0  1  0 |
      | 0  0  1 |
      | 1  1  0 |
```

现在,我们来计算 Q、K 和 V。

**计算 Q = X x W_Q:**

```markdown
Q = | 1.0  0.0  1.0  0.0 |     | 1  0  1 |
    | 0.0  1.0  0.0  1.0 |  x  | 0  1  0 |
    | 1.0  1.0  0.0  0.0 |     | 1  0  0 |
                               | 0  1  1 |
```

第一行("I"):**[1*1 + 0*0 + 1*1 + 0*0, 1*0 + 0*1 + 1*0 + 0*1, 1*1 + 0*0 + 1*0 + 0*1]** = **[2, 0, 1]**

第二行("love"):**[0*1 + 1*0 + 0*1 + 1*0, 0*0 + 1*1 + 0*0 + 1*1, 0*1 + 1*0 + 0*0 + 1*1]** = **[0, 2, 1]**

第三行("AI"):**[1*1 + 1*0 + 0*1 + 0*0, 1*0 + 1*1 + 0*0 + 0*1, 1*1 + 1*0 + 0*0 + 0*1]** = **[1, 1, 1]**

```markdown
Q = | 2  0  1 |   ← "I"
    | 0  2  1 |   ← "love"
    | 1  1  1 |   ← "AI"
```

**计算 K = X x W_K:**

第一行("I"):**[1*0 + 0*1 + 1*0 + 0*1, 1*1 + 0*0 + 1*0 + 0*1, 1*0 + 0*1 + 1*1 + 0*0]** = **[0, 1, 1]**

第二行("love"):**[0*0 + 1*1 + 0*0 + 1*1, 0*1 + 1*0 + 0*0 + 1*1, 0*0 + 1*1 + 0*1 + 1*0]** = **[2, 1, 1]**

第三行("AI"):**[1*0 + 1*1 + 0*0 + 0*1, 1*1 + 1*0 + 0*0 + 0*1, 1*0 + 1*1 + 0*1 + 0*0]** = **[1, 1, 1]**

```markdown
K = | 0  1  1 |   ← "I"
    | 2  1  1 |   ← "love"
    | 1  1  1 |   ← "AI"
```

**计算 V = X x W_V:**

第一行("I"):**[1*1 + 0*0 + 1*0 + 0*1, 1*0 + 0*1 + 1*0 + 0*1, 1*0 + 0*0 + 1*1 + 0*0]** = **[1, 0, 1]**

第二行("love"):**[0*1 + 1*0 + 0*0 + 1*1, 0*0 + 1*1 + 0*0 + 1*1, 0*0 + 1*0 + 0*1 + 1*0]** = **[1, 2, 0]**

第三行("AI"):**[1*1 + 1*0 + 0*0 + 0*1, 1*0 + 1*1 + 0*0 + 0*1, 1*0 + 1*0 + 0*1 + 0*0]** = **[1, 1, 0]**

```
V = | 1  0  1 |   ← "I"
    | 1  2  0 |   ← "love"
    | 1  1  0 |   ← "AI"
```

现在,Q、K 和 V 矩阵都准备好了。

**注意:** 在真实模型中,这些权重矩阵不是手工设置的,而是在训练过程中学习得到的。这里为了便于理解,我们使用了简单数字。

到目前为止,我们已经学会了如何从输入创建 Q、K 和 V。现在进入下一步。

### 计算注意力分数(Q x K^T)

注意力公式里的第一步,是计算 **Q x K^T**。

这个结果表示每个词应该在多大程度上关注其他各个词。计算时,要把每个词的查询向量与其他每个词的键向量相乘。

首先,我们需要 **K^T**(K 的转置)。转置的意思很简单:交换行和列。第一行变成第一列,第二行变成第二列,依此类推:

```
K^T = | 0  2  1 |
      | 1  1  1 |
      | 1  1  1 |
```

现在,计算 **Q x K^T**:

```
Q x K^T = | 2  0  1 |     | 0  2  1 |
          | 0  2  1 |  x  | 1  1  1 |
          | 1  1  1 |     | 1  1  1 |
```

"I" 对所有词的注意力分数:

- "I" → "I":**2*0 + 0*1 + 1*1** = **1**
- "I" → "love":**2*2 + 0*1 + 1*1** = **5**
- "I" → "AI":**2*1 + 0*1 + 1*1** = **3**

"love" 对所有词的注意力分数:

- "love" → "I":**0*0 + 2*1 + 1*1** = **3**
- "love" → "love":**0*2 + 2*1 + 1*1** = **3**
- "love" → "AI":**0*1 + 2*1 + 1*1** = **3**

"AI" 对所有词的注意力分数:

- "AI" → "I":**1*0 + 1*1 + 1*1** = **2**
- "AI" → "love":**1*2 + 1*1 + 1*1** = **4**
- "AI" → "AI":**1*1 + 1*1 + 1*1** = **3**

```markdown
            "I"   "love"   "AI"
Scores = |  1      5       3  |   ← "I"
         |  3      3       3  |   ← "love"
         |  2      4       3  |   ← "AI"
```

这里可以看到,"I" 给 "love" 的注意力分数最高,为 **5**,意味着 "I" 认为 "love" 最相关。"love" 给所有词的分数都一样,都是 **3**。"AI" 给 "love" 的分数最高,为 **4**。

注意力分数的计算就到这里。现在进入缩放步骤。

### 缩放分数

现在,我们把每个分数都除以 **sqrt(d_k)**。

在这个例子里,**d_k = 3**(也就是键向量的维度),所以 **sqrt(3) = 1.732**。

问题来了:为什么要缩放?答案是:如果点积的值太大,下一步里的 softmax 函数会产生非常极端的值(接近 0 或 1)。这会让模型更难学习。缩放可以把数值保持在一个更容易处理的范围内。

```markdown
Scaled Scores = Scores / sqrt(3)
```

```markdown
                    "I"      "love"     "AI"
Scaled Scores = |  0.577    2.887     1.732  |   ← "I"
                |  1.732    1.732     1.732  |   ← "love"
                |  1.155    2.309     1.732  |   ← "AI"
```

这里可以注意到,分数的相对顺序没有改变。"I" 仍然最关注 "love"。但数值变小了,这正是我们想要的。

以后,我计划写一篇文章,解释为什么选择除以 **sqrt(d_k)**,而不是其他因子。

接下来应用 softmax。

### 应用 softmax

现在,我们对每一行应用 **softmax** 函数。[Softmax](https://www.youtube.com/watch?v=2Zx6x01WwWM) 会把分数转换成概率,并且这些概率加起来等于 1。

一行里某个值 **x_i** 的 softmax 公式是:

```markdown
softmax(x_i) = e^(x_i) / sum(e^(x_j) for all j in that row)
```

这里,**e** 是数学常数(约等于 2.718)。不用太纠结这个公式。我们会一步步算出来。

**对 "I" 这一行:[0.577, 2.887, 1.732]**

- **e^0.577** = 1.781
- **e^2.887** = 17.940
- **e^1.732** = 5.651
- 总和 = 1.781 + 17.940 + 5.651 = 25.372

注意力权重:

- "I" → "I":1.781 / 25.372 = **0.070**
- "I" → "love":17.940 / 25.372 = **0.707**
- "I" → "AI":5.651 / 25.372 = **0.223**

**对 "love" 这一行:[1.732, 1.732, 1.732]**

所有值都相等,所以每个词获得相同的注意力:

- "love" → "I":**0.333**
- "love" → "love":**0.333**
- "love" → "AI":**0.333**

**对 "AI" 这一行:[1.155, 2.309, 1.732]**

- **e^1.155** = 3.174
- **e^2.309** = 10.063
- **e^1.732** = 5.651
- 总和 = 3.174 + 10.063 + 5.651 = 18.888

注意力权重:

- "AI" → "I":3.174 / 18.888 = **0.168**
- "AI" → "love":10.063 / 18.888 = **0.533**
- "AI" → "AI":5.651 / 18.888 = **0.299**

最终的**注意力权重矩阵**是:

```markdown
                       "I"     "love"    "AI"
Attention Weights = | 0.070    0.707    0.223 |   ← "I"
                    | 0.333    0.333    0.333 |   ← "love"
                    | 0.168    0.533    0.299 |   ← "AI"
```

这里可以看到:

- **"I"** 把 70.7% 的注意力放在 **"love"** 上,22.3% 放在 **"AI"** 上,只有 7.0% 放在自己身上。
- **"love"** 对三个词的注意力相同(各 33.3%)。
- **"AI"** 把 53.3% 的注意力放在 **"love"** 上,29.9% 放在自己身上,16.8% 放在 **"I"** 上。

每一行加起来都是 1.0(也就是 100%)。这正是 softmax 所保证的。

现在,我们有了注意力权重。接下来计算最终输出。

### 计算最终输出(注意力权重 x V)

现在,我们把注意力权重矩阵和值矩阵 **V** 相乘,得到最终输出。

```markdown
Output = Attention Weights x V
```

```markdown
Output = | 0.070  0.707  0.223 |     | 1  0  1 |
         | 0.333  0.333  0.333 |  x  | 1  2  0 |
         | 0.168  0.533  0.299 |     | 1  1  0 |
```

**对 "I":**

- **0.070*1 + 0.707*1 + 0.223*1** = **1.000**
- **0.070*0 + 0.707*2 + 0.223*1** = **1.637**
- **0.070*1 + 0.707*0 + 0.223*0** = **0.070**

**对 "love":**

- **0.333*1 + 0.333*1 + 0.333*1** = **0.999**
- **0.333*0 + 0.333*2 + 0.333*1** = **0.999**
- **0.333*1 + 0.333*0 + 0.333*0** = **0.333**

**对 "AI":**

- **0.168*1 + 0.533*1 + 0.299*1** = **1.000**
- **0.168*0 + 0.533*2 + 0.299*1** = **1.365**
- **0.168*1 + 0.533*0 + 0.299*0** = **0.168**

```markdown
Output = | 1.000  1.637  0.070 |   ← "I"
         | 1.000  1.000  0.333 |   ← "love"
         | 1.000  1.365  0.168 |   ← "AI"
```

这里可以看到,每个词现在都有了一个新向量,它是所有词的 V 向量的**加权组合**。"I" 得到的新表示受 "love" 的 V 向量影响很大(因为它对 "love" 的注意力权重最高,为 0.707)。这就是注意力机制的作用。

每个词的输出不再只与这个词本身有关。它现在包含了来自其他所有词的信息,并且这些信息会按相关性加权。这就是模型理解上下文和词与词之间关系的方式。

最终输出的计算就到这里。现在,把所有步骤串起来。

### 把所有步骤串起来

我们把整个计算过程集中总结一下:

**第 1 步:** 从输入嵌入向量(X)开始。

**第 2 步:** 用 X 乘以权重矩阵,得到 Q、K 和 V。

**第 3 步:** 用 Q 乘以 K 的转置(Q x K^T),计算注意力分数。

**第 4 步:** 除以 sqrt(d_k),对分数进行缩放。

**第 5 步:** 应用 softmax,得到注意力权重(概率)。

**第 6 步:** 用注意力权重乘以 V,得到最终输出。

整个过程可以写成一个公式:

```markdown
Attention(Q, K, V) = softmax(Q x K^T / sqrt(d_k)) x V
```

现在,这个公式的每一部分都清楚了。

这就是注意力机制中 Q、K 和 V 背后的数学。

每个大语言模型(LLM)的核心都会用到这套计算。为了便于理解,我们使用的是很小的数字;但在真实模型里,维度会大得多(512、1024 或更高),权重矩阵也是在训练过程中学习得到的。

现在,我们应该已经理解了注意力机制背后的数学:Q、K 和 V。

今天就到这里。

谢谢

**Amit Shekhar**  
[Outcome School](https://outcomeschool.com/) 创始人

[**在这里阅读我的所有高质量博客。**](https://outcomeschool.com/blog)