多项选择
多项选择题任务类似于问答任务,不同之处在于,除了上下文之外,还会提供多个候选答案,模型被训练以选择正确的答案。
本指南将向您展示如何:
在开始之前,请确保已安装所有必要的库:
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")您想要创建的预处理函数需要:
- 创建
sent1字段的四个副本,并将每个副本与sent2组合,以重现句子的开头。 - 将
sent2与四种可能的句子结尾分别组合。 - 将这两个列表展平以便进行分词,之后再将其恢复原状,使每个示例都拥有对应的
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 函数已准备就绪,在配置训练时您将再次用到它。
训练
现在可以开始训练模型了!使用 AutoModelForMultipleChoice 加载 BERT:
>>> from transformers import AutoModelForMultipleChoice, TrainingArguments, Trainer
>>> model = AutoModelForMultipleChoice.from_pretrained("google-bert/bert-base-uncased")此时,只剩下三个步骤:
- 在 TrainingArguments 中定义训练超参数。唯一必需的参数是
output_dir,用于指定模型的保存位置。通过设置push_to_hub=True,你可以将该模型推送到 Hub(上传模型前需要登录 Hugging Face 账户)。在每个 epoch 结束时,Trainer 会评估准确率并保存训练检查点。 - 将训练参数与模型、数据集、分词器、数据整理器以及
compute_metrics函数一起传递给 Trainer。 - 调用 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