当前位置: 首页 > news >正文

Transformer核心算法详解——Scaled Dot-Product Attention(缩放点积注意力)源码解析

前言

在自然语言处理(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×512

K:

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.7

Value:

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梯度饱和
Maskmasked_fill()[2,4,4]屏蔽非法位置
Softmaxsoftmax()[2,4,4]得到注意力权重
Dropoutdropout()[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 MaskLook-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
]

建议学习顺序遵循以下路径:

  1. 熟悉矩阵乘法与张量维度变化,能够手工推导QKᵀAttention×Value的维度。

  2. 深入理解 Softmax 的概率归一化作用,以及为什么需要使用√d_k对点积进行缩放。

  3. 掌握 Padding Mask 和 Look-Ahead Mask 的设计目的及实现方式。

  4. 在理解单头注意力(Single-Head Attention)的基础上,进一步学习多头注意力(Multi-Head Attention)、残差连接(Residual Connection)、层归一化(Layer Normalization)和前馈神经网络(Feed Forward Network),最终掌握完整的 Transformer 编码器与解码器结构。

对于初学者而言,这段代码是理解 Transformer 的最佳切入点;当能够独立解释每一行代码的功能、每一步的数学意义以及每个张量的维度变化时,也就真正掌握了 Transformer 注意力机制的核心原理。

http://www.jsqmd.com/news/1154413/

相关文章:

  • 高精度运动控制系统:A3908与STM32F446ZE的工程实践
  • Google Voice个人付费方案上线:每月十美元永久保号,虚拟号码终于不再“流浪“
  • STM32与PAM8904实现低功耗音频警报系统设计
  • OpenClaw Windows 部署全指南:解决 PowerShell 策略、PATH 别名与 Redis 集成问题
  • 鸿蒙智能体开发实战:15.使用工作流
  • C语言入门:学会选择和循环
  • 免费字幕编辑神器:Subtitle Edit 完全指南 - 从零开始制作专业级字幕
  • 挫折教育,允许孩子失败学会调整心态
  • STM32F446ZE与A3908高精度运动控制系统设计
  • AI大模型红利来袭!小白也能抓住的收藏必备学习指南
  • 高精度ADC ADS127L11与MK24FN256VDC12 MCU的工业级信号采集方案
  • 第二章Netty,如何处理ChannelFuture中的连接失败
  • 从8年Java后端到AI应用开发:33岁裸辞转型,踩坑无数却月薪涨30%,这3类人慎重!
  • 数据库管理工具的数据安全机制对比:权限管控与审计
  • 工业信号采集:FOD4216光耦与PIC24FJ单片机实战方案
  • 259.run_hw_ila [get_hw_ilas -of_objects [get_hw_devices xc7k325t_0] -filter {CELL_NAME=~“u_ila_0“}]
  • 全球主要国家电压频率一览
  • 青少年CTF Web 8题实战:SQL注入到PHP反序列化,5类漏洞完整复现
  • Ctool:一站式开发工具箱,让编码效率提升300%的终极解决方案
  • 工业负载控制方案:TPD2017FN与STM32F765ZI应用设计
  • Codex想用得溜?这几个配置提前设好,效率翻倍不踩坑
  • WarcraftHelper:魔兽争霸III终极优化插件完全指南
  • 3分钟告别城通网盘限速:完全免费的开源极速下载解决方案
  • OpenClaw本地Agent部署与Windows深度集成指南
  • IIC通信协议详解(一篇文章搞懂I2C原理、时序与读写流程)
  • 我以为 AMD AI Dev Kit 能平替 NVIDIA,结果第一步就卡在驱动上
  • TMC7300与PIC18F46K42构建高效有刷直流电机控制系统
  • Vue组件的二次封装(案例)
  • 钢结构深化设计进度及质量管理办法
  • Windows Cleaner:彻底解决C盘爆红的免费开源优化工具