{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "3a1575c0",
   "metadata": {},
   "source": [
    "# 第三章 编码注意力机制"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "66113cf6",
   "metadata": {},
   "source": [
    "**本章介绍**： "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "51eda009",
   "metadata": {},
   "source": [
    "- 探索在神经网络中使用注意力机制的原因 \n",
    "- 引入基本的自我注意力框架并逐步发展到增强的自我注意力机制 \n",
    "- 实现因果注意力模块，允许 LLM 一次生成一个令牌 \n",
    "- 用丢弃来掩盖随机选择的注意力权重，以减少过度拟合 \n",
    "- 将多个因果注意力模块堆叠到一个多头注意力模块中"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "70639a43",
   "metadata": {},
   "source": [
    "​\t\t在上一章中，你学习了如何准备用于训练 LLM 的输入文本。这涉及将文本拆分为单独的单词和子单词标记，这些标记可以编码为LLM的向量表示，即所谓的嵌入。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e27240ef",
   "metadata": {},
   "source": [
    "​\t\t在本章中，我们现在将研究 LLM 架构本身的一个组成部分，即注意力机制，如图 3.1 所示。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "96bed9d4",
   "metadata": {},
   "source": [
    "图 3.1 对 LLM 进行编码的三个主要阶段的心智模型，在通用文本数据集上预训练 LLM，并在标记数据集上对其进行微调。本章重点介绍注意力机制，它是 LLM 架构的一个组成部分。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6110037d",
   "metadata": {},
   "source": [
    "![image-20240422132155860](../img/fig-3-1.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c881b69f",
   "metadata": {},
   "source": [
    "图 3.1 对 LLM 进行编码的三个主要阶段的心智模型，在通用文本数据集上预训练 LLM，并在标记数据集上对其进行微调。本章重点介绍注意力机制，它是 LLM 架构的一个组成部分。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "12929d08",
   "metadata": {},
   "source": [
    "​\t\t注意力机制是一个综合性的话题，这就是为什么我们用一整章来讨论它。我们将在很大程度上孤立地看待这些注意力机制，并在机制层面上关注它们。在下一章中，我们将围绕自注意力机制对 LLM 的其余部分进行编码，以查看它的实际效果并创建一个模型来生成文本。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1a46364a",
   "metadata": {},
   "source": [
    "​\t\t在本章中，我们将实现四种不同的注意力机制变体，如图 3.2 所示。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4d7832f4",
   "metadata": {},
   "source": [
    "图 3.2 该图描述了我们将在本章中编写的不同注意力机制，从简化版本的自我注意力开始，然后添加可训练的权重。因果注意机制为自我注意力添加了一个掩码，允许 LLM 一次生成一个单词。最后，多头注意力将注意力机制组织成多个头，使模型能够并行捕获输入数据的各个方面。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "722bd9ac",
   "metadata": {},
   "source": [
    "![image-20240422132325918](../img/fig-3-2.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8f7c69a1",
   "metadata": {},
   "source": [
    "图 3.2 该图描述了我们将在本章中编写的不同注意力机制，从简化版本的自我注意力开始，然后添加可训练的权重。因果注意机制为自我注意力添加了一个掩码，允许 LLM 一次生成一个单词。最后，多头注意力将注意力机制组织成多个头，使模型能够并行捕获输入数据的各个方面。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e5d44ac0",
   "metadata": {},
   "source": [
    "​\t\t图 3.2 中所示的这些不同的注意力变体是相互构建的，目标是在本章末尾实现一个紧凑而高效的多头注意力实现，然后我们可以将其插入到我们将在下一章中编写的 LLM 架构中。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2ce0f1ad",
   "metadata": {},
   "source": [
    "## 3.1 长序列建模的问题"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f0236642",
   "metadata": {},
   "source": [
    "​\t\t在本章后面深入探讨 LLM 核心的自注意力机制之前，在 LLM 之前没有注意力机制的架构有什么问题？假设我们想要开发一个语言翻译模型，将文本从一种语言翻译成另一种语言。如图 3.3 所示，由于源语言和目标语言的语法结构，我们不能简单地逐字翻译文本。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a7aa5953",
   "metadata": {},
   "source": [
    "图 3.3 将文本从一种语言翻译成另一种语言时，例如德语翻译成英语时，不可能只是逐字翻译。相反，翻译过程需要上下文理解和语法对齐。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "273dc1ef",
   "metadata": {},
   "source": [
    "![image-20240422132534189](../img/fig-3-3.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "84566bb5",
   "metadata": {},
   "source": [
    "​\t\t为了解决我们无法逐字翻译文本的问题，通常使用具有两个子模块的深度神经网络，即所谓的编码器和解码器。编码器的工作是首先读取并处理整个文本，然后解码器生成翻译后的文本。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f8211d92",
   "metadata": {},
   "source": [
    "​\t\t在第 1 章（第 1.4 节，将 LLM 用于不同的任务）中介绍 transformer 架构时，我们已经简要讨论了编码器-解码器网络。在 Transformer 出现之前，递归神经网络 （RNN） 是语言翻译中最流行的编码器-解码器架构。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "79004eae",
   "metadata": {},
   "source": [
    "​\t\tRNN 是一种神经网络，其中先前步骤的输出作为输入馈送到当前步骤，使其非常适合文本等顺序数据。如果您不熟悉 RNN，请不要担心，您无需了解 RNN 的详细工作原理即可进行此讨论;我们在这里的重点更多地放在编码器-解码器设置的一般概念上。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e7bb634b",
   "metadata": {},
   "source": [
    "​\t\t在编码器-解码器 RNN 中，输入文本被馈送到编码器中，编码器按顺序对其进行处理。编码器在每个步骤中更新其隐藏状态（隐藏层的内部值），试图在最终隐藏状态下捕获输入句子的全部含义，如图 3.4 所示。然后，解码器采用这种最终的隐藏状态开始生成翻译的句子，一次一个单词。它还会在每一步更新其隐藏状态，这应该携带下一个单词预测所需的上下文。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "03937031",
   "metadata": {},
   "source": [
    "图 3.4 在变压器模型出现之前，编码器-解码器 RNN 是机器翻译的热门选择。编码器将源语言中的一系列标记作为输入，其中编码器的隐藏状态（中间神经网络层）对整个输入序列的压缩表示进行编码。然后，解码器使用其当前隐藏状态开始逐个标记的转换。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fb703346",
   "metadata": {},
   "source": [
    "![image-20240422132721999](../img/fig-3-4.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "311eba8a",
   "metadata": {},
   "source": [
    "​\t\t虽然我们不需要知道这些编码器-解码器 RNN 的内部工作原理，但这里的关键思想是编码器部分将整个输入文本处理成隐藏状态（存储单元）。然后，解码器采用此隐藏状态以生成输出。你可以把这个隐藏状态看作是一个嵌入向量，这是我们在第 2 章中讨论的一个概念。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "afb6a419",
   "metadata": {},
   "source": [
    "​\t\t编码器-解码器 RNN 的最大问题和局限性在于，在解码阶段，RNN 无法直接从编码器访问早期的隐藏状态。因此，它完全依赖于当前的隐藏状态，该状态封装了所有相关信息。这可能会导致上下文丢失，尤其是在依赖关系可能跨越很长距离的复杂句子中。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d1da34f5",
   "metadata": {},
   "source": [
    "​\t\t对于不熟悉 RNN 的读者来说，理解或研究这种架构并不是必需的，因为我们不会在本书中使用它。本节的要点是，编码器-解码器 RNN 有一个缺点，激发了注意力机制的设计。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
