LLMファインチューニングのチュートリアル

近年、自然言語処理(NLP)の分野では大規模言語モデル(LLM)の活用が急速に進んでいます。特に、特定のタスク向けにモデルの性能を向上させる「ファインチューニング」は、プロジェクトでの需要が増えつつあります。
本記事では、初心者の方でも理解しやすいように、ファインチューニングの基本的な流れを体験できるチュートリアルを用意しました。
環境設定と事前準備
このチュートリアルは、macOS環境(例: M2 MacBook Pro)をベースにしています。以下のコマンドで仮想環境を作成し、必要なライブラリをインストールしましょう。
仮想環境のセットアップ
python -m venv .env source .env/bin/activate
必要なライブラリのインストール
以下のコマンドを実行して、必要なPythonライブラリをインストールします。
pip install transformers datasets evaluate accelerate scikit-learn torch
動作確認
ライブラリが正しくインストールされたか確認するために、以下のテストコードを実行します。
python -c "from transformers import pipeline; print(pipeline('sentiment-analysis')('we love you'))"
期待される出力:
[{'label': 'POSITIVE', 'score': 0.9998704195022583}]
ファインチューニングスクリプトの作成と実行
ファインチューニングの手順を示したPythonスクリプト(finetune.py)を以下に示します。このスクリプトでは、Yelpレビューのデータセットを使用します。
finetune.py
from datasets import load_dataset from transformers import AutoTokenizer, AutoModelForSequenceClassification, TrainingArguments, Trainer import numpy as np import evaluate # データセットの準備 dataset = load_dataset("yelp_review_full") # トークナイザーによるトークナイズ tokenizer = AutoTokenizer.from_pretrained("google-bert/bert-base-cased") def tokenize_function(examples): return tokenizer(examples["text"], padding="max_length", truncation=True) tokenized_datasets = dataset.map(tokenize_function, batched=True) # 学習データとテストデータ作成 small_train_dataset = tokenized_datasets["train"].shuffle(seed=42).select(range(500)) small_eval_dataset = tokenized_datasets["test"].shuffle(seed=42).select(range(500)) # モデルのロード model = AutoModelForSequenceClassification.from_pretrained("google-bert/bert-base-cased", num_labels=5, torch_dtype="auto") # 評価関数 metric = evaluate.load("accuracy") def compute_metrics(eval_pred): logits, labels = eval_pred predictions = np.argmax(logits, axis=-1) return metric.compute(predictions=predictions, references=labels) # 学習設定 training_args = TrainingArguments(output_dir="test_trainer", eval_strategy="epoch") trainer = Trainer( model=model, args=training_args, train_dataset=small_train_dataset, eval_dataset=small_eval_dataset, compute_metrics=compute_metrics, ) # 学習の実行 trainer.train() # モデルとトークナイザーの保存 save_dir = './finetuned/bert-base-cased' tokenizer.save_pretrained(save_dir) model.save_pretrained(save_dir)
実行結果
スクリプトを実行すると、以下のような評価結果が表示されます。
python3 finetune.py {'eval_loss': 1.5970934629440308, 'eval_accuracy': 0.242, 'eval_runtime': 39.0603, 'eval_samples_per_second': 12.801, 'eval_steps_per_second': 1.613, 'epoch': 1.0} {'eval_loss': 1.468526840209961, 'eval_accuracy': 0.346, 'eval_runtime': 36.1194, 'eval_samples_per_second': 13.843, 'eval_steps_per_second': 1.744, 'epoch': 2.0} {'eval_loss': 1.4037985801696777, 'eval_accuracy': 0.368, 'eval_runtime': 35.7517, 'eval_samples_per_second': 13.985, 'eval_steps_per_second': 1.762, 'epoch': 3.0} {'train_runtime': 467.6126, 'train_samples_per_second': 3.208, 'train_steps_per_second': 0.404, 'train_loss': 1.5324497121982474, 'epoch': 3.0} 100%|██████████████████████████████████████████████████████████████████████████████████| 189/189 [07:47<00:00, 2.47s/it]
ファインチューニングスクリプトの解説
以下は、ファインチューニングスクリプト finetune.py の各パートを詳しく解説しまとめたものです。
1. データセットのロード
dataset = load_dataset("yelp_review_full")
解説:
- Hugging Faceの
datasetsライブラリを使用して、Yelpのレビューコメントデータセットをロードします。このデータセットにはレビューコメントと1~5の評価スコアが含まれています。
ポイント:
- データセットの種類:Hugging Faceの
load_datasetを使えば、豊富な事前構築データセットに簡単にアクセス可能。 - カスタムデータの利用:自分のデータを使いたい場合、CSVやJSON形式で読み込むことも可能です。
2. トークナイズ
tokenizer = AutoTokenizer.from_pretrained("google-bert/bert-base-cased") def tokenize_function(examples): return tokenizer(examples["text"], padding="max_length", truncation=True) tokenized_datasets = dataset.map(tokenize_function, batched=True)
解説:
- トークナイザーを使ってテキストを数値データに変換します。これにより、モデルが扱える形式に整えられます。
padding="max_length"で固定長の入力に揃え、truncation=Trueで最大トークン数を超えた部分をカットします。
ポイント:
- トークナイザーの選択:モデルに対応するトークナイザーを使用することが重要(例: BERTモデルならBERT用のトークナイザー)。
- 効率化:
batched=Trueを指定することで、複数のデータを一度にトークナイズして処理速度を向上。
3. データの分割と縮小
small_train_dataset = tokenized_datasets["train"].shuffle(seed=42).select(range(500)) small_eval_dataset = tokenized_datasets["test"].shuffle(seed=42).select(range(500))
解説:
- 訓練データと評価データを分割し、ファインチューニング用にサブセット(500件)を作成します。
shuffle(seed=42)はデータをランダムに並び替えますが、同じ結果を再現するためシード値を設定しています。
ポイント:
- データサイズの調整:学習時間やリソースの制約に合わせてデータサイズを選択できます。
- 小規模学習のメリット:小規模データでもモデルの動作確認や理解が可能。
4. モデルのロード
model = AutoModelForSequenceClassification.from_pretrained( "google-bert/bert-base-cased", num_labels=5, torch_dtype="auto" )
解説:
- Hugging Faceから事前学習済みのBERTモデルをロードし、分類タスク用に調整します。
num_labels=5は分類クラスの数(Yelpの評価スコア1~5)を指定しています。
ポイント:
- 事前学習モデルの再利用:大規模な事前学習済みモデルを活用することで、少ないデータでも良い結果が得られる。
- モデルのカスタマイズ:分類クラス数や出力層を調整して特定のタスクに適応。
5. 評価関数の設定
metric = evaluate.load("accuracy") def compute_metrics(eval_pred): logits, labels = eval_pred predictions = np.argmax(logits, axis=-1) return metric.compute(predictions=predictions, references=labels)
解説:
evaluateライブラリを使用して、モデルの精度(accuracy)を評価する関数を定義しています。- 推論結果(
logits)をargmaxで予測ラベルに変換し、実際のラベルと比較してスコアを計算します。
ポイント:
- 評価指標の選択:分類タスクでは
accuracyが一般的ですが、タスクに応じてprecisionやrecallも検討すべきです。 - 簡単な実装:
evaluateライブラリを使うと、一般的な評価指標を簡単に利用可能。
6. 学習設定
training_args = TrainingArguments( output_dir="test_trainer", eval_strategy="epoch" ) trainer = Trainer( model=model, args=training_args, train_dataset=small_train_dataset, eval_dataset=small_eval_dataset, compute_metrics=compute_metrics, )
解説:
TrainingArgumentsで学習パラメータを指定します。ここでは、モデル保存先(output_dir)と評価タイミング(eval_strategy="epoch")を設定。Trainerクラスは、学習プロセスを簡略化するための高レベルAPIです。
ポイント:
- 簡単な学習管理:
Trainerを使うと、ループの作成や勾配計算の実装を気にする必要がありません。 - 設定の柔軟性:学習率やバッチサイズなどの詳細設定も可能です。
7. モデルの保存
tokenizer.save_pretrained('./finetuned/bert-base-cased') model.save_pretrained('./finetuned/bert-base-cased')
解説:
- ファインチューニング後のトークナイザーとモデルを保存します。この保存済みモデルは、将来的に推論やさらなる調整に使用できます。
ポイント:
- 再利用性の向上:モデルを保存しておくことで、他のプロジェクトやデプロイメントに活用可能。
- Hugging Face互換:保存形式はHugging Faceライブラリでの再利用に最適化されています。
チューニング前後のモデル性能比較
ファインチューニングによる効果を確認するため、同じ入力データを使ってモデルの予測結果を比較します。
チューニング前のモデルで推論
以下のスクリプトで推論を行います。
from transformers import AutoTokenizer, AutoModelForSequenceClassification import numpy as np model_path = 'google-bert/bert-base-cased' tokenizer = AutoTokenizer.from_pretrained(model_path) model = AutoModelForSequenceClassification.from_pretrained(model_path) text = "I visit this bar at first time. Service is good. Making drinks and talking with Bartender is also good. I spend good 2 hours. I will come again next month." inputs = tokenizer(text, return_tensors="pt", padding=True, truncation=True) outputs = model(**inputs) predicted_class = np.argmax(outputs.logits.detach().numpy(), axis=-1) print(predicted_class)
出力結果:
[0] # 配列なので0始まり。0は評価1。
inputのtextからは4か5の高評価を期待しますが、評価が「1」となりました。
チューニング後のモデルで推論
同じテキストを以下のスクリプトで推論します。
model_path = './finetuned/bert-base-cased' tokenizer = AutoTokenizer.from_pretrained(model_path) model = AutoModelForSequenceClassification.from_pretrained(model_path) text = "I visit this bar at first time. Service is good. Making drinks and talking with Bartender is also good. I spend good 2 hours. I will come again next month." inputs = tokenizer(text, return_tensors="pt", padding=True, truncation=True) outputs = model(**inputs) predicted_class = np.argmax(outputs.logits.detach().numpy(), axis=-1) print(predicted_class)
出力結果:
[4] # 配列なので0始まり。4は評価5。
この結果は、より正確な評価となっており、モデルが改善されたことを示しています。
まとめ
このチュートリアルでは、transformersライブラリを使用してLLMのファインチューニングを行い、わずか500件のデータでもモデルの性能が向上することを確認できました。
本記事で紹介した手順は、あくまで学習目的です。
本格的な案件では、より大規模なデータセットや高性能なハードウェアを利用することを推奨します。
学びのポイント
- LLMの基本操作とトークナイズの仕組みが理解できる。
- Hugging Faceのエコシステムを活用する方法が習得できる。
- 簡単なファインチューニングによるモデルの改善効果を確認できる。
今後のプロジェクトや個人学習にぜひ役立ててください。
参考
- https://huggingface.co/docs/transformers/training
- https://huggingface.co/docs/transformers/installation
- https://huggingface.co/datasets/Yelp/yelp_review_full
この記事をシェアする
合同会社raisexでは一緒に働く仲間を募集中です。
ご興味のある方は以下の採用情報をご確認ください。