# 1.3 注意力的诞生：让模型学会“看哪里”

注意力机制（Attention Mechanism）的出现，是从 RNN 时代走向 Transformer 时代的关键转折点。理解它的诞生背景和设计动机，是理解 Transformer 架构的基础。

## 1.3.1 编码器-解码器：理解与生成的分离

2014 年，Sutskever 等人提出的 **序列到序列**（Sequence-to-Sequence，Seq2Seq）模型为机器翻译带来了革命性进步。Seq2Seq 的核心思想，是将任务拆分为 **“理解”和“生成”** 两个独立的阶段，分别交由 **编码器**（Encoder）和 **解码器**（Decoder）负责。

### 为什么要分离

这种分离的动机来自任务本身的结构。在翻译中，输入是一种语言，输出是另一种语言——它们的词汇、语法和表达方式都不同。将“理解输入”和“生成输出”耦合在同一个模块中会让模型承担过重的负担。将二者分开，让各自专注于一件事，是一种自然的分治策略。这也对应了人类处理此类任务的方式：先理解原文的意思，再用目标语言重新表达。

### 编码器的本质

**编码器的任务是“理解”——将离散的、变长的输入序列转化为一组连续的内部表示。** 在 Seq2Seq 中，编码器是一个 RNN，逐词阅读输入序列，每读一个词就更新自己的隐藏状态。到序列末尾时，最终的隐藏状态理论上浓缩了整个输入的语义信息——这个向量被称为**上下文向量**（Context Vector），可以看作编码器对输入的一份“理解摘要”。

编码器的核心价值在于：**它将“不同长度的文字序列”这一结构化输入，统一映射为“固定格式的数值表示”**，为后续的生成提供了可操作的语义基础。

### 解码器的本质

**解码器的任务是“生成”——在给定编码器提供的语义表示的条件下，逐步构建输出序列。** 解码器同样是一个 RNN，但它的工作方式与编码器不同：它以编码器的上下文向量作为初始状态，每一步生成一个输出词元，并将这个词元反馈给自己作为下一步的输入。因此，**解码器的每次生成都同时依赖两种信息：来自编码器的“对输入的理解”和自身已经生成的部分内容。**

这就像一位同声传译员的工作过程：先听完并理解一段话（编码），再逐词地用另一种语言表达出来（解码），每翻译一个词时，既参考对原话的理解，也考虑自己已经说出的部分，确保译文连贯。

### 协作与信息瓶颈

下图展示了 Seq2Seq 的编码器-解码器结构。注意中间那个固定大小的上下文向量——编码器的所有“理解”都必须压缩进这一个向量，解码器对输入的全部了解也只来源于它：

```mermaid
graph LR
    subgraph encoder["编码器（逐词阅读）"]
        direction LR
        x1["我"] --> e1["RNN"]
        x2["爱"] --> e2["RNN"]
        x3["学习"] --> e3["RNN"]
        e1 --> e2 --> e3
    end

    e3 --> ctx["上下文向量<br/>(固定维度)"]

    subgraph decoder["解码器（逐词生成）"]
        direction LR
        d1["RNN"] --> y1["I"]
        d1 --> d2["RNN"] --> y2["love"]
        d2 --> d3["RNN"] --> y3["learning"]
    end

    ctx --> d1

    style ctx fill:#e74c3c,color:#fff,stroke:#c0392b,stroke-width:3px
    style encoder fill:#3498db15,stroke:#3498db
    style decoder fill:#2ecc7115,stroke:#2ecc71
```

图 1-4：Seq2Seq 编码器-解码器架构，所有信息必须通过中间的固定维度向量

这个架构在短句翻译上效果出色，但在长句上性能急剧下降。原因很直观：**无论输入句子有多长，编码器都必须将所有信息压缩到一个固定维度的向量中。** 这就像试图把一整本书的内容浓缩成一句话——短文或许做得到，长文必然会丢失大量细节。

这个问题被称为**信息瓶颈**（Information Bottleneck）。从离散近似的角度看，如果每个维度只能承载有限精度的信息，固定长度上下文向量的容量会受到 $$d\_c$$ 限制；而输入序列的信息量随长度 $$n$$ 增长（每个词贡献约 $$\log\_2 V$$ bits，其中 $$V$$ 是词汇量）。这种随长度增长的输入信息与固定维度表示之间的不匹配，会在实践中形成压缩瓶颈。

> 编码器-解码器的分离是一个影响深远的架构思想。虽然 Seq2Seq 中的信息瓶颈很快就被注意力机制解决（下一节将详细讨论），但“理解与生成分离”这一设计理念延续到了 Transformer 时代——Transformer 的原始架构仍然是编码器-解码器结构，而后续的 BERT（仅编码器）、GPT（仅解码器）和 T5（编码器-解码器）则分别发展了这一思想的不同侧面。这些架构变体将在[第三章](/llm_internals/di-yi-bu-fen-ji-chu-pian/03_components/3.7_full_architecture.md)中系统对比。

## 1.3.2 Bahdanau 注意力：关键的突破

2015 年，Bahdanau 等人提出了一个优雅的解决方案：**在解码每个词时，不再只看那一个固定的上下文向量，而是让解码器“回头看”编码器在每个位置产生的隐藏状态，并自动决定关注哪些位置。**

> 为什么要看“隐藏状态”而不是原始的输入词向量？回顾 [1.2 节](/llm_internals/di-yi-bu-fen-ji-chu-pian/01_introduction/1.2_rnn_cnn_limits.md)的讨论：RNN 在每个时间步产生的隐藏状态 $$h\_j$$，不仅编码了当前位置的词，还融合了它之前所有词的上下文信息。换句话说，$$h\_1$$ 只知道第一个词，但 $$h\_3$$ 已经“读过”了前三个词，它对第三个词的表示是带着上下文理解的。如果直接看原始词向量，“苹果”在“吃苹果”和“苹果公司”中的表示完全一样，无法区分语义；而隐藏状态则已经融入了上下文，能区分这两种含义。因此，**隐藏状态是编码器在每个位置留下的“带上下文的阅读笔记”**，比原始词向量包含了更丰富、更准确的信息，是注意力机制理想的关注对象。

这个想法的直觉非常自然。以翻译为例：翻译一个英文句子中的某个法语词时，并不需要同等地关注源句子中的每一个词——通常只需要特别留意与当前翻译相关的几个词。注意力机制让模型自动学会了这种选择性关注。

具体而言，在解码器生成第 $$t$$ 个输出时，注意力机制执行以下步骤：

1. **计算相关性分数**：用解码器当前状态 $$s\_t$$ 和编码器每个位置的隐藏状态 $$h\_j$$ 计算一个“对齐分数” $$e\_{tj} = \text{score}(s\_t, h\_j)$$
2. **归一化为概率分布**：通过 Softmax 转换为注意力权重 $$\alpha\_{tj} = \text{softmax}(e\_{tj})$$
3. **加权求和**：用注意力权重对编码器隐藏状态求加权和，得到上下文向量 $$c\_t = \sum\_j \alpha\_{tj} h\_j$$

> 这三步的逻辑是：注意力权重决定了“看哪里”，加权求和将“看到的内容”汇总成上下文向量 $$c\_t$$，然后解码器将 $$c\_t$$ 与自身的当前状态 $$s\_t$$ 结合，预测下一个输出词。以“我爱学习”→“I love learning”为例：解码第一个词时，注意力权重在“我”上最大，$$c\_1$$ 因此主要包含“我”的信息，解码器据此输出“I”；解码第二个词时，注意力转向“爱”，$$c\_2$$ 主要反映“爱”的信息，输出“love”；以此类推。**注意力权重并不直接决定输出什么词——它决定的是本轮解码“该参考源句子的哪些部分”，最终由解码器综合这些信息来做出预测。**
>
> 这里的上下文向量 $$c\_t$$ 带有下标 $$t$$，这正是与 Seq2Seq 的根本区别。Seq2Seq 的上下文向量只有**一个**，对所有解码步骤完全相同；而注意力机制中，**每一步解码都重新计算一个专属的上下文向量**，相当于每次带着不同的问题重新翻阅原文。

下图展示了 Bahdanau 注意力机制的工作流程：

```mermaid
graph TB
    subgraph encoder["编码器"]
        direction LR
        h1["h₁"] ~~~ h2["h₂"] ~~~ h3["h₃"] ~~~ h4["h₄"]
    end

    subgraph attn["注意力计算"]
        direction TB
        score["计算对齐分数<br/>eₜⱼ = score(sₜ, hⱼ)"]
        softmax["Softmax 归一化<br/>αₜⱼ = softmax(eₜⱼ)"]
        weighted["加权求和<br/>cₜ = Σⱼ αₜⱼhⱼ"]
        score --> softmax --> weighted
    end

    subgraph decoder["解码器"]
        st["当前状态 sₜ"]
        yt["输出 yₜ"]
    end

    h1 & h2 & h3 & h4 -->|"全部隐藏状态"| score
    st -->|"当前状态"| score
    weighted -->|"上下文向量 cₜ"| yt

    style score fill:#9b59b6,color:#fff
    style softmax fill:#8e44ad,color:#fff
    style weighted fill:#7d3c98,color:#fff
    style h1 fill:#3498db,color:#fff
    style h2 fill:#3498db,color:#fff
    style h3 fill:#3498db,color:#fff
    style h4 fill:#3498db,color:#fff
```

图 1-5：Bahdanau 注意力机制工作流程，解码器动态关注编码器各位置

其中，对齐分数的计算方式有多种。Bahdanau 使用了一个小型前馈网络：

$$e\_{tj} = v^T \tanh(W\_s s\_t + W\_h h\_j)$$

这种方式也被称为**加性注意力**（Additive Attention），因为它将两个向量线性变换后相加。

注意力机制的效果是显著的。它不仅大幅提升了长句翻译的质量，还提供了一个宝贵的副产品：可解释性。通过可视化注意力权重矩阵，可以清晰地看到翻译每个目标词时，模型关注了源句子中的哪些位置。

## 1.3.3 从加性注意力到点积注意力

Bahdanau 提出加性注意力后不久，Luong 等人在 2015 年提出了更简洁的**点积注意力**（Dot-Product Attention）：

$$e\_{tj} = s\_t^T h\_j$$

直接计算两个向量的点积作为相关性分数。这种方式不需要额外的可学习参数，计算效率更高（可以用矩阵乘法批量完成），且在实践中效果相当。

点积的数学含义是衡量两个向量的“相似度”：方向越接近的两个向量，点积值越大。因此，点积注意力的直觉是：**解码器在寻找与自己当前状态最“相似”的编码器位置。**

这种从加性到乘性（点积）的简化看似微小，却为后来 Transformer 的高效计算铺平了道路——在 Transformer 中，所有注意力计算都基于点积，正是因为点积可以利用高度优化的矩阵乘法库在 GPU 上极其高效地执行。

## 1.3.4 注意力带来的根本性变化

回顾 1.1 节提出的三个核心挑战，注意力机制带来了两个根本性的进步：

**第一，打破了信息瓶颈。** 解码器不再依赖一个固定大小的向量，而是可以访问编码器在每个位置的完整表示。信息容量不再受限于一个向量的维度。

**第二，缩短了信息传递路径。** 在传统的 Seq2Seq 中，源句子第一个词的信息必须依次通过所有时间步才能到达解码器，路径长度为 $$O(n)$$。有了注意力机制，解码器可以直接“看到”任意源位置，路径长度降为 $$O(1)$$。

然而，这一阶段的注意力机制仍然是“附属品”——它被**嫁接在 RNN 之上**，编码器和解码器仍然是 LSTM 或 GRU。RNN 的串行计算瓶颈依然存在。一个自然的问题出现了：**既然注意力机制已经能够直接连接任意两个位置，那还需要 RNN 吗？**

这正是 Transformer 给出的回答。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://yeasy.gitbook.io/llm_internals/di-yi-bu-fen-ji-chu-pian/01_introduction/1.3_attention_birth.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
