<FrameworkSwitchCourse {fw} />

# 使用 Trainer API 微调模型 [[使用 Trainer API 微调模型]]

<CourseFloatingBanner chapter={3}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/zh-CN/chapter3/section3.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/zh-CN/chapter3/section3.ipynb"},
]} />

<Youtube id="nvBXf7s7vTI"/>

🤗 Transformers提供了一个 **Trainer** 类来帮助您在自己的数据集上微调任何预训练模型。完成上一节中的所有数据预处理工作后，您只需要执行几个步骤来创建 **Trainer** .最难的部分可能是为 **Trainer.train()**配置运行环境，因为它在 CPU 上运行速度会非常慢。如果您没有设置 GPU，您可以访问免费的 GPU 或 TPU[Google Colab](https://colab.research.google.com/).

下面的示例假设您已经执行了上一节中的示例。下面这段代码，概括了您需要提前运行的代码：

```py
from datasets import load_dataset
from transformers import AutoTokenizer, DataCollatorWithPadding

raw_datasets = load_dataset("glue", "mrpc")
checkpoint = "bert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)


def tokenize_function(example):
    return tokenizer(example["sentence1"], example["sentence2"], truncation=True)


tokenized_datasets = raw_datasets.map(tokenize_function, batched=True)
data_collator = DataCollatorWithPadding(tokenizer=tokenizer)
```

### Training [[Training]]

在我们定义我们的 **Trainer** 之前首先要定义一个 **TrainingArguments** 类，它将包含 **Trainer**用于训练和评估的所有超参数。您唯一必须提供的参数是保存训练模型的目录，以及训练过程中的检查点。对于其余的参数，您可以保留默认值，这对于基本微调应该非常有效。

```py
from transformers import TrainingArguments

training_args = TrainingArguments("test-trainer")
```

<Tip>

💡 如果您想在训练期间自动将模型上传到 Hub，请将push_to_hub=True添加到TrainingArguments之中. 我们将在[第四章](/course/chapter4/3)中详细介绍这部分。

</Tip>

第二步是定义我们的模型。正如在[之前的章节](/2_Using Transformers/Introduction)一样，我们将使用 **AutoModelForSequenceClassification** 类，它有两个参数：

```py
from transformers import AutoModelForSequenceClassification

model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2)
```

你会注意到，和[第二章](/course/chapter2)不一样的是，在实例化此预训练模型后会收到警告。这是因为 BERT 没有在句子对分类方面进行过预训练，所以预训练模型的头部已经被丢弃，而是添加了一个适合句子序列分类的新头部。警告表明一些权重没有使用（对应于丢弃的预训练头的那些），而其他一些权重被随机初始化（新头的那些）。最后鼓励您训练模型，这正是我们现在要做的。

一旦我们有了我们的模型，我们就可以定义一个 **Trainer** 通过将之前构造的所有对象传递给它——我们的**model** 、**training_args** ，训练和验证数据集，**data_collator** ，和 **tokenizer** ：

```py
from transformers import Trainer

trainer = Trainer(
    model,
    training_args,
    train_dataset=tokenized_datasets["train"],
    eval_dataset=tokenized_datasets["validation"],
    data_collator=data_collator,
    tokenizer=tokenizer,
)
```

请注意，当您在这里完成**tokenizer**后，默认 **Trainer**使用 的**data_collator**会使用之前预定义的 **DataCollatorWithPadding** ，因此您可以在这个例子中跳过 **data_collator=data_collator**。在第 2 节中向您展示这部分处理仍然很重要！

为了让预训练模型在在我们的数据集上微调，我们只需要调用**Trainer**的**train()** 方法 ：

```py
trainer.train()
```

这将开始微调（在GPU上应该需要几分钟），并每500步报告一次训练损失。但是，它不会告诉您模型的性能如何（或质量如何）。这是因为:

1. 我们没有通过将**evaluation_strategy**设置为“**steps**”(在每次更新参数的时候评估)或“**epoch**”(在每个epoch结束时评估)来告诉**Trainer**在训练期间进行评估。
2. 我们没有为**Trainer**提供一个**compute_metrics()**函数来直接计算模型的好坏(否则评估将只输出loss，这不是一个非常直观的数字)。


### 评估 [[评估]]

让我们看看如何构建一个有用的 **compute_metrics()** 函数并在我们下次训练时使用它。该函数必须采用 **EvalPrediction** 对象（带有 **predictions** 和 **label_ids** 字段的参数元组）并将返回一个字符串到浮点数的字典（字符串是返回的指标的名称，而浮点数是它们的值）。我们可以使用 **Trainer.predict()** 命令来使用我们的模型进行预测：

```py
predictions = trainer.predict(tokenized_datasets["validation"])
print(predictions.predictions.shape, predictions.label_ids.shape)
```

```python out
(408, 2) (408,)
```

 **predict()** 的输出结果是具有三个字段的命名元组： **predictions** , **label_ids** ， 和 **metrics** .这 **metrics** 字段将只包含传递的数据集的loss，以及一些运行时间（预测所需的总时间和平均时间）。如果我们定义了自己的 **compute_metrics()** 函数并将其传递给 **Trainer** ，该字段还将包含**compute_metrics()**的结果。

**predict()** 方法是具有三个字段的命名元组： **predictions** , **label_ids** ， 和 **metrics** .这 **metrics** 字段将只包含传递的数据集的loss，以及一些运行时间（预测所需的总时间和平均时间）。如果我们定义了自己的 **compute_metrics()** 函数并将其传递给 **Trainer** ，该字段还将包含**compute_metrics()** 的结果。如你看到的， **predictions** 是一个形状为 408 x 2 的二维数组（408 是我们使用的数据集中元素的数量）。这些是我们传递给**predict()**的数据集的每个元素的结果(logits)（正如你在[之前的章节](/course/chapter2)看到的情况）。要将我们的预测的可以与真正的标签进行比较，我们需要在第二个轴上取最大值的索引：

```py
import numpy as np

preds = np.argmax(predictions.predictions, axis=-1)
```

现在建立我们的 **compute_metric()** 函数来较为直观地评估模型的好坏，我们将使用 🤗 [Evaluate](https://github.com/huggingface/evaluate/) 库中的指标。我们可以像加载数据集一样轻松加载与 MRPC 数据集关联的指标，这次使用 **evaluate.load()** 函数。返回的对象有一个 **compute()**方法我们可以用来进行度量计算的方法：

```py
import evaluate

metric = evaluate.load("glue", "mrpc")
metric.compute(predictions=preds, references=predictions.label_ids)
```

```python out
{'accuracy': 0.8578431372549019, 'f1': 0.8996539792387542}
```

您获得的确切结果可能会有所不同，因为模型头的随机初始化可能会影响最终建立的模型。在这里，我们可以看到我们的模型在验证集上的准确率为 85.78%，F1 分数为 89.97。这是用于评估 GLUE 基准的 MRPC 数据集结果的两个指标。而在[BERT 论文](https://arxiv.org/pdf/1810.04805.pdf)中展示的基础模型的 F1 分数为 88.9。那是 **uncased** 模型，而我们目前正在使用 **cased** 模型，通过改进得到了更好的结果。

最后将所有东西打包在一起，我们得到了我们的 **compute_metrics()** 函数：

```py
def compute_metrics(eval_preds):
    metric = evaluate.load("glue", "mrpc")
    logits, labels = eval_preds
    predictions = np.argmax(logits, axis=-1)
    return metric.compute(predictions=predictions, references=labels)
```

为了查看模型在每个训练周期结束的好坏，下面是我们如何使用**compute_metrics()**函数定义一个新的 **Trainer** ：

```py
training_args = TrainingArguments("test-trainer", evaluation_strategy="epoch")
model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2)

trainer = Trainer(
    model,
    training_args,
    train_dataset=tokenized_datasets["train"],
    eval_dataset=tokenized_datasets["validation"],
    data_collator=data_collator,
    tokenizer=tokenizer,
    compute_metrics=compute_metrics,
)
```

请注意，我们设置了了一个新的 **TrainingArguments** 它的**evaluation_strategy** 设置为 **epoch** 并创建了一个新模型。如果不创建新的模型就直接训练，就只会继续训练之前我们已经训练过的模型。要启动新的训练运行，我们执行：

```py
trainer.train()
```

这一次，它将在训练loss之外，还会输出每个 epoch 结束时的验证loss和指标。同样，由于模型的随机头部初始化，您达到的准确率/F1 分数可能与我们发现的略有不同，但它应该在同一范围内。

这 **Trainer** 将在多个 GPU 或 TPU 上开箱即用，并提供许多选项，例如混合精度训练（在训练的参数中使用 **fp16 = True** ）。我们将在第 10 章讨论它支持的所有内容。

使用**Trainer** API微调的介绍到此结束。对最常见的 NLP 任务执行此操作的示例将在[第 7 章](/course/chapter7)中给出，但现在让我们看看如何在纯 PyTorch 中执行相同的操作。

<Tip>

✏️ **试试看!** 使用您在第 2 节中进行的数据处理，在 GLUE SST-2 数据集上微调模型。

</Tip>

