Revert "REAEME 文件中,增加「在线阅读」地址,并且,所有图片设置为居中。"

This commit is contained in:
long_long_ago
2025-08-01 11:33:51 +08:00
committed by GitHub
parent 678d5d2193
commit 759bd92089
11 changed files with 169 additions and 489 deletions

View File

@@ -29,9 +29,7 @@
在之前的章节中,我们实现了 LLM 的架构,进行了预训练,并学习了如何从外部来源(如 OpenAI导入预训练权重。本章将在此基础上通过微调 LLM 来完成特定目标任务,比如文本分类(见图 6.1)。我们将以一个具体的例子来说明如何将文本消息分类为垃圾短信或正常短信。
<div style="text-align: center;">
<img src="Image/chapter6/figure6.1.png" width="75%" />
</div>
<img src="../Image/chapter6/figure6.1.png" width="75%" />
图 6.1 展示了微调 LLM 的两种主要方式:用于分类的微调(步骤 8和用于指令遵循的微调步骤 9。在下一节中我们将深入探讨这两种微调方式。
@@ -41,9 +39,7 @@
微调语言模型最常见的方法是指令微调和分类微调。指令微调通过在一组任务上使用特定指令训练模型,用以提升模型对自然语言提示中任务描述的理解和执行能力,如图 6.2 所示。
<div style="text-align: center;">
<img src="Image/chapter6/figure6.2.png" width="75%" />
</div>
<img src="../Image/chapter6/figure6.2.png" width="75%" />
下一章将讨论指令微调,相关内容在图 6.2 中有所展示。而本章的重点是分类微调,如果您有机器学习基础,可能已经对这一概念比较熟悉。
@@ -51,9 +47,7 @@
但有一个关键点需要注意,经过分类微调的模型只能预测训练中遇到的类别。例如,它可以判断某内容是‘垃圾短信’还是‘非垃圾短信’(如图 6.3 所示),但不能对输入文本提供其他方面的信息。
<div style="text-align: center;">
<img src="Image/chapter6/figure6.3.png" width="75%" />
</div>
<img src="../Image/chapter6/figure6.3.png" width="75%" />
与图6.3中所示的分类微调模型不同,指令微调模型通常可以执行更广泛的任务。分类微调模型可以视为高度专业化的模型,而相比之下,开发一个适用于各种任务的通用型模型通常更具挑战性。
@@ -71,9 +65,7 @@
在本章的剩余部分,我们将对之前章节中实现并预训练的 GPT 模型进行修改和分类微调。我们从下载并准备数据集开始,如图 6.4 所示。
<div style="text-align: center;">
<img src="Image/chapter6/figure6.4.png" width="75%" />
</div>
<img src="../Image/chapter6/figure6.4.png" width="75%" />
为了提供一个直观实用的分类微调示例,我们将采用一个包含垃圾消息和非垃圾消息的文本消息数据集。
@@ -128,9 +120,7 @@ df #A
保存的数据集如图 6.5 所示:
<div style="text-align: center;">
<img src="Image/chapter6/figure6.5.png" width="75%" />
</div>
<img src="../Image/chapter6/figure6.5.png" width="75%" />
我们来看一下数据集中类别标签的分布情况:
@@ -240,9 +230,7 @@ test_df.to_csv("test.csv", index=None)
在实现细节上,我们可以在编码后的文本消息中添加与 `"<|endoftext|>"` 对应的 token ID而不是直接将字符串 `"<|endoftext|>"` 附加到每条文本消息后,如图 6.6 所示。
<div style="text-align: center;">
<img src="Image/chapter6/figure6.6.png" width="75%" />
</div>
<img src="../Image/chapter6/figure6.6.png" width="75%" />
图 6.6 假定 50,256 是填充 token `<|endoftext|>` 的 token ID。我们可以通过使用 tiktoken 包中的 GPT-2 分词器对 `<|endoftext|>` 进行编码来进一步验证此 token ID 是否正确(该分词器在前几章中已使用过):
@@ -352,9 +340,7 @@ test_dataset = SpamDataset(
将以上的数据集作为输入,我们就可以实例化数据加载器(可以回顾第 2 章中的操作)。然而,在本例中,目标表示的是类别标签,而非文本中的下一个 token。例如选择批量大小为 8 时,每个批次包含 8 个长度为 120 的训练样本和相应的类别标签,如图 6.7 所示。
<div style="text-align: center;">
<img src="Image/chapter6/figure6.7.png" width="75%" />
</div>
<img src="../Image/chapter6/figure6.7.png" width="75%" />
以下代码创建了训练集、验证集和测试集的数据加载器,以批量大小为 8 加载文本消息及其标签(如图 6.7 所示):
@@ -431,9 +417,7 @@ print(f"{len(test_loader)} test batches")
在本节中,我们将准备用于垃圾短信分类微调的模型。首先,我们初始化上一章使用过的预训练模型,如图 6.8 所示。
<div style="text-align: center;">
<img src="Image/chapter6/figure6.8.png" width="75%" />
</div>
<img src="../Image/chapter6/figure6.8.png" width="75%" />
现在我们通过复用第 5 章的配置,开始进行模型准备过程:
@@ -536,9 +520,7 @@ The following text 'spam'? Answer with 'yes' or 'no': 'You are a winner
本节我们将修改预训练的模型为分类任务的微调做准备。为此我们需要替换原始输出层原输出层将隐层表示映射到50,257个词汇的词汇表而我们用一个较小的输出层将其映射到两个类别0非垃圾短信和1垃圾短信如图6.9所示。
<div style="text-align: center;">
<img src="Image/chapter6/figure6.9.png" width="75%" />
</div>
<img src="../Image/chapter6/figure6.9.png" width="75%" />
如图 6.9 所示,我们使用与前几章相同的模型,唯一的不同是替换了输出层。
@@ -619,9 +601,7 @@ model.out_head = torch.nn.Linear(
此外,我们还需将最后一个 Transformer 模块以及连接该模块和输出层的 LayerNorm 模块配置为可训练如图6.10所示。
<div style="text-align: center;">
<img src="Image/chapter6/figure6.10.png" width="75%" />
</div>
<img src="../Image/chapter6/figure6.10.png" width="75%" />
为了让最终的 LayerNorm 和最后一个 Transformer 模块参与训练(如图 6.10 所示),我们将它们的 `requires_grad` 设置为 `True`
@@ -678,9 +658,7 @@ Outputs dimensions: torch.Size([1, 4, 2])
请注意,我们希望微调该模型,使其能够输出一个分类标签,用于判断输入是否为垃圾短信。为实现这一点,我们不需要微调所有 4 行输出,只需聚焦于单个输出 token。具体来说我们将重点关注最后一行对应的输出 token如图 6.11 所示。
<div style="text-align: center;">
<img src="Image/chapter6/figure6.11.png" width="75%" />
</div>
<img src="../Image/chapter6/figure6.11.png" width="75%" />
```python
# To extract the last output token, illustrated in figure 6.11, from the output tensor, we use the following code:
@@ -697,9 +675,7 @@ Last output token: tensor([[-3.5983, 3.9902]])
在第 3 章中,我们探讨了注意力机制,该机制在每个输入 token 与其他所有输入 token 之间建立关系。随后,我们引入了因果注意力掩码的概念,这在 GPT 类模型中被广泛使用。这种掩码限制每个 token 的关注范围,使其只能关注当前位置及之前的内容,从而确保每个 token 只能受到自身及前面 token 的影响,如图 6.12 所示。
<div style="text-align: center;">
<img src="Image/chapter6/figure6.12.png" width="75%" />
</div>
<img src="../Image/chapter6/figure6.12.png" width="75%" />
在图 6.12 所示的因果注意力掩码设置中,序列中的最后一个 token 聚合了所有前面 token 的信息。因此,在垃圾短信分类任务的微调过程中,我们会重点关注这个最后的 token。
@@ -717,9 +693,7 @@ Last output token: tensor([[-3.5983, 3.9902]])
本章到目前为止,我们已完成了数据集准备、预训练模型的加载,以及对模型进行分类微调的修改。在微调正式开始前,还剩下一小部分工作:实现微调过程中使用的模型评估函数(如图 6.13 所示)。我们将在本节完成这一部分。
<div style="text-align: center;">
<img src="Image/chapter6/figure6.13.png" width="75%" />
</div>
<img src="../Image/chapter6/figure6.13.png" width="75%" />
在实现评估工具之前,我们先简单讨论一下如何将模型输出转换为类别标签预测。
@@ -727,9 +701,7 @@ Last output token: tensor([[-3.5983, 3.9902]])
模型对每个输入文本的最后一个 token 生成的输出被转换为概率得分。然后,通过查找概率得分中最高值的位置来确定对应的分类标签。请注意,由于模型尚未经过训练,目前对垃圾短信标签的预测是不准确的。
<div style="text-align: center;">
<img src="Image/chapter6/figure6.14.png" width="75%" />
</div>
<img src="../Image/chapter6/figure6.14.png" width="75%" />
为了通过具体示例来说明图 6.14,我们来看一下前一节代码示例中的最后一个输出 token
@@ -879,9 +851,7 @@ Test loss: 2.322
在本节中,我们定义并使用训练函数,对预训练的 LLM 进行微调,以提升其垃圾短信分类的准确率。训练循环的整体结构与第 5 章中的相同(详见图 6.15),唯一的区别在于,这里计算的是分类准确率,而不是通过生成文本来评估模型。
<div style="text-align: center;">
<img src="Image/chapter6/figure6.15.png" width="75%" />
</div>
<img src="../Image/chapter6/figure6.15.png" width="75%" />
可以看到,图 6.15 中所示的训练函数逻辑,与第 5 章中用于模型预训练的 `train_model_simple` 函数非常相似。
@@ -1032,9 +1002,7 @@ plot_values(epochs_tensor, examples_seen_tensor, train_losses, val_losses)
图6.16展示了最终的损失曲线。
<div style="text-align: center;">
<img src="Image/chapter6/figure6.16.png" width="75%" />
</div>
<img src="../Image/chapter6/figure6.16.png" width="75%" />
从图 6.16 中陡峭的下降曲线可以看出,模型在训练数据上的学习效果很好,且没有明显的过拟合迹象,训练集和验证集的损失值几乎没有差距。
@@ -1054,9 +1022,7 @@ plot_values(epochs_tensor, examples_seen_tensor, train_accs, val_accs, label="ac
The resulting accuracy graphs are shown in figure 6.17.
```
<div style="text-align: center;">
<img src="Image/chapter6/figure6.17.png" width="75%" />
</div>
<img src="../Image/chapter6/figure6.17.png" width="75%" />
从图 6.17 的准确率曲线可以看出,模型在第 4 到 5 个训练周期后,训练和验证准确率均达到了较高水平。
@@ -1094,9 +1060,7 @@ Test accuracy: 95.67%
在前几节对模型进行微调和评估后,我们现在进入本章的最后阶段(见图 6.18):使用模型进行垃圾短信分类。
<div style="text-align: center;">
<img src="Image/chapter6/figure6.18.png" width="75%" />
</div>
<img src="../Image/chapter6/figure6.18.png" width="75%" />
最后,我们将使用微调后的基于 GPT 的垃圾短信分类模型。以下的 `classify_review` 函数遵循了与本章之前实现的 `SpamDataset` 类似的数据预处理步骤。函数先将文本处理为 token ID然后使用模型预测一个整数类别标签与 6.6 节中的实现类似),并返回对应的类别名称: