2026年7月21日51约 2709 字9 分钟阅读

为什么 Attention 能干掉 RNN?

RNN 必须逐词传递信息,第 180 个词想看第 3 个词时信号已经衰减殆尽。Self-Attention 用一次矩阵乘法让任意两个词直接对话,这就是 Transformer 取代 RNN 的根本原因。

从 LLM 到 Agent

第 1 篇 / 共 1 篇

INFO

系列导读 本文是《从 LLM 到 Agent》系列的第 1 篇。

先说一个坐标系

如果你是前端工程师,大概率没追过 AI 的技术演进。这三十秒的背景能帮你定位"这篇在讲什么阶段的事"。

1990s-2012:规则和统计。机器翻译靠人工写规则、词频表查概率。效果勉强能用,但碰到稍微复杂的句子就崩。

2013:Word2Vec 让词变成了向量。Mikolov 在 Google 证明:把每个词映射成一组数字(向量),词和词之间的语义关系会自然浮现——"国王 - 男 + 女 ≈ 女王"。从此 NLP 进入"用数字表示语义"的时代,进阶篇第 2 篇 Embedding 就讲这个。

2014-2017:LSTM 统治序列建模。RNN 的改良版 LSTM 成为所有序列任务的默认方案。2016 年底 Google 翻译突然变好了——背后就是 8 层 LSTM + Attention 的 GNMT 系统。那时候所有人都觉得 LSTM 就是终局。

2017:Transformer 登场,LSTM 退位。Vaswani 等人发表 Attention Is All You Need,完全抛弃循环结构,用纯注意力机制处理序列。训练速度快了一个数量级,长距离依赖不再是问题。之后的 GPT、BERT、ChatGPT 全部基于 Transformer。

这篇文章就从 LSTM 的问题开始——理解它为什么失败,你才能理解 Transformer 为什么成功。

RNN 的致命缺陷

一段 200 词的文本,第 3 个词是"John",第 180 个词是"he"。人类读到"he"时,瞬间知道它指的是"John"。

RNN(循环神经网络)做不到 1

RNN 的结构要求信息逐步传递——处理完第 1 个词,把隐藏状态传给第 2 个词,再传给第 3 个词……一直到第 180 个词。"John"的信息要经过 177 步传递才能到达"he"。每传一步,信号就衰减一点。

这不是 RNN"不够聪明",而是结构性的物理限制。LSTM 通过门控机制缓解了衰减,但没有根治——信息传递的路径长度仍然是 O(n)O(n)O(n),和句子长度成正比。句子越长,早期词的信号越弱。

除了信号衰减,还有一个同样致命的问题:无法并行。第 nnn 步必须等第 n1n-1n1 步完成才能开始,100 个词就是 100 步串行计算。GPU 有数千个并行计算核心,但 RNN 只能用上一个。

2017 年,Vaswani 等人提出了一个激进的想法 2把 RNN 的循环结构整个扔掉,只用注意力。论文标题即宣言——Attention Is All You Need

先体验:注意力在做什么

在讲公式之前,先看看注意力的效果。

下面的 Demo 模拟了 Self-Attention 的工作方式。点击任意一个词,观察它在"关注"谁——弧线越粗,注意力权重越大:

Self-Attention:每个词在"关注"谁?

NOTE

教学简化说明 上面的注意力权重是为教学设计的模拟数据。实际模型的注意力分布更分散且多层叠加。但核心机制相同:每个 token 通过 Q/K 相似度计算决定"关注谁多一些"。

关键观察:点击"它",48% 的注意力指向了"苹果"——模型通过注意力权重"理解"了代词指代关系。而且这是一步完成的——"它"直接看到了"苹果",不需要经过中间的"很"。

RNN 里,"它"要理解"苹果"必须通过隐藏状态逐步传递。Self-Attention 里,任意两个词之间的距离变成了 O(1)O(1)O(1)——常数时间,不随句子长度增长。

这就是 Attention 能干掉 RNN 的核心原因。现在来看它是怎么做到的。

公式拆解:三步理解 Self-Attention

Self-Attention 的完整公式是:

Attention(Q,K,V)=softmax(QKTdk)V\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)VAttention(Q,K,V)=softmax(dkQKT)V自注意力机制

一次看这个公式会懵。拆成三步,每步解决一个问题。

第一步:QKTQK^TQKT——"这两个词有多相关?"

每个 token 先被转换成一个固定长度的数字向量(叫 embedding),作为模型可以计算的数学表示。然后这个 embedding 被线性变换成三个向量:

  • Query(查询):"我在寻找什么信息?"
  • Key(键):"我能提供什么信息?"
  • Value(值):"我的实际内容是什么"

QKTQK^TQKT 计算的是 Query 和 Key 的点积——两个向量方向越相似,点积越大。当"它"的 Query 和"苹果"的 Key 方向一致时,得分就高,意味着"它"应该关注"苹果"。

Q、K、V 是同一份数据通过三个不同的权重矩阵投影出来的。为什么要三个角色?因为"我在找什么"和"我能提供什么"不一样。一个词作为查询者和作为被查询者时,关注的语义维度不同。

到这里我们解决了:任意两个词之间的相关性打分。O(1)O(1)O(1) 直接连接,不需要逐步传递。

第二步:除以 dk\sqrt{d_k}dk——防止 softmax 饱和

dkd_kdk 是 Key 向量的维度。当维度很高时(比如 64 维),点积的数值会变得很大。

为什么这是个问题?因为下一步要过 softmax。softmax 会把最大值推向 1、其余推向 0——如果输入值太大,softmax 的输出会接近 one-hot 分布,梯度几乎为零,训练卡死。

除以 dk\sqrt{d_k}dk 把点积的量级拉回合理范围。这不是调参技巧,是数学必要——dkd_kdk 维向量的点积期望方差为 dkd_kdk,除以 dk\sqrt{d_k}dk 后方差归一化为 1。

到这里我们解决了:数值稳定性。保证 softmax 输出的梯度健康,训练能正常进行。

第三步:乘以 VVV——"拿多少信息"

softmax 把原始分数转换成 0-1 之间的概率分布(所有权重加起来 = 1)。这些权重决定了每个词从其他词那里"拿多少信息"。

最后乘以 VVV(Value 矩阵),就是用这些权重对所有词的实际内容做加权求和。"它"的新表示 = 48% × 苹果的内容 + 12% × 我的内容 + 8% × 吃了的内容 + ……

到这里我们解决了:信息聚合。每个词的输出不再只是它自己,而是融合了全句上下文信息的新表示。

三步合起来:计算相关性(QKTQK^TQKT)→ 稳定数值(/dk/ \sqrt{d_k}/dk)→ 聚合信息(×V\times V×V)。一次矩阵运算,所有词同时完成,完全并行。

多头注意力:一个头不够

单头注意力只能学到一种关注模式。但语言中的关系是多维的——同一个句子里同时存在语法关系(主谓宾)、指代关系(代词→名词)、位置关系(相邻词)。

解法:拆分并行

多头注意力(Multi-Head Attention)把 Q/K/V 各拆成 hhh 份(原论文用 8 个头),每份独立做注意力计算,最后 concat 起来再做一次线性投影:

MultiHead(Q,K,V)=Concat(head1,...,headh)WO\text{MultiHead}(Q, K, V) = \text{Concat}(\text{head}_1, ..., \text{head}_h)W^OMultiHead(Q,K,V)=Concat(head1,...,headh)WO多头注意力

精妙之处:拆成 hhh 个头后,每个头处理的维度变成 d/hd/hd/h,总计算量和单头几乎一样。8 个头用相同的算力,获得了 8 个不同的关注视角。

Multi-Head Attention:8 个头各看一个维度

实际训练出来的注意力头确实学到了不同的模式。后续的 BERTology 系列研究 3 发现:某些头专注于语法依赖(主语→谓语),某些头捕捉共指关系(代词→先行词),某些头关注相邻词的局部上下文。模型自动学会了这种分工,不需要人为指定。

位置编码:补上顺序信息

到目前为止,Self-Attention 有一个致命缺陷:它不关心词的顺序

把输入 token 打乱,注意力分数不会变。"狗咬人"和"人咬狗"在 Self-Attention 看来完全等价。

原因:RNN 按顺序处理,天然感知位置。Self-Attention 做的是集合运算(所有词两两比较),没有"先后"的概念。

解法:给每个位置一个独特的向量,加到 token embedding 上。原论文用正弦和余弦函数的组合生成位置编码——不同频率的三角函数让每个位置有唯一的"指纹"。后来旋转位置编码 RoPE 4 成为主流方案,被 LLaMA 等现代模型广泛采用。

加了位置编码后,"狗咬人"中"狗"的表示 = 狗的语义向量 + 位置 1 的编码,"人咬狗"中"狗"的表示 = 狗的语义向量 + 位置 3 的编码。两者不再相同,Self-Attention 就能区分语序了。

完整的 Transformer Block

前面的模块组合起来,就是一个 Transformer Block:

Transformer 数据流动画

每个 Block 包含两个子层,各自带残差连接和 LayerNorm

注意力子层:Multi-Head Attention → Add & LayerNorm。负责 token 之间的信息交换

FFN 子层:两层全连接网络(中间 GELU 激活)→ Add & LayerNorm。负责每个 token 独立的信息加工——注意力告诉 token"你应该关注什么",FFN 告诉 token"拿到这些信息后怎么处理"。

残差连接output=f(x)+x\text{output} = f(x) + xoutput=f(x)+x)保证深层网络的梯度能传回去 5。原论文堆了 6 层,GPT-3 堆了 96 层——没有残差,梯度传不过 10 层。

模型就是把这个 Block 重复堆叠 NNN 次。每一层的注意力模式不同:浅层关注局部语法,深层捕捉全局语义。

亲手验证

打开上面的注意力可视化 Demo,做以下实验:

  1. 验证指代消解:点击"它",预测注意力最高的词应该是"苹果"(因为"它"指代"苹果")。验证你的预测。然后思考:如果把句子改成"我吃了一个苹果,很贵"——"它"现在可能指"苹果"也可能指吃苹果这件事。模型的注意力分布会如何变化?

  2. 验证语法关系:点击"一个",注意力应该集中在"苹果"上(量词修饰名词)。点击"很",注意力应该指向"甜"(副词修饰形容词)。这些语法关系不是硬编码的规则,而是从数据中学出来的模式。

  3. 理解 RNN 做不到的事:在这个 Demo 里,"甜"可以一步看到"苹果"(22%)。如果是 RNN,"甜"的信息要经过"很"→"它"→"苹果"三步传递才能建立这个联系。每多一步,信号就弱一点。当句子更长——比如"苹果"在第 3 个位置,"甜"在第 180 个位置——RNN 的信号几乎衰减为零,而 Self-Attention 仍然是一步到位。

如果你能向别人解释:Self-Attention 让任意两个词直接对话(O(1)O(1)O(1) 距离),同时完全并行化(矩阵乘法),这两点解决了 RNN 的长距离遗忘和串行瓶颈——那你理解了 Transformer 的核心设计动机。

参考文献

  1. Long Short-Term MemoryHochreiter & Schmidhuber · Neural Computation, 1997 · 论文提出门控机制缓解梯度消失,Transformer 之前序列建模的主力架构。
  2. Attention Is All You NeedVaswani et al. · NeurIPS 2017 · 论文提出 Transformer 架构,8 位作者后来分散到不同方向——Gomez 联合创办 Cohere,Shazeer 联合创办 Character.AI。
  3. "What Does BERT Look At? An Analysis of BERT's Attention"Clark et al. · ACL Workshop BlackboxNLP 2019 · 论文系统分析 BERT 各注意力头的功能分工——语法依赖、共指关系、局部上下文等模式。
  4. "RoFormer: Enhanced Transformer with Rotary Position Embedding"Su et al. · arXiv 2021 · 论文提出旋转位置编码 RoPE,被 LLaMA、GPT-NeoX 等主流大模型采用。
  5. Deep Residual Learning for Image RecognitionHe et al. · CVPR 2016 · 论文残差连接的原始出处,来自 CV 领域但直接影响了 Transformer 的设计。