27. OpenAIでGPTモデルをファインチューニング!マネージド型の簡単な方法を体験

スポンサーリンク

27. OpenAIでGPTモデルをファインチューニング!マネージド型の簡単な方法を体験

前回まで、Llama 3.2 1Bモデルでベースラインパフォーマンスを測定しました。でも、「もっと強力なモデルならどうなるの?」って気になりますよね。

今回は、同じSAMSum要約タスクでGPT-4o-miniのようなフロンティアモデル(最先端の高性能モデル)を使った場合に何が起こるか見ていきます。まず何もしない状態、次にファインチューニング後です。

これにより、同じデータセットでのオープンウェイトモデルとフロンティアモデルの明確な比較が得られ、マネージドファインチューニングが強力なベースモデルをどれだけ改善できるかがわかります。

しかも、必要な場合にフロンティアモデルをファインチューニングする方法も学べるんです!

これは、オープンウェイトモデルを使った実践的なファインチューニングに戻る前の、ちょっとした寄り道だと考えてください。でも、この寄り道が実はとても価値があるんですよ。

なぜこの小休止が必要なの?

ファインチューニングといえば、ノートブック、GPU、カスタムトレーニングループを思い浮かべますよね。次にやることはまさにそれです。

でもその前に、「すべての作業を代行してもらった場合に何が起こるか」を見ておくと役立つんです。

OpenAIやGoogleのような企業は、マネージドファインチューニングサービスを提供しています。データをアップロードし、ベースモデルを指定すれば、残りはすべて彼らが処理します。インフラ、最適化、スケーリング、チェックポイント作成、すべてです!

迅速で信頼性がありますが、トレードオフもあります:

  • モデル内部への制御や可視性が少ない:何が起こっているか詳しく見えません
  • トークンあたりのコストが高い:お金がかかります
  • 中間チェックポイントへのアクセスがない:途中経過が見えません

このレッスンでは、Colabでのセルフホスト型ファインチューニングに戻る前に、トレードオフを理解するために一度だけこのワークフローを見ていきます。

比較する2つのワークフロー

OpenAI APIの仕組みを理解したところで、作業を2つの明確なワークフローに分けます:

Workflow 1:ベースモデルの評価

GPT-4o-miniをファインチューニングせずに評価します。「素の状態でどれくらいできるの?」を確認するんです。

Workflow 2:マネージドファインチューニング

OpenAIのホストAPIを使ってGPT-4o-miniをファインチューニングし、まったく同じパイプラインを使って再評価します。

この分離により一貫性が保たれます。同じデータセット、プロンプト、ROUGE計算を両方のワークフローで再利用し、モデルとそのトレーニングソースのみを変更します。

これで、フェアな比較ができるんですね!

Workflow 1:フロンティアモデルの評価(GPT-4o-miniベースライン)

まずベースライン評価ワークフローから始めましょう。

メカニクスの理解:一度に1つの例

OpenAIのAPIを使用する場合、タスクを説明するチャットメッセージのリストを送信します。各SAMSum対話はモデルの「会話」となり、モデルはその要約で応答します。

from datasets import load_dataset
from openai import OpenAI

client = OpenAI()
dataset = load_dataset("knkarthick/samsum")
val_data = dataset["validation"].shuffle(seed=42).select(range(200))

def build_user_prompt(dialog: str):
    prompt = (
        "You are a helpful assistant who writes concise, factual summaries of conversations. "
        "Summarize the following conversation in one clear sentence. "
        "If it can be shorter, make it as brief as possible.\n"
        f"## Dialog: {dialog}\n"
        "## Summary:\n"
    )
    return prompt

sample = {
    "dialogue": (
        "Jane: Hey, are we still on for lunch?\n"
        "John: Yes, but let's move it to 1 PM instead of noon.\n"
        "Jane: Works for me."
    )
}

messages = [{"role": "user", "content": build_user_prompt(sample["dialogue"])}]

response = client.chat.completions.create(model="gpt-4o-mini", messages=messages, temperature=0)
print(response.choices[0].message.content)

出力:

Jane and John agreed to reschedule lunch from noon to 1 PM.

シンプルで明快ですね!これは、数百のサンプルにスケールする同じメカニズムです。すべての予測を生成し、リファレンス要約に対してROUGEスコアを計算します。

ベースライン評価の実装

前のレッスンで使った同じヘルパー関数を再利用できます:

  • load_and_prepare_dataset(cfg):SAMSumデータのロードとサンプリング
  • compute_rouge(predictions, samples):要約品質の評価
  • build_messages_for_sample(sample, task_instruction):OpenAIプロンプトの構造化

そして2つの関数を追加します:

  • generate_openai_predictions():すべてのサンプルに対してスレッド化されたAPI推論を実行
  • evaluate_openai_model():評価ワークフローをラップ(生成 + スコアリング + 保存)
def evaluate_openai_model(model_name: str, cfg: dict, limit: int = None, max_workers: int = 5):
    """Run evaluation on an OpenAI model (base or fine-tuned)."""
    print(f"\n🚀 Evaluating OpenAI model: {model_name}")
    _, val_data, _ = load_and_prepare_dataset(cfg)
    if limit:
        val_data = val_data.select(range(limit))
    preds = generate_openai_predictions(model_name, val_data, cfg["task_instruction"], len(val_data), max_workers, 0.1)
    scores = compute_rouge(preds, val_data)
    print("\nROUGE Summary:")
    print(f"ROUGE-1: {scores['rouge1']:.2%}, ROUGE-2: {scores['rouge2']:.2%}, ROUGE-L: {scores['rougeL']:.2%}")
    return scores, preds

ベースライン結果

ベースGPT-4o-miniは、ファインチューニングなしですでにオープンウェイトのLlama 3.2 1Bベースラインを上回ります。フロンティアモデルの事前トレーニングの利点が見えますね!

Workflow 2:OpenAIのマネージドAPIでGPTモデルをファインチューニング

ベースモデルの評価方法を見たところで、2番目のワークフローに移りましょう。OpenAIのホストインフラを使って同じモデルをファインチューニングします。

このワークフローは、Llama 3.2でローカルに行ったことと同じですが、OpenAIがGPUリソース、トレーニングループ、チェックポイントを処理してくれる点が異なります。

再利用するもの

以下を再利用します:

  • 同じ評価関数(evaluate_openai_model)
  • 同じ指示プロンプトとROUGEメトリクス

ここで必要な新しいロジックは:

  • データセットをOpenAI JSONL形式に変換
  • APIにアップロード
  • ファインチューニングジョブを起動・監視
  • 結果として得られたファインチューニング済みモデルを評価

Step 1:データの準備とアップロード

OpenAIのファインチューニングAPIは、JSONL形式のデータを期待します。各レコードはユーザーとアシスタントのメッセージを含むチャット例です。

from openai import OpenAI
import json

client = OpenAI()

def build_user_prompt(dialogue):
    return (
        "You are a helpful assistant who writes concise, factual summaries of conversations. "
        "Summarize the following conversation into a single sentence.\n"
        f"## Dialog:\n{dialogue}\n"
        "## Summary:\n"
    )

# Convert dataset to JSONL format
def convert_to_jsonl(dataset, out_path):
    with open(out_path, "w") as f:
        for sample in dataset:
            record = {
                "messages": [
                    {"role": "user", "content": build_user_prompt(sample["dialogue"])},
                    {"role": "assistant", "content": sample["summary"]}
                ]
            }
            f.write(json.dumps(record) + "\n")
    print(f"✅ Saved: {out_path}")

convert_to_jsonl(train_data, "samsum_train.jsonl")
convert_to_jsonl(val_data, "samsum_val.jsonl")

次に両方のファイルをOpenAIにアップロードします:

train_file = client.files.create(file=open("samsum_train.jsonl", "rb"), purpose="fine-tune")
val_file = client.files.create(file=open("samsum_val.jsonl", "rb"), purpose="fine-tune")

print("Training file ID:", train_file.id)
print("Validation file ID:", val_file.id)

Step 2:ファインチューニングジョブの作成

次に、ベースモデルとしてgpt-4o-miniを使ってファインチューニングジョブを作成します:

job = client.fine_tuning.jobs.create(
    model="gpt-4o-mini",
    training_file=train_file.id,
    validation_file=val_file.id,
    suffix="samsum-ft",
    hyperparameters={"n_epochs": 1, "learning_rate_multiplier": 1, "batch_size": 8}
)

print("✅ Fine-tuning job created:", job.id)

ジョブは完全にOpenAIのインフラ上で実行されます。GPUやColabのセットアップは不要です!

OpenAIダッシュボードから直接進捗を監視でき、損失と精度の曲線がリアルタイムで更新されます。便利ですよね。

Step 3:トレーニング進捗の監視

ノートブックまたはターミナルから以下を使って進捗を確認できます:

import time

while True:
    status = client.fine_tuning.jobs.retrieve(job.id)
    print(f"🕒 {status.status} | Trained tokens: {status.trained_tokens or 0}")
    if status.status in ("succeeded", "failed", "cancelled"):
        break
    time.sleep(30)

完了すると、レスポンスにはファインチューニング済みモデルIDが含まれます。例えば:

ft:gpt-4o-mini-2024-11-07:ready-tensor-inc:samsum-ft

Step 4:ファインチューニング済みモデルの評価

最後に、Workflow 1と同じヘルパー関数を使ってファインチューニング済みモデルを評価します:

tuned_model_id = "ft:gpt-4o-mini-2024-11-07:ready-tensor-inc:samsum-ft"
scores, preds = evaluate_openai_model(tuned_model_id, cfg, limit=200)

結果:

ROUGE Summary:
ROUGE-1: 55.72%, ROUGE-2: 32.80%, ROUGE-L: 47.77%

素晴らしい改善ですね!

これまでの結果

SAMSum要約ベンチマーク(検証セット200サンプル)での結果を比較してみましょう:

モデル ROUGE-1 ROUGE-2 ROUGE-L
Llama 3.2 1B(ベース) 約30-35% 約15-20% 約25-30%
GPT-4o-mini(ベース) 約50% 約28% 約43%
GPT-4o-mini(FT後) 55.72% 32.80% 47.77%

比較すると明確な進歩が見られます:

  • Llama 3.2 1Bモデルは妥当な性能を示しますが、小さなサイズによる制限があります
  • ベースGPT-4o-miniは、ファインチューニングなしですでに強力な要約品質を示します
  • ファインチューニング済みGPT-4o-miniは、すべてのROUGEメトリクスで大幅に改善し、ROUGE-Lで47.77%近くを達成!

これらの結果は、モデルの規模とファインチューニングアプローチが要約性能にどのように影響するかを示しています。次のレッスンでセルフホスト型ファインチューニングに移る前の明確なベンチマークになりますね。

次のステップ

マネージドファインチューニングが最初から最後までどのように機能するかを見ました。高速でシンプル、完全にホストされています。

これは迅速な改善を得る効率的な方法ですが、トレードオフもあります:

  • 透明性の制限:内部で何が起こっているか見えません
  • 高コスト:トークンあたりの料金が発生します
  • 制御が少ない:舞台裏で何が起こっているかを調整できません

次は、より実践的なアプローチを取ります!

次のレッスンでは、LoRAを使ってLlama 3.2 1Bを自分でファインチューニングし、プロセスのすべての部分を管理します。データの準備、アダプターの設定からトレーニング、監視、結果の評価まで、すべてです。

そこで、ファインチューニングはブラックボックスではなく、真のエンジニアリングになります。

さあ、構築しましょう!

コメント

タイトルとURLをコピーしました