さっそくですが
こちらのGoogleフォームからクイズに回答することで、LLMが実際にベンチマークで解かされている問題の一部をみなさんも解き、ChatGPTなどと点数で勝負することができます。記事を読む前に、ぜひチャレンジしてみてください!
本題
この記事は TSG Advent Calendar 2024 の12日目 (+35日遅刻) の記事です。
ChatGPTなどのLLMが台頭する現代、これらのLLMの性能を画一的・数値的に評価するための枠組みも進化しつつあります。その中でも特に日本語を処理する性能について評価するものはあまり多く知られていませんが、その代表的なものとして Weights & Biases 社が公開している「Nejumi LLMリーダーボード3」が存在します。
しかし、実際のところ、このようなLLMの評価メソッドはどのような手法で行われているのでしょうか。そして、LLMはどのようなタスクを処理しているのでしょうか。また、人間が実際にこれらを行うとどの程度の点数が取れるのでしょうか。
LLMモデルを評価する手法が適切であることは、LLMの進化の方向を決定づけるという意味で非常に重要です。なので、そのために使用されているデータセットのクオリティや種別を知ることで、現在のLLMの開発がどのような趣旨で行われているかを知ることができるといえるでしょう。
そこで今回、このLLMリーダーボードにおいてLLMに与えられるのと同じタスクを人間も体験できる、クイズ形式のフォームを作成してみました。また、数名の知人にこれを解いてもらい、どの程度のスコアを獲得できたかを計測しました。このフォームはこちらで公開されており、みなさんも自由に解いてLLMと競うことができるようになっているので、ぜひチャレンジしてみてください。
おことわり
今回作成したGoogleフォームは、原理的に上記のLLMリーダーボードを構築するのと同じ評価手法で人間の回答を評価できるように設計していますが、一部Googleフォームの形式で出題できなかった設問があるほか、そもそも人間側が解くサンプル数が圧倒的に少ないため、LLMと人間を比較する統計的に適切な手法ではありません。 あくまで、LLMがどのようなタスクをこなしているかという雰囲気を掴むためのお遊びとしてお考えください。
設問の設計について
コンセプト
「Nejumi LLMリーダーボード3」(およびその他多くのLLMリーダーボード) では、言語処理の研究で用いられるさまざまなデータセットを同一の手法でさまざまなLLMに入力し、その出力を評価することでLLM同士の比較が行われています。
例えば、「知識・質問応答」の評価軸で用いられているデータセットの一つ、JCommonsenseQAでは、以下のような形式の質問が与えられます。
{
"q_id": 8939,
"question": "電子機器で使用される最も主要な電子回路基板の事をなんと言う?",
"choice0": "掲示板",
"choice1": "パソコン",
"choice2": "マザーボード",
"choice3": "ハードディスク",
"choice4": "まな板",
"label": 2
}
このデータセットでは、質問と選択肢が与えられ、そのうち正解の選択肢のインデックスが label
として与えられています。このデータセットを用いて、LLMに質問を入力し、その出力と label
を比較することで、LLMの性能を評価することができます。
今回のGoogleフォームでも、このような形式の質問を設定し、人間に回答を選択させることで、LLMの性能を評価するのと同じ軸で人間の性能を測定できるようにしました。
なお、本来LLMの性能検証においては訓練用データのリークを防ぐため、訓練用データに含まれないテスト用データのみを用いることが一般的ですが、人間が回答するうえではこのような問題は起きないと考えられるため、このGoogleフォームの作成にあたっては訓練用データとテスト用データを同様に扱っています。
ジャンルと問題の選定について
「Nejumi LLMリーダーボード3」では、十数個程度の評価軸を用いてLLMの性能を評価しています。ですが、一部Googleフォームでの人間の評価に適さない評価軸に関しては今回は採用を見送り、9つの評価軸のみを採用しています。
特に、このリーダーボードには、複数ターンの会話を行い質問への回答を評価する「MT-bench」を用いた評価が多く含まれていますが、これはGoogleフォームを用いた質問形式にそぐわない上、回答の評価にChatGPTなどのハイエンドなLLMを必要とするため、コストの観点からも採用を見送りました。
こうしてフォームの形に落とし込むことが可能な9つの評価軸を選定し、それぞれの評価軸に関して20点満点になるように設問を調整して、計180点満点の評価用フォームを作成しました。
採用した評価軸
- 翻訳
- 情報検索
- 数学的推論
- 抽出
- 知識・質問応答
- 意味解析
- 英語
- 倫理・道徳
- 真実性
採用を見送った評価軸
- 表現: MT-benchのみを評価に用いているため
- 論理的推論: MT-benchのみを評価に用いているため
- 構文解析: データセットのライセンスが不明瞭なため
- 制御性: Googleフォームでの回答収集の形式にそぐわないため
- 毒性: データセットの再頒布が許可されていないため
- バイアス: データセットの再頒布が許可されていないため
- 堅牢性: Googleフォームでの回答収集の形式にそぐわないため
LLMのスコア
2025年1月15日現在「Nejumi LLMリーダーボード3」で公開されている各LLMのジャンルごとの獲得スコアを、評価軸ごとに20点満点となるように正規化し、ランク付けしたところ、TOP20は以下のようになりました (なお、一部の評価軸のみを採用していることから、リーダーボードで公開されている順位とは異なります)。
model_name | 翻訳 | 情報検索 | 数学的推論 | 抽出 | 知識・質問応答 | 英語 | 意味解析 | 倫理・道徳 | 真実性 | 合計 |
---|---|---|---|---|---|---|---|---|---|---|
o1-2024-12-17 | 17.29 | 16.87 | 18.53 | 7.06 | 17.64 | 18.74 | 16.96 | 18.20 | 14.22 | 145.5 |
o1-preview | 17.29 | 16.69 | 18.23 | 7.53 | 17.52 | 18.67 | 16.30 | 18.20 | 12.61 | 143.0 |
anthropic.claude-3-5-sonnet-20241022-v2:0 | 17.38 | 15.78 | 16.70 | 7.36 | 15.88 | 16.84 | 15.86 | 19.40 | 13.81 | 139.0 |
gemini-2.0-flash-exp | 17.42 | 16.00 | 15.73 | 7.33 | 16.41 | 16.91 | 15.22 | 19.00 | 14.54 | 138.6 |
gpt-4o-2024-11-20 | 17.41 | 15.13 | 16.27 | 7.59 | 16.64 | 16.60 | 15.90 | 19.20 | 13.47 | 138.2 |
anthropic.claude-3-5-sonnet-20240620-v1:0 | 17.37 | 16.28 | 16.37 | 7.27 | 16.01 | 16.91 | 15.32 | 19.20 | 13.44 | 138.1 |
gemini-1.5-pro-002 | 17.33 | 16.37 | 15.10 | 6.60 | 16.00 | 17.47 | 15.74 | 18.40 | 14.43 | 137.4 |
gpt-4o-2024-05-13 | 17.37 | 16.39 | 15.80 | 7.31 | 16.56 | 15.47 | 15.76 | 19.00 | 13.54 | 137.2 |
deepseek-chat | 17.39 | 16.81 | 15.87 | 7.11 | 16.08 | 17.40 | 15.74 | 18.40 | 12.41 | 137.2 |
chatgpt-4o-latest | 17.41 | 16.46 | 16.07 | 7.64 | 16.62 | 14.46 | 15.84 | 19.00 | 13.40 | 136.9 |
gpt-4o-2024-08-06 | 17.36 | 16.02 | 16.20 | 7.60 | 16.47 | 14.25 | 15.96 | 19.40 | 12.99 | 136.3 |
anthropic.claude-3-opus-20240229-v1:0 | 17.42 | 15.69 | 13.70 | 7.58 | 15.14 | 15.86 | 14.66 | 19.40 | 12.71 | 132.2 |
Nexusflow/Athene-V2-Agent | 17.20 | 17.78 | 14.67 | 7.32 | 13.97 | 15.58 | 15.86 | 17.80 | 10.89 | 131.1 |
Nexusflow/Athene-V2-Chat | 17.18 | 17.61 | 14.33 | 6.98 | 13.83 | 16.14 | 15.64 | 17.80 | 11.20 | 130.7 |
meta-llama/Meta-Llama-3.1-405B-Instruct-FP8 | 17.34 | 16.93 | 12.53 | 7.07 | 14.95 | 14.70 | 15.62 | 19.00 | 12.37 | 130.5 |
Qwen/Qwen2.5-72B-Instruct | 17.16 | 17.69 | 14.57 | 7.05 | 13.80 | 15.79 | 15.68 | 17.60 | 10.82 | 130.1 |
gemini-1.5-flash-002 | 17.23 | 14.21 | 13.80 | 6.95 | 14.95 | 16.11 | 15.44 | 18.20 | 13.26 | 130.1 |
grok-beta | 17.21 | 16.73 | 14.37 | 6.10 | 14.45 | 16.60 | 14.78 | 19.00 | 10.82 | 130.0 |
gpt-4o-mini-2024-07-18 | 17.26 | 17.57 | 13.70 | 6.85 | 14.06 | 15.09 | 14.68 | 19.40 | 10.96 | 129.6 |
mistralai/Mistral-Large-Instruct-2411 | 17.15 | 15.50 | 14.20 | 6.98 | 14.31 | 15.19 | 15.00 | 19.20 | 11.34 | 128.9 |
完全なランキングは以下のリンクから確認することができます。
人間が解いた結果
この設問をTSGの (人間の) メンバー数名に回答してもらったところ、結果は以下のようになりました。
翻訳 | 情報検索 | 数学的推論 | 抽出 | 知識・質問応答 | 英語 | 意味解析 | 倫理・道徳 | 真実性 | 合計 | |
---|---|---|---|---|---|---|---|---|---|---|
A | 17.73 | 17.80 | 20.00 | 0.00 | 11.00 | 0.00 | 13.00 | 16.00 | 20.00 | 115.5 |
B | 14.04 | 20.00 | 20.00 | 0.00 | 5.00 | 0.00 | 20.00 | 20.00 | 20.00 | 119.0 |
C | 14.99 | 17.80 | 15.00 | 0.00 | 6.00 | 0.00 | 20.00 | 20.00 | 20.00 | 113.8 |
D | 16.58 | 0.00 | 15.00 | 10.00 | 6.00 | 10.00 | 20.00 | 16.00 | 20.00 | 113.6 |
E | 6.43 | 17.80 | 15.00 | 0.00 | 5.00 | 10.00 | 20.00 | 20.00 | 20.00 | 114.2 |
F | 14.40 | 20.00 | 10.00 | 0.00 | 3.00 | 0.00 | 13.00 | 20.00 | 20.00 | 100.4 |
G | 13.31 | 20.00 | 15.00 | 0.00 | 6.00 | 10.00 | 13.00 | 16.00 | 20.00 | 113.3 |
人間平均 | 13.9 | 16.2 | 15.7 | 1.4 | 6.0 | 4.3 | 17.0 | 18.3 | 20.0 | 112.8 |
「LLMベンチマークを人間が解く」の技術的裏側
今回作成したGoogleフォームでは、単純な選択肢問題だけでなく、自由記述の設問があり、送信した回答はLLMに対して行うのと同じ手法で自動的に採点されます。この仕組みを構築するために多少のエンジニアリングが必要でしたので、知見を共有します。
Googleフォームへの提出を監視する
「Nejumi LLMリーダーボード3」と同様の手法で自由記述の設問を評価するには、翻訳の採点に特化したモデル (COMET) や、真実性の採点に特化したモデル (nlp-waseda/roberta_jtruthfulqa) を動作させる必要があります。これはGoogleフォームの機能で完結させることが難しいため、採点用の外部のサーバーを用意し、フォームへの回答があるたびにそのサーバーに通知を送る仕組みを作成しました。
Googleフォームへの提出を監視するためには、Googleフォームに紐づけられた Google Apps Script から外部のURLにリクエストを飛ばす必要があります。
const POST_URL = "XXXXXXXXXX";
const API_KEY = "XXXXXXXXXX";
function onSubmit(e) {
const itemResponses = e.response.getItemResponses();
const responseId = e.response.getId();
const responseTimestamp = e.response.getTimestamp();
const items = [];
for (const itemResponse of itemResponses) {
const item = itemResponse.getItem();
const response = responses[i].getResponse();
items.push({
item: {
title: item.getTitle(),
id: item.getId(),
index: item.getIndex(),
type: item.getType(),
},
response,
});
}
UrlFetchApp.fetch(POST_URL, {
method: "post",
contentType: "application/json",
payload: JSON.stringify({
token: API_KEY,
id: responseId,
timestamp: responseTimestamp,
itemResponses: items,
})
});
};
回答の採点を行う
採点用のサーバーは、Google Apps Script から送られてきた回答を受け取り、COMETやroberta_jtruthfulqaを用いて採点を行います。今回は回答の通知のために Firebase Cloud Functions 経由で Google Cloud Pub/Sub を叩き、ワーカープロセスである採点サーバーに通知するようにしました。
採点結果をGoogleフォームに反映する
採点結果は、Googleフォームでテストを作成することができる機能を使い、回答の点数として反映させます。回答の点数を設定するAPIは、調べた範囲では Google Apps Script 経由でしか叩くことができないようなので、採点結果を反映する専用のエンドポイントを作成し、そこに採点結果を送信するようにしました。
// 採点結果をGoogleフォームに反映する
function doPost(e) {
const {id, scores} = JSON.parse(e.postData.contents);
const form = FormApp.getActiveForm();
const formResponse = form.getResponse(id);
const itemResponses = formResponse.getItemResponses();
let updatedItems = 0;
for (const score of scores) {
const item = itemResponses.find((item) => item.getItem().getId() === score.id);
if (item) {
if (item.getItem().getType() === FormApp.ItemType.TEXT) {
const textItem = item.getItem().asTextItem();
const points = textItem.getPoints();
item.setScore(score.score * points);
formResponse.withItemGrade(item);
updatedItems++;
} else if (item.getItem().getType() === FormApp.ItemType.PARAGRAPH_TEXT) {
const paragraphItem = item.getItem().asParagraphTextItem();
const points = paragraphItem.getPoints();
item.setScore(score.score * points);
formResponse.withItemGrade(item);
updatedItems++;
}
}
}
FormApp.getActiveForm().submitGrades([formResponse]);
const output = ContentService.createTextOutput(JSON.stringify({result:"ok",updatedItems}));
output.setMimeType(ContentService.MimeType.JSON);
return output;
}