mirror of
https://github.com/datawhalechina/llms-from-scratch-cn.git
synced 2026-05-01 11:58:17 +08:00
246 lines
9.1 KiB
Plaintext
246 lines
9.1 KiB
Plaintext
{
|
||
"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": [
|
||
""
|
||
]
|
||
},
|
||
{
|
||
"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": [
|
||
""
|
||
]
|
||
},
|
||
{
|
||
"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": [
|
||
""
|
||
]
|
||
},
|
||
{
|
||
"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": [
|
||
""
|
||
]
|
||
},
|
||
{
|
||
"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
|
||
}
|