Skip to content

Commit d3d91bf

Browse files
authored
refactor(tasks): migrate 10 benchmarks from llm_judge to the verifiers pipeline (#1388)
* refactor(tasks): migrate 10 benchmarks from llm_judge to the verifiers pipeline * fix(tasks): restore judge-failure fallbacks and judge system prompts in verifier migrations
1 parent e9ef9f6 commit d3d91bf

10 files changed

Lines changed: 501 additions & 335 deletions

File tree

lmms_eval/tasks/ami/utils.py

Lines changed: 52 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,16 @@
11
import os
22
import re
33
import string
4+
import threading
45

56
import numpy as np
67
from loguru import logger as eval_logger
78

8-
from lmms_eval.llm_judge import ServerConfig, get_server
9+
from lmms_eval.verifiers import VerificationPipeline, VerifyResult
10+
from lmms_eval.verifiers.openai import OpenAIVerifier
911

10-
API_TYPE = os.getenv("API_TYPE", "openai")
1112
JUDGE_MODEL_VERSION = os.getenv("JUDGE_MODEL_VERSION", "gpt-4o-mini")
1213

13-
server_config = ServerConfig(
14-
model_name=JUDGE_MODEL_VERSION,
15-
)
16-
server = get_server(server_name=API_TYPE, config=server_config)
17-
1814

1915
def get_column_value(doc, candidates):
2016
"""Helper function to get value from document with multiple possible column names"""
@@ -259,16 +255,7 @@ def calculate_wer(reference, hypothesis):
259255
return wer
260256

261257

262-
def ami_process_results_llm_judge(doc, results):
263-
"""
264-
Process results using LLM as judge for open-ended evaluation.
265-
Similar to voicebench's open-ended evaluation.
266-
"""
267-
parsed_preds = []
268-
scores = []
269-
270-
# Evaluation prompt template
271-
meta_prompt = """I need your help to evaluate the quality of an automatic speech recognition (ASR) transcription.
258+
AMI_LLM_JUDGE_PROMPT = """I need your help to evaluate the quality of an automatic speech recognition (ASR) transcription.
272259
273260
You will be provided with:
274261
1. [Reference]: The ground truth transcription
@@ -288,6 +275,51 @@ def ami_process_results_llm_judge(doc, results):
288275
After evaluating, please output the score only without anything else.
289276
You don't need to provide any explanations."""
290277

278+
279+
# Previously sent as a system message; now included as a prefix in the user prompt.
280+
_AMI_SYSTEM_INSTRUCTION = "You are a helpful assistant who evaluates speech recognition quality."
281+
282+
283+
def _ami_judge_prompt_fn(question, prediction, ground_truth, **kwargs):
284+
prompt = AMI_LLM_JUDGE_PROMPT.format(reference=ground_truth, hypothesis=prediction)
285+
return f"{_AMI_SYSTEM_INSTRUCTION}\n\n{prompt}"
286+
287+
288+
def _parse_raw_score(text):
289+
"""Parse raw 1-5 score without normalization."""
290+
numbers = re.findall(r"\d+(?:\.\d+)?", text.strip())
291+
score = float(numbers[0]) if numbers else 0.0
292+
return VerifyResult(score=score, is_correct=score >= 3.0, raw_output=text)
293+
294+
295+
_ami_judge_pipeline = None
296+
_ami_judge_pipeline_lock = threading.Lock()
297+
298+
299+
def _get_ami_judge_pipeline():
300+
global _ami_judge_pipeline
301+
if _ami_judge_pipeline is None:
302+
with _ami_judge_pipeline_lock:
303+
if _ami_judge_pipeline is None: # double-check
304+
_ami_judge_pipeline = VerificationPipeline(
305+
verifier=OpenAIVerifier(
306+
model=JUDGE_MODEL_VERSION,
307+
custom_prompt=_ami_judge_prompt_fn,
308+
response_parser=_parse_raw_score,
309+
temperature=0.5,
310+
max_tokens=10,
311+
),
312+
)
313+
return _ami_judge_pipeline
314+
315+
316+
def ami_process_results_llm_judge(doc, results):
317+
"""
318+
Process results using LLM as judge for open-ended evaluation.
319+
Similar to voicebench's open-ended evaluation.
320+
"""
321+
scores = []
322+
291323
for pred in results:
292324
prediction = pred.strip() if isinstance(pred, str) else str(pred)
293325

@@ -304,34 +336,9 @@ def ami_process_results_llm_judge(doc, results):
304336
# Get reference text
305337
reference_text = get_column_value(doc, ["text", "transcript", "transcription"])
306338

307-
formatted_prompt = meta_prompt.format(reference=reference_text, hypothesis=prediction)
308-
309-
try:
310-
from lmms_eval.llm_judge.protocol import Request, ServerConfig
311-
312-
custom_config = ServerConfig(model_name=JUDGE_MODEL_VERSION, temperature=0.5, max_tokens=10)
313-
314-
request = Request(messages=[{"role": "system", "content": "You are a helpful assistant who evaluates speech recognition quality."}, {"role": "user", "content": formatted_prompt}], config=custom_config)
315-
316-
response = server.evaluate(request)
317-
318-
if response.success:
319-
judge_response = response.content.strip()
320-
try:
321-
judge_score = int(judge_response)
322-
except ValueError:
323-
eval_logger.error(f"Failed to parse score: {judge_response}")
324-
judge_score = 0.0
325-
else:
326-
eval_logger.error(f"Judge evaluation failed: {response.content}")
327-
judge_score = 0.0
328-
329-
except Exception as e:
330-
eval_logger.error(f"Error getting judge response: {e}")
331-
judge_score = 0.0
332-
333-
scores.append(judge_score)
334-
parsed_preds.append(prediction)
339+
pipeline = _get_ami_judge_pipeline()
340+
result = pipeline(question="", prediction=prediction, ground_truth=reference_text)
341+
scores.append(result.score)
335342

336343
avg_score = sum(scores) / len(scores) if scores else 0.0
337344
return {"llm_as_judge_eval": avg_score}

lmms_eval/tasks/browsecomp/utils.py

Lines changed: 47 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import hashlib
33
import os
44
import re
5+
import threading
56
from collections import defaultdict
67
from pathlib import Path
78

@@ -22,23 +23,43 @@ def _load_yaml_stripped(path: Path) -> dict:
2223
_config = _load_yaml_stripped(_default_template_path)
2324
_config.update(_load_yaml_stripped(_browsecomp_config_path))
2425

25-
_judge_server = None
26-
_judge_server_config = None
27-
if _config.get("metadata", {}).get("use_lmms_judge"):
28-
try:
29-
from lmms_eval.llm_judge import get_server
30-
from lmms_eval.llm_judge.protocol import ServerConfig
31-
32-
API_TYPE = os.getenv("API_TYPE", "openai").lower()
33-
DEPLOYMENT_NAME = os.getenv("DEPLOYMENT_NAME") or os.getenv("OPENAI_API_MODEL", "gpt-4o")
34-
35-
_judge_server_config = ServerConfig(model_name=DEPLOYMENT_NAME)
36-
_judge_server = get_server(server_name=API_TYPE, config=_judge_server_config)
37-
eval_logger.info("Using LMMS judge server for BrowseComp task.")
38-
except Exception as err:
39-
eval_logger.warning("Failed to initialize LMMS judge for BrowseComp: {}", err)
40-
_judge_server = None
41-
_judge_server_config = None
26+
_use_lmms_judge = _config.get("metadata", {}).get("use_lmms_judge", False)
27+
28+
# Lazy pipeline singleton for LLM judge
29+
_pipeline = None
30+
_pipeline_lock = threading.Lock()
31+
32+
33+
def _get_pipeline():
34+
global _pipeline
35+
if _pipeline is None:
36+
with _pipeline_lock:
37+
if _pipeline is None: # double-check
38+
from lmms_eval.verifiers import VerificationPipeline
39+
from lmms_eval.verifiers.extractors import StripReasoningExtractor
40+
from lmms_eval.verifiers.openai import OpenAIVerifier
41+
42+
API_TYPE = os.getenv("API_TYPE", "openai").lower()
43+
DEPLOYMENT_NAME = os.getenv("DEPLOYMENT_NAME") or os.getenv("OPENAI_API_MODEL", "gpt-4o")
44+
45+
def _build_prompt(question, prediction, ground_truth, **kwargs):
46+
return BROWSECOMP_JUDGE_PROMPT.format(
47+
question=question,
48+
response=prediction,
49+
correct_answer=ground_truth,
50+
)
51+
52+
_pipeline = VerificationPipeline(
53+
extractors=[StripReasoningExtractor()],
54+
verifier=OpenAIVerifier(
55+
model=DEPLOYMENT_NAME,
56+
api_type=API_TYPE,
57+
custom_prompt=_build_prompt,
58+
response_format="binary",
59+
),
60+
)
61+
eval_logger.info("Using LMMS judge server for BrowseComp task.")
62+
return _pipeline
4263

4364

4465
BROWSECOMP_JUDGE_PROMPT = """Judge whether the following [response] to [question] is correct based on the [correct_answer].
@@ -128,25 +149,18 @@ def _normalize_for_exact_match(text: str) -> str:
128149

129150

130151
def _judge_is_correct(question: str, response: str, correct_answer: str):
131-
if _judge_server is None or _judge_server_config is None:
152+
if not _use_lmms_judge:
132153
return None
133154

134155
try:
135-
from lmms_eval.llm_judge.protocol import Request
136-
137-
submit_prompt = BROWSECOMP_JUDGE_PROMPT.format(
138-
question=question,
139-
response=response,
140-
correct_answer=correct_answer,
141-
)
142-
request = Request(messages=[{"role": "user", "content": submit_prompt}], config=_judge_server_config)
143-
judge_response_obj = _judge_server.evaluate(request)
144-
judge_result = str(judge_response_obj.content).strip().lower()
145-
146-
if "incorrect" in judge_result:
147-
return False
148-
if "correct" in judge_result:
149-
return True
156+
pipeline = _get_pipeline()
157+
result = pipeline(question=question, prediction=response, ground_truth=correct_answer)
158+
# OpenAIVerifier swallows judge-call errors and flags them via
159+
# judge_failed metadata; return None so the caller falls back to exact
160+
# match instead of scoring an infra failure as incorrect.
161+
if result.metadata.get("judge_failed"):
162+
return None
163+
return result.is_correct
150164
except Exception as err:
151165
eval_logger.debug("BrowseComp LLM judge failed, fallback to exact match: {}", err)
152166

lmms_eval/tasks/corecognition/utils.py

Lines changed: 51 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import logging
88
import os
99
import re
10+
import threading
1011
from collections import defaultdict
1112
from pathlib import Path
1213
from typing import Any, Dict, Optional
@@ -30,24 +31,43 @@ def _load_yaml_stripped(path: Path) -> dict:
3031
_corecognition_config = _load_yaml_stripped(_default_template_path)
3132
_corecognition_config.update(_load_yaml_stripped(_corecognition_config_path))
3233

33-
# Initialize LLM judge server when use_lmms_judge is True (reference: stare/utils.py)
34-
_judge_server = None
35-
_judge_server_config = None
36-
if _corecognition_config.get("metadata", {}).get("use_lmms_judge"):
37-
try:
38-
from lmms_eval.llm_judge import get_server
39-
from lmms_eval.llm_judge.protocol import ServerConfig
40-
41-
eval_logger.info("Using LMMS judge server for CoreCognition task.")
42-
API_TYPE = os.getenv("API_TYPE", "openai").lower()
43-
DEPLOYMENT_NAME = os.getenv("DEPLOYMENT_NAME") or os.getenv("OPENAI_API_MODEL", "gpt-4o")
44-
45-
_judge_server_config = ServerConfig(model_name=DEPLOYMENT_NAME)
46-
_judge_server = get_server(server_name=API_TYPE, config=_judge_server_config)
47-
except Exception as e:
48-
eval_logger.warning("Failed to initialize LMMS judge for CoreCognition: %s", e)
49-
_judge_server = None
50-
_judge_server_config = None
34+
_use_lmms_judge = _corecognition_config.get("metadata", {}).get("use_lmms_judge", False)
35+
36+
# Lazy pipeline singleton for LLM judge
37+
_pipeline = None
38+
_pipeline_lock = threading.Lock()
39+
40+
41+
def _get_pipeline():
42+
global _pipeline
43+
if _pipeline is None:
44+
with _pipeline_lock:
45+
if _pipeline is None: # double-check
46+
from lmms_eval.verifiers import VerificationPipeline
47+
from lmms_eval.verifiers.extractors import StripReasoningExtractor
48+
from lmms_eval.verifiers.openai import OpenAIVerifier
49+
50+
eval_logger.info("Using LMMS judge server for CoreCognition task.")
51+
API_TYPE = os.getenv("API_TYPE", "openai").lower()
52+
DEPLOYMENT_NAME = os.getenv("DEPLOYMENT_NAME") or os.getenv("OPENAI_API_MODEL", "gpt-4o")
53+
54+
def _build_prompt(question, prediction, ground_truth, **kwargs):
55+
return CORECOGNITION_JUDGE_PROMPT.format(
56+
response=prediction,
57+
answer=ground_truth,
58+
)
59+
60+
_pipeline = VerificationPipeline(
61+
extractors=[StripReasoningExtractor()],
62+
verifier=OpenAIVerifier(
63+
model=DEPLOYMENT_NAME,
64+
api_type=API_TYPE,
65+
custom_prompt=_build_prompt,
66+
response_format="binary",
67+
),
68+
)
69+
return _pipeline
70+
5171

5272
# Judge prompt for binary correct/incorrect (same style as stare create_test_prompt)
5373
CORECOGNITION_JUDGE_PROMPT = """You are judging whether a model's response matches the correct answer for a single-choice or yes/no question.
@@ -59,12 +79,6 @@ def _load_yaml_stripped(path: Path) -> dict:
5979
Correct_or_not:"""
6080

6181

62-
def _create_judge_prompt(doc: dict[str, Any], pred: str) -> str:
63-
"""Build judge prompt: response + ground truth answer."""
64-
answer = str(doc.get("answer", "")).strip()
65-
return CORECOGNITION_JUDGE_PROMPT.format(response=pred, answer=answer)
66-
67-
6882
# Answer options for template matching
6983
OPTIONS_MCQ = ["A", "B", "C", "D", "E", "F"]
7084
OPTIONS_YORN = ["YES", "NO"]
@@ -199,19 +213,21 @@ def corecognition_process_results(doc: dict[str, Any], results: list[str]) -> di
199213
is_correct = matched == gt_normalized
200214
else:
201215
# Template match failed: try LLM judge if enabled, else direct comparison
202-
if _judge_server is not None and _judge_server_config is not None:
216+
if _use_lmms_judge:
203217
try:
204-
from lmms_eval.llm_judge.protocol import Request
205-
206-
submit_prompt = _create_judge_prompt(doc, pred)
207-
request = Request(
208-
messages=[{"role": "user", "content": submit_prompt}],
209-
config=_judge_server_config,
210-
)
211-
judge_response_obj = _judge_server.evaluate(request)
212-
judge_result = judge_response_obj.content.strip().lower()
213-
is_correct = "correct" in judge_result and "incorrect" not in judge_result
218+
pipeline = _get_pipeline()
219+
result = pipeline(question=pred, prediction=pred, ground_truth=ground_truth)
220+
if result.metadata.get("judge_failed"):
221+
# OpenAIVerifier swallows judge-call errors and flags them
222+
# here; fall back to direct comparison rather than counting
223+
# an infra failure as a wrong answer.
224+
pred_normalized = _rm_model_special(pred).upper().strip()
225+
gt_normalized = ground_truth.upper().strip()
226+
is_correct = pred_normalized == gt_normalized
227+
else:
228+
is_correct = result.is_correct
214229
except Exception as e:
230+
# Pipeline construction (import/config) failed.
215231
eval_logger.debug("CoreCognition LLM judge failed, falling back to direct comparison: %s", e)
216232
pred_normalized = _rm_model_special(pred).upper().strip()
217233
gt_normalized = ground_truth.upper().strip()

0 commit comments

Comments
 (0)