Transformers 文档

多项选择

Hugging Face's logo
加入 Hugging Face 社区

并获得增强的文档体验

开始使用

多项选择

多项选择任务类似于问答,只是提供了几个候选答案和上下文,模型经过训练可以选择正确答案。

本指南将向您展示如何:

  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("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'}

虽然这里看起来有很多字段,但实际上相当简单:

  • sent1sent2:这些字段显示一个句子是如何开始的,如果将两者放在一起,您将得到 startphrase 字段。
  • ending:建议一个句子可能如何结束,但只有一个是正确的。
  • label:标识正确的句子结尾。

预处理

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

>>> from transformers import AutoTokenizer

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

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

  1. 复制四份 sent1 字段,并将它们分别与 sent2 结合,以重新创建句子开头。
  2. sent2 与四个可能的句子结尾中的每一个结合。
  3. 将这些列表展平以便进行分词,然后再次展平,使每个示例都具有相应的 input_idsattention_masklabels 字段。
>>> 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)

为了创建一批示例,更有效的方法是在整理过程中将句子*动态填充*到批次中最长的长度,而不是将整个数据集填充到最大长度。DataCollatorForMultipleChoice 会展平所有模型输入,应用填充,然后展平结果。

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

评估

在训练期间包含一个指标通常有助于评估模型的性能。您可以使用 🤗 Evaluate 库快速加载评估方法。对于此任务,加载 准确度 指标(请参阅 🤗 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 函数现在可以使用了,您将在设置训练时再次用到它。

训练

PyTorch
隐藏 Pytorch 内容

如果您不熟悉如何使用 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()
TensorFlow
隐藏 TensorFlow 内容

如果您不熟悉如何使用 Keras 对模型进行微调,请参阅此处的基本教程!

要在 TensorFlow 中对模型进行微调,首先要设置优化器函数、学习率调度和一些训练超参数
>>> from transformers import create_optimizer

>>> batch_size = 16
>>> num_train_epochs = 2
>>> total_train_steps = (len(tokenized_swag["train"]) // batch_size) * num_train_epochs
>>> optimizer, schedule = create_optimizer(init_lr=5e-5, num_warmup_steps=0, num_train_steps=total_train_steps)

然后您可以使用 TFAutoModelForMultipleChoice 加载 BERT。

>>> from transformers import TFAutoModelForMultipleChoice

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

使用 prepare_tf_dataset() 将数据集转换为 tf.data.Dataset 格式

>>> data_collator = DataCollatorForMultipleChoice(tokenizer=tokenizer)
>>> tf_train_set = model.prepare_tf_dataset(
...     tokenized_swag["train"],
...     shuffle=True,
...     batch_size=batch_size,
...     collate_fn=data_collator,
... )

>>> tf_validation_set = model.prepare_tf_dataset(
...     tokenized_swag["validation"],
...     shuffle=False,
...     batch_size=batch_size,
...     collate_fn=data_collator,
... )

使用 compile 配置模型进行训练。请注意,Transformers 模型都带有一个默认的任务相关损失函数,因此除非您需要,否则无需指定它。

>>> model.compile(optimizer=optimizer)  # No loss argument!

在开始训练之前,需要设置的最后两件事是计算预测的准确度,并提供一种将模型推送到 Hub 的方法。这两者都通过使用 Keras 回调 完成。

将您的 compute_metrics 函数传递给 KerasMetricCallback

>>> from transformers.keras_callbacks import KerasMetricCallback

>>> metric_callback = KerasMetricCallback(metric_fn=compute_metrics, eval_dataset=tf_validation_set)

PushToHubCallback 中指定将模型和分词器推送到何处

>>> from transformers.keras_callbacks import PushToHubCallback

>>> push_to_hub_callback = PushToHubCallback(
...     output_dir="my_awesome_model",
...     tokenizer=tokenizer,
... )

然后将回调函数捆绑在一起

>>> callbacks = [metric_callback, push_to_hub_callback]

最后,您已准备好开始训练模型!调用 fit 并传入您的训练和验证数据集、时期数以及您的回调函数,以微调模型。

>>> model.fit(x=tf_train_set, validation_data=tf_validation_set, epochs=2, callbacks=callbacks)

训练完成后,您的模型会自动上传到 Hub,供所有人使用!

有关如何微调多项选择模型的更深入示例,请参阅相应的 PyTorch notebookTensorFlow 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
隐藏 Pytorch 内容

对每个提示和候选答案对进行分词,并返回 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
TensorFlow
隐藏 TensorFlow 内容

对每个提示和候选答案对进行分词,并返回 TensorFlow 张量。

>>> from transformers import AutoTokenizer

>>> tokenizer = AutoTokenizer.from_pretrained("username/my_awesome_swag_model")
>>> inputs = tokenizer([[prompt, candidate1], [prompt, candidate2]], return_tensors="tf", padding=True)

将您的输入传递给模型并返回 logits

>>> from transformers import TFAutoModelForMultipleChoice

>>> model = TFAutoModelForMultipleChoice.from_pretrained("username/my_awesome_swag_model")
>>> inputs = {k: tf.expand_dims(v, 0) for k, v in inputs.items()}
>>> outputs = model(inputs)
>>> logits = outputs.logits

获取概率最高的类别。

>>> predicted_class = int(tf.math.argmax(logits, axis=-1)[0])
>>> predicted_class
0
< > 在 GitHub 上更新