eval-framework 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- eval_framework/__init__.py +7 -0
- eval_framework/base_config.py +36 -0
- eval_framework/context/__init__.py +0 -0
- eval_framework/context/determined.py +170 -0
- eval_framework/context/eval.py +114 -0
- eval_framework/context/local.py +52 -0
- eval_framework/evaluation_generator.py +231 -0
- eval_framework/exceptions.py +2 -0
- eval_framework/external/ifeval_impl/README.md +5 -0
- eval_framework/external/ifeval_impl/instructions.py +1523 -0
- eval_framework/external/ifeval_impl/instructions_registry.py +161 -0
- eval_framework/external/ifeval_impl/instructions_util.py +1689 -0
- eval_framework/external/ifeval_impl/utils.py +135 -0
- eval_framework/llm/__init__.py +0 -0
- eval_framework/llm/aleph_alpha.py +323 -0
- eval_framework/llm/base.py +58 -0
- eval_framework/llm/huggingface.py +332 -0
- eval_framework/llm/mistral.py +73 -0
- eval_framework/llm/models.py +16 -0
- eval_framework/llm/openai.py +205 -0
- eval_framework/llm/vllm.py +438 -0
- eval_framework/logger.py +3 -0
- eval_framework/main.py +187 -0
- eval_framework/metrics/__init__.py +0 -0
- eval_framework/metrics/base.py +40 -0
- eval_framework/metrics/completion/__init__.py +1 -0
- eval_framework/metrics/completion/accuracy_completion.py +16 -0
- eval_framework/metrics/completion/bleu.py +76 -0
- eval_framework/metrics/completion/chrf.py +62 -0
- eval_framework/metrics/completion/code_assertion.py +44 -0
- eval_framework/metrics/completion/code_execution_pass_at_one.py +126 -0
- eval_framework/metrics/completion/comet.py +56 -0
- eval_framework/metrics/completion/concordance_index.py +38 -0
- eval_framework/metrics/completion/csv_format.py +102 -0
- eval_framework/metrics/completion/cwe_accuracy.py +49 -0
- eval_framework/metrics/completion/exponential_similarity.py +65 -0
- eval_framework/metrics/completion/f1.py +42 -0
- eval_framework/metrics/completion/format_checker.py +56 -0
- eval_framework/metrics/completion/grid_difference.py +77 -0
- eval_framework/metrics/completion/ifeval.py +73 -0
- eval_framework/metrics/completion/json_format.py +171 -0
- eval_framework/metrics/completion/language_checker.py +74 -0
- eval_framework/metrics/completion/length_control.py +83 -0
- eval_framework/metrics/completion/math_reasoning_completion.py +303 -0
- eval_framework/metrics/completion/niah_accuracy.py +163 -0
- eval_framework/metrics/completion/placeholder_checker.py +27 -0
- eval_framework/metrics/completion/repetition.py +88 -0
- eval_framework/metrics/completion/rouge_1.py +35 -0
- eval_framework/metrics/completion/rouge_2.py +45 -0
- eval_framework/metrics/completion/rouge_geometric_mean.py +36 -0
- eval_framework/metrics/completion/rouge_l.py +52 -0
- eval_framework/metrics/completion/struct_eval_metrics.py +248 -0
- eval_framework/metrics/completion/ter.py +67 -0
- eval_framework/metrics/completion/text_counter.py +182 -0
- eval_framework/metrics/efficiency/__init__.py +0 -0
- eval_framework/metrics/efficiency/bytes_per_sequence_position.py +48 -0
- eval_framework/metrics/llm/__init__.py +0 -0
- eval_framework/metrics/llm/base.py +8 -0
- eval_framework/metrics/llm/graders/chatbot_style_grader.py +92 -0
- eval_framework/metrics/llm/graders/comparison_grader.py +146 -0
- eval_framework/metrics/llm/graders/conciseness_grader.py +93 -0
- eval_framework/metrics/llm/graders/contains_names_grader.py +71 -0
- eval_framework/metrics/llm/graders/format_correctness_grader.py +109 -0
- eval_framework/metrics/llm/graders/instruction_grader.py +177 -0
- eval_framework/metrics/llm/graders/language.py +56 -0
- eval_framework/metrics/llm/graders/long_context_grader.py +72 -0
- eval_framework/metrics/llm/graders/models.py +74 -0
- eval_framework/metrics/llm/graders/refusal_grader.py +57 -0
- eval_framework/metrics/llm/graders/sql_quality_grader.py +145 -0
- eval_framework/metrics/llm/graders/summary_world_knowledge_grader.py +103 -0
- eval_framework/metrics/llm/llm_judge_chatbot_style.py +36 -0
- eval_framework/metrics/llm/llm_judge_completion_accuracy.py +39 -0
- eval_framework/metrics/llm/llm_judge_conciseness.py +37 -0
- eval_framework/metrics/llm/llm_judge_contains_names.py +36 -0
- eval_framework/metrics/llm/llm_judge_format_correctness.py +43 -0
- eval_framework/metrics/llm/llm_judge_instruction.py +58 -0
- eval_framework/metrics/llm/llm_judge_mtbench_pair.py +205 -0
- eval_framework/metrics/llm/llm_judge_mtbench_single.py +188 -0
- eval_framework/metrics/llm/llm_judge_refusal.py +35 -0
- eval_framework/metrics/llm/llm_judge_sql.py +394 -0
- eval_framework/metrics/llm/llm_judge_world_knowledge.py +37 -0
- eval_framework/metrics/loglikelihood/__init__.py +0 -0
- eval_framework/metrics/loglikelihood/accuracy_loglikelihood.py +51 -0
- eval_framework/metrics/loglikelihood/probability_mass.py +56 -0
- eval_framework/py.typed +0 -0
- eval_framework/response_generator.py +416 -0
- eval_framework/result_processors/__init__.py +0 -0
- eval_framework/result_processors/base.py +74 -0
- eval_framework/result_processors/hf_processor.py +87 -0
- eval_framework/result_processors/result_processor.py +129 -0
- eval_framework/run.py +314 -0
- eval_framework/run_direct.py +42 -0
- eval_framework/shared/types.py +227 -0
- eval_framework/tasks/__init__.py +6 -0
- eval_framework/tasks/base.py +314 -0
- eval_framework/tasks/benchmarks/__init__.py +0 -0
- eval_framework/tasks/benchmarks/arc.py +46 -0
- eval_framework/tasks/benchmarks/arc_de.py +46 -0
- eval_framework/tasks/benchmarks/arc_fi.py +46 -0
- eval_framework/tasks/benchmarks/belebele.py +60 -0
- eval_framework/tasks/benchmarks/bigcodebench.py +155 -0
- eval_framework/tasks/benchmarks/casehold.py +47 -0
- eval_framework/tasks/benchmarks/chembench.py +85 -0
- eval_framework/tasks/benchmarks/copa.py +39 -0
- eval_framework/tasks/benchmarks/duc.py +91 -0
- eval_framework/tasks/benchmarks/flores200.py +62 -0
- eval_framework/tasks/benchmarks/flores_plus.py +84 -0
- eval_framework/tasks/benchmarks/gpqa.py +177 -0
- eval_framework/tasks/benchmarks/gsm8k.py +148 -0
- eval_framework/tasks/benchmarks/hellaswag.py +44 -0
- eval_framework/tasks/benchmarks/hellaswag_de.py +52 -0
- eval_framework/tasks/benchmarks/humaneval.py +97 -0
- eval_framework/tasks/benchmarks/ifeval.py +78 -0
- eval_framework/tasks/benchmarks/include.py +119 -0
- eval_framework/tasks/benchmarks/infinitebench.py +302 -0
- eval_framework/tasks/benchmarks/math_reasoning.py +569 -0
- eval_framework/tasks/benchmarks/mbpp.py +192 -0
- eval_framework/tasks/benchmarks/mmlu.py +190 -0
- eval_framework/tasks/benchmarks/mmlu_de.py +109 -0
- eval_framework/tasks/benchmarks/mmlu_pro.py +139 -0
- eval_framework/tasks/benchmarks/mmmlu.py +529 -0
- eval_framework/tasks/benchmarks/openbookqa.py +37 -0
- eval_framework/tasks/benchmarks/opengptx_eu20.py +363 -0
- eval_framework/tasks/benchmarks/pawsx.py +65 -0
- eval_framework/tasks/benchmarks/piqa.py +39 -0
- eval_framework/tasks/benchmarks/quality.py +56 -0
- eval_framework/tasks/benchmarks/sciq.py +44 -0
- eval_framework/tasks/benchmarks/sphyr.py +75 -0
- eval_framework/tasks/benchmarks/squad.py +89 -0
- eval_framework/tasks/benchmarks/struct_eval.py +110 -0
- eval_framework/tasks/benchmarks/tablebench.py +117 -0
- eval_framework/tasks/benchmarks/triviaqa.py +42 -0
- eval_framework/tasks/benchmarks/truthfulqa.py +95 -0
- eval_framework/tasks/benchmarks/winogender.py +39 -0
- eval_framework/tasks/benchmarks/winogrande.py +44 -0
- eval_framework/tasks/benchmarks/winox.py +57 -0
- eval_framework/tasks/benchmarks/wmt.py +160 -0
- eval_framework/tasks/benchmarks/zero_scrolls.py +197 -0
- eval_framework/tasks/eval_config.py +112 -0
- eval_framework/tasks/perturbation.py +83 -0
- eval_framework/tasks/registry.py +186 -0
- eval_framework/tasks/task_loader.py +80 -0
- eval_framework/tasks/task_names.py +138 -0
- eval_framework/tasks/utils.py +578 -0
- eval_framework/utils/constants.py +9 -0
- eval_framework/utils/generate_task_docs.py +229 -0
- eval_framework/utils/helpers.py +3 -0
- eval_framework/utils/logging.py +50 -0
- eval_framework/utils/packaging.py +52 -0
- eval_framework-0.2.0.dist-info/METADATA +514 -0
- eval_framework-0.2.0.dist-info/RECORD +161 -0
- eval_framework-0.2.0.dist-info/WHEEL +4 -0
- eval_framework-0.2.0.dist-info/entry_points.txt +3 -0
- template_formatting/README.md +83 -0
- template_formatting/__init__.py +0 -0
- template_formatting/formatter.py +536 -0
- template_formatting/mistral_formatter.py +159 -0
- template_formatting/py.typed +0 -0
- template_formatting/tests/test_formatter_eval.py +408 -0
- template_formatting/tests/test_formatter_scaling.py +253 -0
- template_formatting/tests/test_mistral_formatter.py +136 -0
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import ast
|
|
2
|
+
import logging
|
|
3
|
+
import re
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from eval_framework.metrics.completion.code_assertion import (
|
|
7
|
+
CodeCompletionAssertion,
|
|
8
|
+
)
|
|
9
|
+
from eval_framework.shared.types import BaseMetricContext
|
|
10
|
+
from eval_framework.tasks.base import BaseTask, Language, ResponseType, Sample
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
BEGIN = "```python"
|
|
15
|
+
END = "```"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class MBPPMetricContext(BaseMetricContext):
|
|
19
|
+
tests_code: str
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class MBPP(BaseTask[str]):
|
|
23
|
+
"""
|
|
24
|
+
MBPP provides both the problem statement and the test cases upfront. It says, "Here's the problem and here are the
|
|
25
|
+
tests; write code that passes them.". Note that LLMs can cheat and only write code that passes the tests without
|
|
26
|
+
solving the given problem.
|
|
27
|
+
|
|
28
|
+
MBPP_PROMPT_WITHOUT_TESTS, on the other hand, only gives you the problem statement and function signature
|
|
29
|
+
initially. It says, "Here's the problem and function signature; write code, then we'll run tests later."
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
NAME = "MBPP"
|
|
33
|
+
DATASET_PATH = "google-research-datasets/mbpp"
|
|
34
|
+
SAMPLE_SPLIT = "test"
|
|
35
|
+
FEWSHOT_SPLIT = "train"
|
|
36
|
+
RESPONSE_TYPE = ResponseType.COMPLETION
|
|
37
|
+
METRICS = [CodeCompletionAssertion]
|
|
38
|
+
SUBJECTS = ["full"] # , "sanitized"] # these are HF dataset SUBSETS!
|
|
39
|
+
LANGUAGE = Language.ENG
|
|
40
|
+
|
|
41
|
+
def __init__(self, num_fewshot: int = 0) -> None:
|
|
42
|
+
super().__init__(num_fewshot)
|
|
43
|
+
|
|
44
|
+
self.stop_sequences = [END]
|
|
45
|
+
|
|
46
|
+
@staticmethod
|
|
47
|
+
def _code_expander(code: str, gt_asserts: str) -> str:
|
|
48
|
+
"""
|
|
49
|
+
code variable carries the LLM-generated code snippet. We append the asserts for code testing
|
|
50
|
+
here. If no valid code is found in the LLM output, this function is not called.
|
|
51
|
+
Important: gt_asserts come as a stringiied list of assert strings. We safely reconvert this string
|
|
52
|
+
back to the list of of individual assert statements (also strings) by ast.literal_eval
|
|
53
|
+
"""
|
|
54
|
+
if not gt_asserts: # no ground truth (data asserts) are given, we return the original code
|
|
55
|
+
return code
|
|
56
|
+
gt_asserts = ast.literal_eval(gt_asserts) # never use eval!
|
|
57
|
+
if not isinstance(gt_asserts, list):
|
|
58
|
+
logger.info("*** WARNING, we expect a list of ground truth asserts here! Sample can not be finalized")
|
|
59
|
+
return code
|
|
60
|
+
postfix = ""
|
|
61
|
+
stacked_asserts = ""
|
|
62
|
+
for gt_assert in gt_asserts:
|
|
63
|
+
stacked_asserts += " " + gt_assert + "\n"
|
|
64
|
+
postfix = "try:\n" + stacked_asserts + " score = True\nexcept:\n score = False\nprint(score)"
|
|
65
|
+
return code + postfix
|
|
66
|
+
|
|
67
|
+
@staticmethod
|
|
68
|
+
def _get_function_name(line: str) -> str:
|
|
69
|
+
match = re.search(r"def\s+(\w+)\s*\(", line)
|
|
70
|
+
function_name = ""
|
|
71
|
+
if match:
|
|
72
|
+
function_name = match.group(1)
|
|
73
|
+
return function_name
|
|
74
|
+
|
|
75
|
+
def _get_instruction_text(self, item: dict[str, Any]) -> str:
|
|
76
|
+
"""
|
|
77
|
+
Passing selected task and tests depending on zero or few-shot setting
|
|
78
|
+
"""
|
|
79
|
+
tests = "\n".join(item["test_list"])
|
|
80
|
+
text = item["text"] if "text" in item else item["prompt"]
|
|
81
|
+
|
|
82
|
+
instruction_text = f"You are an expert Python programmer, and here is your task: {text} Your code should pass these tests:\n\n{tests}\n" # noqa E501
|
|
83
|
+
return instruction_text
|
|
84
|
+
|
|
85
|
+
def _get_cue_text(self, item: dict[str, Any]) -> str:
|
|
86
|
+
return BEGIN
|
|
87
|
+
|
|
88
|
+
def _get_ground_truth(self, item: dict[str, Any]) -> str | None:
|
|
89
|
+
"""
|
|
90
|
+
asserts are being passed as ground_truth, this is expected by CodeCompletionAssertion metrics
|
|
91
|
+
"""
|
|
92
|
+
return f"{item['test_list']}"
|
|
93
|
+
|
|
94
|
+
def _get_fewshot_target_text(self, item: dict[str, Any]) -> str:
|
|
95
|
+
target = item["code"]
|
|
96
|
+
assert target is not None
|
|
97
|
+
assert isinstance(target, str)
|
|
98
|
+
return f"{BEGIN}\n" + target + f"\n{END}"
|
|
99
|
+
|
|
100
|
+
def _sample_fewshot_examples(self, item: dict[str, Any]) -> list[dict]:
|
|
101
|
+
fewshot_examples = self.rnd.sample(self.dataset[self.FEWSHOT_SPLIT], self.num_fewshot)
|
|
102
|
+
return fewshot_examples
|
|
103
|
+
|
|
104
|
+
def _get_context(self, item: dict[str, Any]) -> MBPPMetricContext:
|
|
105
|
+
return MBPPMetricContext(tests_code="\n".join(item["test_list"]))
|
|
106
|
+
|
|
107
|
+
def post_process_generated_completion(self, completion_text: str, sample: Sample | None = None) -> str:
|
|
108
|
+
assert sample is not None
|
|
109
|
+
|
|
110
|
+
if BEGIN in completion_text:
|
|
111
|
+
completion_text = completion_text.split(f"{BEGIN}\n")[1]
|
|
112
|
+
|
|
113
|
+
if END in completion_text:
|
|
114
|
+
completion_text = completion_text.split(END)[0]
|
|
115
|
+
|
|
116
|
+
extracted_code = completion_text + "\n"
|
|
117
|
+
mbpp_ground_truth = str(sample.ground_truth)
|
|
118
|
+
code = self._code_expander(extracted_code, mbpp_ground_truth)
|
|
119
|
+
return code
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class MBPP_SANITIZED(MBPP):
|
|
123
|
+
NAME = "MBPP_SANITZED"
|
|
124
|
+
SUBJECTS = ["sanitized"]
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class MBPP_PROMPT_WITHOUT_TESTS(MBPP):
|
|
128
|
+
"""
|
|
129
|
+
MBPP provides both the problem statement and the test cases upfront. It says, "Here's the problem and here are the
|
|
130
|
+
tests; write code that passes them.". Note that LLMs can cheat and only write code that passes the tests without
|
|
131
|
+
solving the given problem.
|
|
132
|
+
|
|
133
|
+
MBPP_PROMPT_WITHOUT_TESTS, on the other hand, only gives you the problem statement and function signature
|
|
134
|
+
initially. It says, "Here's the problem and function signature; write code, then we'll run tests later."
|
|
135
|
+
"""
|
|
136
|
+
|
|
137
|
+
NAME = "MBPP_PROMPT_WITHOUT_TESTS"
|
|
138
|
+
|
|
139
|
+
def _get_instruction_text(self, item: dict[str, Any]) -> str:
|
|
140
|
+
"""
|
|
141
|
+
Passing selected task and tests depending on zero or few-shot setting
|
|
142
|
+
"""
|
|
143
|
+
text = item["text"] if "text" in item else item["prompt"]
|
|
144
|
+
instruction_text = f"You are an expert Python programmer, and here is your task: {text}\n\n" # noqa E501
|
|
145
|
+
return instruction_text
|
|
146
|
+
|
|
147
|
+
def _get_cue_text(self, item: dict[str, Any]) -> str:
|
|
148
|
+
function_header = self._get_function_header(item["code"])
|
|
149
|
+
return f"{BEGIN}\n{function_header}"
|
|
150
|
+
|
|
151
|
+
def _get_fewshot_target_text(self, item: dict[str, Any]) -> str:
|
|
152
|
+
target = item["code"]
|
|
153
|
+
assert target is not None
|
|
154
|
+
assert isinstance(target, str)
|
|
155
|
+
return f"{BEGIN}\n" + target + f"\n{END}"
|
|
156
|
+
|
|
157
|
+
@staticmethod
|
|
158
|
+
def _get_function_header(line: str) -> str:
|
|
159
|
+
match = re.search(r"^\s*def\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\(.*?\)\s*:", line, re.MULTILINE)
|
|
160
|
+
postfix = ""
|
|
161
|
+
if match is not None: # extract up to next open parenthesis in the found substring
|
|
162
|
+
postfix = line[match.start() :]
|
|
163
|
+
match = re.search(r"\)", postfix)
|
|
164
|
+
if match is not None:
|
|
165
|
+
end = match.start()
|
|
166
|
+
postfix = postfix[: end + 1]
|
|
167
|
+
else:
|
|
168
|
+
postfix = ""
|
|
169
|
+
|
|
170
|
+
if postfix == "":
|
|
171
|
+
return postfix
|
|
172
|
+
return f"{postfix.strip()}:"
|
|
173
|
+
|
|
174
|
+
def post_process_generated_completion(self, completion_text: str, sample: Sample | None = None) -> str:
|
|
175
|
+
assert sample is not None
|
|
176
|
+
|
|
177
|
+
if BEGIN in completion_text:
|
|
178
|
+
completion_text = completion_text.split(BEGIN)[1]
|
|
179
|
+
|
|
180
|
+
if END in completion_text:
|
|
181
|
+
completion_text = completion_text.split(END)[0]
|
|
182
|
+
|
|
183
|
+
extracted_code = completion_text + "\n"
|
|
184
|
+
mbpp_ground_truth = str(sample.ground_truth)
|
|
185
|
+
function_header = self._get_function_header(sample.messages[-1].content)
|
|
186
|
+
code = self._code_expander(extracted_code, mbpp_ground_truth)
|
|
187
|
+
return function_header + code
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
class MBPP_PROMPT_WITHOUT_TESTS_SANITIZED(MBPP_PROMPT_WITHOUT_TESTS):
|
|
191
|
+
NAME = "MBPP_PROMPT_WITHOUT_TESTS_SANITIZED"
|
|
192
|
+
SUBJECTS = ["sanitized"]
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from eval_framework.metrics.completion.accuracy_completion import AccuracyCompletion
|
|
5
|
+
from eval_framework.metrics.loglikelihood.accuracy_loglikelihood import (
|
|
6
|
+
AccuracyLoglikelihood,
|
|
7
|
+
AccuracyNormLoglikelihood,
|
|
8
|
+
)
|
|
9
|
+
from eval_framework.tasks.base import BaseTask, Language, ResponseType, Sample
|
|
10
|
+
from eval_framework.tasks.utils import get_n_letters
|
|
11
|
+
|
|
12
|
+
MMLU_SUBJECTS = [
|
|
13
|
+
"abstract_algebra",
|
|
14
|
+
"anatomy",
|
|
15
|
+
"astronomy",
|
|
16
|
+
"business_ethics",
|
|
17
|
+
"clinical_knowledge",
|
|
18
|
+
"college_biology",
|
|
19
|
+
"college_chemistry",
|
|
20
|
+
"college_computer_science",
|
|
21
|
+
"college_mathematics",
|
|
22
|
+
"college_medicine",
|
|
23
|
+
"college_physics",
|
|
24
|
+
"computer_security",
|
|
25
|
+
"conceptual_physics",
|
|
26
|
+
"econometrics",
|
|
27
|
+
"electrical_engineering",
|
|
28
|
+
"elementary_mathematics",
|
|
29
|
+
"formal_logic",
|
|
30
|
+
"global_facts",
|
|
31
|
+
"high_school_biology",
|
|
32
|
+
"high_school_chemistry",
|
|
33
|
+
"high_school_computer_science",
|
|
34
|
+
"high_school_european_history",
|
|
35
|
+
"high_school_geography",
|
|
36
|
+
"high_school_government_and_politics",
|
|
37
|
+
"high_school_macroeconomics",
|
|
38
|
+
"high_school_mathematics",
|
|
39
|
+
"high_school_microeconomics",
|
|
40
|
+
"high_school_physics",
|
|
41
|
+
"high_school_psychology",
|
|
42
|
+
"high_school_statistics",
|
|
43
|
+
"high_school_us_history",
|
|
44
|
+
"high_school_world_history",
|
|
45
|
+
"human_aging",
|
|
46
|
+
"human_sexuality",
|
|
47
|
+
"international_law",
|
|
48
|
+
"jurisprudence",
|
|
49
|
+
"logical_fallacies",
|
|
50
|
+
"machine_learning",
|
|
51
|
+
"management",
|
|
52
|
+
"marketing",
|
|
53
|
+
"medical_genetics",
|
|
54
|
+
"miscellaneous",
|
|
55
|
+
"moral_disputes",
|
|
56
|
+
"moral_scenarios",
|
|
57
|
+
"nutrition",
|
|
58
|
+
"philosophy",
|
|
59
|
+
"prehistory",
|
|
60
|
+
"professional_accounting",
|
|
61
|
+
"professional_law",
|
|
62
|
+
"professional_medicine",
|
|
63
|
+
"professional_psychology",
|
|
64
|
+
"public_relations",
|
|
65
|
+
"security_studies",
|
|
66
|
+
"sociology",
|
|
67
|
+
"us_foreign_policy",
|
|
68
|
+
"virology",
|
|
69
|
+
"world_religions",
|
|
70
|
+
]
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class MMLU(BaseTask[str]):
|
|
74
|
+
"""MMLU dataset: https://huggingface.co/datasets/cais/mmlu"""
|
|
75
|
+
|
|
76
|
+
NAME = "MMLU"
|
|
77
|
+
DATASET_PATH = "cais/mmlu"
|
|
78
|
+
SAMPLE_SPLIT = "test"
|
|
79
|
+
FEWSHOT_SPLIT = "dev"
|
|
80
|
+
RESPONSE_TYPE = ResponseType.LOGLIKELIHOODS
|
|
81
|
+
METRICS = [AccuracyLoglikelihood, AccuracyNormLoglikelihood]
|
|
82
|
+
SUBJECTS = MMLU_SUBJECTS
|
|
83
|
+
PERTURBATION_UNMODIFIABLE_WORDS = ["Question", "Answer"] + get_n_letters(4)
|
|
84
|
+
LANGUAGE = Language.ENG
|
|
85
|
+
|
|
86
|
+
def __init__(self, num_fewshot: int = 0) -> None:
|
|
87
|
+
super().__init__(num_fewshot)
|
|
88
|
+
|
|
89
|
+
self.keys = get_n_letters(4)
|
|
90
|
+
|
|
91
|
+
def _get_subject_name(self, item: dict[str, Any]) -> str:
|
|
92
|
+
return " ".join(item["subject"].split("_"))
|
|
93
|
+
|
|
94
|
+
def _get_initial_prompt_text(self, item: dict[str, Any]) -> str:
|
|
95
|
+
return f"The following are multiple choice questions (with answers) about {self._get_subject_name(item)}."
|
|
96
|
+
|
|
97
|
+
def _get_instruction_text(self, item: dict[str, Any]) -> str:
|
|
98
|
+
question = item["question"].strip()
|
|
99
|
+
choices = "".join([f"{key}. {choice}\n" for key, choice in zip(self.keys, item["choices"])])
|
|
100
|
+
return f"Question: {question}\n{choices}"
|
|
101
|
+
|
|
102
|
+
def _get_fewshot_target_text(self, item: dict[str, Any]) -> str:
|
|
103
|
+
ground_truth = self._get_ground_truth(item)
|
|
104
|
+
assert ground_truth is not None
|
|
105
|
+
return f"{self._get_cue_text(item)}{ground_truth}"
|
|
106
|
+
|
|
107
|
+
def _get_cue_text(self, item: dict[str, Any]) -> str:
|
|
108
|
+
return "Answer:"
|
|
109
|
+
|
|
110
|
+
def _get_ground_truth(self, item: dict[str, Any]) -> str | None:
|
|
111
|
+
return f" {self.keys[item['answer']]}"
|
|
112
|
+
|
|
113
|
+
def _get_possible_completions(self, item: dict[str, Any]) -> list[str] | None:
|
|
114
|
+
return [f" {key}" for key in self.keys]
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class FullTextMMLU(MMLU):
|
|
118
|
+
"""MMLU dataset but where the model is expected to replicate choice text, rather than just the key."""
|
|
119
|
+
|
|
120
|
+
NAME = "Full Text MMLU"
|
|
121
|
+
PERTURBATION_UNMODIFIABLE_WORDS = ["Question", "answers"] + get_n_letters(4)
|
|
122
|
+
|
|
123
|
+
def _get_initial_prompt_text(self, item: dict[str, Any]) -> str:
|
|
124
|
+
subject_name = self._get_subject_name(item)
|
|
125
|
+
return f"""The following are multiple choice questions (with possible answers) about {subject_name}.
|
|
126
|
+
Answer with the full text of the correct answer."""
|
|
127
|
+
|
|
128
|
+
def _get_instruction_text(self, item: dict[str, Any]) -> str:
|
|
129
|
+
question = item["question"].strip()
|
|
130
|
+
choices = "".join([f"- {choice}\n" for choice in item["choices"]])
|
|
131
|
+
return f"Question: {question}\nPossible answers:\n{choices}"
|
|
132
|
+
|
|
133
|
+
def _get_ground_truth(self, item: dict[str, Any]) -> str | None:
|
|
134
|
+
return f" {item['choices'][item['answer']]}"
|
|
135
|
+
|
|
136
|
+
def _get_possible_completions(self, item: dict[str, Any]) -> list[str] | None:
|
|
137
|
+
return [f" {choice}" for choice in item["choices"]]
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class MMLU_COT(MMLU):
|
|
141
|
+
"""
|
|
142
|
+
MMLU dataset with instruction to summarize reasoning and conclude with answer.
|
|
143
|
+
Inspired by https://arxiv.org/pdf/2411.15124 (Table 44)
|
|
144
|
+
"""
|
|
145
|
+
|
|
146
|
+
NAME = "MMLU_COT"
|
|
147
|
+
RESPONSE_TYPE = ResponseType.COMPLETION
|
|
148
|
+
METRICS = [AccuracyCompletion]
|
|
149
|
+
PERTURBATION_UNMODIFIABLE_WORDS = ["Question", "Therefore", "the", "answer", "is", "ANSWER_LETTER"] + get_n_letters(
|
|
150
|
+
4
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
ANS_RE = re.compile(r"Therefore, the answer is: ([ABCD])")
|
|
154
|
+
|
|
155
|
+
def __init__(self, num_fewshot: int = 0) -> None:
|
|
156
|
+
assert num_fewshot == 0, "Fewshot is not supported for MMLU_COT"
|
|
157
|
+
super().__init__(num_fewshot)
|
|
158
|
+
self.stop_sequences: list[str] = ["Question:"]
|
|
159
|
+
|
|
160
|
+
def _extract_answer(self, completion: str) -> str:
|
|
161
|
+
match = self.ANS_RE.search(completion)
|
|
162
|
+
if match:
|
|
163
|
+
match_str = match.group(1)
|
|
164
|
+
return match_str
|
|
165
|
+
else:
|
|
166
|
+
return "[invalid]"
|
|
167
|
+
|
|
168
|
+
def _get_cue_text(self, item: dict[str, Any]) -> str:
|
|
169
|
+
return ""
|
|
170
|
+
|
|
171
|
+
def _get_ground_truth(self, item: dict[str, Any]) -> str | None:
|
|
172
|
+
return self.keys[item["answer"]]
|
|
173
|
+
|
|
174
|
+
def post_process_generated_completion(self, completion_text: str, sample: Sample | None = None) -> str:
|
|
175
|
+
for stop_sequence in self.stop_sequences:
|
|
176
|
+
if stop_sequence in completion_text:
|
|
177
|
+
completion_text = completion_text.split(stop_sequence)[0]
|
|
178
|
+
return self._extract_answer(completion_text)
|
|
179
|
+
|
|
180
|
+
def _get_instruction_text(self, item: dict[str, Any]) -> str:
|
|
181
|
+
question = item["question"].strip()
|
|
182
|
+
choices = "\n".join([f"{key}. {choice}" for key, choice in zip(self.keys, item["choices"])])
|
|
183
|
+
return f"Question: {question}\n{choices}"
|
|
184
|
+
|
|
185
|
+
def _get_initial_prompt_text(self, item: dict[str, Any]) -> str:
|
|
186
|
+
return (
|
|
187
|
+
f"The following are multiple choice questions about {self._get_subject_name(item)}. "
|
|
188
|
+
'Summarize your reasoning concisely, then conclude with "Therefore, the answer is: X", where X is '
|
|
189
|
+
"one of A, B, C, or D."
|
|
190
|
+
)
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from eval_framework.metrics.loglikelihood.accuracy_loglikelihood import (
|
|
4
|
+
AccuracyLoglikelihood,
|
|
5
|
+
AccuracyNormLoglikelihood,
|
|
6
|
+
)
|
|
7
|
+
from eval_framework.tasks.base import BaseTask, Language, ResponseType
|
|
8
|
+
from eval_framework.tasks.utils import get_n_letters
|
|
9
|
+
|
|
10
|
+
MMLU_SUBJECTS_TRANSLATION = {
|
|
11
|
+
"abstract_algebra": "Abstrakte Algebra",
|
|
12
|
+
"anatomy": "Anatomie",
|
|
13
|
+
"astronomy": "Astronomie",
|
|
14
|
+
"business_ethics": "Wirtschaftsethik",
|
|
15
|
+
"clinical_knowledge": "Klinisches Wissen",
|
|
16
|
+
"college_biology": "Hochschulbiologie",
|
|
17
|
+
"college_chemistry": "Hochschulchemie",
|
|
18
|
+
"college_computer_science": "Hochschulinformatik",
|
|
19
|
+
"college_mathematics": "Hochschulmathematik",
|
|
20
|
+
"college_medicine": "Hochschulmedizin",
|
|
21
|
+
"college_physics": "Hochschulphysik",
|
|
22
|
+
"computer_security": "Computersicherheit",
|
|
23
|
+
"conceptual_physics": "Konzeptuelle Physik",
|
|
24
|
+
"econometrics": "Ökonometrie",
|
|
25
|
+
"electrical_engineering": "Elektrotechnik",
|
|
26
|
+
"elementary_mathematics": "Elementarmathematik",
|
|
27
|
+
"formal_logic": "Formale Logik",
|
|
28
|
+
"global_facts": "Globale Fakten",
|
|
29
|
+
"high_school_biology": "Gymnasialbiologie",
|
|
30
|
+
"high_school_chemistry": "Gymnasialchemie",
|
|
31
|
+
"high_school_computer_science": "Gymnasiale Informatik",
|
|
32
|
+
"high_school_european_history": "Gymnasiale Europäische Geschichte",
|
|
33
|
+
"high_school_geography": "Gymnasiale Geographie",
|
|
34
|
+
"high_school_government_and_politics": "Gymnasiale Regierung und Politik",
|
|
35
|
+
"high_school_macroeconomics": "Gymnasiale Makroökonomie",
|
|
36
|
+
"high_school_mathematics": "Gymnasialmathematik",
|
|
37
|
+
"high_school_microeconomics": "Gymnasiale Mikroökonomie",
|
|
38
|
+
"high_school_physics": "Gymnasialphysik",
|
|
39
|
+
"high_school_psychology": "Gymnasialpsychologie",
|
|
40
|
+
"high_school_statistics": "Gymnasialstatistik",
|
|
41
|
+
"high_school_us_history": "Gymnasiale US-Geschichte",
|
|
42
|
+
"high_school_world_history": "Gymnasiale Weltgeschichte",
|
|
43
|
+
"human_aging": "Menschliches Altern",
|
|
44
|
+
"human_sexuality": "Menschliche Sexualität",
|
|
45
|
+
"international_law": "Internationales Recht",
|
|
46
|
+
"jurisprudence": "Rechtswissenschaft",
|
|
47
|
+
"logical_fallacies": "Logische Fehlschlüsse",
|
|
48
|
+
"machine_learning": "Maschinelles Lernen",
|
|
49
|
+
"management": "Management",
|
|
50
|
+
"marketing": "Marketing",
|
|
51
|
+
"medical_genetics": "Medizinische Genetik",
|
|
52
|
+
"miscellaneous": "Verschiedenes",
|
|
53
|
+
"moral_disputes": "Moralische Streitfragen",
|
|
54
|
+
"moral_scenarios": "Moralische Szenarien",
|
|
55
|
+
"nutrition": "Ernährung",
|
|
56
|
+
"philosophy": "Philosophie",
|
|
57
|
+
"prehistory": "Urgeschichte",
|
|
58
|
+
"professional_accounting": "Berufliche Buchhaltung",
|
|
59
|
+
"professional_law": "Berufliches Recht",
|
|
60
|
+
"professional_medicine": "Berufliche Medizin",
|
|
61
|
+
"professional_psychology": "Berufliche Psychologie",
|
|
62
|
+
"public_relations": "Öffentlichkeitsarbeit",
|
|
63
|
+
"security_studies": "Sicherheitsstudien",
|
|
64
|
+
"sociology": "Soziologie",
|
|
65
|
+
"us_foreign_policy": "US-Außenpolitik",
|
|
66
|
+
"virology": "Virologie",
|
|
67
|
+
"world_religions": "Weltreligionen",
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class MMLU_DE(BaseTask[str]):
|
|
72
|
+
"""MMLU DE dataset: https://huggingface.co/datasets/LeoLM/MMLU_de"""
|
|
73
|
+
|
|
74
|
+
NAME = "MMLU_DE"
|
|
75
|
+
DATASET_PATH = "LeoLM/MMLU_de"
|
|
76
|
+
SAMPLE_SPLIT = "test"
|
|
77
|
+
FEWSHOT_SPLIT = "validation"
|
|
78
|
+
RESPONSE_TYPE = ResponseType.LOGLIKELIHOODS
|
|
79
|
+
METRICS = [AccuracyLoglikelihood, AccuracyNormLoglikelihood]
|
|
80
|
+
SUBJECTS = list(MMLU_SUBJECTS_TRANSLATION.keys())
|
|
81
|
+
PERTURBATION_UNMODIFIABLE_WORDS = ["Frage"] + get_n_letters(4)
|
|
82
|
+
LANGUAGE = Language.DEU
|
|
83
|
+
|
|
84
|
+
def __init__(self, num_fewshot: int = 0) -> None:
|
|
85
|
+
super().__init__(num_fewshot)
|
|
86
|
+
|
|
87
|
+
self.keys = get_n_letters(4)
|
|
88
|
+
|
|
89
|
+
def _get_initial_prompt_text(self, item: dict[str, Any]) -> str:
|
|
90
|
+
return f"Die folgenden sind Multiple Choice Fragen (mit Antworten) über {MMLU_SUBJECTS_TRANSLATION[item['subject']]}." # noqa: E501
|
|
91
|
+
|
|
92
|
+
def _get_instruction_text(self, item: dict[str, Any]) -> str:
|
|
93
|
+
question = item["question_de"].strip()
|
|
94
|
+
choices = "".join([f"{key}. {choice}\n" for key, choice in zip(self.keys, item["choices_de"])])
|
|
95
|
+
return f"Frage: {question}\n{choices}"
|
|
96
|
+
|
|
97
|
+
def _get_fewshot_target_text(self, item: dict[str, Any]) -> str:
|
|
98
|
+
ground_truth = self._get_ground_truth(item)
|
|
99
|
+
assert ground_truth is not None
|
|
100
|
+
return f"{self._get_cue_text(item)}{ground_truth}"
|
|
101
|
+
|
|
102
|
+
def _get_cue_text(self, item: dict[str, Any]) -> str:
|
|
103
|
+
return "Antwort:"
|
|
104
|
+
|
|
105
|
+
def _get_ground_truth(self, item: dict[str, Any]) -> str | None:
|
|
106
|
+
return f" {self.keys[item['answer']]}"
|
|
107
|
+
|
|
108
|
+
def _get_possible_completions(self, item: dict[str, Any]) -> list[str] | None:
|
|
109
|
+
return [f" {key}" for key in self.keys]
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import random
|
|
2
|
+
import re
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from eval_framework.metrics.completion.accuracy_completion import AccuracyCompletion
|
|
6
|
+
from eval_framework.metrics.loglikelihood.accuracy_loglikelihood import (
|
|
7
|
+
AccuracyLoglikelihood,
|
|
8
|
+
AccuracyNormLoglikelihood,
|
|
9
|
+
)
|
|
10
|
+
from eval_framework.tasks.base import NO_SUBJECT, RANDOM_SEED, BaseTask, Language, ResponseType, Sample
|
|
11
|
+
from eval_framework.tasks.utils import get_n_letters
|
|
12
|
+
|
|
13
|
+
MMLU_PRO_SUBJECTS = [
|
|
14
|
+
"engineering",
|
|
15
|
+
"physics",
|
|
16
|
+
"psychology",
|
|
17
|
+
"chemistry",
|
|
18
|
+
"biology",
|
|
19
|
+
"law",
|
|
20
|
+
"philosophy",
|
|
21
|
+
"computer science",
|
|
22
|
+
"other",
|
|
23
|
+
"economics",
|
|
24
|
+
"business",
|
|
25
|
+
"history",
|
|
26
|
+
"math",
|
|
27
|
+
"health",
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class MMLU_PRO(BaseTask[str]):
|
|
32
|
+
"""MMLU_PRO dataset: https://huggingface.co/datasets/TIGER-Lab/MMLU-Pro"""
|
|
33
|
+
|
|
34
|
+
NAME = "MMLU Pro"
|
|
35
|
+
DATASET_PATH = "TIGER-Lab/MMLU-Pro"
|
|
36
|
+
SAMPLE_SPLIT = "test"
|
|
37
|
+
FEWSHOT_SPLIT = "test"
|
|
38
|
+
RESPONSE_TYPE = ResponseType.LOGLIKELIHOODS
|
|
39
|
+
METRICS = [AccuracyLoglikelihood, AccuracyNormLoglikelihood]
|
|
40
|
+
SUBJECTS = MMLU_PRO_SUBJECTS
|
|
41
|
+
PERTURBATION_UNMODIFIABLE_WORDS = get_n_letters(10)
|
|
42
|
+
LANGUAGE = Language.ENG
|
|
43
|
+
|
|
44
|
+
def __init__(self, num_fewshot: int = 0) -> None:
|
|
45
|
+
super().__init__(num_fewshot)
|
|
46
|
+
|
|
47
|
+
self.keys = get_n_letters(10)
|
|
48
|
+
|
|
49
|
+
def _load_dataset(self, subject: str) -> None:
|
|
50
|
+
name = subject if subject != NO_SUBJECT else None
|
|
51
|
+
|
|
52
|
+
hf_dataset = self._load_hf_dataset(path=self.DATASET_PATH)
|
|
53
|
+
|
|
54
|
+
hf_dataset = hf_dataset.filter(lambda example: example["category"] == name)
|
|
55
|
+
|
|
56
|
+
self.dataset = {}
|
|
57
|
+
for split, data in hf_dataset.items():
|
|
58
|
+
data_list = list(data)
|
|
59
|
+
assert len(data_list) > 0
|
|
60
|
+
|
|
61
|
+
if split == self.SAMPLE_SPLIT:
|
|
62
|
+
self.rnd = random.Random(RANDOM_SEED)
|
|
63
|
+
self.rnd.shuffle(data_list)
|
|
64
|
+
|
|
65
|
+
if split in [self.SAMPLE_SPLIT, self.FEWSHOT_SPLIT]:
|
|
66
|
+
self.dataset[split] = data_list
|
|
67
|
+
|
|
68
|
+
def _get_initial_prompt_text(self, item: dict[str, Any]) -> str:
|
|
69
|
+
return f"The following are multiple choice questions (with answers) about {item['subject']}."
|
|
70
|
+
|
|
71
|
+
def _get_instruction_text(self, item: dict[str, Any]) -> str:
|
|
72
|
+
instruction_text = item["question"].strip() + "\n"
|
|
73
|
+
instruction_text += "".join([f"{key}. {choice}\n" for key, choice in zip(self.keys, item["options"])])
|
|
74
|
+
return instruction_text
|
|
75
|
+
|
|
76
|
+
def _get_fewshot_target_text(self, item: dict[str, Any]) -> str:
|
|
77
|
+
ground_truth = self._get_ground_truth(item)
|
|
78
|
+
assert ground_truth is not None
|
|
79
|
+
return f"{self._get_cue_text(item)}{ground_truth}"
|
|
80
|
+
|
|
81
|
+
def _get_cue_text(self, item: dict[str, Any]) -> str:
|
|
82
|
+
return "Answer:"
|
|
83
|
+
|
|
84
|
+
def _get_ground_truth(self, item: dict[str, Any]) -> str | None:
|
|
85
|
+
return f" {self.keys[item['answer_index']]}"
|
|
86
|
+
|
|
87
|
+
def _get_possible_completions(self, item: dict[str, Any]) -> list[str] | None:
|
|
88
|
+
return [f" {key}" for key in self.keys]
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class MMLU_PRO_COT(MMLU_PRO):
|
|
92
|
+
NAME = "MMLU_PRO_COT"
|
|
93
|
+
RESPONSE_TYPE = ResponseType.COMPLETION
|
|
94
|
+
METRICS = [AccuracyCompletion]
|
|
95
|
+
PERTURBATION_UNMODIFIABLE_WORDS = ["Question", "Therefore", "the", "answer", "is", "ANSWER_LETTER"] + get_n_letters(
|
|
96
|
+
4
|
|
97
|
+
)
|
|
98
|
+
ANS_RE = re.compile(r"Therefore, the answer is \(([ABCDEFGHIJ])\)")
|
|
99
|
+
|
|
100
|
+
def __init__(self, num_fewshot: int = 0) -> None:
|
|
101
|
+
assert num_fewshot == 0, "Fewshot is not supported for MMLU_PRO_COT"
|
|
102
|
+
super().__init__(num_fewshot)
|
|
103
|
+
|
|
104
|
+
self.stop_sequences: list[str] = ["Question:"]
|
|
105
|
+
|
|
106
|
+
def _extract_answer(self, completion: str) -> str:
|
|
107
|
+
match = self.ANS_RE.search(completion)
|
|
108
|
+
if match:
|
|
109
|
+
match_str = match.group(1)
|
|
110
|
+
return match_str
|
|
111
|
+
else:
|
|
112
|
+
return "[invalid]"
|
|
113
|
+
|
|
114
|
+
def _get_cue_text(self, item: dict[str, Any]) -> str:
|
|
115
|
+
return ""
|
|
116
|
+
|
|
117
|
+
def _get_ground_truth(self, item: dict[str, Any]) -> str | None:
|
|
118
|
+
return self.keys[item["answer_index"]]
|
|
119
|
+
|
|
120
|
+
def post_process_generated_completion(self, completion_text: str, sample: Sample | None = None) -> str:
|
|
121
|
+
for stop_sequence in self.stop_sequences:
|
|
122
|
+
if stop_sequence in completion_text:
|
|
123
|
+
completion_text = completion_text.split(stop_sequence)[0]
|
|
124
|
+
return self._extract_answer(completion_text)
|
|
125
|
+
|
|
126
|
+
def _get_instruction_text(self, item: dict[str, Any]) -> str:
|
|
127
|
+
# using the reasoning prompt from "Figure 44 of Tülu 3 paper: https://arxiv.org/pdf/2411.15124"
|
|
128
|
+
instruction_text = (
|
|
129
|
+
"Answer the following multiple-choice question by giving the correct answer letter in parentheses. "
|
|
130
|
+
"Provide CONCISE reasoning for the answer, and make sure to finish the response with "
|
|
131
|
+
'"Therefore, the answer is (ANSWER_LETTER)" where (ANSWER_LETTER) is one of (A), (B), (C), (D), (E), etc.'
|
|
132
|
+
)
|
|
133
|
+
instruction_text += f"\n\nQuestion: {item['question'].strip()}\n"
|
|
134
|
+
instruction_text += "\n".join([f"({key}) {choice}" for key, choice in zip(self.keys, item["options"])])
|
|
135
|
+
instruction_text += (
|
|
136
|
+
"\n\nAnswer the above question and REMEMBER to finish your response with the exact phrase "
|
|
137
|
+
'"Therefore, the answer is (ANSWER_LETTER)" where (ANSWER_LETTER) is one of (A), (B), (C), (D), (E), etc.'
|
|
138
|
+
)
|
|
139
|
+
return instruction_text
|