OpenAIのモデルをFine-tuningして、商品分類ができるかをやってみた

2023.06.02

OpenAIのAPIは特定タスクに特化させるためのFine-tuningが可能です。今回はECサイトの商品に対するラベル付けとして活用できないかと思い、検証してみたので記事にしたいと思います。

Fine-tuningについての概要に関してはコチラの記事が詳しいので、あわせて確認してみてください。 実装に関してはopenAIさんが公開している例を参考にしました。実装途中で存在に気づきましたが試してみたい方は、公式のexampleが大変参考になるのでオススメです。

やりたいこと/解決したい課題

情報(文章)に対するラベル付けが可能であるかをこの記事では検証してみます。

具体的なユースケースとしては、

  • ECサイトを運用していて数多くの商品が頻繁に新しく追加されるときに、商品に対するカテゴリー付けが大変
  • アンケートなど大量の情報に対してカテゴリー付けを行うときに、めっちゃ時間がかかる」など

大量の情報を決まったパターンへ分類するタスクの手間を機械にお任せして解決できるかを検証してみます。

どうやって検証するの?

商品分類を行うために利用するデータセットとして、こちらのデータセットを利用します。

ちょうどいい日本語のデータセットが見つけられなかったので、今回は英語のデータを基にして実施します。

検証を行う全体の流れは以下です。

  • データの準備
    • データセットの中から商品説明と商品カテゴリーを抽出する。
    • 検証するためのカテゴリーは4つの分類でデータを抽出します。学習に利用するデータ数は各カテゴリーごとに500データずつ利用します。(参考
    • 抽出したデータを加工して、OpenAI APIでFine-tuningするために変換します。
  • データの変換
    • 変換したデータを使って、Fine-tuningを行います。
  • 結果の測定
    • 今回のやりたいことが実現できたかの精度を検証します。

結局のところ、結果はどうだった?(結果の測定)

まずは結果から。評価データを用いて検証を行った結果としては約96%の精度となりました。

細かいチューニングなどを行えば更に精度の向上が見込めますが検証目的としては良い結果ではないでしょうか。

データ数の増減や分類数によって精度は変わるので、その点については今後の検証対象です。

ただ、今回の目的であった「大量の情報を決まったパターンへ分類するタスクの手間を機械にお任せしたい。」という目的は達成できるという検証結果になりました。

検証結果(精度 x ステップ数)

openai_classification_fine_tuning

以下は実際に検証したプロセスです。

データの準備

OpenAIの公式ドキュメントによるとFine tuningを行うためには、以下のようなフォーマットのJSONLファイルに変換する必要があるようです。

{"prompt": "prompt text", "completion": "ideal generated text"}

まずは、上記のフォーマットに変換する前に、今回利用するデータセットから今回対象とするカテゴリーごとのデータの抽出を行います。訓練用データとして500件, 検証用データとして100件を準備します。

import pandas as pd

# CSVファイルを読み込む
df = pd.read_csv(‘ecommerceDataset.csv’, header=None)

# 各カテゴリからランダムに選択(訓練用500行 + 評価用100行)
categories = [‘Household’, ‘Books’, ‘Clothing & Accessories’, ‘Electronics’]
selected_rows = pd.concat([df[df[0] == category].drop_duplicates().sample(600) for category in categories])

# 列の順序を変更(0列目と1列目を入れ替え)
selected_rows = selected_rows[[1, 0]]

# 各カテゴリから最初の100行を評価データとして選択
evaluation_rows = pd.concat([selected_rows[selected_rows[0] == category].iloc[:100] for category in categories])
# 評価データを元のデータフレームから削除
selected_rows = selected_rows.drop(evaluation_rows.index)
# 評価用のCSVファイルに出力
evaluation_rows.to_csv(‘evaluation_ecommerceDataset.csv’, index=False, header=False)
# 訓練用のCSVファイルに出力
selected_rows.to_csv(‘selected_ecommerceDataset.csv’, index=False, header=False)

 

データの変換とFine-tuningもやってみよう

続いて、これらのデータをOpenAIが指定しているフォーマットへの加工を行います。(参考にした公式ドキュメント

上記のページによると、、、、

  1. promptの末尾(separator)として、 \n\n###\n\n を指定するのが良い
  2. completionのはじめには空白を入れる必要がある
  3. completionの末尾には、\nや###などの他には出現しない文字を指定する
  4. 推論するときのpromptも、トレーニングで利用したデータと同じようにformatしてね。(末尾に \n\n###\n\n をいれる)

1~3の範囲をFine-tuningに利用するデータに対して実行する必要があるとのことなので、抽出したデータに対して適用します。

 

import pandas as pd

def process_csv_files(file_names):
for file_name in file_names:

# CSVファイルを読み込む
df = pd.read_csv(file_name, header=None)

# 1列目の各値の終わりに ‘\n\n###\n\n’ を追加
df[0] = df[0] + ‘\n\n###\n\n’

# 2列目のデータを取得し、各行の始めに空白を追加し、各行の終わりに ‘###’ を追加する
# 数値を文字列に変換
df[1] = ' ' + df[1].astype(str) + ‘###’

# 列名を設定する
df.columns = [‘prompt’, ‘completion’]

# 新しいCSVファイルに出力
output_file_name = ‘processed_’ + file_name
df.to_csv(output_file_name, index=False, header=True)

print(f”Processed and saved file: {output_file_name}“)

# Example usage
file_names = [‘selected_ecommerceDataset.csv’, ‘evaluation_ecommerceDataset.csv’]

process_csv_files(file_names)

 

続いて、fine-tuningを行う際には、JSONLファイルに変換する必要があります。openai CLIを利用するといい感じに変換してもらえるようなので、以下のコマンドで変換を行います。

openai tools fine_tunes.prepare_data -f selected_ecommerceDataset.csv
- [Recommended] Remove 1 long examples [Y/n]:
- [Recommended] Would you like to split into training and validation set? [Y/n]:

上記を実行すると、いくつかRecommendedとして追加の処理が提案されました。今回の場合評価用のデータに分割する?の問いに対しては No で返答しましたが、それ以外はYesで返答しました。

分割してくれることを知らなかったため事前に分割しましたが、この段階で行っても良いと思います(未検証)。

無事に処理が完了すると以下のようなフォーマットされたJSONLファイルが出力されます。

promptには商品説明、completionには対象となる分類が記載されています。

{“prompt”:“Casa Decor New Year Sale of Set of 6 Jute Ball Shape Handmade Drawer Pull Cabinet Dresser Handle Wardrobe Jute Knobs Our unique knobs collection can be used for updating the furniture or refurbishing a kitchen cabinet. This knobs are mostly hand painted. We offer pantone color variations, prints & transfers and bespoke paint patterns. We have showcased a small selection of the knobs that have been done in the past. These ceramic are knobs are glazed & baked to specific temperatures to experience truer colors. They are produced in various shapes & sizing with vibrant color patterns.So, buy knobs online today and give a perfect look to your furniture.\n\n###\n\n”,“completion”:” Household###“}

Fine-tuningの実施

テキスト分類を行うためのモデルをFine-tuningするために、以下のコマンドを実行します(参考にした公式ドキュメント)。

!openai api fine_tunes.create -t “selected_ecommerceDataset_prepared_train.jsonl” -v “selected_ecommerceDataset_prepared_valid.jsonl” --compute_classification_metrics --classification_n_classes 4 -m ada

-compute_classification_metrics のオプションをつけると、分類の精度を表示する列が追加されるようです。 -classification_n_classes <N_CLASSES> の部分には、今回は4つのカテゴリーで分類を行うため、4を指定しました。

冒頭にて紹介した記事と同様に私の環境でもfine-tuningの途中で処理が何度か終了したため、

!openai api fine_tunes.follow -i ID

上記のコマンドを実行すると処理が再開されます。(多分10回ぐらいやった気がする)

 

結果の測定

以下のように実行すると、文章に対しての検証結果が表示できます。

今回は実験として某有名家電製品や家庭用品などの英語の商品説明を入力したところ、私の感覚では正しい分類が実施されていました。

ft_model = ‘xxxx’ # モデルのIDをいれる
sample= “”"
検証したい文章をいれる
“”"
res = openai.Completion.create(model=ft_model, prompt=sample + ‘\n\n###\n\n’, max_tokens=1, temperature=0)
res[‘choices’][0][‘text’]

まとめ

OpenAI APIを用いて特定タスクの最適化を行うアプローチとしてはプロンプトのチューニングをする方法とFine-tuningを行う方法の2つが代表的かと思いますが、今回はFine-tuningのアプローチで実施しました。

感じたメリットとしてはプロンプトチューニングのアプローチと比較して、 回答が決まった選択肢の中から行われること, そもそもプロンプトを考える必要がないこと, プロンプトが長くなる前提の場合はトークンの消費量を抑えられることがメリットかと思います。

Fine-tuningにかかったコストは正確な金額は忘れましたが、$1未満程度だったので上位モデルを利用するよりはかなりコストを抑えられることになるのではないでしょうか。

気になった方は是非お試しください!