HuggingFace Transformers 4.5 : 利用方法 : 訓練と再調整 (翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 05/11/2021 (4.5.1)
* 本ページは、HuggingFace Transformers の以下のドキュメントを翻訳した上で適宜、補足説明したものです:
- Using Transformers : Training and fine-tuning
* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。
スケジュールは弊社 公式 Web サイト でご確認頂けます。
- お住まいの地域に関係なく Web ブラウザからご参加頂けます。事前登録 が必要ですのでご注意ください。
- ウェビナー運用には弊社製品「ClassCat® Webinar」を利用しています。
人工知能研究開発支援 | 人工知能研修サービス | テレワーク & オンライン授業を支援 |
PoC(概念実証)を失敗させないための支援 (本支援はセミナーに参加しアンケートに回答した方を対象としています。) |
◆ お問合せ : 本件に関するお問い合わせ先は下記までお願いいたします。
株式会社クラスキャット セールス・マーケティング本部 セールス・インフォメーション |
E-Mail:sales-info@classcat.com ; WebSite: https://www.classcat.com/ ; Facebook |
HuggingFace Transformers : 利用方法 : 訓練と再調整
- 訳注 : 本ドキュメントの TensorFlow バージョンは こちら をご覧ください。
Transformers の Model クラスは native PyTorch と TensorFlow 2 と互換であるように設計されそしていずれとも共にシームレスに利用可能です。このクイックスタートでは、いずれのフレームワークでも利用可能な標準訓練ツールを使用してモデルをどのように再調整するか (or スクラッチから訓練するか) を示します。含まれる Trainer() クラスをどのように使用するかも示します、これは訓練の複雑さの大半を貴方のために処理します。
このガイドは推論のためにモデルをロードして使用することに既に馴染みがあることを仮定します : そうでないなら タスクの要点 を見てください。貴方が PyTorch か TF2 のいずれかの深層ニューラルネットワークの訓練に馴染みがあることも仮定し、 Transformers の訓練のためのニュアンスとツールに特にフォーカスします。
native PyTorch で再調整する
TF で始まらない Transformers の Model クラスは PyTorch モジュールで、つまり推論と最適化の両者のために丁度 PyTorch の任意のモデルのようにそれらを利用できます。
シークエンス分類データセット上で BERT のようなマスク付き言語モデルを再調整する一般的なタスクを考えましょう。モデルを from_pretrained() でインスタンス化するとき、モデルを初期化するために指定されたモデルのモデル configuration と事前訓練重みが使用されます。ライブラリはまた幾つかのタスク固有の最終層や「ヘッド」も含みます、それらの重みは指定された事前訓練モデルに存在しないときはランダムにインスタンス化されます。例えば、BertForSequenceClassification.from_pretrained(‘bert-base-uncased’, num_labels=2) によるモデルのインスタンス化は bert-base-uncased モデルからコピーされたエンコーダ重みとエンコーダの上に 2 の出力サイズを持つランダムに初期化されたシークエンス分類ヘッドで BERT モデルインスタンスを作成します。モデルはデフォルトでは eval モードで初期化されます。それを train モードにするために model.train() を呼び出すことができます。
from transformers import BertForSequenceClassification
model = BertForSequenceClassification.from_pretrained('bert-base-uncased')
model.train()
これは有用です、何故ならばそれは事前訓練された BERT エンコーダを利用して選択するどのようなシークエンス分類データセットの上でもそれを容易に訓練することを許容するからです。任意の PyTorch optimizer を利用できますが、ライブラリはまた AdamW() optimizer も提供します、これは重み減衰に加えて勾配バイアス補正 (= gradient bias correction) を実装しています。
from transformers import AdamW
optimizer = AdamW(model.parameters(), lr=1e-5)
optimizer は特定のパラメータグループのために異なるハイパーパラメータを適用することを許容します。例えば、重み減衰をバイアスと層正規化項以外の総てのパラメータに適用できます :
no_decay = ['bias', 'LayerNorm.weight']
optimizer_grouped_parameters = [
{'params': [p for n, p in model.named_parameters() if not any(nd in n for nd in no_decay)], 'weight_decay': 0.01},
{'params': [p for n, p in model.named_parameters() if any(nd in n for nd in no_decay)], 'weight_decay': 0.0}
]
optimizer = AdamW(optimizer_grouped_parameters, lr=1e-5)
今は __call__() を使用して単純なダミー訓練バッチをセットアップすることができます。これは BatchEncoding() インスタンスを返します、これはモデルに渡す必要があるかもしれない総てを準備します。
from transformers import BertTokenizer
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
text_batch = ["I love Pixar.", "I don't care for Pixar."]
encoding = tokenizer(text_batch, return_tensors='pt', padding=True, truncation=True)
input_ids = encoding['input_ids']
attention_mask = encoding['attention_mask']
分類モデルを labels 引数で呼び出すとき、最初の返される要素は予測と渡されたラベルの間の交差エントロピー損失です。optimizer を既にセットアップしていますので、それから backwards パスを行ない重みを更新することができます :
labels = torch.tensor([1,0]).unsqueeze(0)
outputs = model(input_ids, attention_mask=attention_mask, labels=labels)
loss = outputs.loss
loss.backward()
optimizer.step()
代わりに、単にロジットを得て損失を貴方自身で計算することもできます。次は前のサンプルと同値です :
from torch.nn import functional as F
labels = torch.tensor([1,0])
outputs = model(input_ids, attention_mask=attention_mask)
loss = F.cross_entropy(outputs.logits, labels)
loss.backward()
optimizer.step()
もちろん、通常のようにモデルと入力上で to(‘cuda’) を呼び出して GPU 上で訓練することができます。
2, 3 の学習率スケジューリング・ツールも提供します。以下によって、スケジューラのセットアップができます、これは num_warmup_steps の間ウォームアップしてから訓練の終わりまでに 0 に線形に減衰します。
from transformers import get_linear_schedule_with_warmup
scheduler = get_linear_schedule_with_warmup(optimizer, num_warmup_steps, num_train_steps)
それから行なわなければならないことの総ては optimizer.step() の後で scheduler.step() を呼び出すことです。
loss.backward()
optimizer.step()
scheduler.step()
下で議論されるように、Trainer() を使用することを強く勧めます、これは混合精度と容易な tensorboard ロギングのような機能とともに Transformers モデルを訓練する可動部を便利に処理します。
エンコーダを凍結する
場合によっては、事前訓練されたエンコーダの重みを凍結し続けてヘッド層の重みだけを最適化することに関心があるかもしれません。そのためには、エンコーダ・パラメータ上で単純に requires_grad 属性を False に設定します、これはライブラリの任意のタスク固有モデル上 base_model サブモジュールでアクセスできます :
for param in model.base_model.parameters():
param.requires_grad = False
native TensorFlow 2 で再調整する
モデルはまた TensorFlow 2 でもネイティブに訓練できます。ちょうど PyTorch でのように、TensorFlow モデルは事前訓練モデルからエンコーダの重みをロードするために from_pretrained() でインスタンス化できます。
from transformers import TFBertForSequenceClassification
model = TFBertForSequenceClassification.from_pretrained('bert-base-uncased')
GLUE からの MRPC データセット をロードするために tensorflow_datasets を使用しましょう。それから MRPC をトークン化してそれを TensorFlow Dataset オブジェクトに変換するために組込み glue_convert_examples_to_features() を利用できます。tokenizer はフレームワーク不可知ですので、事前訓練された tokenizer 名に TF を先頭に追加する必要はありません。
from transformers import BertTokenizer, glue_convert_examples_to_features
import tensorflow as tf
import tensorflow_datasets as tfds
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
data = tfds.load('glue/mrpc')
train_dataset = glue_convert_examples_to_features(data['train'], tokenizer, max_length=128, task='mrpc')
train_dataset = train_dataset.shuffle(100).batch(32).repeat(2)
そしてモデルは任意の Keras モデルとしてコンパイルされて訓練できます :
optimizer = tf.keras.optimizers.Adam(learning_rate=3e-5)
loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)
model.compile(optimizer=optimizer, loss=loss)
model.fit(train_dataset, epochs=2, steps_per_epoch=115)
TensorFlow と PyTorch モデル間の緊密な相互運用性により、モデルをセーブしてからそれを PyTorch モデルとして再ロードすることさえできます (or vice-versa) :
from transformers import BertForSequenceClassification
model.save_pretrained('./my_mrpc_model/')
pytorch_model = BertForSequenceClassification.from_pretrained('./my_mrpc_model/', from_tf=True)
Trainer
Trainer() と TFTrainer() を通して単純ですが feature-complete な訓練と評価インターフェイスもまた提供します。広範囲の訓練オプションとロギング、勾配集積 (= accumulation) と混合精度のような組込み特徴で任意の Transformers モデルを訓練し、再調整し、そして評価することができます。
from transformers import BertForSequenceClassification, Trainer, TrainingArguments
model = BertForSequenceClassification.from_pretrained("bert-large-uncased")
training_args = TrainingArguments(
output_dir='./results', # output directory
num_train_epochs=3, # total # of training epochs
per_device_train_batch_size=16, # batch size per device during training
per_device_eval_batch_size=64, # batch size for evaluation
warmup_steps=500, # number of warmup steps for learning rate scheduler
weight_decay=0.01, # strength of weight decay
logging_dir='./logs', # directory for storing logs
)
trainer = Trainer(
model=model, # the instantiated 🤗 Transformers model to be trained
args=training_args, # training arguments, defined above
train_dataset=train_dataset, # training dataset
eval_dataset=test_dataset # evaluation dataset
)
今は単純に訓練するために trainer.train() をそして評価するために trainer.evaluate() を呼び出します。貴方自身のモジュールもまた利用できますが、forward から返される最初の引数は最適化することを望む損失でなければなりません。
Trainer() はバッチを順番に並べてそれらをモデルに供給されるように準備するために組込みのデフォルト関数を使用します。必要であれば、貴方自身の collator 関数を渡すために data_collator 引数も使用できます、これは貴方のデータセットにより提供される形式のデータを取りそしてモデルに供給される準備ができたバッチを返します。TFTrainer は渡されたデータセットが tensorflow_datasets からのデータセット・オブジェクトであることを想定していることに注意してください。
損失に加えて追加のメトリクスを計算するために、貴方自身の compute_metrics 関数も定義してそれを Trainer に渡すこともできます。
from sklearn.metrics import accuracy_score, precision_recall_fscore_support
def compute_metrics(pred):
labels = pred.label_ids
preds = pred.predictions.argmax(-1)
precision, recall, f1, _ = precision_recall_fscore_support(labels, preds, average='binary')
acc = accuracy_score(labels, preds)
return {
'accuracy': acc,
'f1': f1,
'precision': precision,
'recall': recall
}
最後に、指定された logging_dir ディレクトリで tensorboard を起動することにより任意の計算されたメトリクスを含む結果を見ることができます。
以上