見出し画像

【蒸留GPT】すぐに試せるファインチューニング~gpt3.5_turboをgpt4レベルにする方法

はじめに

みなさんファインチューニングしてますか?

OpenAI公式では、「ファインチューニングの前にプロンプト調整などを試すべき」と書かれていることもあり、あまり実践でファインチューニングを使う例は見ない印象です。

しかし、私はファインチューニングは実践でこそガンガン使うべきだと考えます。
最後の手段と捉えるのではなく、プロンプトエンジニアリングと同等に扱うべきです。

なぜなら、ファインチューニングによって以下のようなモデルが作成できるからです。

  • 応答速度はgpt-3.5-turbo並

  • 精度は特定のタスクに対してのみgpt-4並(場合によってはそれ以上)

  • 価格はgpt-4-turboの1/3~1/5以下

    • Fewshotなどが要らなくなることで桁違いのコスト削減が可能な場合も

極端な例ではありますが、私のプロジェクトではgpt4を使ったシステムをファインチューニングによって以下のように改善しました。

  • 精度は同じ(特定条件においてはそれ以上)

  • 応答速度5倍

  • コスト500分の1

この記事では、誰でもすぐに試せる形でOpenAIのGPTモデルをファインチューニングし、実践的なモデルを作成する方法を解説します。
ファインチューニングに必要なデータは、オープンデータを元にしてGPTに作成させるので、今手元にデータがなくても実践可能です。

必要なもの

  • 基礎的なPythonのスキル

  • OpenAIのアカウント

やり方解説

今回は「livedoor ニュースコーパス」を元にしたニュースの要約特化モデルの作成を例にして解説します。

単純な要約だと差が出にくいので、以下のような少し難しい要約をさせましょう。

  • 三行の箇条書き

  • 一つの行は20文字以下

1. 元データの用意

まず、livedoor ニュースコーパスから必要なデータをダウンロードします。
こちらにアクセスして「ダウンロード(通常テキスト):ldcc-20140209.tar.gz」をダウンロードしてください。

ダウンロードしたファイルを解凍し、一例として以下のように配置してください。

main.py # 訓練データ生成のコード(後述)
text # 解凍したテキストファイルが格納されたディレクトリ

要はmain.pyからtextディレクトリを参照できるようにすればOKです。

2. GPT4を用いて訓練データを生成

オープンデータだけだと要約特化モデルを作成するには不十分なので、GPT4で要約文を作成し、ファインチューニングを行うためのフォーマットで出力します。

GPT4の出力を元にファインチューニングすることで、gpt-3.5-turboでgpt-4並の精度が出せるようになります。

以下は訓練データ生成のコードです。

import os
import random
from openai import OpenAI
from tqdm import tqdm
import glob
import json

def read_random_txt_files(directory, num_files):
    """
    指定したディレクトリ内のtxtファイルからランダムに指定した数だけ読み込み、
    その内容を文字列のリストとして返す関数。

    :param directory: 読み込むファイルがあるディレクトリのパス
    :param num_files: 読み込むファイルの数
    :return: ファイルの内容のリスト
    """

    # ディレクトリ内の全てのtxtファイルのパスを取得
    txt_files = glob.glob(os.path.join(directory, '**', '*.txt'), recursive=True)

    # ランダムにファイルを選択
    selected_files = random.sample(txt_files, min(num_files, len(txt_files)))

    # 選択したファイルの内容を読み込む
    contents = []
    for file in selected_files:
        with open(file, 'r', encoding='utf-8') as f:
            contents.append(f.read())

    return contents

# 訓練データと検証データのサイズ
TRAIN_DATA_NUM = 100
TEST_DATA_NUM = 30
ALL_DATA_NUM = TRAIN_DATA_NUM + TEST_DATA_NUM

# APIキーを設定
client = OpenAI(api_key=API_KEY)

# フォルダの中からランダムにtxtファイルを読み込み
news_texts = read_random_txt_files("./text", ALL_DATA_NUM)


# 要約のためのシステムプロンプト
system_prompt = """\
You are a summary assistant.
The summary should be in three-line bullet points.
Each line should be no more than 20 characters.
Please make sure that as little information as possible is missing.
In Japanese.
"""

# 訓練データを生成
dataset = []
for nt in tqdm(news_texts):
    messages = [
        {"role": "system", "content": system_prompt},
        {"role": "user", "content": nt},
    ]

    # GPT4を使って要約
    completion = client.chat.completions.create(
        model="gpt-4",
        messages=messages,
    )

    content = completion.choices[0].message.content
    
    # 訓練データに追加
    dataset.append({"messages": messages + [{"role": "assistant", "content": content}]})

# 訓練データと検証データに分割
train_dataset = dataset[:TRAIN_DATA_NUM]
test_dataset = dataset[TRAIN_DATA_NUM:]

# ファインチューニングを行うためのフォーマットで出力
with open("train_dataset.jsonl", "w") as f:
    f.write("\n".join([json.dumps(td) for td in train_dataset]))

with open("test_dataset.jsonl", "w") as f:
    f.write("\n".join([json.dumps(td) for td in test_dataset]))

上記を実行して出力されるtrain_dataset.jsonlとtest_dataset.jsonlを訓練データとテストデータとして使用します。

ちなみに訓練データだけでもファインチューニングは問題なく可能です。
GPTの利用料が気になる方はコードを修正してください。

3. ファインチューニング

APIを使って行うことも可能ですが、今回はOpenAIのダッシュボードから行います。

まず、ファインチューンダッシュボードに移動し、右上の「+ Create」を選択してください。

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

次に以下のように設定します。

  • Base model : gpt-3.5-turbo-1106

  • Training data : train_dataset.jsonl

  • Validation data : test_dataset.jsonl

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

あとはCreateを選択し、10分ほど待てばモデルが作成されます。

このとき、Validation lossを確認して、値が悪ければ再度実行すると良いです。
同じデータを使用しても、モデルの性能に差が出る時があります。
Azure OpenAI Serviceのようにバッチサイズなどを調整できると良いのですが、その機能はまだ無いみたいです。

4. ファインチューニングしたモデルの検証

私の記事を要約させてみます。
gpt4, gpt3.5-turbo, finetune-model(今回作成したモデル)を比較しました。

システムプロンプトは訓練時と同じものを使用しています。

=gpt4=
- GPT APIを使ったシステム開発時のコツ
- プロンプトは単一タスクごとに設定、GPT3.5とGPT4を使い分け
- タスク整理しGPTには得意な領域を任せ、不要な処理は他AIで実行


=gpt3.5-turbo=
- GPT APIを開発するときは、プロンプトを単純にすることが重要。
- タスクを分割し、複数のプロンプトを組み合わせることで安定性を向上。
- GPT3.5-turboとGPT4を使い分けることで処理の高速化・コスト削減を実現。
- GPTにはGPTにしかできない処理のみを任せ、他のAIやプログラムで解決する。
- function_callingやJSONモードを使用してGPTの動作を安定化させる。
- バッチ処理を活用し、事前に処理しておくことで処理速度やコストを削減。
- チャットを活用してユーザー体験を向上させることができる。


=finetune-model=
- GPT APIを組み込む際のポイント
- プロンプトは単一タスク指示が重要
- 機能分化、バッチ処理、チャット活用も

=gpt4=
- GPT PhoneがGPTsの普及を推進
- GPT Phoneは目的能率的なツール
- GPTsが生活と深く結びつく展望


=gpt3.5-turbo=
- GPT PhoneがGPT Storeから出る予測
- GPTsはChatGPT Plusユーザーのみ
- GPT Phoneの予想
- GPT Phoneにより利用シーンが増加
- 企業間でのGPTs開発競争
- スマートスピーカーが増加
- 新たな文化が生まれる
- GPTを使った新ユーザー体験模索
- 先行者として立つ
- AIアシスタントが社会に定着することを願う


=finetune-model=
- GPT Phoneが世界を変える可能性
- GPTsの欠点を解消、一般ユーザ増加
- GPT Phoneによる社会変化予測

gpt3.5-turboの場合は三行や20文字以下のルールを守れていませんが、gpt4やfinetune-modelの場合は守れており、精度の差もほとんど無いように見えます。

まとめ

実践的なファインチューニングの方法をまとめてみました。

今回は無印のOpenAIを使いましたが、Azure OpenAI Serviceでも同じことができます。

JSONモードやFunction Callingと組み合わせることもできるので、色々試してみてください。

この記事は一週間限定で無料配信し、その後有料に切り替えたいと思います。
今後も同じような記事を作っていこうと思うので、フォローよろしくお願いいたします。 

この記事が気に入ったらサポートをしてみませんか?