Multiple choice
多肢選択タスクは質問応答に似ていますが、いくつかの候補の回答がコンテキストとともに提供され、正しい回答を選択するようにモデルがトレーニングされる点が異なります。
このガイドでは、次の方法を説明します。
始める前に、必要なライブラリがすべてインストールされていることを確認してください。
pip install transformers datasets evaluate
モデルをアップロードしてコミュニティと共有できるように、Hugging Face アカウントにログインすることをお勧めします。プロンプトが表示されたら、トークンを入力してログインします。
>>> from huggingface_hub import notebook_login
>>> notebook_login()
Load SWAG dataset
まず、🤗 データセット ライブラリから SWAG データセットの「通常」構成をロードします。
>>> 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'}
ここにはたくさんのフィールドがあるように見えますが、実際は非常に簡単です。
sent1
とsent2
: これらのフィールドは文の始まりを示し、この 2 つを組み合わせるとstartphrase
フィールドが得られます。ending
: 文の終わり方として考えられる終わり方を示唆しますが、正しいのは 1 つだけです。label
: 正しい文の終わりを識別します。
Preprocess
次のステップでは、BERT トークナイザーをロードして、文の始まりと 4 つの可能な終わりを処理します。
>>> from transformers import AutoTokenizer
>>> tokenizer = AutoTokenizer.from_pretrained("google-bert/bert-base-uncased")
作成する前処理関数は次のことを行う必要があります。
sent1
フィールドのコピーを 4 つ作成し、それぞれをsent2
と組み合わせて文の始まりを再現します。sent2
を 4 つの可能な文末尾のそれぞれと組み合わせます。- これら 2 つのリストをトークン化できるようにフラット化し、その後、各例に対応する
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)
🤗 Transformers には多肢選択用のデータ照合器がないため、DataCollatorWithPadding
を調整してサンプルのバッチを作成する必要があります。データセット全体を最大長までパディングするのではなく、照合中にバッチ内の最長の長さまで文を 動的にパディング する方が効率的です。
DataCollatorForMultipleChoice
は、すべてのモデル入力を平坦化し、パディングを適用して、結果を非平坦化します。
>>> from dataclasses import dataclass
>>> from transformers.tokenization_utils_base import PreTrainedTokenizerBase, PaddingStrategy
>>> from typing import Optional, Union
>>> import torch
>>> @dataclass
... class DataCollatorForMultipleChoice:
... """
... Data collator that will dynamically pad the inputs for multiple choice received.
... """
... tokenizer: PreTrainedTokenizerBase
... padding: Union[bool, str, PaddingStrategy] = True
... max_length: Optional[int] = None
... pad_to_multiple_of: Optional[int] = None
... def __call__(self, features):
... label_name = "label" if "label" in features[0].keys() else "labels"
... labels = [feature.pop(label_name) for feature in features]
... batch_size = len(features)
... num_choices = len(features[0]["input_ids"])
... flattened_features = [
... [{k: v[i] for k, v in feature.items()} for i in range(num_choices)] for feature in features
... ]
... flattened_features = sum(flattened_features, [])
... batch = self.tokenizer.pad(
... flattened_features,
... padding=self.padding,
... max_length=self.max_length,
... pad_to_multiple_of=self.pad_to_multiple_of,
... return_tensors="pt",
... )
... batch = {k: v.view(batch_size, num_choices, -1) for k, v in batch.items()}
... batch["labels"] = torch.tensor(labels, dtype=torch.int64)
... return batch
>>> from dataclasses import dataclass
>>> from transformers.tokenization_utils_base import PreTrainedTokenizerBase, PaddingStrategy
>>> from typing import Optional, Union
>>> import tensorflow as tf
>>> @dataclass
... class DataCollatorForMultipleChoice:
... """
... Data collator that will dynamically pad the inputs for multiple choice received.
... """
... tokenizer: PreTrainedTokenizerBase
... padding: Union[bool, str, PaddingStrategy] = True
... max_length: Optional[int] = None
... pad_to_multiple_of: Optional[int] = None
... def __call__(self, features):
... label_name = "label" if "label" in features[0].keys() else "labels"
... labels = [feature.pop(label_name) for feature in features]
... batch_size = len(features)
... num_choices = len(features[0]["input_ids"])
... flattened_features = [
... [{k: v[i] for k, v in feature.items()} for i in range(num_choices)] for feature in features
... ]
... flattened_features = sum(flattened_features, [])
... batch = self.tokenizer.pad(
... flattened_features,
... padding=self.padding,
... max_length=self.max_length,
... pad_to_multiple_of=self.pad_to_multiple_of,
... return_tensors="tf",
... )
... batch = {k: tf.reshape(v, (batch_size, num_choices, -1)) for k, v in batch.items()}
... batch["labels"] = tf.convert_to_tensor(labels, dtype=tf.int64)
... return batch
Evaluate
トレーニング中にメトリクスを含めると、多くの場合、モデルのパフォーマンスを評価するのに役立ちます。 🤗 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
関数の準備が整いました。トレーニングをセットアップするときにこの関数に戻ります。
Train
これでモデルのトレーニングを開始する準備が整いました。 AutoModelForMultipleChoice を使用して BERT をロードします。
>>> from transformers import AutoModelForMultipleChoice, TrainingArguments, Trainer
>>> model = AutoModelForMultipleChoice.from_pretrained("google-bert/bert-base-uncased")
この時点で残っている手順は次の 3 つだけです。
- TrainingArguments でトレーニング ハイパーパラメータを定義します。唯一の必須パラメータは、モデルの保存場所を指定する
output_dir
です。push_to_hub=True
を設定して、このモデルをハブにプッシュします (モデルをアップロードするには、Hugging Face にサインインする必要があります)。各エポックの終了時に、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"],
... tokenizer=tokenizer,
... data_collator=DataCollatorForMultipleChoice(tokenizer=tokenizer),
... compute_metrics=compute_metrics,
... )
>>> trainer.train()
トレーニングが完了したら、 push_to_hub() メソッドを使用してモデルをハブに共有し、誰もがモデルを使用できますように。
>>> trainer.push_to_hub()
Keras を使用したモデルの微調整に慣れていない場合は、こちら の基本的なチュートリアルをご覧ください。
>>> 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!
トレーニングを開始する前にセットアップする最後の 2 つのことは、予測から精度を計算することと、モデルをハブにプッシュする方法を提供することです。どちらも 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)
トレーニングが完了すると、モデルは自動的にハブにアップロードされ、誰でも使用できるようになります。
複数選択用にモデルを微調整する方法の詳細な例については、対応するセクションを参照してください。 PyTorch ノートブック または TensorFlow ノートブック。
Inference
モデルを微調整したので、それを推論に使用できるようになりました。
いくつかのテキストと 2 つの回答候補を考えてください。
>>> 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 テンソルを返します。いくつかのlables
も作成する必要があります。
>>> from transformers import AutoTokenizer
>>> tokenizer = AutoTokenizer.from_pretrained("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("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 テンソルを返します。
>>> from transformers import AutoTokenizer
>>> tokenizer = AutoTokenizer.from_pretrained("my_awesome_swag_model")
>>> inputs = tokenizer([[prompt, candidate1], [prompt, candidate2]], return_tensors="tf", padding=True)
入力をモデルに渡し、logits
を返します。
>>> from transformers import TFAutoModelForMultipleChoice
>>> model = TFAutoModelForMultipleChoice.from_pretrained("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'