Fine-Tuning GPT Models: OpenAI’s Managed Fine-Tuning API Walkthrough

スポンサーリンク

Fine-Tuning GPT Models: OpenAI’s Managed Fine-Tuning API Walkthrough

  • Fine-Tuning Workflow
  • Frontier Models
  • GPT-4o
  • JSONL Dataset
  • LLM Evaluation
  • LLM Fine-Tuning
  • Managed LLM Training
  • OpenAI Fine-Tuning
  • ROUGE
  • SAMSum
  • Mohamed Abdelhamid
  • Ready Tensor

🏠
Home – All Lessons

⬅️
Previous – SAMSum Fine-Tuning Project

➡️
Next – Fine-Tuning Llama 3

その前に、同じSAMSum要約タスクでGPT-4o-miniのようなフロンティアモデルを使った場合に何が起こるか見てみましょう — まず何もしない状態、次にファインチューニング後です。

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

これは、オープンウェイトモデルを使った実践的なファインチューニングに戻る前の、好奇心に基づくベンチマークと考えてください。

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

ファインチューニングといえば、ノートブック、GPU、カスタムトレーニングループを思い浮かべます。
次にやることはまさにそれですが — その前に、すべての作業を代行してもらった場合に何が起こるかを見ておくと役立ちます。

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

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

  • モデル内部への制御や可視性が少ない
  • トークンあたりのコストが高い
  • 中間チェックポイントへのアクセスがない

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

ここから: 比較する2つのワークフロー

OpenAI APIの単一呼び出しの仕組みを理解したところで、スケールアップしましょう — そして作業を2つの明確なワークフローに分けます:

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

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

🎥 Fine-Tune GPT Models for Conversation Summarization

このビデオでは、OpenAIのマネージドサービスを使ってSamSumデータセットでGPT-4o-miniをファインチューニングする方法を見ます。データ準備からROUGEメトリクスによる評価までの完全なワークフローを学びます。

Workflow 1: Evaluating the Frontier Model (GPT-4o-mini Baseline)

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

メカニクスの理解: 一度に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スコアを計算します。

ベースライン評価の実装

前のレッスンで使った同じヘルパー関数を再利用して、データセットのロード、ROUGEの計算、プロンプトの構造化を行えます。これらは:

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

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

  • generate_openai_predictions() — すべてのサンプルに対してスレッド化されたAPI推論を実行
    generate_openai_predictions()
  • evaluate_openai_model() — 評価ワークフローをラップ(生成 + スコアリング + 保存)
    evaluate_openai_model()

では、このプロセスを自動化する2つのヘルパー関数を導入しましょう。

予測の生成

def generate_openai_predictions(model_name, dataset, task_instruction, num_samples=None, max_workers=10, sleep_time=0.25):
    """Generate predictions from an OpenAI model using concurrent threads."""
    if num_samples is not None and num_samples < len(dataset):
        dataset = dataset.select(range(num_samples))
    total = len(dataset)
    preds = [None] * total

    def process_sample(idx, sample):
        messages = build_messages_for_sample(sample, task_instruction, include_assistant=False)
        try:
            response = client.chat.completions.create(model=model_name, messages=messages, temperature=0.2, max_tokens=128)
            return idx, response.choices[0].message.content.strip()
        except Exception as e:
            print(f"⚠️ Error on sample {idx}: {e}")
            return idx, ""

    with ThreadPoolExecutor(max_workers=max_workers) as executor:
        futures = [executor.submit(process_sample, i, dataset[i]) for i in range(total)]
        for i, future in enumerate(as_completed(futures), start=1):
            idx, output_text = future.result()
            preds[idx] = output_text
            if i % 10 == 0 or i == total:
                print(f"✅ Completed {i}/{total}")
            time.sleep(sleep_time)
    return preds

評価の実行

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: Fine-Tuning GPT Models with OpenAI’s Managed API

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

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

再利用するもの

以下を再利用します:

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

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

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

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

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

user
assistant

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を使ってファインチューニングジョブを作成します:

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サンプル)での結果は以下の通りです:

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

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

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

次のステップ

マネージドファインチューニングが最初から最後までどのように機能するかを見ました — 高速でシンプル、完全にホストされています。
これは迅速な改善を得る効率的な方法ですが、トレードオフもあります: 透明性の制限、高コスト、舞台裏で何が起こっているかへの制御が少ない。

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

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

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

さあ、構築しましょう。

  • A Quick Detour: Managed Fine-Tuning By OpenAI

コメント

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