| import json |
| import os |
| import math_utils |
| import nest_asyncio |
| from concurrent.futures import ThreadPoolExecutor |
| import asyncio |
| from termcolor import cprint |
|
|
| from omegaconf import OmegaConf, MISSING |
|
|
| def get_config(): |
| cli_conf = OmegaConf.from_cli() |
| yaml_conf = OmegaConf.load(cli_conf.config) |
| conf = OmegaConf.merge(yaml_conf, cli_conf) |
| return conf |
|
|
| def get_eval_config(config, key, default=MISSING): |
| """ |
| Helper function to get evaluation config with fallback to old locations. |
| Priority: config.evaluation.* > config.dataset.* > config.rollout.* > default |
| """ |
| |
| eval_val = OmegaConf.select(config, f"evaluation.{key}", default=MISSING) |
| if eval_val is not MISSING: |
| return eval_val |
| |
| |
| dataset_key_map = { |
| "eval_dataset": "dataset.eval_dataset", |
| "data_type": "dataset.data_type", |
| } |
| |
| rollout_key_map = { |
| "output_unmasking_history": "rollout.output_unmasking_history", |
| } |
| |
| |
| if key in dataset_key_map: |
| dataset_val = OmegaConf.select(config, dataset_key_map[key], default=MISSING) |
| if dataset_val is not MISSING: |
| return dataset_val |
| |
| |
| if key in rollout_key_map: |
| rollout_val = OmegaConf.select(config, rollout_key_map[key], default=MISSING) |
| if rollout_val is not MISSING: |
| return rollout_val |
| |
| |
| if default is not MISSING: |
| return default |
| |
| |
| raise KeyError(f"Config key '{key}' not found in evaluation section or fallback locations") |
|
|
| if __name__ == "__main__": |
|
|
| config = get_config() |
|
|
| project_name = config.experiment.project |
| |
|
|
| dataset = get_eval_config(config, "eval_dataset") |
| |
| checkpoint_path = get_eval_config(config, "checkpoint_path", MISSING) |
| if checkpoint_path is MISSING or checkpoint_path is None: |
| |
| if isinstance(config.model, str): |
| pretrained_model = config.model |
| else: |
| pretrained_model = config.model.pretrained_model |
| else: |
| pretrained_model = checkpoint_path |
| |
| |
| if pretrained_model is None: |
| raise ValueError( |
| "pretrained_model is None. Please set either:\n" |
| " - evaluation.checkpoint_path in config, or\n" |
| " - model (as string) or model.pretrained_model in config" |
| ) |
|
|
| outputs_name = "eval-" + pretrained_model.split("/")[-1] + "-" + dataset |
| output_base = OmegaConf.select(config, "experiment.output_dir", default=None) or getattr(config.experiment, "output_dir", "..") |
| output_base = os.path.expanduser(str(output_base)) |
| _script_dir = os.path.dirname(os.path.abspath(__file__)) |
| if not os.path.isabs(output_base): |
| output_base = os.path.normpath(os.path.join(_script_dir, output_base)) |
| file_name = os.path.join(output_base, project_name, "temp_data", "outputs-" + outputs_name + ".json") |
|
|
| with open(file_name, "r", encoding="utf-8") as f: |
| data = json.load(f) |
|
|
| index_list = [] |
| extracted_output_list = [] |
| ground_truth_list = [] |
| response_length_list = [] |
| data_type = get_eval_config(config, "data_type") |
| |
| for i in range(len(data)): |
| |
| response_length_list = response_length_list + data[i]["response_length"] |
| index_list = index_list + [i] * len(data[i]["extracted_output"]) |
| extracted_output_list = extracted_output_list + data[i]["extracted_output"] |
| if data_type == "math": |
| data[i]["correctness"] = [] |
| |
| if "ground_truth_answer" in data[i]: |
| ground_truth_list = ground_truth_list + [data[i]["ground_truth_answer"]] * len(data[i]["extracted_output"]) |
| else: |
| ground_truth_list = ground_truth_list + [None] * len(data[i]["extracted_output"]) |
| |
|
|
| if data_type == "math": |
|
|
| nest_asyncio.apply() |
|
|
| async def get_correctness(): |
| executor = ThreadPoolExecutor(max_workers=64) |
| tasks = [] |
| for i in range(len(index_list)): |
| tasks.append(math_utils.is_equal(extracted_output_list[i], ground_truth_list[i], executor)) |
| results = await asyncio.gather(*tasks) |
| return results |
| |
| correctness_list = asyncio.run(get_correctness()) |
| for i in range(len(index_list)): |
| index_i = index_list[i] |
| data[index_i]["correctness"].append(correctness_list[i]) |
|
|
|
|
|
|
| def z_score_normalize(lst): |
| mean = sum(lst) / len(lst) |
| std = (sum((x - mean) ** 2 for x in lst) / len(lst)) ** 0.5 |
| if std == 0: |
| return [0 for x in lst] |
| return [(x - mean) / std for x in lst] |
|
|
|
|
|
|
| data_type = get_eval_config(config, "data_type") |
| if data_type == "math": |
| acc = sum(correctness_list)/len(correctness_list) |
| else: |
| num_task = 0 |
| num_correct_task = 0 |
| for x in data: |
| for y in x["correctness"]: |
| num_correct_task += all(y) |
| num_task += 1 |
| acc = num_correct_task / num_task if num_task else 0 |
|
|
| if not get_eval_config(config, "output_unmasking_history", True): |
| for i in range(len(data)): |
| data[i]["step_map"] = [] |
| |
| os.makedirs(os.path.dirname(file_name), exist_ok=True) |
| with open(file_name, "w", encoding="utf-8") as f: |
| json.dump(data, f, indent=2, ensure_ascii=False) |
|
|
|
|
| outputs_result_name = os.path.join(output_base, project_name, "results", "results-" + outputs_name + ".txt") |
| os.makedirs(os.path.dirname(outputs_result_name), exist_ok=True) |
| with open(outputs_result_name, "a") as f: |
| |
| def save_and_print(text): |
| cprint("\n\n\n" + text, color="green") |
| f.write(text + "\n") |
| |
| |
| avg_len = sum(response_length_list)/len(response_length_list) |
|
|
| save_and_print(f"acc: {acc:.4f}\navg length: {avg_len:.4f}") |