Skip to content

評価結果の正確性に関する問題を修正 - #298

Open
kiakiraki wants to merge 1 commit into
mainfrom
fix/evaluation-correctness
Open

評価結果の正確性に関する問題を修正#298
kiakiraki wants to merge 1 commit into
mainfrom
fix/evaluation-correctness

Conversation

@kiakiraki

@kiakiraki kiakiraki commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

概要

評価結果の正確性や再現性に影響する5件の問題を修正します。単なるリファクタリングではなく、誤った応答を評価する、入力件数と出力件数がずれる、集計値がNaNになる、異なる問題同士を比較する、といった評価結果そのものに影響する不具合が対象です。

1. LLM Judgeプリセットが最終回答を評価していない

問題

単一ターン用のLLM Judgeプリセットが messages[0] / messages[1] を固定参照していました。

evaluate_chat_response が最終回答を除いた会話履歴を extra_info に渡すため、system prompt付きデータではsystem文が「質問」、最初のuser発話が「回答」として扱われます。また複数ターンのデータでは、実際の最終生成結果 lm_output が評価対象になりませんでした。

修正

  • userロールのメッセージを抽出し、最後のuser発話を質問として使用
  • 回答には常に実際の最終生成結果 lm_output を使用
  • Pairwise Judgeでは各モデルの lm_output をそれぞれ使用
  • ChatbotBenchのreferenceも、最後のuserターンに対応するものを選択
  • 複数ターン入力では「最終回答のみを評価する」仕様をドキュメントに明記

主な対象

  • flexeval/preset_configs/Metric/assistant_eval_*_single_turn.jsonnet
  • flexeval/preset_configs/PairwiseJudge/assistant_judge_*_single_turn.jsonnet
  • flexeval/core/chat_dataset/chatbot_bench.py
  • docs/how_to/evaluate_with_llm_judges.md

テスト

system prompt、過去のuser/assistantターン、最終ターンにそれぞれsentinel文字列を入れ、レンダリング結果に最終質問・最終回答だけが含まれることを確認しています。

2. G-Evalの入力件数とラベル展開数が一致しない

問題

G-Evalは、各入力について有効ラベルごとのlog probabilityを取得します。しかしtext版は実際の端数バッチではなく設定値 batch_size を使って入力を展開していました。chat版は入力件数を参照せず、ラベル数を基準に展開していました。

その結果、端数バッチや「バッチ件数 > ラベル数」の場合に件数不一致が発生し、バックエンドによっては IndexError でクラッシュします。緩いテストスタブでは zip によって余分な要素が切り捨てられ、問題が検出されませんでした。

修正

  • 実際の evaluator_inputs 件数を基準に入力とラベルを展開
  • 入力ごとに全ラベルを一巡する順序へ統一
  • LMが返したlog probability件数が期待値と異なる場合は ValueError
  • progress barを設定上のバッチサイズではなく実処理件数で更新

主な対象

  • flexeval/core/metric/llm_geval_score.py

テスト

text/chatの両方について、端数バッチ、バッチ件数がラベル数を上回るケース、LMが不正な件数を返すケースを追加しています。

3. Bradley-TerryスコアがNaNになる

問題

旧実装には次の2つの問題がありました。

  • 分母計算で「対象モデルが勝った相手」しか走査しておらず、負けた相手が欠落する
  • 0を含むスコアを幾何平均で正規化し、log(0) からNaNが全モデルへ伝播する

さらに、全敗モデルを含む場合など、勝敗の有向グラフが強連結でなければBradley-Terryの有限MLE自体が存在しません。このケースを数値計算だけで処理しようとしていたため、無効なスコアが正常結果として返っていました。

修正

  • 対戦相手を勝ち・負け双方の辺の和集合から取得
  • 推定前に勝敗グラフの強連結性を検証
  • iteration中の0以下の値と非有限値を明示的に検出
  • 有限MLEが存在しない場合はBradley-Terryスコアを生成しない
  • スコアラーごとに例外を隔離し、失敗したスコアだけを警告付きで省略
  • win_rate と完了済みのjudge結果は返すため、高額なLLM judge呼び出し結果を失わない
  • eps 引数は後方互換のため受理しつつ、指定時に FutureWarning を出す非動作パラメータとして非推奨化

主な対象

  • flexeval/core/pairwise_comparison/scorer/bradley_terry.py
  • flexeval/core/evaluate_pairwise.py

テスト

1勝のみの2モデル、正常な相互対戦に全敗モデルを追加したケースを拒否し、強連結なサイクルでは有限スコアを返すことを確認しています。また、1つのスコアラーが失敗しても他のスコアと対戦結果が返ることを確認しています。

4. Pairwise評価が行番号だけで出力を対応付ける

問題

モデル間で出力件数だけを確認し、各行が同じ問題に対応しているかを検証していませんでした。並び順が異なるJSONLを渡しても評価が正常終了し、異なる問題の回答同士から無意味なスコアが生成されます。

フレームワーク全体には共通のinstance IDがないため、完全なID照合ではなく、利用可能な入力情報を使った検証が必要です。

修正

  • judge実行前に各行の referencesextra_info / task_inputs をモデル間で比較
  • chat履歴ではモデル固有になりうるassistantロールを比較対象から除外
  • 一方にidentity情報があり、他方にないケースも不整合として拒否
  • 両方にidentity情報がない古い形式は、後方互換のため従来どおり行順を信頼

主な対象

  • flexeval/core/evaluate_pairwise.py

テスト

行順が異なるケース、片方だけidentity情報がないケースを拒否し、assistant履歴だけが異なる正当なケースは許可することを確認しています。

5. Few-shot適用時にキャッシュ済み会話が破壊的に変更される

問題

few-shotメッセージを追加する際、datasetが返した ChatInstance.messages をin-placeで置換していました。同じインスタンスをキャッシュして返すdatasetでは、評価を繰り返すたびにメッセージが累積します。--num_repeats は浅いコピーを使うため、この問題の影響を受けます。

修正

  • few-shotを適用する場合だけ ChatInstance をdeep copyしてからメッセージを追加
  • ChatbotBenchも内部のmessagesリストを直接渡さず、__getitem__ で防御的にコピー

主な対象

  • flexeval/core/evaluate_chat_response.py
  • flexeval/core/chat_dataset/chatbot_bench.py

テスト

同じキャッシュ済みインスタンスを使って評価を2回実行し、元のmessagesが変更されず、2回の出力も一致することを確認しています。ChatbotBenchについても、取得したインスタンスのリスト変更が次回取得へ残らないことを確認しています。

@kiakiraki
kiakiraki marked this pull request as ready for review July 20, 2026 09:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant