Transformers documentation

多项选择

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

多项选择

多项选择题任务类似于问答任务,不同之处在于,除了上下文之外,还会提供多个候选答案,模型被训练以选择正确的答案。

本指南将向您展示如何:

  1. 在 SWAG 数据集的 regular 配置上微调 BERT,根据多个选项和部分上下文选择最佳答案。
  2. 使用微调后的模型进行推理。

在开始之前,请确保已安装所有必要的库:

pip install transformers datasets evaluate

我们建议您登录 Hugging Face 账户,以便上传模型并与社区共享。当系统提示时,请输入您的令牌以完成登录:

>>> from huggingface_hub import notebook_login

>>> notebook_login()

加载 SWAG 数据集

首先,从 🤗 Datasets 库中加载 SWAG 数据集的 regular 配置:

>>> from datasets import load_dataset

>>> swag = load_dataset("allenai/swag", "regular")

然后来看一个示例:

>>> swag["train"][0]
{'ending0': 'passes by walking down the street playing their instruments.',
 'ending1': 'has heard approaching them.',
 'ending2': "arrives and they're outside dancing and asleep.",
 'ending3': 'turns the lead singer watches the performance.',
 'fold-ind': '3416',
 'gold-source': 'gold',
 'label': 0,
 'sent1': 'Members of the procession walk down the street holding small horn brass instruments.',
 'sent2': 'A drum line',
 'startphrase': 'Members of the procession walk down the street holding small horn brass instruments. A drum line',
 'video-id': 'anetv_jkn6uvmqwh4'}

虽然这里看起来有很多字段,但实际上非常简单明了:

  • sent1 和 sent2:这些字段展示了句子的开头部分,将两者组合起来即可得到 startphrase 字段。
  • ending:提示句子可能的结尾方式,但其中只有一种是正确的。
  • label:标识正确的句子结尾。

预处理

下一步是加载一个 BERT 分词器,以处理句子开头和四种可能的结尾:

>>> from transformers import AutoTokenizer

>>> tokenizer = AutoTokenizer.from_pretrained("google-bert/bert-base-uncased")

您想要创建的预处理函数需要:

  1. 创建 sent1 字段的四个副本,并将每个副本与 sent2 组合,以重现句子的开头。
  2. 将 sent2 与四种可能的句子结尾分别组合。
  3. 将这两个列表展平以便进行分词,之后再将其恢复原状,使每个示例都拥有对应的 input_ids、attention_mask 和 labels 字段。
>>> ending_names = ["ending0", "ending1", "ending2", "ending3"]


>>> def preprocess_function(examples):
...     first_sentences = [[context] * 4 for context in examples["sent1"]]
...     question_headers = examples["sent2"]
...     second_sentences = [
...         [f"{header} {examples[end][i]}" for end in ending_names] for i, header in enumerate(question_headers)
...     ]

...     first_sentences = sum(first_sentences, [])
...     second_sentences = sum(second_sentences, [])

...     tokenized_examples = tokenizer(first_sentences, second_sentences, truncation=True)
...     return {k: [v[i : i + 4] for i in range(0, len(v), 4)] for k, v in tokenized_examples.items()}

要对整个数据集应用预处理函数,请使用 🤗 Datasets 的 map 方法。你可以通过设置 batched=True 来一次处理数据集中的多个元素,从而加速 map 函数:

>>> tokenized_swag = swag.map(preprocess_function, batched=True)

要创建一批示例,在数据整理(collation)阶段将句子动态填充到该批次中最长的长度,比将整个数据集填充到最大长度更高效。DataCollatorForMultipleChoice 会先展平所有模型输入,应用填充,然后再将结果恢复为原始形状。

>>> from transformers import DataCollatorForMultipleChoice
>>> collator = DataCollatorForMultipleChoice(tokenizer=tokenizer)

评估

在训练过程中加入评估指标通常有助于评估模型的性能。您可以使用 🤗 Evaluate 库快速加载评估方法。对于本任务,请加载 accuracy 指标(请参阅 🤗 Evaluate 的 快速入门 以了解如何加载和计算指标):

>>> import evaluate

>>> accuracy = evaluate.load("accuracy")

然后创建一个函数,将你的预测值和标签传递给 compute 以计算准确率:

>>> import numpy as np


>>> def compute_metrics(eval_pred):
...     predictions, labels = eval_pred
...     predictions = np.argmax(predictions, axis=1)
...     return accuracy.compute(predictions=predictions, references=labels)

您的 compute_metrics 函数已准备就绪,在配置训练时您将再次用到它。

训练

如果您不熟悉使用 Trainer 对模型进行微调,请查看此处的基础教程!

现在可以开始训练模型了!使用 AutoModelForMultipleChoice 加载 BERT:

>>> from transformers import AutoModelForMultipleChoice, TrainingArguments, Trainer

>>> model = AutoModelForMultipleChoice.from_pretrained("google-bert/bert-base-uncased")

此时,只剩下三个步骤:

  1. 在 TrainingArguments 中定义训练超参数。唯一必需的参数是 output_dir,用于指定模型的保存位置。通过设置 push_to_hub=True,你可以将该模型推送到 Hub(上传模型前需要登录 Hugging Face 账户)。在每个 epoch 结束时,Trainer 会评估准确率并保存训练检查点。
  2. 将训练参数与模型、数据集、分词器、数据整理器以及 compute_metrics 函数一起传递给 Trainer。
  3. 调用 train() 来微调你的模型。
>>> training_args = TrainingArguments(
...     output_dir="my_awesome_swag_model",
...     eval_strategy="epoch",
...     save_strategy="epoch",
...     load_best_model_at_end=True,
...     learning_rate=5e-5,
...     per_device_train_batch_size=16,
...     per_device_eval_batch_size=16,
...     num_train_epochs=3,
...     weight_decay=0.01,
...     push_to_hub=True,
... )

>>> trainer = Trainer(
...     model=model,
...     args=training_args,
...     train_dataset=tokenized_swag["train"],
...     eval_dataset=tokenized_swag["validation"],
...     processing_class=tokenizer,
...     data_collator=collator,
...     compute_metrics=compute_metrics,
... )

>>> trainer.train()

训练完成后,使用 push_to_hub() 方法将您的模型共享到 Hub,以便所有人都能使用您的模型:

>>> trainer.push_to_hub()

如需了解如何针对多项选择任务微调模型的更详细示例,请参阅对应的 PyTorch notebook。

推理

很好,现在你已经微调了一个模型,可以使用它进行推理了!

想出一些文本和两个候选答案:

>>> prompt = "France has a bread law, Le Décret Pain, with strict rules on what is allowed in a traditional baguette."
>>> candidate1 = "The law does not apply to croissants and brioche."
>>> candidate2 = "The law applies to baguettes."

对每个提示和候选答案对进行分词,并返回 PyTorch 张量。您还应该创建一些 labels:

>>> from transformers import AutoTokenizer

>>> tokenizer = AutoTokenizer.from_pretrained("username/my_awesome_swag_model")
>>> inputs = tokenizer([[prompt, candidate1], [prompt, candidate2]], return_tensors="pt", padding=True)
>>> labels = torch.tensor(0).unsqueeze(0)

将输入和标签传入模型,并返回 logits:

>>> from transformers import AutoModelForMultipleChoice

>>> model = AutoModelForMultipleChoice.from_pretrained("username/my_awesome_swag_model")
>>> outputs = model(**{k: v.unsqueeze(0) for k, v in inputs.items()}, labels=labels)
>>> logits = outputs.logits

获取概率最高的类别:

>>> predicted_class = logits.argmax().item()
>>> predicted_class
0
Update on GitHub