ファインチューニングで ChatGPT の出力を自分なりの表現に近づける

ファインチューニングの方法については公式の以下のページに沿って行います。
https://platform.openai.com/docs/guides/fine-tuning

# 大まかな流れ
ファインチューニングの大まかな流れは以下になります。
1. データセットの作成
1. チューニングモデルの作成
1. チューニングモデルの使用

# データセットの作成
### データセットのフォーマット
まずはデータセットの作成を行なっていきます。
データセットはこのようなフォーマットで用意します。
```
{"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What's the capital of France?"}, {"role": "assistant", "content": "Paris, as if everyone doesn't know that already."}]}
{"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "Who wrote 'Romeo and Juliet'?"}, {"role": "assistant", "content": "Oh, just some guy named William Shakespeare. Ever heard of him?"}]}
{"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "How far is the Moon from Earth?"}, {"role": "assistant", "content": "Around 384,400 kilometers. Give or take a few, like that really matters."}]}
```
モデルのチューニングを行うには最低10個のデータセットを用意する必要があります。
また、チューニングの結果は５０〜１００個のトレーニングサンプルを使うことで劇的に改善が結果が現れるようです。
※ユースケースにより結果は異なるとのことですので注意が必要かもしれません。
### データセットの作成
今回は ChatGPT を使ってデータセットを50個作成してもらうことにします。
念の為以下のページの内容を ChatGPT に確認してもらい、ファインチューニングについて知っておいてもらいます。
https://platform.openai.com/docs/guides/fine-tuning
ページの内容をコピペしているだけです。
![スクリーンショット 2023-09-09 21.13.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77379/10ec8528-7647-5875-2664-ef7a390b07dd.png)

データセットの作成を手伝ってもらいたい旨を伝えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77379/cb4a5c56-5613-aed3-ea02-01b60bb6eb67.png)

最終的なゴールを提示します。
今回は私なりのメール文章の作成をゴールとしました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77379/1d0e81a6-a50e-e5f4-9c6f-25e487d77995.png)

詳細な条件を定義します。
粒度がバラバラなところは大目に見て下さいｗ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77379/5175d02e-0838-9e2e-0122-46e7e2c95aed.png)

結果が納得できるものであればそれを元にさらに例を50個(もしくはもっと多く)作成してもらいます。
その後、チューニングに使用する形式(jsonl)に整形してもらいます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77379/0ac02e91-0319-13b8-9388-1461ae3846ff.png)

### データセットファイルの作成
出力結果を「my-tuning.jsonl」のような名前で保存します。
```
$ mkdir fine-tuning
$ cd fine-tuning/
$ vi my-tuning.jsonl
$ ll
-rw-r--r--  1 goto  staff  12928  9  9 21:47 my-tuning.jsonl
```
# チューニングモデルの作成
### ファイルのアップロード
ファイルアップロードのためのコードを作成します。
```python:file-create.py
import os
import openai
openai.api_key = os.getenv("OPENAI_API_KEY")
file_create = openai.File.create(
  file=open("my-tuning.jsonl", "rb"),
  purpose='fine-tune'
)
print(file_create)
```
```
$ vi file-create.py
YoshiakiGOTOnoiMac:fine-tuning goto$ ll
total 40
-rw-r--r--  1 goto  staff    226  9  9 21:50 file-create.py
-rw-r--r--  1 goto  staff  12928  9  9 21:47 my-tuning.jsonl
```
```
$ export OPENAI_API_KEY=OPENAI_API_KEY
YoshiakiGOTOnoiMac:fine-tuning goto$ python3 file-create.py
{
  "object": "file",
  "id": "file-xxxxxxxxxxxxxxxx",
  "purpose": "fine-tune",
  "filename": "file",
  "bytes": 12928,
  "created_at": 1694264288,
  "status": "uploaded",
  "status_details": null
}
```
コードを実行すると上記のようなレスポンスが帰ってきます。
※OPENAI_API_KEY は適宜ご自身ののもに書き換えて下さい。

### チューニングの実行
チューニング実行のため以下のコードを作成します。
「training_file」には、先ほどのレスポンスに記載の id を記入します。
```python:fine-tuning-run.py
import os
import openai

openai.api_key = os.getenv("OPENAI_API_KEY")

result = openai.FineTuningJob.create(training_file="file-xxxxxxxxxxxxxxxx", model="gpt-3.5-turbo")
print(result)
```
```
$ python3 fine-tuning-run.py
{
  "object": "fine_tuning.job",
  "id": "ftjob-xxxxxxxxxxxxxxxx",
  "model": "gpt-3.5-turbo-0613",
  "created_at": 1694264782,
  "finished_at": null,
  "fine_tuned_model": null,
  "organization_id": "org-xxxxxxxxxxxxxxxx",
  "result_files": [],
  "status": "created",
  "validation_file": null,
  "training_file": "file-xxxxxxxxxxxxxxxx",
  "hyperparameters": {
    "n_epochs": 3
  },
  "trained_tokens": null,
  "error": null
}
```
### チューニング状況の確認等
以下の関数を使用することで、チューニングモデルのリスト表示や状況の確認などができます。
```
# List 10 fine-tuning jobs
openai.FineTuningJob.list(limit=10)

# Retrieve the state of a fine-tune
openai.FineTuningJob.retrieve("ft-abc123")

# Cancel a job
openai.FineTuningJob.cancel("ft-abc123")

# List up to 10 events from a fine-tuning job
openai.FineTuningJob.list_events(id="ft-abc123", limit=10)

# Delete a fine-tuned model (must be an owner of the org the model was created in)
openai.Model.delete("ft-abc123")
```
試しに先ほど実行したチューニングを検索してみます。
検索には openai.FineTuningJob.retrieve が使用できます。
```python:fine-tuning-Retrieve.py
import os
import openai

openai.api_key = os.getenv("OPENAI_API_KEY")

result = openai.FineTuningJob.retrieve("ftjob-xxxxxxxxxxxxxxxx")
print(result)
```
実行結果は以下になります。
チューニングが完了すると status が succeeded になります。
まだ、running ですね。
```
$ python3 fine-tuning-Retrieve.py
{
  "object": "fine_tuning.job",
  "id": "ftjob-xxxxxxxxxxxxxxxx",
  "model": "gpt-3.5-turbo-0613",
  "created_at": 1694264782,
  "finished_at": null,
  "fine_tuned_model": null,
  "organization_id": "org-xxxxxxxxxxxxxxxx",
  "result_files": [],
  "status": "running",
  "validation_file": null,
  "training_file": "file-xxxxxxxxxxxxxxxx",
  "hyperparameters": {
    "n_epochs": 3
  },
  "trained_tokens": null,
  "error": null
}
```
チューニングが完了すると以下のようなメールが届きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77379/ef94c808-ff0b-b883-1b87-ada7e3b6967d.png)
# チューニングモデルの使用
チューニングモデルを使用するには model に ft:gpt-3.5-turbo-0613:personal::xxxxxxx を指定します。
```python
MODEL_NAME = "ft:gpt-3.5-turbo-0613:personal::xxxxxxx"
<省略>
completion = openai.ChatCompletion.create(model=MODEL_NAME, messages=conversation)
<省略>
```