logo蛋烘糕.

不写博客的工程师不是好的搬砖工🧱

AI 技术演进与核心算法实战 | 第四篇:注意力机制解密:Self-Attention 的矩阵运算图解与 Q,K,V 的物理意义

Cover Image for AI 技术演进与核心算法实战 | 第四篇:注意力机制解密:Self-Attention 的矩阵运算图解与 Q,K,V 的物理意义
蛋烘糕
蛋烘糕

Transformer 架构之所以能一统 NLP 和 CV,本质就在于它赋予了模型“注意力”。而 Q、K、V 就是理解注意力的钥匙。

在上一篇中,我们探讨了 Embedding 原理,了解到词汇是如何被映射到高维连续空间的。模型通过 Embedding 获得了词汇本身的“孤立语义”。

然而,人类语言是极其复杂的,一个词的意思往往取决于它的上下文。 例如:“苹果”这个词,在“我吃了一个苹果”和“苹果发布了新手机”中,意思截然不同。如果仅仅使用静态的 Embedding,模型是无法区分这两种情况的。

为了解决这个问题,2017 年 Google 在其划时代论文《Attention Is All You Need》中提出了 Self-Attention(自注意力机制)。它使得模型能够在处理每个词时,动态地去“关注”句子中的其他词,从而获得包含上下文信息的动态 Embedding

本篇是 《AI 技术演进与核心算法实战》第一模块的第四篇。我们将剥开 Self-Attention 的数学外衣,通过直观的图解和极简的 Python 代码,带你真正搞懂 Q、K、V 的物理意义以及矩阵运算背后的直觉。


1. 什么是注意力?从“找对象”说起

为了通俗地理解 Q、K、V 的概念,我们不妨想象一个“相亲/找对象”的场景:

假设你是一个正在寻找伴侣的人:

  • Query (Q,查询):你对理想伴侣的要求。比如“我想要一个性格开朗、喜欢旅游、会做饭的人”。这代表了你主动寻找信息的意图
  • Key (K,键):其他候选人身上的标签和特质。比如候选人 A 的标签是“性格内向、宅、会写代码”,候选人 B 的标签是“性格开朗、热爱户外、厨艺精湛”。这代表了被检索对象的特征
  • Value (V,值):候选人真正的内在价值或详细信息。比如候选人 B 除了上述标签,他的真实性格、工作情况、生活细节等完整内容。

注意力机制的计算过程就是:

  1. 拿你的要求 Q 去和所有候选人的标签 K 进行匹配(点积计算)。
  2. 匹配度越高(点积越大),你分配给那个人的“注意力”(Attention Score)就越多。
  3. 最后,你根据分配的注意力权重,综合所有候选人的真实价值 V,得到一个最终的判断(输出)。

在语言模型中,一句话中的每个词都同时扮演着寻找者(Q)、被寻找的标签(K)和真实的价值(V)三个角色。每个词都在看句子里的其他词,看看谁和自己最相关,然后把相关词的信息吸收过来,丰富自己的语义。


2. Self-Attention 核心步骤与通俗图解

为了让大家彻底摆脱对公式的恐惧,我们放弃冷冰冰的矩阵符号,用具体的例子来看看 Self-Attention 到底在干什么。

假设我们有一句话:“吃 苹果”。这两个词在进入模型前,各自拥有一个初始的词向量(Embedding)。接下来,它们要经历一场“信息交流大会”。

步骤 1:分身有术 —— 提取 Q、K、V

每个词在交流前,都会通过三个不同的“滤镜”(模型学到的权重),变出三个不同的身份:

  • Q (Query/查询):拿着大喇叭,喊出“我在找什么”。
  • K (Key/胸牌):挂在胸前,写着“我是谁,我有什么特征”。
  • V (Value/内涵):揣在兜里,装着“我真实的语义内容”。
词: "吃" Q (查询) "我要找食物" K (胸牌) "我是动词" V (内涵) 咀嚼的动作 词: "苹果" Q (查询) "我要找吃法" K (胸牌) "我是食物" V (内涵) 红色的水果

步骤 2:确认眼神 —— 计算匹配度 (Attention Scores)

接下来,“” 这个词想要丰富自己的含义,它举起自己的大喇叭(Q),去和句子里所有词的胸牌(K)进行配对。 在数学上,这个配对过程就是点积运算。点积结果越大,说明两个词越“来电”。

  • “吃”的 Q(找食物) 配对 “吃”自己的 K(动词):匹配度一般(比如得分 10)。
  • “吃”的 Q(找食物) 配对 “苹果”的 K(食物):完美契合!(比如得分 90)。
"吃" 的 Q 我要找食物 "吃" 的 K 我是动词 "苹果" 的 K 我是食物 10分 90分

步骤 3:分配注意力比例 —— Softmax 归一化

刚才算出的得分(10分、90分)是绝对数值,为了方便后续计算,模型会施加一个叫做 Softmax 的魔法漏斗。 它的作用很简单:把所有的得分变成百分比,并且保证加起来等于 100%。(在此之前还会稍微除以一个数“冷静”一下,防止极端值)。

经过 Softmax 后:

  • “吃”对“吃”自己的注意力比例:10%
  • “吃”对“苹果”的注意力比例:90%

这就意味着,“吃”这个词在理解自身当前语境时,决定花 90% 的精力去关注“苹果”。

步骤 4:取长补短,融为一体 —— 加权求和 (Weighted Sum)

终于到了最后一步!“吃”这个词根据刚才定好的比例,去拿大家兜里的内涵(V)

  • 从“吃”自己的 V 里抽取 10%
  • 从“苹果”的 V 里抽取 90%

把这些抽出来的内涵(向量)全部加起来揉碎,就得到了“吃”这个词全新的词向量(Output)

"吃" 的 V × 10% (权重) "苹果" 的 V × 90% (权重) + "吃" 的新向量 包含 90% 苹果的语义

此时的“吃”,已经不再是一个干巴巴的动作,而是变成了“吃苹果”这个具体情境下的“吃”。同理,“苹果”也会以类似的方式融合“吃”的信息,变成“被吃的苹果”。

这就是 Self-Attention 的核心魔力:它让孤立的词汇相互交流,根据语境动态地改变彼此的含义!


3. 极简代码实现:手写 Self-Attention

理解了理论后,我们用 PyTorch 来把这个过程变成可运行的代码。在写代码之前,我们先理清思路,并弄明白我们的“原材料”从哪里来。

代码实现思路梳理

  1. 输入 XX 是什么? 在上一篇文章中,我们学到了 Embedding。这里的输入矩阵 XX,其实就是一句话被分词后,查表得到的初始词向量的集合。 比如句子长度为 3(“我”, “吃”, “苹果”),每个词的向量维度是 4,那么 XX 就是一个 3×4 的矩阵。在深度学习中,为了并行计算,我们通常还会加一个批次(Batch)维度,所以实际的形状是 (batch_size, seq_len, embed_size)
  2. 如何生成 Q、K、V? 在 PyTorch 中,我们可以使用 nn.Linear(线性层)来代表我们上文提到的权重矩阵 WQW^QWKW^KWVW^V。输入 XX 经过这三个线性层,就会分别变成 Q、K、V。
  3. 计算公式的对应
    • 点积匹配度:利用 torch.matmul(矩阵乘法)计算 QKTQ \cdot K^T
    • 缩放与 Softmax:除以维度的平方根,并调用 F.softmax
    • 最终融合:再次利用 torch.matmul 将概率矩阵与 VV 相乘。

环境准备与运行方法

在运行代码之前,你需要确保本地安装了 Python 和 PyTorch 库。

  1. 安装 PyTorch:打开你的终端(Terminal)或命令行,输入以下命令安装 torch

    pip install torch
    

    (注:如果你的网络环境较慢,可以添加国内镜像源,例如 pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple)

  2. 保存并运行代码:将下面的代码保存为 self_attention_demo.py 文件,然后在终端中运行:

    python self_attention_demo.py
    

核心代码实现

import torch
import torch.nn as nn
import torch.nn.functional as F

class SelfAttention(nn.Module):
    def __init__(self, embed_size):
        super(SelfAttention, self).__init__()
        self.embed_size = embed_size
        
        # 定义生成 Q, K, V 的线性映射
        self.W_q = nn.Linear(embed_size, embed_size, bias=False)
        self.W_k = nn.Linear(embed_size, embed_size, bias=False)
        self.W_v = nn.Linear(embed_size, embed_size, bias=False)
        
    def forward(self, x):
        # x shape: (batch_size, seq_len, embed_size)
        
        # 1. 计算 Q, K, V
        Q = self.W_q(x)  # (batch_size, seq_len, embed_size)
        K = self.W_k(x)  # (batch_size, seq_len, embed_size)
        V = self.W_v(x)  # (batch_size, seq_len, embed_size)
        
        # 2. 计算注意力分数: Q 和 K^T 的点积
        # K.transpose(1, 2) 将 seq_len 和 embed_size 维度互换
        attention_scores = torch.matmul(Q, K.transpose(1, 2)) 
        
        # 3. 缩放 (Scaling)
        d_k = self.embed_size
        scaled_attention_scores = attention_scores / (d_k ** 0.5)
        
        # 4. Softmax 归一化,得到注意力权重
        attention_weights = F.softmax(scaled_attention_scores, dim=-1)
        
        # 5. 加权求和得到输出
        output = torch.matmul(attention_weights, V)
        
        return output, attention_weights

if __name__ == "__main__":
    # 模拟输入:批次大小 1,序列长度 3(3个词),词向量维度 4
    x = torch.rand(1, 3, 4)
    print("输入 X:\n", x)
    
    attention = SelfAttention(embed_size=4)
    output, weights = attention(x)
    
    print("\n注意力权重 (Attention Weights):\n", weights)
    print("\n输出 Output:\n", output)

运行结果解析

运行上述代码后,你会看到类似如下的输出(由于权重初始化和 torch.rand 是随机的,每次运行的具体数字会不同,但结构一致):

输入 X:
 tensor([[[0.4862, 0.0456, 0.9413, 0.7616],
         [0.0483, 0.1623, 0.6971, 0.2962],
         [0.6240, 0.8581, 0.4798, 0.0640]]])

注意力权重 (Attention Weights):
 tensor([[[0.3379, 0.3476, 0.3146],
         [0.3362, 0.3416, 0.3222],
         [0.3465, 0.3393, 0.3142]]], grad_fn=<SoftmaxBackward0>)

输出 Output:
 tensor([[[ 0.7261, -0.1013,  0.2098,  0.0596],
         [ 0.7279, -0.1009,  0.2071,  0.0592],
         [ 0.7295, -0.1022,  0.2118,  0.0608]]], grad_fn=<UnsafeViewBackward0>)
  • 输入 X:代表了 3 个词,每个词是一个 4 维的向量(初始的 Embedding)。
  • 注意力权重:这是一个 3×33 \times 3 的矩阵。你可以看到第一行的三个值加起来刚好是 1(例如 0.3379 + 0.3476 + 0.3146 ≈ 1),这就是 Softmax 的功劳,代表第一个词对这 3 个词分别分配了多少“注意力比例”。
  • 输出 Output:这是融合了上下文信息后的全新矩阵,形状依然是 3×43 \times 4。但此时每一行的向量,都已经包含了整个句子的综合语义!

4. 总结

Self-Attention 的精妙之处在于,它打破了传统 RNN/LSTM 必须按顺序处理文本的限制。在 Self-Attention 中,句子里的每一个词都可以同时“看”到其他所有的词,并通过点积运算自动计算出它们之间的关联度。

这种机制不仅让模型拥有了极强的捕获长距离依赖(Long-term Dependency)的能力,而且矩阵乘法天生适合 GPU 并行计算,这正是 Transformer 能够高效训练海量数据的根本原因。


📚 参考文献与延伸阅读

  1. Attention Is All You Need (Vaswani et al., 2017) - 深度学习历史上最重要的论文之一,正式提出了 Transformer 架构和 Self-Attention 机制。
  2. The Illustrated Transformer (Jay Alammar) - 极度推荐的可视化博客,用生动的图解详细剖析了 Transformer 的内部结构。
  3. Neural Machine Translation by Jointly Learning to Align and Translate (Bahdanau et al., 2014) - 最早将注意力机制引入 NLP(Seq2Seq 模型)的奠基之作。

下一篇预告: Transformer 架构深潜:Positional Encoding、Layer Norm 与前馈网络的手写实现(NanoGPT 复现)

博客日历
2026年03月
SuMoTuWeThFrSa
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
01
02
03
04
05
06
07
08
09
10
11
更多
--
--
--
--