nikkie-ftnextの日記

イベントレポートや読書メモを発信

Stability-AI/lm-evaluation-harnessをColabで動かす(cyberagent-open-calm-7bをJCommonsenseQAタスクで評価)

はじめに

エミリーちゃん、お誕生日おめでとうございました!1 nikkieです。

LLMの性能評価に興味を持ち、いくつかある評価ツールの中の1つ、Stability-AI/lm-evaluation-harnessを動かしました。
日本語の1タスクで性能を求めた例であり、車輪の再実装です。

目次

Stability-AI/lm-evaluation-harness

EleutherAI/lm-evaluation-harness2をStability AI社がフォークして、日本語のベンチマークを追加しています。

先日のW&Bミートアップ「LLMの評価方法」のスライドより3

先日構築方法を見たJGLUEもサポートしています

Stability-AI/lm-evaluation-harnessを動かす!

リポジトリで案内されます。
https://github.com/Stability-AI/lm-evaluation-harness/tree/effdbeaf742e74ea1787871e99272c12146ba346#how-to-evaluate-your-model

  1. リポジトリをgit clone
  2. modelsディレクトリ下にあるharness.shを編集
  3. あとはharness.shを叩くだけ!(sh models/.../harness.sh

今回は動かし方を1つ知りたいので、CyberAgentさんのopen-calm-7b4をJCommonsenseQAタスクで性能評価します。
リポジトリLeaderboardには 24.22 というスコアがあります

Colabにてopen-calm-7bをJCommonsenseQAタスクで評価

3bまで落としても無料のColab(T4)だとメモリに載らなかったので、Colab Pro(A100)+7bの組合せとなりました5
ローカルでは3bでスクリプトデバッグをしています(breakpointを入れて中間データを見る)

JCommonsenseQAタスク

JCommonsenseQAは、常識推論能力を評価するための5択のQAタスク。
例えば
「質問:会社の最高責任者を何というか?」に対して
「選択肢:教師、部長、社長、部下、バイト」の中から社長を選べれば正解です。

回答方法ですが、それぞれの選択肢ごとに質問と選択肢をつなげたテキストを作り、それをLLMに入力して文章としてのもっともらしさの数値を得て比較する、という理解です。
一番もっともらしいテキストの選択肢を選ぶわけですね6

W&Bミートアップ「LLMの評価方法」スライドより(右下に注目)

Stability-AI/lm-evaluation-harnessはHugging Face Hubにあるshunk031/JGLUEを使っています。

JCommonsenseQAのvalidationセットは、Hugging Face Hub上では1.12kと表示されます。
質問が1100あり、それぞれ5択ですから、LLMに入力されるテキストは全部でデータセットの5倍(5500)です。
1つの質問に答えるのに、LLMにテキストを5つ入力する必要があるのです。

harness.shの指定

MODEL_ARGS="pretrained=cyberagent/open-calm-7b"
TASK="jcommonsenseqa-1.1-0.2.1"
python main.py --model hf-causal --model_args $MODEL_ARGS --tasks $TASK --num_fewshot "3" --device "cuda" --verbose --output_path "models/cyberagent/cyberagent-open-calm-7b/result.json"

タスクとしての指定はjcommonsenseqa-1.1-0.2.1
リポジトリは0.2.1ではなく0.2だったのですが、以下のwarning7を見たので案内に従いました。

prompt version 0.2 for JCommonsenseQA tends to output low scores! We highly recommend using 0.2.1 instead!

1つ方法が分かればいいのでTASKは1つに絞っています。
合わせてnum_fewshotも対応する1つだけを残しました。
複数タスクを指定して、few-shotのexample数は変えるというのもサポートしています

--verboseを指定すると、間違えたデータが出力されるようになるので、エラー分析に有用そうでした

ローカルで動かすときは--device "cpu"--limitを指定しています。
limitを整数で指定(--limit 5)してデータセットを絞り、デバッグを速いサイクルで回せました。
小数で指定すると全体の何%に絞るかの指定になるようです

few-shot learning

プロンプトはfew-shotです(3つの例が入っています)8

与えられた選択肢の中から、最適な答えを選んでください。

質問:街のことは?
選択肢:
- タウン
- 劇場
- ホーム
- ハウス
- ニューヨークシティ
回答:タウン

質問:必要な機器などを取り付けることをなんという?
選択肢:
- 用意
- ペーパー
- 準備
- 装備
- 針金
回答:装備

質問:ブラウザと言えば?
選択肢:
- ペンタゴン
- 記憶媒体
- 会社
- グーグル
- フロッピー
回答:グーグル

質問:生理現象なのは?
選択肢:
- 準備する
- おしっこする
- 風
- 雨
- ベッドに入る
回答:

このプロンプトを構築する実装は以下にあります。
https://github.com/Stability-AI/lm-evaluation-harness/blob/effdbeaf742e74ea1787871e99272c12146ba346/lm_eval/tasks/ja/jcommonsenseqa.py#L149-L166
jcommonsenseqa-1.1-0.2.1という指定で、このクラスを指定したことになります

評価結果

評価結果はこちら(harness.shの出力の最後の行です):

hf-causal (pretrained=cyberagent/open-calm-7b), limit: None, num_fewshot: [3], batch_size: None
|          Task          |Version| Metric |Value |   |Stderr|
|------------------------|------:|--------|-----:|---|-----:|
|jcommonsenseqa-1.1-0.2.1|    1.1|acc     |0.2681|±  |0.0132|
|                        |       |acc_norm|0.2779|±  |0.0134|

再現していますね!🙌
Accuracyが少しだけ大きくなったのは、指定を0.2.1に変えた効果なのかも。

notebookはこちらです。
LLMの推論(ダウンロード除く)に20分くらいかかりました

終わりに

Stability-AI/lm-evaluation-harnessを使って、JCommonsenseQAタスクのvalidationセットに対して、open-calm-7bの3-shot learningのaccuracyを求められました。
この方法を展開していけば、LLM間で雌雄が決されますね(それがLeaderboard!)

Stability-AI/lm-evaluation-harness(過去時点のEleutherAI/lm-evaluation-harness)のソースコードを今回読んだのですが、色々と勉強になるところはありつつも、Stability AI社がforkして構築したのはどうだったのかなという感想です。

  • TODO: completely refactor this entire function to not be a huge mess, ideally breaking it down into smaller pieces

  • jp-stableブランチですが、執筆時点で「This branch is 266 commits ahead of, 1941 commits behind EleutherAI/lm-evaluation-harness:main.」
    • EleutherAI/lm-evaluation-harness側の最新版を取り込むのがみんな嬉しいんじゃないかと思うけど、果たしてどうやるんだろう?
  • 私的に一番よさそうなのは、EleutherAIのlm-evalに対して日本語評価(仮称 lm-eval-ja)がプラグインの扱いになること
    • EleutherAI側の最新のコードで日本語のタスクが動く!
    • これはforkした今のコードベースだとかなり実現しづらそうなんですよね

日本語LLMの評価タスクは今後も拡充されそうですが、EleutherAI/lm-evaluation-harnessのアップデートへの追従が難しくて、内部品質が低いままなのが今後の発展に対するリスクのように映りました。


  1. 後夜祭です!
  2. lm-evalパッケージとしてインストールできるようでした(インストールは未検証) lm-eval · PyPI
  3. ありがたいことに、YouTubeアーカイブもあります!
  4. 以前にも動かしました
  5. 参考
  6. W&Bミートアップのスライドではもっともらしさの数値5つのsoftmaxを取っています。Stability-AI/lm-evaluation-harnessの実装を追ったところ、loglikelihood(対数尤度。負値)のnumpy.argmaxでした(このあたり)。実装は違いますが、同じ結果になりますよね?(宿題:念のため検証したい9
  7. 送出箇所 https://github.com/Stability-AI/lm-evaluation-harness/blob/effdbeaf742e74ea1787871e99272c12146ba346/lm_eval/tasks/ja/jcommonsenseqa.py#L133-L137
  8. 3例はtraining setから取られるようです。「for sets with no training docs, draw from other set *but ensure no overlap with current doc*」と気を使った実装をしていました
  9. 💡yahoojapan/JGLUEリポジトリのスクリプトを参考にしてもいいかも