HuggingFace Transformers 4.17 : ガイド : 下流タスク用の再調整 – 質問応答 (翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 04/28/2022 (v4.17.0)
* 本ページは、HuggingFace Transformers の以下のドキュメントを翻訳した上で適宜、補足説明したものです:
* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。
- 人工知能研究開発支援
- 人工知能研修サービス(経営者層向けオンサイト研修)
- テクニカルコンサルティングサービス
- 実証実験(プロトタイプ構築)
- アプリケーションへの実装
- 人工知能研修サービス
- PoC(概念実証)を失敗させないための支援
- お住まいの地域に関係なく Web ブラウザからご参加頂けます。事前登録 が必要ですのでご注意ください。
◆ お問合せ : 本件に関するお問い合わせ先は下記までお願いいたします。
- 株式会社クラスキャット セールス・マーケティング本部 セールス・インフォメーション
- sales-info@classcat.com ; Web: www.classcat.com ; ClassCatJP
HuggingFace Transformers : ガイド : 下流タスク用の再調整 – 質問応答
質問応答タスクは質問が与えられたときに答えを返します。質問応答の 2 つの一般的な形式があります :
- Extractive : 与えられたコンテキストから答えを抽出する。
- Abstractive : コンテキストから正しく質問に答える答えを生成する。
このガイドは extractive 質問応答に対して SQuAD データセット上で DistilBERT を再調整する方法を示します。
Note : 質問応答と関連するモデル、データセットとメトリクスの他の形式についての詳細は質問応答 タスクのページ を見てください。
SQuAD データセットのロード
Datasets ライブラリから SQuAD データセットをロードします :
from datasets import load_dataset
squad = load_dataset("squad")
そしてサンプルを見てみましょう :
squad["train"][0]
{'answers': {'answer_start': [515], 'text': ['Saint Bernadette Soubirous']}, 'context': 'Architecturally, the school has a Catholic character. Atop the Main Building\'s gold dome is a golden statue of the Virgin Mary. Immediately in front of the Main Building and facing it, is a copper statue of Christ with arms upraised with the legend "Venite Ad Me Omnes". Next to the Main Building is the Basilica of the Sacred Heart. Immediately behind the basilica is the Grotto, a Marian place of prayer and reflection. It is a replica of the grotto at Lourdes, France where the Virgin Mary reputedly appeared to Saint Bernadette Soubirous in 1858. At the end of the main drive (and in a direct line that connects through 3 statues and the Gold Dome), is a simple, modern stone statue of Mary.', 'id': '5733be284776f41900661182', 'question': 'To whom did the Virgin Mary allegedly appear in 1858 in Lourdes France?', 'title': 'University_of_Notre_Dame' }
answers フィールドは答えの開始位置と答えのテキストを含む辞書です。
前処理
質問とコンテキストフィールドを処理するために DistilBERT トークナイザーをロードします :
from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("distilbert-base-uncased")
知っておくべき、質問応答に特有の幾つかの前処理ステップがあります :
- データセットの幾つかのサンプルは、モデルの最大入力長を超える、非常に長いコンテキストを持っている可能性があります。truncation=”only_second” を設定することでコンテキストだけを切り詰めてください。
- 次に、return_offset_mapping=True を設定して答えの開始と終了位置を元のコンテキストにマップします。
- 手動でマッピングすることで、答えの開始と終了トークンを見つけることができます。sequence_ids メソッドを使用して、オフセットのどの部分が質問に対応するのか、そしてどの部分がコンテキストに対応するのか見つけられます。
ここに、切り詰めて、答えの開始とトークンをコンテキストにマップする関数を作成できる方法があります :
def preprocess_function(examples):
questions = [q.strip() for q in examples["question"]]
inputs = tokenizer(
questions,
examples["context"],
max_length=384,
truncation="only_second",
return_offsets_mapping=True,
padding="max_length",
)
offset_mapping = inputs.pop("offset_mapping")
answers = examples["answers"]
start_positions = []
end_positions = []
for i, offset in enumerate(offset_mapping):
answer = answers[i]
start_char = answer["answer_start"][0]
end_char = answer["answer_start"][0] + len(answer["text"][0])
sequence_ids = inputs.sequence_ids(i)
# Find the start and end of the context
idx = 0
while sequence_ids[idx] != 1:
idx += 1
context_start = idx
while sequence_ids[idx] == 1:
idx += 1
context_end = idx - 1
# If the answer is not fully inside the context, label it (0, 0)
if offset[context_start][0] > end_char or offset[context_end][1] < start_char:
start_positions.append(0)
end_positions.append(0)
else:
# Otherwise it's the start and end token positions
idx = context_start
while idx <= context_end and offset[idx][0] <= start_char:
idx += 1
start_positions.append(idx - 1)
idx = context_end
while idx >= context_start and offset[idx][1] >= end_char:
idx -= 1
end_positions.append(idx + 1)
inputs["start_positions"] = start_positions
inputs["end_positions"] = end_positions
return inputs
データセット全体に対して前処理関数を適用するためには Datasets map 関数を使用します。データセットの複数の要素を一度に処理する batched=True を設定することで map 関数を高速化できます。必要でないカラムは削除します :
tokenized_squad = squad.map(preprocess_function, batched=True, remove_columns=squad["train"].column_names)
サンプルのバッチを作成するために DefaultDataCollator を使用します。 Transformers の他のデータ collator とは違い、DefaultDataCollator はパディングのような追加の前処理を適用しません。
from transformers import DefaultDataCollator
data_collator = DefaultDataCollator()
from transformers import DefaultDataCollator
data_collator = DefaultDataCollator(return_tensors="tf")
Trainer で再調整
AutoModelForQuestionAnswering で DistilBERT をロードします :
from transformers import AutoModelForQuestionAnswering, TrainingArguments, Trainer
model = AutoModelForQuestionAnswering.from_pretrained("distilbert-base-uncased")
この時点で、3 つのステップだけが残っています :
- TrainingArguments で訓練ハイパーパラメータを定義します。
- 訓練引数をモデル、データセット、トークナイザー、そしてデータ collator と共に Trainer に渡します。
- モデルを再調整するために train() を呼び出します。
training_args = TrainingArguments(
output_dir="./results",
evaluation_strategy="epoch",
learning_rate=2e-5,
per_device_train_batch_size=16,
per_device_eval_batch_size=16,
num_train_epochs=3,
weight_decay=0.01,
)
trainer = Trainer(
model=model,
args=training_args,
train_dataset=tokenized_squad["train"],
eval_dataset=tokenized_squad["validation"],
tokenizer=tokenizer,
data_collator=data_collator,
)
trainer.train()
TensorFlow による再調整
TensorFlow でモデルを再調整することは、幾つかの違いはありますが、同様に簡単です。
データセットを to_tf_dataset で tf.data.Dataset 形式に変換します。columns で入力と答えの開始と終了位置を、データセット順序をシャッフルするか否か、バッチサイズ、そしてデータ collator を指定します :
tf_train_set = tokenized_squad["train"].to_tf_dataset(
columns=["attention_mask", "input_ids", "start_positions", "end_positions"],
dummy_labels=True,
shuffle=True,
batch_size=16,
collate_fn=data_collator,
)
tf_validation_set = tokenized_squad["validation"].to_tf_dataset(
columns=["attention_mask", "input_ids", "start_positions", "end_positions"],
dummy_labels=True,
shuffle=False,
batch_size=16,
collate_fn=data_collator,
)
optimizer 関数, 学習率スケジュール, そして幾つかの訓練ハイパーパラメータをセットアップします :
from transformers import create_optimizer
batch_size = 16
num_epochs = 2
total_train_steps = (len(tokenized_squad["train"]) // batch_size) * num_epochs
optimizer, schedule = create_optimizer(
init_lr=2e-5,
num_warmup_steps=0,
num_train_steps=total_train_steps,
)
TFAutoModelForQuestionAnswering で DistilBERT をロードします :
from transformers import TFAutoModelForQuestionAnswering
model = TFAutoModelForQuestionAnswering("distilbert-base-uncased")
compile で訓練するためにモデルを configure します :
import tensorflow as tf
model.compile(optimizer=optimizer)
モデルを再調整するために fit を呼び出します :
model.fit(x=tf_train_set, validation_data=tf_validation_set, epochs=3)
Note : 質問応答のためにモデルを再調整する方法の詳細なサンプルについては、対応する PyTorch ノートブック か TensorFlow ノートブック を見てください。
以上