ファイナンシャル・プランニング技能検定試験問題で LLM を Fine-tuning してみた / OpenAI Fine-tuning API 編

Web 上で公開されているファイナンシャル・プランニング技能検定（FP 技能検定）の過去問題を用いて、LLM を Fine-tuning した際の効果を検証しました。

今回は OpenAI が公開している Fine-tuning API を用いて、GPT-3.5-turbo および GPT-4o-mini の Fine-tuning を行った過程を紹介します。
また、OpenAI Evals および llm-jp-eval を用いた Fine-tuning 前後でのタスク性能の検証についても紹介します。

## タスク設計

今回は、定量的な評価のしやすさから、多肢選択問題のみによって構成されている 3 級および 2 級の FP 技能検定の学科試験を解くこととしました。
以下に学科試験問題の例を示します。

### 3 級 FP 技能検定 学科試験

3 級の FP 技能検定学科試験では、2 つの大問が設定されています。

大問１では、与えられた文章が適切か・不適切かを回答する正誤（二肢択一）問題が 30 問出題されます。

```text
【第１問】 次の各文章（(1)～(30)）を読んで、正しいものまたは適切なものには①を、誤っているものまたは不適切なものには②を、解答用紙にマークしなさい。〔30問〕

(1) 公的介護保険の第２号被保険者は、要介護状態または要支援状態となった原因を問わず、保険給付を受けることができる。
```
3級FP技能検定学科試験 第1問の出題例 / 出典：日本FP協会 3級ファイナンシャル・プランニング技能検定学科試験（2021 年 5 月）

大問２では、空欄を含む文章が与えられ、その空欄に当てはまる適切な語句・数値・またはその組み合わせを 3 つの選択肢の中から 1 つを選択する三肢択一問題です。こちらも 30 問出題されます。

```text
【第２問】 次の各文章（(31)～(60)）の（ ）内にあてはまる最も適切な文章、語句、数字またはそれらの組合せを1)～3)のなかから選び、その番号を解答用紙にマークしなさい。 〔30問〕

(31) 一定の利率で複利運用しながら一定期間経過後に目標とする額を得るために必要な毎年の積立額を試算する際、目標とする額に乗じる係数は、（　　　）である。
1) 現価係数
2) 資本回収係数
3) 減債基金係数
```
3級FP技能検定学科試験 第2問の出題例 / 出典：日本FP協会 3級ファイナンシャル・プランニング技能検定学科試験（2021 年 5 月）

### 2 級学科試験 学科試験

一回の試験につき、問題文とともに 4 つの選択肢が与えられ、選択肢の中から 1 つの回答を選択する四肢択一問題が 60 問出題されます。

```text
問題1 ファイナンシャル・プランナー（以下「ＦＰ」という）の顧客に対する行為に関する次の記述のうち、関連法規に照らし、最も不適切なものはどれか。

１．弁護士の資格を有しないＦＰのＡさんは、顧客から成年後見制度について相談を受け、法定後見制度と任意後見制度の違いについて一般的な説明をした。
２．税理士の資格を有しないＦＰのＢさんは、顧客から所得税の医療費控除について相談を受け、実際に支払った医療費のうち、保険金などで補てんされる金額については医療費控除の対象とならないことを説明した。
３．社会保険労務士の資格を有しないＦＰのＣさんは、顧客から老齢基礎年金の繰下げ受給について相談を受け、顧客の「ねんきん定期便」の年金受取見込額を基に、繰り下げた場合の年金額を試算した。
４．金融商品取引業の登録を受けていないＦＰのＤさんは、顧客と資産運用に関する投資助言契約を締結したうえで、値上がりが期待できる株式の個別銘柄の購入を勧めた。
```
2級FP技能検定学科試験の出題例 / 出典：日本FP協会 2級ファイナンシャル・プランニング技能検定学科試験（2021 年 5 月）

## データセット作成

### PDF からテキストのパース

Web ページ[^1]上で公開されていた PDF 形式のファイルからプレーンテキストを抽出し、問題文と回答のペアを作成しました。
このペアを作成する際に、問題文については、例えば「その番号を解答用紙にマークしなさい」のような、プロンプトとして入力するには不自然な表現に対して修正を施しています。

[^1]: <https://www.jafp.or.jp/exam/mohan/>

| データセット | 実施時期                     | 件数 |
| ------------ | ---------------------------- | ---- |
| Train        | 2021 年 5 月 〜 2023 年 5 月 | 840  |
| Dev          | 2023 年 9 月                 | 116  |
| Test         | 2024 年 1 月                 | 117  |

学科試験問題の中には、図や表で与えられる情報をもとに回答をする問題も含まれています。
今回は、Train データについてはそのような問題のテキストもそのまま利用しました。
一方、Dev データと Test データに含まれているそのような問題のテキストは人手で除外しました。

### JSON Lines へ整形

OpenAI の Fine-tuning API を利用するためには、データセットを所定のフォーマット（JSON Lines）に整形する必要があります。
入力形式についての詳細は[^2]をご確認ください。

[^2]: <https://platform.openai.com/docs/guides/fine-tuning/preparing-your-dataset>

今回は、システムプロンプトに指示文を、ユーザープロンプトに問題文と選択肢を、アシスタントの出力に正答をそれぞれ設定しました。
以下にサンプルとして JSON Lines から 1 行抽出し、改行とインデントを設定したものを示します。

```json
{
  "messages": [
    {
      "role": "system",
      "content": "問題に対する答えを選択肢から1つ選び、その番号と内容を出力しなさい。"
    },
    {
      "role": "user",
      "content": "ファイナンシャル・プランナー（以下「ＦＰ」という）の顧客に対する行為に関する次の記述のうち、関連法規に照らし、最も不適切なものはどれか。\n\n１．弁護士の資格を有しないＦＰのＡさんは、顧客から成年後見制度について相談を受け、法定後見制度と任意後見制度の違いについて一般的な説明をした。\n２．税理士の資格を有しないＦＰのＢさんは、顧客から所得税の医療費控除について相談を受け、実際に支払った医療費のうち、保険金などで補てんされる金額については医療費控除の対象とならないことを説明した。\n３．社会保険労務士の資格を有しないＦＰのＣさんは、顧客から老齢基礎年金の繰下げ受給について相談を受け、顧客の「ねんきん定期便」の年金受取見込額を基に、繰り下げた場合の年金額を試算した。\n４．金融商品取引業の登録を受けていないＦＰのＤさんは、顧客と資産運用に関する投資助言契約を締結したうえで、値上がりが期待できる株式の個別銘柄の購入を勧めた。"
    },
    {
      "role": "assistant",
      "content": "４．金融商品取引業の登録を受けていないＦＰのＤさんは、顧客と資産運用に関する投資助言契約を締結したうえで、値上がりが期待できる株式の個別銘柄の購入を勧めた。"
    }
  ]
}
```
問題文の出典：日本FP協会 2級ファイナンシャル・プランニング技能検定学科試験（2021 年 5 月）を加工して作成

なお、作成した JSONLines が Fine-tuning API の仕様に沿っているかをチェックするソースコードが、OpenAI Cookbook [^3]で紹介されています。
Fine-tuning API を手元のデータで試される方は、データ整形の後でこちらも試されると良いかもしれません。

[^3]: <https://cookbook.openai.com/examples/chat_finetuning_data_prep>

### データセットのアップロード

JSON Lines に整形したデータセットは、OpenAI プラットフォームへアップロードします。
アップロードの方法は 2 種類あり、1 つは OpenAI の Files エンドポイント [^4] を介する方法と、OpenAI ダッシュボードの Storage メニュー[^5] からアップロードをする方法です。

[^4]: <https://platform.openai.com/docs/api-reference/files>
[^5]: <https://platform.openai.com/storage/>

今回は OpenAI Python API ライブラリ [^6] (v1.30.4) を用いて、Files エンドポイントから Train と Dev のデータセットをアップロードします。
ただ、後述しますがアップロード後にダッシュボードへアクセスする必要があるので、最初からそちらを使った方が楽かもしれません。

[^6]: <https://pypi.org/project/openai/>

```python:upload_dataset.py
import argparse
import os

from dotenv import load_dotenv
from openai import OpenAI


def main(input_jsonl_path):
    load_dotenv()
    assert os.getenv("OPENAI_API_KEY")
    assert os.getenv("ORGANIZATION_ID")

    client = OpenAI(organization=os.getenv("ORGANIZATION_ID"))
    client.files.create(file=open(input_jsonl_path, "rb"), purpose="fine-tune")


if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("input_jsonl_path", type=str)
    args = parser.parse_args()
    main(args.input_jsonl_path)
```

上記のコードでは、API キーと Organization ID を .env ファイルに保存してある前提のもとで、python-dotenv [^7] でそれらを環境変数として読み込んでいます。もちろん、これ以外の方法で API キー等を指定しても結果は変わりません。

[^7]: <https://pypi.org/project/python-dotenv/>

```sh
$ python upload_dataset.py \
      --input_jsonl_path "dataset/fp-exam_train.jsonl"
$ python upload_dataset.py \
      --input_jsonl_path "dataset/fp-exam_dev.jsonl"
```

アップロードが成功すると、OpenAI ダッシュボードの Storage メニューから、前の手順でアップロードしたデータセットの File ID が確認できます。
Fine-tuning のジョブを登録する際に、どのデータセットを使ってモデルを学習するか File ID によって指定する必要があるので、Train と Dev のそれぞれのデータセットに割り振られた File ID （`file-` から始まる 29 文字の識別子）を記録しておきます。

## Fine-tuning ジョブの登録

Fine-tuning の方法もファイルのアップロードと同様に、エンドポイントを介してジョブを登録する方法と、OpenAI ダッシュボードの Fine-tuning メニュー[^8] からジョブを登録する 2 つの方法があります。
こちらでも OpenAI Python API ライブラリ (v1.30.4) を用いて、 Fine-tuning ジョブを登録してみます。

[^8]: <https://platform.openai.com/finetune>

```python:create_finetuning_job.py
import argparse
import os

from dotenv import load_dotenv
from openai import OpenAI


def main(args):
    load_dotenv()
    assert os.getenv("OPENAI_API_KEY")
    assert os.getenv("ORGANIZATION_ID")

    client = OpenAI(organization=os.getenv("ORGANIZATION_ID"))
    client.fine_tuning.jobs.create(
        training_file=args.training_file_id,
        model=args.model,
        hyperparameters={
            "batch_size": args.batch_size,
            "learning_rate_multiplier": args.learning_rate_multiplier,
            "n_epochs": args.n_epochs,
        },
        suffix=args.suffix,
        validation_file=args.validation_file_id,
        seed=args.seed,
    )


if __name__ == "__main__":

    parser = argparse.ArgumentParser()
    parser.add_argument("--model", required=True, type=str)
    parser.add_argument("--training_file_id", required=True, type=str)
    parser.add_argument("--validation_file_id", required=False, type=str)
    parser.add_argument("--suffix", required=False, type=str)
    parser.add_argument("--batch_size", type=str, default="auto")
    parser.add_argument("--learning_rate_multiplier", type=str, default="auto")
    parser.add_argument("--n_epochs", type=str, default="auto")
    parser.add_argument("--seed", type=int, default=42)
    args = parser.parse_args()
    main(args)
```

```sh
$ python src/create_finetuning_job.py \
      --training_file_id "<TrainデータのFile ID>" \
      --validation_file_id "<DevデータのFile ID>" \
      --suffix "fp-exam" \
      --batch_size 4 \
      --learning_rate_multiplier 0.8 \
      --n_epochs 3 \
      --model "gpt-3.5-turbo-0613" \
      --seed 42
```

指定できる引数やパラメータについては、API reference [^9] をご確認ください。
今回の実験では、GPT-3.5-Turbo の学習パラメータとして上記引数で設定した値 (`epochs=3, batch_size=4, learning_rate_multiplier=0.8, seed=42`) を設定しました。GPT-4o-mini については、`learning_rate_multiplier` のみ 0.6 に設定し、それ以外のパラメータについては上記と同じ値を設定しました。

[^9]: <https://platform.openai.com/docs/api-reference/fine-tuning/create>

登録された Fine-tuning ジョブは、ダッシュボードから loss の遷移などをリアルタイムで確認することができます。
また、Fine-tuning ジョブが終了（成功または失敗）した際には、メールによる通知が行われます。

Fine-tuning が成功すると、ダッシュボード上で Succeeded というステータスラベルが表示されると同時に、Output model の項目に文字列（`ft:gpt-4o-mini-` や、`ft:gpt-3.5-turbo-`から始まる識別子）が表示されます。
この文字列が Fine-tuning されたモデルの ID です。
以後はこのモデル ID を使って性能の検証を行います。

## Test データにおける性能評価（OpenAI Evals による評価）

今回は OpenAI Evals[^10] (v3.0.1.post1) を用いて、Test データセットにおける Fine-tuning 前後のモデル性能の評価を行いました。

[^10]: <https://github.com/openai/evals>

### Test データセットの準備

OpenAI Evals では、OpenAI プラットフォームに登録した際とはまた別のフォーマットに従った JSON Lines が必要になります。
具体的には、各データポイントに `input` と `ideal` の 2 つの属性を定義し、前者には言語モデルに入力する文字列を、後者には出力すべき文字列をそれぞれ設定する必要があります。
入力形式についての詳細は[^11]ご確認ください。

[^11]: <https://github.com/openai/evals/blob/main/docs/build-eval.md#formatting-your-data>

以下にサンプルとして、OpenAI Evals 用の JSON Lines から 1 行抽出し、改行とインデントを設定したものを示します。

```json
{
  "input": [
    {
      "role": "system",
      "content": "次の文章を読んで、正しいものまたは適切なものには①を、誤っているものまたは不適切なものには②を、出力しなさい。"
    },
    {
      "role": "user",
      "content": "弁護士の登録を受けていないファイナンシャル・プランナーが、資産管理の相談に来た顧客の求めに応じ、有償で、当該顧客を委任者とする任意後見契約の受任者となることは、弁護士法に抵触する。"
    }
  ],
  "ideal": "②"
}
```
問題文の出典：日本FP協会 3級ファイナンシャル・プランニング技能検定学科試験（2024 年 1 月）を加工して作成

### Yaml の作成

Evals では、評価指標やデータセットを Yaml ファイル上で定義して評価を実行します。
今回は GPT モデルの出力と ideal の属性値が一致するかどうかを基に評価したいため、評価指標として accuracy を指定した Match eval を定義します。
また、今回は評価タスクの名前と、Test データセットのパスを、それぞれ `fp-exam`、 `fp-exam/samples.json` とします。
これらの定義値はまた後ほど参照します。

```yaml
fp-exam:
  id: fp-exam.dev.v0
  metrics: [accuracy]

fp-exam.dev.v0:
  class: evals.elsuite.basic.match:Match
  args:
    completion_fns: [OpenAIChatCompletionFn]
    samples_jsonl: fp-exam/samples.jsonl
```

Yaml の各属性については、[^12] 等を参照してください。

[^12]: <https://github.com/openai/evals/blob/main/docs/build-eval.md#registering-the-eval>

### 各ファイルの配置

作成した Test データセットと Yaml は、所定のディレクトリ構造を持つレジストリ（今回は registry という名前のディレクトリを用意します）の中に配置します。

Yaml は registry/evals の中に格納します。
ファイル名は <評価タスク名>.yaml とする必要があるため、今回は `fp-exam.yaml` となります。

Test データセット (samples.json) は、Yaml で `samples_json` の属性で定義したパス構造を保ちながら、registry/data の中に配置します。
今回は Yaml の中でデータセットのパスを `fp-exam/samples.jsonl` として定義しているので、パスは `registry/data/fp-exam/samples.jsonl` となります。

全体のパス構造は以下となります。

```text
registry/
├── data
│   └── fp-exam
│       └── samples.jsonl
└── evals
    └── fp-exam.yaml
```

### Evals のソースコード修正

OpenAI Evals では、ソースコード中で事前に定義された接頭辞を持つモデルのみが OpenAI ChatCompletions モデルとして認識されて、適切なクラスによってインスタンス化がされます。
今回の評価で用いる Evals v3.0.1.post1 では、登録されている接頭辞だけでは OpenAI プラットフォーム上で Fine-tuning されたモデルを OpenAI ChatCompletions モデルとして正しく認識できないため、ライブラリのソースコードを直接編集して、接頭辞を追加します。

編集箇所は、`<PathToYourPythonLib>/site-packages/evals/registry.py` の 103 行目付近にある以下の部分です。

```diff_python
-     for model_prefix in {"gpt-3.5-turbo-", "gpt-4-"}:
+     for model_prefix in {"gpt-3.5-turbo-", "gpt-4-", "ft:gpt-3.5-turbo-", "ft:gpt-4o-mini-"}:
```

### Evals の実行

Evals の実行はターミナル上から行います。

デフォルトでは、Evals は並行処理によって高速に評価が完了するように挙動しますが、短時間で何度も同じ API を呼び出すことになるため、OpenAI API のレート制限に達しやすくなります。
この振る舞いは、所定の環境変数を定義することで変更することができます。
以下に、評価をシーケンシャルに実行しつつ、タイムアウトの閾値を 120 秒と設定する場合の環境変数の設定例を示します。

```sh
$ export EVALS_THREADS=1
$ export EVALS_SEQUENTIAL=1
$ export EVALS_THREAD_TIMEOUT=120
```

必要に応じて環境変数を定義したのち、oaieval コマンドから評価を実行します。
Fine-tuning 済みのモデルの評価を行う際には、oaieval の第一引数に Fine-tuning 済みモデルの ID を設定すれば良いです。
評価結果は `--record_path` で設定したパスに JSON Lines が出力されます。

```sh
$ model_name="gpt-3.5-turbo-0613"
$ eval_name="fp-exam"
$ oaieval \
    ${model_name} \
    ${eval_name} \
    --registry_path registry \
    --record_path "log/${eval_name}_${model}.jsonl"
```

### 実験結果

#### 正答率

まずは Fine-tuning 前後で全体の正答率がどのように変化したのか、以下の表で示します。
なお、ここでは 3 級と 2 級といった問題の区別はつけず、全ての問題のうち正答することのできた問題の割合を示しています。

また、GPT-4o-mini の性能評価および Fine-tuning には、2024 年 7 月 18 日にリリースされたモデルを利用しています。
つまり、今回の Test データは 2024 年 1 月に実施された FP 技能検定の問題であるため、GPT-4o-mini の学習データに今回用いた Test データがリークしている可能性がある点に留意が必要です。

| モデル名（バージョン）                 | 正答率 |
| -------------------------------------- | :----: |
| Fine-tuning 済み： GPT-4o-mini         | 0.701  |
| Fine-tuning 済み：GPT-3.5-Turbo        | 0.521  |
| ベースモデル：GPT-3.5-Turbo (0613)     | 0.325  |
| ベースモデル：GPT-4o-mini (2024-07-18) | 0.308  |

正答率を Fine-tuning 前後で比較した結果、GPT-3.5-turbo と GPT-4o-mini のいずれにおいても、Test データセットに対する正答率はベースモデルと比べて Fine-tuning 済みモデルがより高くなる結果となりました。

ベースモデルのみを比較すると、後からリリースされた GPT-4o-mini が GPT-3.5-Turbo よりも（その差は大きくないですが）正答率では劣る点が興味深いです。
しかし、Fine-tuning することで GPT-4o-mini の正答率は GPT-3.5-Turbo の正答率を約 0.2 ポイント分超えることから、モデルの持つ性能は GPT-4o-mini がより高いのかなと思われます。

#### 指示追従性能

次に、Fine-tuning 前後の指示追従性能の変化について詳しくみていきます。

今回のタスクでは、与えられた選択肢の中から回答を出力するよう指示をしているので、GPT モデルは選択肢のいずれかと完全一致する文字列を出力することが期待されます。
しかし、Chain of Thought のように回答に至るまでの検討過程を出力したり、正解選択肢が無いとして回答を拒否したり、GPT が指示に追従せずに選択肢に含まれない文字列が出力がされることも考えられます。

以下は、ベースモデルが指示に追従しなかった一方で、Fine-tuning 済みモデルが指示に追従することのできた事例です。

```text
次の文章の（    ）内にあてはまる最も適切な文章、語句、数字またはそれらの組合せを1)～3)のなかから選び、その番号と内容を出力しなさい。

表面利率（クーポンレート）４％、残存期間５年の固定利付債券を額面100円当たり104円で購入した場合の最終利回り（年率・単利）は、（      ）である。なお、税金等は考慮しないものとし、計算結果は表示単位の小数点以下第３位を四捨五入している。

1) 3.08％
2) 3.20％
3) 3.33％

--------------------------------
正答：
1) 3.08％

GPT-4o-mini の出力：
最終利回り（年率・単利）を計算するためには、以下の式を使用します。<br><br>最終利回り = (クーポン収入 + (額面 - 購入価格) / 残存年数) / 購入価格<br><br>ここで、クーポン収入は額面100円に対して4%の利率なので、4円です。残存期間は5年、購入価格は104円です。<br><br>計算を行います。<br><br>1. クーポン収入 = 4円<br>2. 額面 - 購入価格 = 100円 - 104円 = -4円<br>3. 年間の損失 = -4円 / 5年 = -0.8円<br><br>したがって、<br><br>最終利回り = (4円 - 0.8円) / 104円 = 3.2円 / 104円 ≈ 0.030769<br><br>これをパーセントに直すと、約3.08%になります。<br><br>したがって、正しい選択肢は：<br><br>1) 3.08％

Fine-tuning 済みの GPT-4o-mini の出力：
1) 3.08％
```
問題文の出典：日本FP協会 3級ファイナンシャル・プランニング技能検定学科試験（2024 年 1 月）を加工して作成

そこで、指示に追従する/しない件数が Fine-tuning によってどのように変化するかを確認します。

| 指示不追従の件数                                 | GPT-3.5-Turbo | GPT-4o-mini |
| ------------------------------------------------ | ------------: | ----------: |
| ベースモデルが指示に追従しなかった問題 (1)       |   10 / 117 問 | 59 / 117 問 |
| (1) のうち、Fine-tuning 済みモデルが正答した件数 |     6 / 10 問 |  37 / 59 問 |
| Fine-tuning 済みモデルが指示に追従しなかった問題 |    0 / 117 問 |  0 / 117 問 |

まず GPT-3.5-Turbo に着目すると、ベースモデルは 117 問中 10 問において指示に沿わない出力をしました。
このモデルに Fine-tuning を行うと、この指示に不追従であった 10 問において 6 問に正答できました。
また、Fine-tuning によって指示に沿わない出力をする件数をゼロにすることができました。

一方で、GPT-4o-mini の指示不追従件数は 59 件となりました。
この 59 件の事例において多くで見られたのは、全角数字が使われている選択肢記号について、半角数字を使って GPT-4o-mini が出力したことによる正解文字列との不一致によるものでした。
例えば、`１．選択肢その一` として出力すべき場面で、`1．選択肢その一` のように先頭の数字文字が半角になるといった具合です。
GPT-4o-mini においても Fine-tuning を行うことで、ベースモデルが指示に追従しなかった問題 59 問のうち 37 問に正答できるようになり、かつ指示に沿わない出力をする件数をこちらもゼロにすることができました。

OpenAI は Fine-tuning によって見込める効果として、出力のフォーマットや語気の固定、期待する出力がなされるための信頼性の向上、といった点を謳っています [^13]。
今回の実験からも、GPT-3.5-Turbo / GPT-4o-mini いずれにおいても指示不追従の件数をゼロにすることができた点は、こういった Fine-tuning の効果が期待通り現れたのだと思います。

また、GPT-3.5-Turbo は Fine-tuning によって指示追従性能が向上し、正答数が 6 件増加しましたが、全体の正答率も約 0.2 ポイント（約 23 問分）向上しています。
GPT-4o-mini でも同様に、指示追従性能の向上により正答数が 37 件増加した一方で、全体の正答率は約 0.4 ポイント（約 47 問分）向上しました。
これらの結果から、いずれのモデルにおいても Fine-tuning によって指示追従性能だけでなく、ファイナンシャル・プランニング技能検定に関する知識の向上も正答率の改善に寄与している可能性が示唆されます。

[^13]: <https://platform.openai.com/docs/guides/fine-tuning/common-use-cases>

## その他の日本語タスクにおける性能評価（llm-jp-eval による評価）

FP 技能検定の過去問を用いて Fine-tuning された GPT モデルは、FP 技能検定における性能が向上することが確認できました。
他方、Fine-tuning によって一部の能力や性能が低下するのではないかと考え、Fine-tuning 前後でさまざまなタスクにおける性能の変化を調査しました。

ここでのタスク性能の評価には、LLM-jp が作成・公開している llm-jp-eval [^14] (v1.3.0)を用いました。
評価対象のタスク・データセットは、Nejumi LLM リーダーボード Neo [^15] に倣い、NLI・QA・RC・MC・EL・FA・MR の 7 種類のタスクを対象として、各データセットの test データ 100 問 における平均の zero-shot 性能を評価しました。

[^14]: <https://github.com/llm-jp/llm-jp-eval>
[^15]: <https://wandb.ai/wandb-japan/llm-leaderboard/reports/Nejumi-LLM-Neo--Vmlldzo2MTkyMTU0>

### 結果

| モデル                          | 平均  |  NLI  |  QA   |  RC   |  MC   |  EL   |  FA   |  MR   |
| ------------------------------- | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: |
| gpt-4o-2024-05-13 \*            | 0.649 | 0.792 | 0.442 | 0.845 | 0.970 | 0.292 | 0.256 | 0.950 |
| gpt-4-0613 \*                   | 0.646 | 0.768 | 0.415 | 0.891 | 0.960 | 0.300 | 0.220 | 0.970 |
| Fine-tuning 済み：GPT-4o-mini   | 0.645 | 0.748 | 0.472 | 0.877 | 0.940 | 0.363 | 0.207 | 0.910 |
| gpt-4-turbo-2024-04-09 \*       | 0.634 | 0.734 | 0.461 | 0.762 | 0.960 | 0.308 | 0.256 | 0.960 |
| ベースモデル：GPT-4o-mini       | 0.628 | 0.738 | 0.385 | 0.867 | 0.940 | 0.354 | 0.211 | 0.900 |
| Fine-tuning 済み：GPT-3.5-Turbo | 0.559 | 0.584 | 0.371 | 0.851 | 0.850 | 0.326 | 0.184 | 0.750 |
| ベースモデル：GPT-3.5-Turbo \*  | 0.516 | 0.560 | 0.272 | 0.841 | 0.790 | 0.291 | 0.187 | 0.670 |

モデル名に続く \* は、Nejumi LLM リーダーボード Neo に掲載されているスコアを引用していることを表します。

FA タスクでは若干の性能低下が見られますが、他のタスクでは Fine-tuning 済みモデルはベースモデルの性能を上回る結果となりました。
特に、Fine-tuning 済みの GPT-4o-mini は gpt-4-turbo-2024-04-09 を平均スコアで上回る性能を達成しました。
FP 技能検定の過去問題しか学習させていないのにも関わらず、ベースモデルと比べて他の日本語タスクの性能も向上した点はとても興味深いです。

## 所感

今回の実験では、用意した学習データセットの規模が小さいため、出力テキストの文体や形式といった表層的な出力を制御できても、正答率の向上につながるような知識獲得は難しいのではないかと考えていました。

ところが、実際に Fine-tuning をしてみると指示追従性能の向上以外にも、新たな知識獲得が起因しているように見える正答率の向上が見られ、意外な結果となりました。
一方で、Fine-tuning によって指示不追従の件数を 0 にすることができたことから、出力テキストを期待する形式に整えるという観点において期待通りの結果となりました。

また、FP 技能検定の問題で Fine-tuning した GPT モデルが、llm-jp-eval においてもベースモデルの性能を超えた点が興味深かったです。
これについては、ファイナンシャル・プランニングという特定のドメインに関するデータではあるものの、日本語で作成されたテキストで GPT モデルが学習されることで、GPT が事前学習で獲得した日本語に関する知識・テキスト生成能力が呼び起こされやすくなったのかなと想像しています。