项目文件夹

文件
2026-07-13 13:32:05 +08:00

183 行
6.2 KiB
Python

from typing import List, Optional, Dict
from tqdm import tqdm
from deepeval.dataset import Golden
from deepeval.benchmarks.base_benchmark import (
DeepEvalBaseBenchmark,
DeepEvalBaseBenchmarkResult,
)
from deepeval.models import DeepEvalBaseLLM
from deepeval.benchmarks.arc.mode import ARCMode
from deepeval.benchmarks.arc.template import ARCTemplate
from deepeval.benchmarks.schema import MultipleChoiceSchema
from deepeval.telemetry import capture_benchmark_run
class ARC(DeepEvalBaseBenchmark):
def __init__(
self,
n_shots: int = 5,
n_problems: Optional[int] = None,
mode: ARCMode = ARCMode.EASY,
verbose_mode: bool = False,
confinement_instructions: Optional[str] = None,
**kwargs,
):
from deepeval.scorer import Scorer
import pandas as pd
assert n_shots <= 5, "ARC only supports n_shots <= 5"
super().__init__(**kwargs)
self.mode: ARCMode = mode
self.scorer = Scorer()
self.n_shots: int = n_shots
if mode == ARCMode.EASY:
self.n_problems: int = 2376 if n_problems is None else n_problems
assert (
self.n_problems <= 2376
), "ARC-Easy only supports n_problems <= 2376"
else:
self.n_problems: int = 1172 if n_problems is None else n_problems
assert (
self.n_problems <= 1172
), "ARC-Challenge only supports n_problems <= 1172"
self.predictions: Optional[pd.DataFrame] = None
self.overall_score: Optional[float] = None
self.verbose_mode = verbose_mode
if not confinement_instructions:
self.confinement_instructions = (
"Output 'A', 'B', 'C', or 'D'. Full answer not needed."
)
else:
self.confinement_instructions = confinement_instructions
def evaluate(
self, model: DeepEvalBaseLLM, *args, **kwargs
) -> DeepEvalBaseBenchmarkResult:
import pandas as pd
with capture_benchmark_run("ARC", self.n_problems):
overall_correct_predictions = 0
overall_total_predictions = self.n_problems
predictions_row = []
# Solving each problem
goldens: List[Golden] = self.load_benchmark_dataset(self.mode)[
: self.n_problems
]
for idx, golden in enumerate(
tqdm(goldens, desc=f"Processing {self.n_problems} problems")
):
prediction, score = self.predict(model, golden).values()
if score:
overall_correct_predictions += 1
predictions_row.append(
(golden.input, prediction, golden.expected_output, score)
)
if self.verbose_mode:
self.print_verbose_logs(
idx,
golden.input,
golden.expected_output,
prediction,
score,
)
# Calculate overall accuracy
overall_accuracy = (
overall_correct_predictions / overall_total_predictions
)
print(f"Overall ARC Accuracy: {overall_accuracy}")
self.predictions = pd.DataFrame(
predictions_row,
columns=["Input", "Prediction", "Expected Output", "Correct"],
)
self.overall_score = overall_accuracy
return DeepEvalBaseBenchmarkResult(
overall_accuracy=overall_accuracy
)
def predict(self, model: DeepEvalBaseLLM, golden: Golden) -> Dict:
# Define prompt template
prompt: dict = ARCTemplate.generate_output(
input=golden.input,
n_shots=self.n_shots,
)
# Enforced model generation
try:
res: MultipleChoiceSchema = model.generate(
prompt=prompt, schema=MultipleChoiceSchema
)
prediction = res.answer
except TypeError:
prompt += f"\n\n{self.confinement_instructions}"
prediction = model.generate(prompt)
# For native models, shouldn't happen but just in case
if isinstance(prediction, tuple):
prediction = prediction[0]
score = self.scorer.exact_match_score(
golden.expected_output, prediction
)
return {"prediction": prediction, "score": score}
def load_benchmark_dataset(self, mode: ARCMode) -> List[Golden]:
from datasets import load_dataset
# Load full dataset
dataset_mapping = {
ARCMode.CHALLENGE: "challenge_dataset",
ARCMode.EASY: "easy_dataset",
}
dataset_attr = dataset_mapping.get(mode)
if dataset_attr:
if not hasattr(self, dataset_attr):
dataset = load_dataset("ai2_arc", mode.value)
setattr(self, dataset_attr, dataset)
else:
dataset = getattr(self, dataset_attr)
# Construct test set
goldens: List[Golden] = []
for data in dataset["train"]:
input = ARCTemplate.format_question(data, False)
expected_output = ARCTemplate.format_answer(data)
golden = Golden(input=input, expected_output=expected_output)
goldens.append(golden)
return goldens
def print_verbose_logs(
self,
idx: int,
input: str,
expected_output: str,
prediction: str,
score: int,
) -> str:
steps = [
f"Input:\n{input}",
f"Score: {score}\nPrediction: {prediction}\nExpected Output: {expected_output}",
]
verbose_logs = ""
for i in range(len(steps) - 1):
verbose_logs += steps[i]
# don't add new line for penultimate step
if i < len(steps) - 2:
verbose_logs += " \n \n"
if self.verbose_mode:
print("*" * 50)
print(f"Problem {idx + 1}")
print("*" * 50)
print("")
print(verbose_logs + f"\n \n{steps[-1]}")
print("")
print("=" * 70)
return verbose_logs