Simple Transformers 入門 (10) - ハイパーパラメータの最適化
「Simple Transformers」のハイパーパラメータの最適化を行う方法をまとめました。
1. ハイパーパラメーターの最適化
「Weights&Biases」を使用して、「SuperGLUE」の「Recognizing Textual Entailment」タスク(文のペアの2値分類)で、「Simple Transformers」のハイパーパラメータの最適化を行います。
NLPタスクでのTransformerモデルの学習時に、最も考慮すべきハイパーパラメータは、「学習率」と「エポック数」です。「エポック数」が多すぎたり、「学習率」が高すぎたりすると、壊滅的な忘却が発生します。逆に「エポック数」が少なすぎたり、「学習率」が低すぎたりすると、学習不足です。
また、メモリオーバーの場合は、「バッチサイズ」を減らす、またはメモリの多いGPUを用意する必要があります。「バッチサイズ」は大きいほど学習速度が早くなりますが、メモリの消費量も大きくなります。
2. Google Colabの準備
(1) 「Google Colab」のノートブックの作成。
(2) メニュー「編集 → ノートブックの設定」で「GPU」を指定。
(3) 以下のコマンドでGPUを確認。
# GPUの確認
!nvidia-smi
GPUはランダムに選択されます。GPUのメモリは、次のとおりです。
・Tesla P100-PCIE : 16GB
・Tesla T4 : 15GB
・Tesla K80 : 12GB
3. Simple Transformersのインストール
「Simple Transformers」をインストールします。
# Simple Transformersのインストール (最後にRESTART RUNTIMEを押す)
!pip install transformers
!pip install simpletransformers
4. データセットの準備
(1) 「Recognizing Textual Entailment」のデータセットをここからダウンロード。
(2) 「train.jsonl」「val.jsonl」を「Google Colab」にアップロード。
(3) データセットの読み込み。
import pandas as pd
from sklearn.model_selection import train_test_split
# ファイルの読み込み
def load_rte_data_file(filepath):
df = pd.read_json(filepath, lines=True)
df = df.rename(columns={"premise": "text_a", "hypothesis": "text_b", "label": "labels"})
df = df[["text_a", "text_b", "labels"]]
return df
# データセットの準備 (SuperGLUEのRTEデータセットをアップロード後)
train_df = load_rte_data_file("train.jsonl")
eval_df = load_rte_data_file("val.jsonl")
eval_df, test_df = train_test_split(eval_df, test_size=0.5, random_state=4)
5. 学習
学習します。
import logging
from sklearn.metrics import accuracy_score
from simpletransformers.classification import ClassificationArgs, ClassificationModel
# ログの設定
logging.basicConfig(level=logging.INFO)
transformers_logger = logging.getLogger("transformers")
transformers_logger.setLevel(logging.WARNING)
# モデルパラメータの作成
model_args = ClassificationArgs()
# 学習・評価
model_args.manual_seed = 4 # 乱数シード
model_args.learning_rate = 1e-5 # 学習率
model_args.num_train_epochs = 1 # エポック数
model_args.train_batch_size = 8 # 学習のバッチサイズ
model_args.eval_batch_size = 16 # 評価のバッチサイズ
model_args.evaluate_during_training = True
model_args.labels_list = ["not_entailment", "entailment"]
# 保存なし
model_args.save_eval_checkpoints = False
model_args.save_model_every_epoch = False
model_args.no_cache = True
model_args.overwrite_output_dir = True
# モデルの作成
model = ClassificationModel("roberta", "roberta-large", use_cuda=True, args=model_args)
# 学習
model.train_model(train_df, eval_df=eval_df,
accuracy=lambda truth, predictions: accuracy_score(
truth, [round(p) for p in predictions]
),
)
# 評価
model.eval_model(test_df, verbose=True)
{'mcc': 0.4969961597944327, 'tp': 51, 'tn': 53, 'fp': 16, 'fn': 19, 'accuracy': 0.7463768115942029, 'eval_loss': 0.5478038423591189}
学習率「1e-5」、エポック数「1」で、精度は「0.746」でした。
6. wandbのインストールとログイン
「W&B」のサイトの「Settings → API keys」で「API keys」を確認できます。
# wandbのインストールとログイン
!pip install wandb
!wandb login <API keysを記述>
7. wandbでハイパーパラメータの最適化
wandbで最適なハイパーパラメータを見つけます。
import logging
import wandb
from sklearn.metrics import accuracy_score
from simpletransformers.classification import ClassificationArgs, ClassificationModel
# Sweepsの設定
sweep_config = {
"name": "vanilla-sweep-batch-8",
"method": "bayes",
"metric": {"name": "accuracy", "goal": "maximize"},
"parameters": {
"num_train_epochs": {"min": 1, "max": 10},
"learning_rate": {"min": 0, "max": 4e-4},
},
"early_terminate": {"type": "hyperband", "min_iter": 6,},
}
sweep_id = wandb.sweep(sweep_config, project="RTE - Hyperparameter Optimization")
# ログの設定
logging.basicConfig(level=logging.INFO)
transformers_logger = logging.getLogger("transformers")
transformers_logger.setLevel(logging.WARNING)
# モデルパラメータの作成
model_args = ClassificationArgs()
# 学習・評価
model_args.manual_seed = 4
model_args.learning_rate = 4e-4
model_args.num_train_epochs = 10
model_args.train_batch_size = 16
model_args.eval_batch_size = 8
model_args.evaluate_during_training = True
model_args.labels_list = ["not_entailment", "entailment"]
# 保存なし
model_args.save_eval_checkpoints = False
model_args.save_model_every_epoch = False
model_args.no_cache = True
model_args.overwrite_output_dir = True
# 学習
def train():
# wandbの初期化
wandb.init()
# モデルの作成
model = ClassificationModel("roberta", "roberta-large", use_cuda=True,
args=model_args, sweep_config=wandb.config)
# 学習
model.train_model(
train_df, eval_df=eval_df, accuracy=lambda truth, predictions: accuracy_score(
truth, [round(p) for p in predictions]
),
)
# wandbのログ保存
wandb.log(model.results)
# wandbの同期
wandb.join()
# wandbで学習
wandb.agent(sweep_id, train)
学習率「0〜4e-4」とエポック数「1〜10」で探索しています。「early_terminate」は、パフォーマンスの低い実行を中止する設定で、最適化の高速化を行っています。
8. 実験の追跡と可視化
「W&B」のサイトで実験の追跡と可視化が可能です。サンプル12で、以下のようなグラフになりました。
・2回の実行で精度0.8前後。
・5回の実行で精度0.55前後。
・3回の実行で精度0.45前後。
・学習率「1.7-e4」とエポック数「10」のセットが現在のベスト。
・学習率は「0.0005」以上で精度が落ちている。
・10以上のエポック数も試したほうが良さそう。
この記事が気に入ったらサポートをしてみませんか?