前言
在自然语言处理(Natural Language Processing,NLP)领域,Transformer已经成为目前最重要的深度学习模型之一。从BERT、GPT,到如今的大语言模型(LLM),几乎都建立在Transformer架构之上。
Transformer能够取得如此优异的性能,其中最核心的原因就是提出了一种全新的信息交互方式——Attention(注意力机制)。
在传统神经网络中,每个单词通常只依赖于固定范围内的上下文;而注意力机制允许每个单词动态关注句子中的所有其他单词,并根据相关性分配不同的权重,从而学习更加丰富的上下文语义。
本文将结合PyTorch源码,对Transformer中的**Scaled Dot-Product Attention(缩放点积注意力)**进行逐行分析,从数学公式、张量维度变化、代码实现到运行示例,帮助读者彻底理解Attention机制。
第一章 Attention到底解决了什么问题?
1.1 RNN存在的问题
在Transformer出现之前,文本建模主要依赖循环神经网络(RNN)及其改进模型LSTM、GRU。
RNN按照时间顺序依次处理单词:
今天 → 天气 → 很 → 好第一个单词的信息需要逐步传递到最后一个单词。
例如:
今天 ↓ 天气 ↓ 很 ↓ 好这种结构存在两个主要缺陷:
① 长距离依赖问题:前面的信息经过多次传递后容易衰减,导致模型难以捕获远距离词之间的关系。
② 无法并行计算:必须按照顺序处理每个单词,训练效率较低。
1.2 Transformer提出新的思路
Transformer不再采用逐词递归处理,而是让句子中的每个单词都能够直接与所有其他单词建立联系。
例如:
今天 天气 很 好Transformer允许:
今天 → 天气 今天 → 很 今天 → 好 天气 → 今天 天气 → 很 天气 → 好 ……即任意两个词之间都可以直接交互信息。
这种思想就是Attention。
1.3 什么是Attention?
Attention的本质可以理解为:
让模型自动学习:当前单词应该关注哪些单词,以及关注多少。
例如:
小明 去了 北京 因为 他 喜欢 那里当模型处理:
他时:
真正需要关注的是:
小明而不是:
去了 喜欢Attention就能够自动学习这种对应关系。
第二章 Query、Key、Value到底是什么?
Attention最难理解的地方,就是三个矩阵:
Query Key Value很多初学者都会疑惑:
为什么一个Attention要设计三个矩阵?
实际上,它们分别承担不同职责。
Query(查询)
Query表示:
当前单词希望寻找哪些信息。
例如:
苹果Query可以理解成:
我要寻找与自己最相关的信息。Key(键)
Key表示:
每个单词向外提供的信息标签。
例如:
香蕉对应一个Key。
苹果也对应一个Key。
Query会逐个与所有Key进行匹配。
Value(值)
Value表示:
真正需要融合的信息。
最后Attention输出的不是Key,而是:
Value所以:
Query负责提问 Key负责匹配 Value负责提供内容第三章 Self-Attention为什么Q=K=V?
代码:
query = key = value = position_x很多人第一次看到都会问:
为什么三个变量完全一样?
这是因为:
当前实现的是:
Self Attention即:
同一句话内部计算注意力。
例如:
我 爱 深度 学习所有单词:
既作为查询者
又作为被查询者。
因此:
Q 来自输入 K 来自输入 V 来自输入虽然输入相同,但真正Transformer里面还会经过:
Q=XWQ K=XWK V=XWV三个不同的线性层。
这里只是为了教学方便,没有加入线性变换。
第四章 Attention数学公式详解
Transformer论文给出的公式:
[
Attention(Q,K,V)=Softmax\left(\frac{QK^T}{\sqrt{d_k}}\right)V
]
整个公式可以拆成四步。
第一步:
计算相关性。
QKᵀ第二步:
缩放。
÷√dk第三步:
Softmax。
得到权重第四步:
加权求和。
Weight×Value代码正好对应四个步骤。
第五章 attention()源码逐行解析
(这里开始,每一行代码都可以配合截图进行讲解。)
第一步 获取特征维度
d_k = query.size(-1)假设:
query.shape [2,4,512]分别表示:
batch_size =2 seq_len=4 embedding=512这里:
size(-1)表示最后一个维度。
所以:
d_k=512为什么需要这个数字?
因为:
后面需要:
√512≈22.6用于缩放Attention Score。
为什么一定要缩放?
假设:
512维向量。
两个随机向量点积:
Q·K可能达到:
300如果直接:
Softmax(300)结果:
0.99999999 0.00000001 0梯度几乎消失。
所以论文提出:
除以√512即可缓解梯度问题。
第六章 为什么要计算QKᵀ?
代码:
scores = torch.matmul(query,key.transpose(-2,-1))很多同学不知道:
为什么不是:
QK而是:
QKᵀ原因就在于:
矩阵乘法维度。
假设:
Q 4×512K:
4×512两个矩阵:
4×512 × 4×512无法相乘。
必须:
4×512 × 512×4因此:
需要:
transpose()得到:
4×4这里:
每一个元素:
都是:
两个单词之间 点积相似度例如:
我 喜欢 吃 苹果 我 喜欢 吃 苹果形成:
4×4 Attention Matrix第七章 为什么Mask可以屏蔽未来信息?
代码:
scores.masked_fill(mask==0,-1e9)很多人疑惑:
为什么:
-1e9就能屏蔽?
答案就在:
Softmax。
Softmax:
exp(x)如果:
x=-1000000000那么:
e^-1000000000≈0最终:
权重≈0因此:
模型永远不会看到:
未来Token。
例如:
Decoder:
今天 天气 很 好预测:
天气只能看到:
今天 天气不能看到:
很 好否则:
模型训练就是作弊。
第八章 Softmax为什么能够表示注意力?
Attention Score:
例如:
[2 5 8]Softmax以后:
↓ [0.02 0.12 0.86]表示:
第三个词:
最重要。
权重最大。
所有权重:
加起来=1因此:
Attention实际上就是:
概率分布。第九章 为什么最后要乘Value?
很多人误以为:
Attention输出:
就是:
Softmax实际上:
真正输出:
Softmax×Value例如:
权重: 0.1 0.2 0.7Value:
A B C最终:
0.1A + 0.2B + 0.7C得到:
新的向量。
因此:
每个单词:
都融合了:
其它单词的信息。
第十章 张量维度变化全过程(重点)
这是学习 Attention 最重要的一部分。假设:
batch_size = 2
seq_len = 4
d_model = 512
那么整个计算过程中,张量形状变化如下:
| 计算步骤 | 运算 | 输出形状 | 说明 |
|---|---|---|---|
| 输入 | Query、Key、Value | [2,4,512] | 两个样本,每句4个词,每词512维 |
| 转置 | K.transpose(-2,-1) | [2,512,4] | 为矩阵乘法准备 |
| 点积 | Q × Kᵀ | [2,4,4] | 每个词与所有词计算相似度 |
| 缩放 | /√512 | [2,4,4] | 防止Softmax梯度饱和 |
| Mask | masked_fill() | [2,4,4] | 屏蔽非法位置 |
| Softmax | softmax() | [2,4,4] | 得到注意力权重 |
| Dropout | dropout() | [2,4,4] | 训练阶段随机失活 |
| 加权求和 | Attention × Value | [2,4,512] | 得到最终上下文表示 |
需要特别注意的是:只有中间的注意力权重矩阵维度变成了[batch_size, seq_len, seq_len],最终输出又恢复到了[batch_size, seq_len, d_model]。这意味着注意力机制不会改变每个词向量的维数,而是改变其包含的信息,使其融合了整个序列的上下文。
第十一章 use_attention()函数完整执行流程
use_attention()是整个实验的测试函数,它模拟了 Transformer 中一次完整的自注意力计算流程。
其执行顺序可以概括为:
Embedding │ ▼ Position Encoding │ ▼ Q = K = V │ ▼ Q × Kᵀ │ ▼ ÷ √dk │ ▼ Mask(可选) │ ▼ Softmax │ ▼ Attention Weight │ ▼ Weight × Value │ ▼ 输出新的特征表示其中,第一次调用attention(query, key, value)时没有使用 Mask,因此属于标准的 Encoder 自注意力;第二次构造了一个全零 Mask,仅用于观察masked_fill()对注意力分数的影响,并不代表实际 Transformer 的 Mask 用法。真实应用中通常使用Padding Mask或Look-Ahead Mask(下三角 Mask)。
第十二章 本代码与Transformer源码的对应关系
这段代码实际上是 Transformer 中Scaled Dot-Product Attention的教学版实现,与论文和 PyTorch 官方实现的主要区别如下:
| 教学代码 | Transformer 实际实现 |
|---|---|
| Q = K = V | 输入相同,但会分别经过三个线性层得到 Q、K、V |
| 单头注意力 | 多头注意力(Multi-Head Attention) |
| 无残差连接 | Attention 后增加残差连接(Residual) |
| 无 LayerNorm | 每层后使用 Layer Normalization |
| 无前馈网络 | 后续接 Position-wise Feed Forward Network |
| 演示用全零 Mask | 实际使用 Padding Mask 或 Look-Ahead Mask |
因此,这段代码虽然只有几十行,却完整体现了 Transformer 注意力计算的核心思想,是学习 Multi-Head Attention 和完整 Transformer 的基础。
第十三章 总结与学习建议
缩放点积注意力(Scaled Dot-Product Attention)是 Transformer 的核心计算单元,其本质是通过计算 Query 与 Key 的相似度,为每个词动态分配注意力权重,再利用这些权重对 Value 进行加权求和,从而生成融合全局上下文信息的新表示。整个过程遵循“计算相似度 → 缩放 → 掩码 → Softmax → 加权求和”五个关键步骤,对应论文中的公式:
[
\text{Attention}(Q,K,V)=\text{Softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V
]
建议学习顺序遵循以下路径:
熟悉矩阵乘法与张量维度变化,能够手工推导
QKᵀ和Attention×Value的维度。深入理解 Softmax 的概率归一化作用,以及为什么需要使用
√d_k对点积进行缩放。掌握 Padding Mask 和 Look-Ahead Mask 的设计目的及实现方式。
在理解单头注意力(Single-Head Attention)的基础上,进一步学习多头注意力(Multi-Head Attention)、残差连接(Residual Connection)、层归一化(Layer Normalization)和前馈神经网络(Feed Forward Network),最终掌握完整的 Transformer 编码器与解码器结构。
对于初学者而言,这段代码是理解 Transformer 的最佳切入点;当能够独立解释每一行代码的功能、每一步的数学意义以及每个张量的维度变化时,也就真正掌握了 Transformer 注意力机制的核心原理。