🤖

GPT4-oにバグチケットの情報をファインチューニングで学習させてみた

2024/09/17に公開

OpenAI GPT-4o を Fine-tuning してみた

はじめに

OpenAIのモデルのファインチューニングに興味があったのですが、やはりお金がかかるので今まで実施してきませんでした。
が、8月末に以下のような内容が書かれたメールがOpenAIから届きました。

Start by visiting the docs or head to the fine-tuning dashboard, click ‘create,’ and select ‘gpt-4o-2024-08-06’ or ‘gpt-4o-mini-2024-07-18’ from the base model drop-down. GPT-4o fine-tuning training costs $25 per million tokens, and inference is $3.75 per million input tokens and $15 per million output tokens. For GPT-4o mini, training cost is $3 per million tokens, and inference is $0.30 per million input tokens and $1.20 per million output tokens.

To help you get started, we’re also offering 1M training tokens per day for free for every organization through September 23 for GPT-4o fine-tuning and 2M training tokens per day for free for GPT-4o mini fine-tuning through September 23.

9/23までの間、GPT-4oのファインチューニングを無料で1日100万トークンまで実施できるということで、早速試してみることにしました。

プロンプトエンジニアリングとRAGとファインチューニングの違い

プロンプトエンジニアリング

教師が生徒に対して質問や指示を出すときの「質問の仕方」に似ています。
生徒が最適な回答を出せるように、質問を工夫するプロセスです。
つまり、質問を適切にすることで、生徒(モデル)が既存の知識(事前学習されたデータ)から最良の答えを引き出す助けとなります。

RAG

図書館でのリサーチに例えることができます。
問題に対する答えを見つけるために、**図書館(データベース)から関連する書籍や資料を集め(検索)、それらの情報を基にしてレポートやエッセイを書く(生成)**過程と似ています。
RAGに用いるデータは容易に変更ができるため低コストで運用できます。

ファインチューニング

特定の科目やテストに向けて勉強する学生に例えることができます。
例えば、生徒が数学の試験に向けて特定のトピック(新しいトレーニングデータ)で追加学習(再訓練)を行うことで、その科目に対する理解とパフォーマンスが向上します。
教科書(事前学習モデル)を使い、特定の試験(タスク)のために重点的に学習するプロセスです。
一度学習させたデータは忘れることができないので学習データを修正したい場合は再度ファインチューニングさせる必要があり運用コストがかかります。

ファインチューニングしてみる

ファインチューニングのやり方

OpenAI APIの契約が前提条件になります

  1. https://platform.openai.com/finetune/ にアクセス
  2. + Create をクリック
  3. 学習モデルを選択し、トレーニングデータをアップロード
    • トレーニングデータのデータ形式はJSON Lines形式です
    • トレーニングデータには最低10件のデータが必要です
  4. Create ボタンをクリック
  5. ファインチューニング完了まで待つ

ファインチューニングしたモデルを使うには、https://platform.openai.com/playground/ からファインチューニングしたモデルを選択することで試すことができます

Web UIからファインチューニングすることもできますが、APIを使ってファインチューニングすることもできます

ファインチューニングのトレーニングデータについて

トレーニングデータを作成する際には、以下の点に注意してください。

  1. データの多様性:様々なシナリオやケーススタディを含めることで、モデルの汎用性を高めます。
  2. 質の高い例:提供するデータは明確で一貫性があり、モデルが学習しやすいものであるべきです。誤った情報や不完全なデータは避けるようにしましょう。

試しにファインチューニングしてみる

Playground で、お笑い芸人のひょうろくについて聞いてみます

別人の内容ですね。
gpt4o-miniにファインチューニングしてみます。
トレーニングデータはWikipediaなどを参照し、以下の内容を作り使いました。

{
    "messages": [
        {"role": "user", "content": "芸人のひょうろくについて教えて"},
        {
            "role": "assistant",
            "content": "# 生年月日:1987年7月7日\n# 出身地:鹿児島県\n# 略歴\nコンビ・ジュウジマルを2020年に解散後、ピン芸人に。「水曜日のダウンタウン」(TBS系)をはじめとする番組に出演し、その独特なキャラクターで注目を集めている。",
        },
    ]
}
{
    "messages": [
        {"role": "user", "content": "お笑い芸人のひょうろくについて教えて"},
        {
            "role": "assistant",
            "content": "2012年に橋口ひとしとともにジュウジマルというコンビを結成、当時は浅井企画に所属。M-1グランプリ2019では3回戦に進出したが、2020年に解散した。2022年にバラエティ番組『水曜日のダウンタウン』(TBSテレビ)に小峠英二(バイきんぐ)の替え玉役として出演し、以後同番組にたびたび出演。業界とのパイプを強めるためにザ・森東の事務所に押しかけたことをきっかけとして、さらば青春の光のマネージャーであるヤマネヒロマサが窓口を担当している。ただし正式に所属してはおらず、フリーで活動している。",
        },
    ]
}
{
    "messages": [
        {"role": "user", "content": "芸人のひょうろくについて教えて"},
        {
            "role": "assistant",
            "content": "2012年に橋口ひとしとジュウジマルを結成しました。彼らは浅井企画に所属しており、コンビとしての活動を始めました。"
        },
    ]
}
{
    "messages": [
        {"role": "user", "content": "お笑い芸人のひょうろくについて教えて"},
        {
            "role": "assistant",
            "content": "ジュウジマルはM-1グランプリ2019で3回戦に進出しましたが、2020年にコンビを解散しました。"
        },
    ]
}
{
    "messages": [
        {"role": "user", "content": "ひょうろくの最近の活動は?"},
        {
            "role": "assistant",
            "content": "2022年、ひょうろくはTBSテレビの「水曜日のダウンタウン」に出演し、小峠英二(バイきんぐ)の替え玉役として注目を集めました。"
        },
    ]
}
{
    "messages": [
        {"role": "user", "content": "水曜日のダウンタウンでのひょうろくはどうだった?"},
        {
            "role": "assistant",
            "content": "その後も「水曜日のダウンタウン」に頻繁に出演し、テレビでの露出を増やしています。"
        },
    ]
}
{
    "messages": [
        {"role": "user", "content": "ひょうろくの業界での立ち位置は?"},
        {
            "role": "assistant",
            "content": "業界内のコネクションを強化するために、ザ・森東の事務所に押しかけたことがあります。"
        },
    ]
}
{
    "messages": [
        {"role": "user", "content": "ひょうろくのマネージャーについて教えてください。"},
        {
            "role": "assistant",
            "content": "さらば青春の光のマネージャー、ヤマネヒロマサがひょうろくの活動の窓口として機能しています。"
        },
    ]
}
{
    "messages": [
        {"role": "user", "content": "ひょうろくはどの事務所に所属していますか?"},
        {
            "role": "assistant",
            "content": "ひょうろくは正式にどの事務所にも所属しておらず、フリーで活動を続けています。"
        },
    ]
}
{
    "messages": [
        {"role": "user", "content": "ひょうろくの人気の秘密は何ですか?"},
        {
            "role": "assistant",
            "content": "バラエティ番組での独特なキャラクターとパフォーマンスで、ひょうろくは多くの視聴者から支持を得ています。"
        },
    ]
}
{
    "messages": [
        {"role": "user", "content": "ひょうろくのピン芸人としてのキャリアについて教えてください。"},
        {
            "role": "assistant",
            "content": "ピン芸人としての活動を開始してからは、彼のキャリアに新たな局面が開けました。"
        },
    ]
}
{
    "messages": [
        {"role": "user", "content": "ひょうろくの将来の展望はどうですか?"},
        {
            "role": "assistant",
            "content": "ひょうろくはエンターテインメント業界で独自のポジションを築き、多様なメディアに出演しています。"
        },
    ]
}

ファインチューニングした gpt-4o-miniで再度聞いてみます

ファインチューニングで学習した内容をもとに回答してくれました

実践

プロダクトコードをすべて学習させてみる -> 失敗

自社サービスのプロダクトコードをすべて学習させれば、機能開発も楽チンなモデルができるのではないかと考えました。
が、ファインチューニングの学習データは、QA形式でないといけないため、試行錯誤しましたがこの案はボツになりました。
やってみたのは、ソースのパスやクラスのコメントをQとして、そのクラスの内容をAとして学習させるというものでした。
なにかいい方法あるのかな・・・。

GitLabのIssueから、バグチケットの内容を学習させてみる -> 失敗のパターン

QA形式で渡す必要があるため、ちょっと悩んだのですが過去のGitLabのバグチケット内容を学習させ、Commitのイベントをフックさせコードをチェックすることで、将来同じようなバグを埋め込んでしまうリスクを抑えることができるのではと考えました。
トレーニングデータは以下のような形式にしました。
※実際はJSON Lines形式なので1行で書きますが、見やすさを優先しています

{
  "messages": [
    {"role": "system", "content": "あなたはxxxのバグを検出するアシスタントです"},
    {"role": "user", "content": "<Issueのタイトル、Issueのdescription>"},
    {"role": "assistant", "content": "<Issueに紐づくMRで修正されたソースのdiff>"}
  ]
}

LLMにこういうバグの場合は、こう直すという情報を学習させようとしたのですが、うまくいきませんでした。
色々やってみた結果、ファインチューニングに用いるトレーニングデータの内容は、追加で学習してほしい内容を渡すというより、モデルがどういう挙動をするかを学習させるというもののようで、この方法は失敗しました。

GitLabのIssueから、バグチケットの内容を学習させてみる -> ちょっと変なパターン

モデルがどういう挙動をするかを学習させるトレーニングデータを作るため、以下のような内容にしました
※実際は改行は\nで繋いでいますが、見やすさを優先しています

{
  "messages": [
    {"role": "system", "content": "あなたはxxxのバグを検出するアシスタントです"},
    {"role": "user", "content": "これはxxxのソースコードです。このコードにバグがあるかどうか確認し、過去のバグ発生チケットと修正案を提案してください
                                 <修正前のソース>"},
    {"role": "assistant", "content": "このコードには過去のバグが含まれている可能性があります。該当しそうな過去のバグチケットと修正案を提案します
                                     <過去のバグチケットの情報>
                                     ## 修正案
                                     <修正後のソース>"}
  ]
}

このトレーニングデータを使って学習させたところ、モデルが過去のバグチケットの内容を参考に回答するようになりました。
しかし修正案がデタラメな内容になってしまっています・・・。
これでは使い物になりません。

GitLabのIssueから、バグチケットの内容を学習させてみる (Validation data指定)

先の方法で用いたトレーニングデータは、大きくズレたようなデータではないと思っています。
なので、Validation data として、トレーニングに用いたデータを指定して、学習してみました。
Validation dataを指定しなかったパターンに比べて改善はされましたが、過去のチケット情報(チケット番号やチケットのタイトル)が存在しない情報を作り出してしまいました。

結果

ファインチューニングは学習に使うデータの整備に時間をかけないと、思うような結果が出ないことがわかりました。
今回は膨大な過去チケットを手軽に処理させたかったので機械的なデータしか作れなかったため、これがイマイチだったのだと思います。

RAGならどうか

ファインチューニングで思うような結果が出ませんでしたが、ではRAGならどうかということで検証してみました。
RAGのメリットとしては、AIにわたす情報と、それに紐づくmetadataを持つことができ、metadata部分はAIによる加工が行われません。
そのため、ファインチューニング時に発生したような、架空のチケットの番号やチケットタイトルを作り出してしまうということが発生しません。

ファインチューニングで用いたデータを加工し、過去のバグと一致するようなバグを仕込んでRAGで問い合わせてみたところ、バッチリな回答を返してくれました。
ファインチューニングは諦めて、RAGを用いたバグ検出Botを作ってみようと思います。

Discussion