このガイドでは、LLMの監督付き微調整について学ぶことができる:
- LLMにおけるスーパーバイズド・ファインチューニングとは?
- この練習の目標は何か
- 導入に必要なリソース
- 教師あり微調整LLMのワークフロー
- SFT導入における技術的課題と検討事項
- LLMで教師あり微調整を再現するためのステップバイステップのチュートリアル
さあ、飛び込もう!
LLMの文脈におけるスーパーバイズド・ファインチューニング(SFT)の定義
教師あり微調整(SFT)は、LLMに適用される転移学習の一形態である。転移学習とは、ある問題を解決して得た知識を、別の、しかし関連する問題の解決に役立てる機械学習手法である。
LLMSの文脈では、教師ありのファインチューニングとは、事前に訓練されたモデルをさらに訓練することである。これは、特定のタスクに関連するラベル付き例を含むキュレートされたデータセットを使用して、そのパラメータを調整することによって行われる。
エンジニアが全プロセスの背後にいるため、「監督付き」という性質がこのプロセスのカギを握っている:
- 彼らは入出力ペアを明示した微調整用データセットを用意する。そのデータセットには、特定のプロンプトに対するモデルの学習の方向性を示す「正解」が含まれている。
- セットアップからモニタリング、検証まで、微調整のプロセス全体をキュレートしてくれる。
詳細には、RAG(Retrieval-Augmented Generation)と比較して、ファインチューニングはモデル自体を修正する。RAGはモデルに手を加えず、新しい関連情報を与えるだけである。その代わり、ファインチューニングでは新たな学習プロセスが必要となる。
LLMにおけるスーパーバイズド・ファインチューニングの目標とは?
教師ありファインチューニングの主な目的は、LLMの一般的な事前学習能力を超えて、特定のタスクのパフォーマンスを向上させることである。これには以下が含まれる:
- タスクの特化:テキスト要約、特定言語のコード生成、センチメント分析などのタスクに精通したモデルにする。
- ドメインの適応:ニッチ分野特有の知識や用語をモデルに組み込む。一般的な例としては、法的文書分析、医療レポート作成、財務予測などがある。
- トーンの調整:一貫したブランドボイス、フォーマルなレベル、またはチャットボットなどのアプリケーションに必要な特定の会話ペルソナを採用するようにモデルを訓練する。
微調整の実施に必要なもの
この時点で、あなたは疑問に思うかもしれない:なぜ最初からそうなるようにLLMを訓練しないのか?理由は簡単だ。LLMのトレーニングには
- 膨大な量のデータは、多くの場合、複数のデータセンターにまたがって保存されている。
- 多くのハードウェアがある。
- 多くのお金と時間を投資する。
例えば、ChatGPTやGeminiのようなモデルをトレーニングするには、以下のようなものが必要だ:
- 数ヶ月、いや、数年かもしれない。
- それぞれが数千ドルもする大量のGPUが、複数のデータセンターに分散されている。
微調整に必要なものは3つだけだ:
- 事前に訓練されたモデル。
- コンピューターだ。
- ラベル付きの小さなデータセット。
微調整がなぜ便利なのか、これではっきりしたはずだ。
監督付き微調整ワークフローを支えるメカニズム
管理された微調整プロセスを実行するには、いくつかの技術的なステップが必要です。プロセス全体を分解してみよう!
ステップ #1: 高品質なSFTデータセットの作成
このプロセスの有効性は、微調整用データセットの質と関連性に大きく依存する。これには以下が含まれる:
- データソーシング:多くのデータソーシング手法のいずれかを使用して、対象タスクに関連する生データを入手する。サイズは数百から数万行に及ぶ。これはタスクの複雑さと事前に訓練されたモデルに依存する。
- データの構造化:生データをSFTプロセスに適した構造化フォーマットに変換する。典型的なフォーマットの1つはJSON Lines(JSONL)であり、各行は入力と目的の出力のための明確なフィールドを含むJSONオブジェクトである。
- 品質保証:データが正確で一貫性があり、多様性に富み、モデルの動作に悪影響を及ぼすような偏りがないことを確認する。
ステップ #2: 適切な事前学習済みモデルを選択する
訓練済みのモデルがいくつかあります。あなたのケースに最適なものを選ぶための主な検討事項は以下の通りです:
- モデルのサイズ:パラメータ数(7B、13B、70Bなど)で示され、複雑なパターンやニュアンスを学習するモデルの能力に関連する。より大きなモデルは一般的に高いパフォーマンスを提供するが、微調整のためにより多くのハードウェア・リソースを必要とする。
- アーキテクチャ:特定のアーキテクチャは特定のタスクに適しています。例
:ポリラン・プレースホルダーは変更しない
- 基本能力:微調整に取り掛かる前に、ターゲットタスクに関連するアカデミックベンチマークで事前学習済みモデルのパフォーマンスを評価する。これはベースラインを提供し、モデルの適性を示します。例
:Polylangのプレースホルダーは変更しないでください。
- ライセンス:モデルがリリースされるライセンスは、そのモデルがどのように使用、修正、配布されるかを決定します。モデルによっては、オープンソースの許可を得ているものもあれば、そうでないものもあります。
- 既存の微調整:関連するタスクに対してすでに微調整されたモデルから始める方が、未加工のベースモデルから始めるよりも効率的な場合がある。これは中間微調整の一種です。
ステップ3:トレーニング・ループの実施
このプロセスの核心は、ラベル付けされたデータセットを繰り返し、モデルの重みをこのように調整することである:
- フォワードパス:モデルはSFTデータセットからの入力(プロンプト)を処理し、出力を生成する。
- 損失計算:損失関数は、トークンごとにモデルが生成した出力を、データセットで提供されたターゲット出力と比較する。これは誤差を定量化するのに便利です。
- バックワードパス(バックプロパゲーション):計算された損失は勾配を計算するために使用され、各モデルの重みがどれだけ誤差に寄与したかを示す。
- 重みの更新:オプティマイザー・アルゴリズムは、勾配と指定された学習率を用いてモデルの重みを調整する。目標は、その後の反復における誤差を最小化することである。
- ハイパーパラメータのチューニング:学習プロセスを制御するパラメータは、モデルの性能を向上させるために調整される。
ステップ4:結果を評価する
最終段階として、微調整したモデルのパフォーマンスを評価しなければならない。これには以下が含まれる:
- 検証セット:ラベル付けされたデータセットの一部は、進捗状況を監視し、オーバーフィッティングを防ぐために使用されなければならない。
- テストセット:ファインチューニング・データセットのサブセットでもよい。このステップは、ファインチューニング完了後の最終評価のために実行されます。
- メトリクス:パフォーマンスを評価するために、タスクに関連する定量的メトリクスを定義する。
- 定性的分析:一貫性、関連性、スタイル順守、安全性を評価するためのモデル出力のレビュー。
SFT導入における技術的課題と考察
SFTの導入には、次のような技術的課題がある:
- データセットの質と規模:最も大きな課題は、十分に大規模で高品質、かつ代表的なラベル付きデータセットを作成または調達することにある。データの質の低さは、モデルの性能の低さに直結する。データの抽出、クリーニング、ラベリング、集計、フォーマットには多大な労力と専門知識が必要です。
- 致命的な忘却の軽減:特定のタスクを集中的にファインチューニングすると、モデルは事前学習で学習した一般的な能力の一部を「忘れる」可能性がある。より低い学習率を使用する、より少ないエポックでファインチューニングを行う、あるいは多様なデータを取り入れるといった戦略は、この現象を軽減するのに役立つ。
- ハイパーパラメータ最適化戦略:最適なハイパーパラメータのセットを見つけることは経験的なプロセスである。そのためには何度も実験を行い、検証指標を注意深く監視する必要がある。自動化されたハイパーパラメータ・チューニング・フレームワークは助けになるが、複雑さが増す。
教師あり微調整LLM:ステップバイステップのチュートリアル
理論を実践する時が来た。このチュートリアルでは、軽量なLLMを微調整する方法を説明します。目標は、LLMを微調整して、特徴のリストが与えられたときにeコマースの商品説明を生成することです。
LLMとしてDistilGPT2を使用することになりますが、これはGPT-2の蒸留版で、サイズと効率が小さくなっています。
選んだモデルを微調整してみよう!
前提条件
このチュートリアルを再現するには、少なくともPython 3.10+がインストールされている必要があります。
また、微調整のためにCSVデータセットが必要です。ここでは、eコマース商品のデータを含むカスタムデータセットを使用します。このデータセットには、商品ごとに以下のフィールドが含まれています:
- カテゴリー電化製品、書籍、キッチン、その他
- 名前:商品名。
- 特徴製品の主な特徴
- 色:製品の色。
- 説明:製品が何であるか、または何をするかを説明するテキスト。
下の画像は、使用されたデータのサンプルである:
ステップ1:スタート
プロジェクトのメインフォルダーをfine_tuning/と
呼ぶとする。このステップが終わると、フォルダは次のような構造になっている:
fine_tuning/
├── data/
| └── data.csv
├── results_distilgpt2/
├── tuning.py
└── venv/
どこでだ:
data.csvには
、先に示したLLMを微調整するためのラベル付きデータが含まれている。results_distilgpts/は
結果を格納するフォルダです。処理中に自動的に作成されます。tuning.pyは
全てのロジックを含むPythonファイルです。venv/には
仮想環境が含まれる。
venv/
仮想環境ディレクトリは次のように作成する:
python -m venv venv
アクティベートするには、ウィンドウズで以下を実行する:
venv\Scripts\activate
同様に、macOS/Linuxでは、次のように実行する:
source venv/bin/activate
起動した仮想環境で、このチュートリアルに必要なライブラリをインストールします:
pip install transformers datasets torch trl
このプロジェクトで使用したライブラリーは以下の通り:
transformers
: Hugging Faceの最先端機械学習モデル用ライブラリ。データセット
データセットへのアクセスと処理のためのHugging Faceのライブラリ。トーチ
PyTorchはオープンソースの機械学習フレームワークです。trl
: Hugging FaceのTransformer Reinforcement Learningライブラリで、SFTTrainerの
ようなSFT用のツールが含まれている。
完璧です!LLM微調整用のPython環境は正しくセットアップされています。
ステップ2:初期設定、データ読み込み、テキストフォーマット
最初のステップとして、tuning.pyで
全てのプロセスを設定する必要があります:
import os
from datasets import load_dataset
from transformers import AutoTokenizer, AutoModelForCausalLM, TrainingArguments, pipeline
from trl import SFTTrainer
# Configure parameters
base_model_name = "distilgpt2" # Pre-trained model to be fine-tuned
data_file_path = "data/data.csv" # Path to your CSV data file
output_model_dir = "./results_distilgpt2" # Directory to save training results and checkpoints
final_model_path = os.path.join(output_model_dir, "final_model") # Path to save the final fine-tuned model
max_seq_length_for_tokenization = 512 # Maximum sequence length for tokenizing inputs
# Load dataset
raw_dataset = load_dataset("csv", data_files=data_file_path)
# Define a function to format entries into a prompt-completion pair
def format_dataset_entry(data_item):
prompt_template = "Generate a product description for the following item:\nFeatures: {features_data}\n\nDescription:"
data_item["text"] = prompt_template.format(features_data=data_item["features"]) + " " + data_item["description"]
return data_item
# Apply the formatting function to the train split of the dataset
text_formatted_dataset = raw_dataset["train"].map(format_dataset_entry)
このスニペット:
base_model_name
で使用する LLM の名前を定義します。- CSV ファイルがあるパスを定義し、
load_dataset()
メソッドでそれを開きます。 - 結果を保存するフォルダを作成する
(results_distilgpt2/)。
format_dataset_entry()
関数を作成し、raw_dataset
の各行をテキスト形式に変換して微調整を行う。また、変更した内容を CSV の “description” カラムに追加します。これにより、モデルにはきれいになったテキスト形式の説明が提供されます。map()
メソッドで、format_dataset_entry()
関数を訓練分割データセットのすべての項目に適用する。
よくやった!これでプロセスの初期設定は完了だ。
ステップ#3: データセットのトークン化
言語モデルは生のテキストを理解しない。トークンと呼ばれる数値表現を操作する。このステップでは、事前に訓練されたトークナイザーをロードし、それを使ってフォーマットされたテキスト・エントリーをトークンIDのシーケンスに変換します:
# Load the tokenizer associated with the base model
tokenizer = AutoTokenizer.from_pretrained(base_model_name)
tokenizer.pad_token = tokenizer.eos_token # Padding token
# Define a function to tokenize the "text" field of the dataset
def tokenize_function(data_items_batch):
return tokenizer(
data_items_batch["text"],
truncation=True,
padding="max_length",
max_length=max_seq_length_for_tokenization,
)
# Apply the tokenization function to the formatted dataset
tokenized_dataset = text_formatted_dataset.map(
tokenize_function,
batched=True,
remove_columns=text_formatted_dataset.column_names
)
上記のコードは次のようになる:
- メソッド
AutoTokenizer.from_pretrained()
を使用して、base_model_name
に関連付けられたトークナイザをロードします。 - 入力配列をモデルに入力する際に、すべての入力配列の長さを同じにするためのパディングトークンを定義します。
- カスタム関数
tokenize_function()
でデータセットをトークン化し、トークン化をデータセットに適用します。
すばらしい!データセットはトークン化されている。
ステップ4:微調整プロセスの設定と実行
データセットが準備され、トークン化されたので、微調整作業の核心に移ることができる:
# Load the pre-trained language model
model = AutoModelForCausalLM.from_pretrained(base_model_name)
# Define training arguments for the SFTTrainer
training_args = TrainingArguments(
output_dir=output_model_dir,
num_train_epochs=3,
per_device_train_batch_size=1,
learning_rate=2e-5,
logging_steps=10,
save_steps=50,
report_to="none",
)
# Initialize the SFTTrainer
trainer = SFTTrainer(
model=model,
args=training_args,
train_dataset=tokenized_dataset,
)
# Begin the training process
trainer.train()
# Save the fine-tuned model and tokenizer to the specified path
trainer.save_model(final_model_path)
tokenizer.save_pretrained(final_model_path)
このコード
AutoModelForCausalLM.from_pretrained()
メソッドでベースモデルをロードします。TrainingArguments()
メソッドを使用して、エポック数、バッチサイズ、学習率などのプロセスの設定を定義します。SFTTrainer() を
初期化して実行し、トークン化されたデータセットとトレーニング引数をモデルに与えます。実際の微調整ループを管理します。- モデルをトレーニングし、結果を専用フォルダに保存します。
素晴らしい!微調整が始まったね。
ステップ5:微調整したモデルの評価とテスト
そのモデルが、まだ見ぬ新しい製品の特徴について、どの程度うまく説明文を生成できるかを評価しなければならない:
# Load the fine-tuned model and tokenizer for testing
fine_tuned_model_for_testing = AutoModelForCausalLM.from_pretrained(final_model_path)
fine_tuned_tokenizer_for_testing = AutoTokenizer.from_pretrained(final_model_path)
# Create a text-generation pipeline with the fine-tuned model
generator_fine_tuned = pipeline("text-generation", model=fine_tuned_model_for_testing, tokenizer=fine_tuned_tokenizer_for_testing)
# Define example product features for testing
test_product_features = [
"Category: Kitchen, Name: Electric Kettle, Features: 1.7L capacity, Stainless steel, Auto shut-off, Boil-dry protection, Color: Silver",
"Category: Office, Name: Ergonomic Office Chair, Features: Lumbar support, Adjustable height, Mesh back, Swivel, Color: Black"
]
# Define the prompt template
prompt_template_inference = "Generate a product description for the following item:\nFeatures: {features}\n\nDescription:"
# Generate descriptions for each test item
for features_item in test_product_features:
full_prompt = prompt_template_inference.format(features=features_item)
print(f"\nPROMPT:\n{full_prompt}")
generated_outputs = generator_fine_tuned(
full_prompt,
max_new_tokens=70,
num_return_sequences=1,
pad_token_id=fine_tuned_tokenizer_for_testing.eos_token_id,
eos_token_id=fine_tuned_tokenizer_for_testing.eos_token_id
)
print(f"GENERATED (Fine-tuned):\n{generated_outputs[0]['generated_text']}")
このスニペットは次のようなものである:
- 微調整されたモデルとトークナイザをロードします。
pipeline()
メソッドを使用して、微調整されたモデルでテキスト生成パイプラインを作成します。test_product_featuresで
モデルの微調整を行い、評価するために、新しい未見の商品説明を提供するリストを定義します。for
ループ内の各テスト項目の説明を生成します。- 微調整されたモデルによって生成された記述を表示します。
クールだ!あなたは、モデルの性能をテストし評価するためのパイプラインを設定した。
ステップ6:すべてをまとめる
tuning.py
ファイルにはこう書かれているはずです:
import os
from datasets import load_dataset
from transformers import AutoTokenizer, AutoModelForCausalLM, TrainingArguments, pipeline
from trl import SFTTrainer
# Configure parameters
base_model_name = "distilgpt2" # Pre-trained model
data_file_path = "data/data.csv" # Path to data
output_model_dir = "./results_distilgpt2" # Directory to save results and checkpoints
final_model_path = os.path.join(output_model_dir, "final_model") # Path to save the final fine-tuned model
max_seq_length_for_tokenization = 512 # Maximum length for tokenizing inputs
# Load dataset
raw_dataset = load_dataset("csv", data_files=data_file_path)
# Define a function to format entries into a prompt-completion pair
def format_dataset_entry(data_item):
prompt_template = "Generate a product description for the following item:\nFeatures: {features_data}\n\nDescription:"
data_item["text"] = prompt_template.format(features_data=data_item["features"]) + " " + data_item["description"]
return data_item
# Apply the formatting function to the train split of the dataset
text_formatted_dataset = raw_dataset["train"].map(format_dataset_entry)
# Load the tokenizer associated with the base model
tokenizer = AutoTokenizer.from_pretrained(base_model_name)
tokenizer.pad_token = tokenizer.eos_token
# Define a function to tokenize the "text" field of the dataset
def tokenize_function(data_items_batch):
return tokenizer(
data_items_batch["text"],
truncation=True,
padding="max_length",
max_length=max_seq_length_for_tokenization,
)
# Apply the tokenization function to the formatted dataset
tokenized_dataset = text_formatted_dataset.map(
tokenize_function,
batched=True,
remove_columns=text_formatted_dataset.column_names
)
# Load the pre-trained language model
model = AutoModelForCausalLM.from_pretrained(base_model_name)
# Define training arguments for the SFTTrainer
training_args = TrainingArguments(
output_dir=output_model_dir,
num_train_epochs=3,
per_device_train_batch_size=1,
learning_rate=2e-5,
logging_steps=10,
save_steps=50,
report_to="none",
)
# Initialize the SFTTrainer
trainer = SFTTrainer(
model=model,
args=training_args,
train_dataset=tokenized_dataset,
)
# Begin the training process
trainer.train()
# Save the fine-tuned model and tokenizer to the specified path
trainer.save_model(final_model_path)
tokenizer.save_pretrained(final_model_path)
# Load the fine-tuned model and tokenizer for testing
fine_tuned_model_for_testing = AutoModelForCausalLM.from_pretrained(final_model_path)
fine_tuned_tokenizer_for_testing = AutoTokenizer.from_pretrained(final_model_path)
# Create a text-generation pipeline with the fine-tuned model
generator_fine_tuned = pipeline("text-generation", model=fine_tuned_model_for_testing, tokenizer=fine_tuned_tokenizer_for_testing)
# Define example product features for testing
test_product_features = [
"Category: Kitchen, Name: Electric Kettle, Features: 1.7L capacity, Stainless steel, Auto shut-off, Boil-dry protection, Color: Silver",
"Category: Office, Name: Ergonomic Office Chair, Features: Lumbar support, Adjustable height, Mesh back, Swivel, Color: Black"
]
# Define the prompt template
prompt_template_inference = "Generate a product description for the following item:\nFeatures: {features}\n\nDescription:"
# Generate descriptions for each test item
for features_item in test_product_features:
full_prompt = prompt_template_inference.format(features=features_item)
print(f"\nPROMPT:\n{full_prompt}")
generated_outputs = generator_fine_tuned(
full_prompt,
max_new_tokens=70,
num_return_sequences=1,
pad_token_id=fine_tuned_tokenizer_for_testing.eos_token_id,
eos_token_id=fine_tuned_tokenizer_for_testing.eos_token_id
)
print(f"GENERATED (Fine-tuned):\n{generated_outputs[0]['generated_text']}")
でコードを実行する:
python tuning.py
予想される結果はこうなる:
図のように、プロンプトはモデルに電気ケトルの説明を作成するよう求め、必要な情報を提供します。モデルは期待通りに説明を作成します。この結果を分解すると、次のようになる:
- 生成される商品名:「ProChef Luxury Living Hood Series X」という、キッチン用品としてもっともらしく聞こえる商品名と説明文が生成される。
- 矛盾する詳細:これは、プロンプトの特徴にある「カラー:シルバー」と矛盾している。このように、微調整はモデルをガイドしますが、完璧な一貫性を保証するものではありません。このようなことは、特に小型モデルや限られたトレーニングで起こります。
不完全性や矛盾は、生成モデル、特にdistilgpt2の
ような小さなモデルの典型的なものである。また、微調整用データセットのサイズや質、学習エポック数にも左右される。この場合、使用したデータセットは300行しかない。もっと大きなデータセットであれば、ケトルについてより良い記述ができただろう。
品質の低下を示すために、5行しかないCSVで期待される結果を以下に示す:
おわかりのように、結果はまったくの幻覚である。それを分解すると
- 生成された製品名****最初のフレーズで “Ergonomic Office chair “ではなく、”Office chair “と命名されます。
- 矛盾した詳細:****2番目のフレーズで、名前が “Lumbar “になっている。つまり、このモデルは名前と機能(「ランバーサポート」)を混同している。
- 一貫性のない文法:どちらのフレーズにも一貫性のない間違った文法がある。
- 欠けている機能:色と機能(「ランバーサポート」、「高さ調節可能」、「回転」)が説明文に記載されていない。
しかし、微調整を行わないdistilgpt2
モデルに同じプロンプトを与えると、出力は著しく悪くなる。これは、このモデルがそのような特定のデータで訓練されていないために起こる。例えば、やかんの説明を提供することはできません。
処理が完了すると、results_distilgpt2/という
フォルダが自動的に生成されることに注意してください。その中には、異なるエポックでモデルによって保存された結果を報告するサブフォルダーがあります:
これらのいずれかをチェックポイントとして取得し、好きなように使いたい場合に便利だ。
やった!LLM微調整完了。
結論
この記事では、LLMの文脈における教師ありファインチューニングとは何かを学んだ。また、ファインチューニング・プロセスを再現するためのステップ・バイ・ステップのプロセスも説明しました。
SFTのコアは、モデルを微調整するための高品質なデータセットに依存しています。幸いなことに、Bright Dataはデータセットの取得や作成のための多くのサービスを提供しています:
- スクレイピング・ブラウザ:ロック解除機能を内蔵したPlaywright、Selenium、Puppeter互換ブラウザ。
- ウェブスクレーパーAPI:100以上の主要ドメインから構造化データを抽出するための設定済みAPI。
- ウェブアンロッカー:ボット対策が施されたサイトのロック解除を行うオールインワンAPI。
- SERP API:検索エンジンの結果をアンロックし、完全なSERPデータを抽出する特別なAPI。
- 基礎モデル:ウェブスケールのデータセットにアクセスし、事前学習、評価、微調整を行うことができます。
- データプロバイダー:信頼できるプロバイダーと接続し、高品質でAIに対応したデータセットを大規模に調達。
- データパッケージ:構造化、エンリッチ化、アノテーションが施された、すぐに使えるデータセットを入手。
Bright Dataのアカウントを無料で作成し、データ抽出サービスをお試しください!
クレジットカードは必要ありません