採点役を信じる前に確かめる
採点役とは、別のモデルの答えを採点するモデルのことです。安上がりなので、多くのチームが使います。けれど採点役には、誰にも見えないかたよりがあるかもしれません。
評価とテストのモジュールでは、採点役と人との一致を扱いました。ここでは、三つのテストを数字で進めます。
このレッスンのゴール
メモ
採点役を頼る前に、そのかたよりを調べられる。
キーワード
| ことば | いみ |
|---|---|
| 採点役 | 答えを採点するモデル |
| カッパ | 偶然で得られる分を除いた、人との一致 |
| 位置のかたより | 答えでなく、並ぶ枠に引かれること |
| 長さのかたより | 長い答えに引かれること |
| 見本の採点 | 採点役を試すために、人が先に採点した答え |
学生が入力するセルは、このプレビューでは空白です。
一致だけでは足りない
採点役が、人と 90 パーセント一致したとします。よさそうに聞こえます。でも合格の答えが大半なら、いつも合格と言う採点役も、高い一致になります。
カッパは、偶然の分を引きます。1 は完全な一致で、0 は偶然と同じ程度の一致です。
例: 採点した 20 の答え
| 項目 | 値 | 求め方 |
|---|---|---|
| 項目の数 | 20 | 数える |
| 採点役と人が合った数 | 18 | 一致は 90 パーセント |
| 偶然に合う数(400 倍) | 296 | p の数どうしの積と、f の数どうしの積の和 |
| カッパ | 0.62 | (360 引く 296)割る(400 引く 296) |
学生が入力するセルは、このプレビューでは空白です。
よくある間違い
注意
一致が高ければ、採点役は信頼できると考える人が多いです。片方のラベルがずっと多いときは、そうとは限りません。カッパを出し、どのラベルも十分にある見本を使いましょう。
順番を入れ替えて位置のかたよりを見る
採点役に、答え X と Y をこの順で見せ、選びを記録します。次に、Y と X の順で見せます。かたよりのない採点役は、どちらでも同じ答えを選びます。
選びが変われば、枠に従っています。変わった数を数え、事例の四分の一以上なら旗を立てます。
長い方が勝つ回数を数える
長い答えを好む採点役もいます。確かめるには、長さが同じ組を除きます。残りの組のうち、採点役が長い方を選んだ回数を数えます。
半分くらいなら問題ありません。四分の三以上なら、長さが採点を引っ張っています。
助っ人 model.js を書く(1)
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const base = process.env.AI_URL || \"http://ai:4000\";' '// 応答のトークン数。なければ null。' 'function count(data, name) {' ' return data.usage && typeof data.usage[name] === \"number\" ? data.usage[name] : null;' '}' > model.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
助っ人 model.js を書く(2)
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function ask(messages, sample, max) {' ' try {' ' const res = await fetch(base + \"/v1/chat/completions\", {' ' method: \"POST\",' ' headers: { \"content-type\": \"application/json\", authorization: \"Bearer lab\" },' ' body: JSON.stringify({ model: \"lab\", messages: messages, max_tokens: max || 100 }),' ' signal: AbortSignal.timeout(30000),' ' });' ' if (res.ok === false) throw new Error(\"status \" + res.status);' ' const data = await res.json();' ' const text = data.choices[0].message.content;' ' return { text, inTokens: count(data, \"prompt_tokens\"), outTokens: count(data, \"completion_tokens\"), recorded: false };' ' } catch (error) {' ' console.log(\"記録済みサンプル: モデルが答えませんでした (\" + error.message + \")。\");' ' return { text: sample, inTokens: null, outTokens: null, recorded: true };' ' }' '}' 'module.exports = { ask };' >> model.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
採点役のテストを書く(1)
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { ask } = require(\"./model\");' 'const H = \"pppppfpppppfpppfpppf\";' 'const J = \"pppppppppppfpppppppf\";' 'const rows = [' ' \"1 40 55 Y Y\", \"2 62 30 X X\", \"3 48 70 Y X\", \"4 33 51 X Y\",' ' \"5 80 45 X Y\", \"6 52 52 X X\", \"7 29 66 Y Y\", \"8 71 40 X Y\",' ' \"9 44 90 Y Y\", \"10 58 36 X X\", \"11 35 62 X Y\", \"12 77 41 X X\",' '].map(function (r) {' ' const p = r.split(\" \");' ' return { x: Number(p[1]), y: Number(p[2]), one: p[3], two: p[4] };' '});' > judge.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
採点役のテストを書く(2)
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'function count(text, ch) { return text.split(ch).length - 1; }' 'const n = H.length;' 'let agree = 0;' 'for (let i = 0; i < n; i++) { if (H[i] === J[i]) agree++; }' 'const chance = count(J, \"p\") * count(H, \"p\") + count(J, \"f\") * count(H, \"f\");' 'const kappa = (agree * n - chance) / (n * n - chance);' >> judge.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
採点役のテストを書く(3)
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'let first = 0;' 'let second = 0;' 'let longer = 0;' 'let unequal = 0;' 'rows.forEach(function (r) {' ' if (r.one === \"X\" && r.two === \"Y\") first++;' ' if (r.one === \"Y\" && r.two === \"X\") second++;' ' if (r.x === r.y) return;' ' unequal++;' ' if ((r.one === \"X\") === (r.x > r.y)) longer++;' '});' >> judge.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
採点役のテストを書く(4)
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' ' console.log(\"一致: \" + (agree * 100 / n) + \" パーセント、カッパ: \" + kappa.toFixed(2));' ' console.log(\"入れ替えテスト: \" + rows.length + \" 件中 \" + (first + second) + \" 件が変わった (先の枠 \" + first + \"、後の枠 \" + second + \")\");' ' console.log(\"長い方が勝った: \" + unequal + \" 件中 \" + longer + \" 件 (\" + Math.floor(longer * 100 / unequal) + \" パーセント)\");' ' const q = \"駅はどこですか、という質問に、だれかに聞いてください、と答えた返事を、合格か不合格かで、一語で採点してください。\";' ' const reply = await ask([{ role: \"user\", content: q }], \"不合格\", 10);' ' console.log(\"本物の採点: \" + reply.text);' '}' 'main();' >> judge.js"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
採点役のテストを動かす
docker exec -w /home/node/project agent node judge.jsここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
テストの出力
| 行 | 意味 |
|---|---|
| 一致: 90 パーセント、カッパ: 0.62 | 一致は高いが、偶然を除くと弱くなる |
| 入れ替えテスト: 12 件中 5 件が変わった (先の枠 4、後の枠 1) | 五つの選びが枠に従った |
| 長い方が勝った: 11 件中 9 件 (81 パーセント) | 長い方が 81 パーセント勝った |
| 本物の採点: ... | ラボからの本物の採点一つ。答えがなければ記録済みサンプル |
学生が入力するセルは、このプレビューでは空白です。