OpenAI Cookbook examples : GPT-3 の微調整 : 分類サンプルの微調整 (翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 08/02/2023
* 本ページは、OpenAI Cookbook レポジトリの以下のドキュメントを翻訳した上で適宜、補足説明したものです:
* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。
- 人工知能研究開発支援
- 人工知能研修サービス(経営者層向けオンサイト研修)
- テクニカルコンサルティングサービス
- 実証実験(プロトタイプ構築)
- アプリケーションへの実装
- 人工知能研修サービス
- PoC(概念実証)を失敗させないための支援
- お住まいの地域に関係なく Web ブラウザからご参加頂けます。事前登録 が必要ですのでご注意ください。
◆ お問合せ : 本件に関するお問い合わせ先は下記までお願いいたします。
- 株式会社クラスキャット セールス・マーケティング本部 セールス・インフォメーション
- sales-info@classcat.com ; Web: www.classcat.com ; ClassCatJP
OpenAI Cookbook : GPT-3 の微調整 : 分類サンプルの微調整
2 つのスポーツ: 野球とホッケーを区別するために ada 分類器を微調整します。
from sklearn.datasets import fetch_20newsgroups
import pandas as pd
import openai
categories = ['rec.sport.baseball', 'rec.sport.hockey']
sports_dataset = fetch_20newsgroups(subset='train', shuffle=True, random_state=42, categories=categories)
データ探索
newsgroup データセットは sklearn を使用してロードできます。最初にデータ自体を見てみましょう :
print(sports_dataset['data'][0])
From: dougb@comm.mot.com (Doug Bank) Subject: Re: Info needed for Cleveland tickets Reply-To: dougb@ecs.comm.mot.com Organization: Motorola Land Mobile Products Sector Distribution: usa Nntp-Posting-Host: 145.1.146.35 Lines: 17 In article <1993Apr1.234031.4950@leland.Stanford.EDU>, bohnert@leland.Stanford.EDU (matthew bohnert) writes: |> I'm going to be in Cleveland Thursday, April 15 to Sunday, April 18. |> Does anybody know if the Tribe will be in town on those dates, and |> if so, who're they playing and if tickets are available? The tribe will be in town from April 16 to the 19th. There are ALWAYS tickets available! (Though they are playing Toronto, and many Toronto fans make the trip to Cleveland as it is easier to get tickets in Cleveland than in Toronto. Either way, I seriously doubt they will sell out until the end of the season.) -- Doug Bank Private Systems Division dougb@ecs.comm.mot.com Motorola Communications Sector dougb@nwu.edu Schaumburg, Illinois dougb@casbah.acns.nwu.edu 708-576-8207
sports_dataset.target_names[sports_dataset['target'][0]]
'rec.sport.baseball'
len_all, len_baseball, len_hockey = len(sports_dataset.data), len([e for e in sports_dataset.target if e == 0]), len([e for e in sports_dataset.target if e == 1])
print(f"Total examples: {len_all}, Baseball examples: {len_baseball}, Hockey examples: {len_hockey}")
Total examples: 1197, Baseball examples: 597, Hockey examples: 600
上記では野球カテゴリーの 1 つのサンプルが見られます。それはメーリングリストへの電子メールです。合計 1197 サンプルを持つことがわかります、これは 2 つのスポーツに均等に分割されます。
データの準備
データセットを、プロンプト (prompt) と補完 (completion) 用のカラムを含む、pandas データフレームに変換します。プロンプトはメーリングリストからの電子メールを含み、補完はスポーツの名前、ホッケーかベースボールのいずれかを含みます。デモ目的だけであることと微調整のスピードのために、300 サンプルだけを取ります。実際のユースケースではサンプルが多ければパフォーマンスもより良くなります。
import pandas as pd
labels = [sports_dataset.target_names[x].split('.')[-1] for x in sports_dataset['target']]
texts = [text.strip() for text in sports_dataset['data']]
df = pd.DataFrame(zip(texts, labels), columns = ['prompt','completion']) #[:300]
df.head()
prompt completion 0 From: dougb@comm.mot.com (Doug Bank)\nSubject:... baseball 1 From: gld@cunixb.cc.columbia.edu (Gary L Dare)... hockey 2 From: rudy@netcom.com (Rudy Wade)\nSubject: Re... baseball 3 From: monack@helium.gas.uug.arizona.edu (david... hockey 4 Subject: Let it be Known\nFrom: <ISSBTL@BYUVM.... baseball
ベースボールとホッケーの両方とも単一トークンです。データセットは jsonl ファイルとしてセーブします。
df.to_json("sport2.jsonl", orient='records', lines=True)
データ準備ツール
ここでデータ準備ツールを使用することができます、これは微調整する前にデータセットに幾つかの改良を提案します。ツールを起動する前に openai ライブラリを更新して最新のデータ準備ツールを使用していることを確実にします。更に -q を指定します、これはすべての提案を自動的に受け入れます。
!pip install --upgrade openai
!openai tools fine_tunes.prepare_data -f sport2.jsonl -q
Analyzing... - Your file contains 1197 prompt-completion pairs - Based on your data it seems like you're trying to fine-tune a model for classification - For classification, we recommend you try one of the faster and cheaper models, such as `ada` - For classification, you can estimate the expected model performance by keeping a held out dataset, which is not used for training - There are 11 examples that are very long. These are rows: [134, 200, 281, 320, 404, 595, 704, 838, 1113, 1139, 1174] For conditional generation, and for classification the examples shouldn't be longer than 2048 tokens. - Your data does not contain a common separator at the end of your prompts. Having a separator string appended to the end of the prompt makes it clearer to the fine-tuned model where the completion should begin. See https://beta.openai.com/docs/guides/fine-tuning/preparing-your-dataset for more detail and examples. If you intend to do open-ended generation, then you should leave the prompts empty - The completion should start with a whitespace character (` `). This tends to produce better results due to the tokenization we use. See https://beta.openai.com/docs/guides/fine-tuning/preparing-your-dataset for more details Based on the analysis we will perform the following actions: - [Recommended] Remove 11 long examples [Y/n]: Y - [Recommended] Add a suffix separator `\n\n###\n\n` to all prompts [Y/n]: Y - [Recommended] Add a whitespace character to the beginning of the completion [Y/n]: Y - [Recommended] Would you like to split into training and validation set? [Y/n]: Y Your data will be written to a new JSONL file. Proceed [Y/n]: Y Wrote modified files to `sport2_prepared_train.jsonl` and `sport2_prepared_valid.jsonl` Feel free to take a look! Now use that file when fine-tuning: > openai api fine_tunes.create -t "sport2_prepared_train.jsonl" -v "sport2_prepared_valid.jsonl" --compute_classification_metrics --classification_positive_class " baseball" After you’ve fine-tuned a model, remember that your prompt has to end with the indicator string `\n\n###\n\n` for the model to start generating completions, rather than continuing with the prompt. Once your model starts training, it'll approximately take 30.8 minutes to train a `curie` model, and less for `ada` and `babbage`. Queue will approximately take half an hour per job ahead of you.
ツールはデータセットへの幾つかの改良を役立つように提案し、データセットを訓練と検証セットに分割します。
プロンプトと補完の間の suffix は、入力テキストが停止したことそして次にクラスを予測する必要があることをモデルに知らせるために必要です。各サンプルで同じ区切り文字 (separator) を使用しますので、モデルは、区切り文字に続いて野球かホッケーかを予測するこをが意図されていることを学習することができます。補完内の空白 prefix は有用です、殆どの単語トークンは空白 prefix でトークン化されるからです。このツールはまたこれが分類タスクである可能性が高いことも認識しましたので、データセットを訓練と検証データセットに分割することを提案しました。これは新しいデータ上で期待されるパフォーマンスを簡単に測定することを可能にします。
微調整
ツールはデータセットを訓練するために次のコマンドを実行することを提案します。これは分類タスクですので、分類ユースケースについて提供される検証セットで汎化性能がどんなものかを知りたいです。ツールは分類メトリクスを計算するために –compute_classification_metrics –classification_positive_class ” baseball” を追加することを提案しています。
CLI ツールから提案されたコマンドを単純にコピーすることができます。安くて高速な ada モデルを微調整するために特に -m ada を追加します、これは分類ユースケースでは通常は遅くて高価なモデルにパフォーマンスの点で匹敵します。
!openai api fine_tunes.create -t "sport2_prepared_train.jsonl" -v "sport2_prepared_valid.jsonl" --compute_classification_metrics --classification_positive_class " baseball" -m ada
Upload progress: 100%|████████████████████| 1.52M/1.52M [00:00<00:00, 1.81Mit/s] Uploaded file from sport2_prepared_train.jsonl: file-Dxx2xJqyjcwlhfDHpZdmCXlF Upload progress: 100%|███████████████████████| 388k/388k [00:00<00:00, 507kit/s] Uploaded file from sport2_prepared_valid.jsonl: file-Mvb8YAeLnGdneSAFcfiVcgcN Created fine-tune: ft-2zaA7qi0rxJduWQpdvOvmGn3 Streaming events until fine-tuning is complete... (Ctrl-C will interrupt the stream, but not cancel the fine-tune) [2021-07-30 13:15:50] Created fine-tune: ft-2zaA7qi0rxJduWQpdvOvmGn3 [2021-07-30 13:15:52] Fine-tune enqueued. Queue number: 0 [2021-07-30 13:15:56] Fine-tune started [2021-07-30 13:18:55] Completed epoch 1/4 [2021-07-30 13:20:47] Completed epoch 2/4 [2021-07-30 13:22:40] Completed epoch 3/4 [2021-07-30 13:24:31] Completed epoch 4/4 [2021-07-30 13:26:22] Uploaded model: ada:ft-openai-2021-07-30-12-26-20 [2021-07-30 13:26:27] Uploaded result file: file-6Ki9RqLQwkChGsr9CHcr1ncg [2021-07-30 13:26:28] Fine-tune succeeded Job complete! Status: succeeded 🎉 Try out your fine-tuned model: openai api completions.create -m ada:ft-openai-2021-07-30-12-26-20 -p <YOUR_PROMPT>
モデルはおよそ 10 分で首尾よく訓練されます。モデル名は ada:ft-openai-2021-07-30-12-26-20 であることが分かります、これを推論を行なうために使用できます。
[Advanced] 結果と期待されるモデル性能
そして結果ファイルをダウンロードして取り置いた検証セット上で期待されるパフォーマンスを観察することができます。
!openai api fine_tunes.results -i ft-2zaA7qi0rxJduWQpdvOvmGn3 > result.csv
results = pd.read_csv('result.csv')
results[results['classification/accuracy'].notnull()].tail(1)
step elapsed_tokens elapsed_examples training_loss training_sequence_accuracy training_token_accuracy classification/accuracy classification/precision classification/recall classification/auroc classification/auprc classification/f1.0 validation_loss validation_sequence_accuracy validation_token_accuracy 929 930 3027688 3720 0.044408 1.0 1.0 0.991597 0.983471 1.0 1.0 1.0 0.991667 NaN NaN NaN
精度は 99.6% に到達します。以下のプロットでは、訓練実行中に検証セット上の精度がどのように上がるかを見ることができます。
results[results['classification/accuracy'].notnull()]['classification/accuracy'].plot()
<AxesSubplot:>
モデルの使用
予測を取得するためにモデルを呼び出すことができるようになりました。
test = pd.read_json('sport2_prepared_valid.jsonl', lines=True)
test.head()
prompt completion 0 From: gld@cunixb.cc.columbia.edu (Gary L Dare)... hockey 1 From: smorris@venus.lerc.nasa.gov (Ron Morris ... hockey 2 From: golchowy@alchemy.chem.utoronto.ca (Geral... hockey 3 From: krattige@hpcc01.corp.hp.com (Kim Krattig... baseball 4 From: warped@cs.montana.edu (Doug Dolven)\nSub... baseball
微調整の間に使用した区切り文字と同じ区切り文字をプロンプトに続いて使用する必要があります。この場合は \n\n###\n\n です。私達は分類に関心がありますので、temperature はできる限り低くあることを望み、そしてモデルの予測を決定するために 1 つのトークンの補完だけを必要とします。
ft_model = 'ada:ft-openai-2021-07-30-12-26-20'
res = openai.Completion.create(model=ft_model, prompt=test['prompt'][0] + '\n\n###\n\n', max_tokens=1, temperature=0)
res['choices'][0]['text']
' hockey'
対数尤度を取得するには、補完リクエストで logprobes パラメータを指定できます。
res = openai.Completion.create(model=ft_model, prompt=test['prompt'][0] + '\n\n###\n\n', max_tokens=1, temperature=0, logprobs=2)
res['choices'][0]['logprobs']['top_logprobs'][0]
<OpenAIObject at 0x7fe114e435c8> JSON: { " baseball": -7.6311407, " hockey": -0.0006307676 }
モデルは野球よりも遥かに尤もらしいとしてホッケーを予測し、これは正しい予測であることが分かります。log_probs をリクエストすると、各クラスに対する予測 (対数) 確率を見ることができます。
汎化 (一般化)
興味深いのは、微調整済み分類器は非常に用途が広いです。様々なメーリングリストへの電子メールで訓練されたにもかかわらず、それはまたツイートを首尾よく予測します。
sample_hockey_tweet = """Thank you to the
@Canes
and all you amazing Caniacs that have been so supportive! You guys are some of the best fans in the NHL without a doubt! Really excited to start this new chapter in my career with the
@DetroitRedWings
!!"""
res = openai.Completion.create(model=ft_model, prompt=sample_hockey_tweet + '\n\n###\n\n', max_tokens=1, temperature=0, logprobs=2)
res['choices'][0]['text']
' hockey'
sample_baseball_tweet="""BREAKING: The Tampa Bay Rays are finalizing a deal to acquire slugger Nelson Cruz from the Minnesota Twins, sources tell ESPN."""
res = openai.Completion.create(model=ft_model, prompt=sample_baseball_tweet + '\n\n###\n\n', max_tokens=1, temperature=0, logprobs=2)
res['choices'][0]['text']
' baseball'
以上