本文へスキップ

ファインチューニングよりヘッドの訓練:BANKING77 で 93.1% ​

decidekit 0.2 は BANKING77 のテスト分割で 90.6% から 93.1% に、CLINC150 で 94.6% から 96.1% に上がりました。エンコーダーは変えていません。最初にファインチューニングを試しましたが、開発用分割で BANKING77 が 2.5 ポイント、CLINC150 が 1.2 ポイント下がりました。効果があったのは、その上の小さなヘッドを当てはめる最適化手法を、jimothy の設定を使ったフルバッチの Adam に置き換えることでした。npm install decidekit で新しい訓練を使えます。

テスト精度、全訓練データ0.10.2変化0.1 だけが正解した数0.2 だけが正解した数
BANKING77(77 ラベル)90.62%93.12%+2.5041118
CLINC150(150 ラベル)94.62%96.13%+1.5139107
HWU64(64 ラベル、調整には一切不使用)90.15%91.17%+1.021829

シードは 1 つで、デフォルトモデル(bge-small-en-v1.5)の q8 埋め込みをキャッシュして計測しました。対応のある検定(McNemar のカイ二乗)は、上の 2 行で 36.3 と 30.7 です。HWU64 の 2.1 はこのサイズでは有意ではないので、この行は良い兆候という以上のものではありません。train() を通した計測は eval/results-h14.json にあり、BANKING77 が 93.05%、CLINC150 が 96.29% です。同じ方法で計測した 0.1 は 90.7% と 94.4% でした。

すべての実行、テストの確認記録とスクリプトは eval/spike にあります。ファインチューニングのスクリプトは残しておらず、あるのは結果だけです。

前提 ​

判定は 2 つの部分からなります。34 MB のエンコーダーがテキストをベクトルに変え、ヘッド(softmax の層が 1 つ)がベクトルをラベルの確率に変えます。すべてのヘッドが 1 つのキャッシュ済みエンコーダーを共有するので、ヘッドは小さく(77 ラベルで 118,580 バイト)、ブラウザのタブで訓練できます。

作業を始める前に合格基準を決めました。BANKING77 と CLINC150 の平均で +0.5 ポイント以上、どちらのデータセットとラベルあたり 5 例と 10 例で低下は 0.2 以内とします。さらに、HWU64 が下がらないこと、ラベルあたり 10 例以上で較正誤差が 0.03 以下であることです。調整にはシードで固定した 20% の開発用分割を使いました。最終候補ごとにテスト分割を見たのは 1 回だけで、その後は何も変えていません。

1. ファインチューニングは逆効果でした ​

ファインチューニングには、報告に使うベンチマーク以外の意図データが必要です。これで思った以上に候補が減りました。SLURP の 13,514 件のうち 5,133 件は HWU64 にそのまま含まれています。使ったのは SNIPS(CC0、13,576 件、7 意図)と PAWS の言い換えで、合わせて 41,119 ペアです。MultipleNegativesRanking で 2 エポック訓練し、RTX 5060 で 271 秒かかりました。

訓練の課題そのものでは成功に見えました。取り分けておいた SNIPS での accuracy@1 は 0.949 から 0.985 に上がりました。しかし、本当に必要なデータでは、試した両方のサイズで下がりました。

開発用分割の精度ラベルあたり元のエンコーダーファインチューニング後
BANKING77全部92.45%89.91%
BANKING771085.92%81.48%
CLINC150全部96.63%95.40%
CLINC1501093.22%90.20%

どちらの列も同じ ONNX 書き出しと q8 量子化を通しているので、差の原因は書き出しではありません。検証はしていませんが、原因は大まかな 7 意図と Wikipedia の言い換えだと推測しています。card_arrival と card_delivery_estimate のような細かい違いを、エンコーダーが見分けにくくなったのでしょう。否定できたのは、このデータの組み合わせとこの設定だけです。

2. 改善の大半はヘッドにありました ​

同じく小さな意図分類器である jimothy は、古いエンコーダー all-MiniLM-L6-v2 で BANKING77 の 92.4% を報告しています。実行してみると、それ自身の分割でレポートの値は 92.66% でした。つまり効いているのはエンコーダーより最適化手法だと考え、その設定を私たちのヘッドで試しました。

各行は開発用分割で全データを使った 1 回の実行です。

ヘッドへの変更BANKING77CLINC150
0.1:ミニバッチ SGD、重み減衰 1e-488.46%95.43%
SGD、重み減衰なし90.55%96.30%
ゼロから Adam、lr 0.05、重み減衰なし、100 エポック92.35%96.67%
同じ設定で、ラベルの重心とラベル名から開始92.85%96.90%
ゼロから Adam、400 エポック92.95%96.57%
L-BFGS、試した中で最良の重み減衰(1e-5)92.75%96.67%

BANKING77 では、重み減衰をなくしただけで改善の約半分になり、残りの大半は Adam によるものです。L-BFGS、400 エポック、ラベルスムージングの差は開発用データで 12 問以内でした。シードが 1 つではこの差で順位は付けられないので、100 エポックの実行を採用しました。decidekit がすでに計算している重心から始めると、少ないデータでの優位が保たれます。ゼロからの Adam は、CLINC150 のラベルあたり 5 例でこれを失いました(91.36% から 90.12%)。

3. 少ないデータでは SGD のままです ​

重心から始めても、CLINC150 のラベルあたり 5 例で Adam は 0.29 ポイント下がり、基準を超えました。そこで 0.2 は、ラベルあたり平均 8 例以上で Adam を使い、それ未満では SGD のままにしています。計測したのは 5 例と 10 例で、境界そのものは計測していないので、8 は判断で決めた値です。

テスト精度、3 シードの平均ラベルあたり0.10.2
BANKING771084.43%87.52%
CLINC1501092.16%92.50%
HWU641085.50%85.38%
3 つすべて5変化なし変化なし

代償 ​

  • 訓練時間: Node でキャッシュ済み埋め込みを使うと、BANKING77 は 84 秒から 123 秒に、CLINC150 は 167 秒から 332 秒に増えました。計測中のマシンは他の作業でも負荷がかかっていました。
  • ページの停止: 問題になるものはありません。Ryzen 7 260 のノート PC の Chrome で BANKING77 を最初から最後まで訓練すると 208 秒かかり、最長の停止は 19 ms でした。
  • サイズ: 増えません。ヘッドの形は同じです。
  • 較正: 全データでは悪化しません。3 つのデータセットすべてで誤差は 0.019 以下です。
  • しきい値: 再訓練したヘッドはスコアが変わるので、0.1 で選んだ minConfidence はそのまま使えません。CLINC150 の範囲外判定のしきい値は 0.9 から 0.98 に変わりました。保存済みのヘッドは変更なしで動きます。

ここからは言えないこと ​

  • HWU64 はラベルあたり 10 例で下がりました。 低下は 0.12 ポイントで、3 シード、各 1,076 問のうち 4 問分です。合格基準の「下がらないこと」は少ないデータも含むのかを決めていなかったので、私たちはこれを、受け入れた未達と見ています。ラベルあたり 10 例の HWU64 では、1 つのシードの較正誤差も 0.034 で、上限の 0.03 を超えました。0.1 の最悪のシードは 0.048 でした。
  • 全データの行はシードが 1 つです。 対応のある検定が見ているのはテストセットで、訓練の実行ごとのばらつきではありません。
  • 報告するベンチマークで調整しています。 開発用分割はテストと分けましたが、BANKING77 と CLINC150 が選択に影響したことは変わりません。関わっていないのは HWU64 だけで、その改善幅は最も小さいものです。
  • jimothy に勝ったわけではありません。 93.1% と 92.66% では分割とエンコーダーが異なり、設定は jimothy のものです。jimothy は Node で訓練するので、事前の訓練に向いています。
  • ラベルあたり 5 例は変わりません。 対照学習の層が役立つかもしれませんが、実行していません。ヘッドごとに約 590 KB(見積もり)増えるうえ、ヘッドの変更ですでに基準を超えていたからです。

自分のラベルで実行して、何が変わったかを Discussions で教えてください。

bash
npm install decidekit@latest