mirror of
https://github.com/hanzoai/open-instruct.git
synced 2026-10-30 18:26:32 +00:00
195 lines
5.8 KiB
Python
195 lines
5.8 KiB
Python
"""
|
|
Usage example:
|
|
python scripts/collect_eval_results.py \
|
|
--experiment_id 01HV0P4E3MW9211HX0JEKM0PXM \
|
|
--job_suffix _tulu2_13b_dpo_ultrainteract_04082024 \
|
|
--output_file metrics.json \
|
|
--task_order gsm_cot gsm_direct toxigen alpaca_eval \
|
|
--print_table \
|
|
--table_file metrics.tsv
|
|
"""
|
|
|
|
import beaker
|
|
from pathlib import Path
|
|
import argparse
|
|
from copy import deepcopy
|
|
import json
|
|
import pandas as pd
|
|
|
|
|
|
def make_parser():
|
|
default_task_order = [
|
|
"alpaca_eval",
|
|
"bbh_cot",
|
|
"bbh_direct",
|
|
"codex_eval_temp_0.1",
|
|
"codex_eval_temp_0.8",
|
|
"gsm_cot",
|
|
"gsm_direct",
|
|
"ifeval",
|
|
"mmlu_0shot",
|
|
"mmlu_5shot",
|
|
"toxigen",
|
|
"truthfulqa",
|
|
"tydiqa_goldp_1shot",
|
|
"tydiqa_no_context_1shot",
|
|
"xstest",
|
|
]
|
|
|
|
parser = argparse.ArgumentParser(
|
|
description="""Point this script at a Beaker job created by `submit_eval_jobs.py`.
|
|
It will will collect all evaluation metrics and dump them in a json
|
|
file. It will also collect summary metrics for each task.""",
|
|
epilog="""Usage example:
|
|
python scripts/collect_eval_results.py
|
|
--experiment_id 01HV0P4E3MW9211HX0JEKM0PXM
|
|
--job_suffix _tulu2_13b_dpo_ultrainteract_04082024
|
|
--task_order gsm_cot gsm_direct toxigen alpaca_eval
|
|
--output_file metrics.json
|
|
--table_file metrics.tsv
|
|
--print_table""",
|
|
)
|
|
parser.add_argument(
|
|
"--experiment_id",
|
|
type=str,
|
|
help="ID of the Beaker experiment for which to collect metrics.",
|
|
)
|
|
parser.add_argument(
|
|
"--job_suffix",
|
|
type=str,
|
|
help="Suffix of job name; remove this from the job name to get the eval task.",
|
|
)
|
|
parser.add_argument(
|
|
"--output_file",
|
|
type=Path,
|
|
default=None,
|
|
help="If given, dump a .json with all metrics to this file.",
|
|
)
|
|
parser.add_argument(
|
|
"--table_file",
|
|
type=Path,
|
|
default=None,
|
|
help="If given, save table of summary results.",
|
|
)
|
|
parser.add_argument(
|
|
"--print_table",
|
|
action="store_true",
|
|
help="If given, print summary metrics to console.",
|
|
)
|
|
parser.add_argument(
|
|
"--task_order",
|
|
nargs="+",
|
|
default=default_task_order,
|
|
help="""If given, display summary metrics in this order.""",
|
|
)
|
|
|
|
return parser
|
|
|
|
|
|
def get_summary_metric(metrics, eval_task):
|
|
summary_lookup = {
|
|
"mmlu_0shot": ["average_acc"],
|
|
"mmlu_5shot": ["average_acc"],
|
|
"gsm_direct": ["exact_match"],
|
|
"gsm_cot": ["exact_match"],
|
|
"bbh_direct": ["average_exact_match"],
|
|
"bbh_cot": ["average_exact_match"],
|
|
"codex_eval_temp_0.1": ["pass@1"],
|
|
"codex_eval_temp_0.8": ["pass@10"],
|
|
"tydiqa_no_context_1shot": ["average", "f1"],
|
|
"tydiqa_goldp_1shot": ["average", "f1"],
|
|
"toxigen": ["overall"],
|
|
"truthfulqa": ["truth-info acc"],
|
|
"xstest": ["gpt4_label", "refusal_prf", "f1"],
|
|
"alpaca_eval": ["win_rate", "model-greedy-long"],
|
|
"ifeval": ["loose", "Accuracy"],
|
|
}
|
|
|
|
# These tasks are scaled 0-100 instead of 0-1; rescale for final summary.
|
|
tasks_scaled_to_100 = [
|
|
"tydiqa_goldp_1shot",
|
|
"tydiqa_no_context_1shot",
|
|
"alpaca_eval",
|
|
]
|
|
|
|
# Get summary metric if available.
|
|
if eval_task not in summary_lookup:
|
|
print(f"No summary metric for {eval_task}. Skipping.")
|
|
return None
|
|
|
|
# Descend through result dict to get the result we want.
|
|
key_list = summary_lookup[eval_task]
|
|
result_loop = deepcopy(metrics)
|
|
for key in key_list:
|
|
result_loop = result_loop[key]
|
|
|
|
# Rescale the tasks that are on a 0-100 scale.
|
|
if eval_task in tasks_scaled_to_100:
|
|
result_loop = result_loop / 100
|
|
|
|
# Return the value and the full field name.
|
|
return result_loop, eval_task + ":" + ":".join(key_list)
|
|
|
|
|
|
def make_summary_table(summary_metrics, args):
|
|
tbl = []
|
|
for k, v in summary_metrics.items():
|
|
splt = k.split(":")
|
|
task = splt[0]
|
|
metric = ":".join(splt[1:])
|
|
tbl.append({"task": task, "metric": metric, "value": v})
|
|
summary_table = pd.DataFrame(tbl).set_index("task")
|
|
summary_table = summary_table.loc[args.task_order].round(4)
|
|
|
|
return summary_table
|
|
|
|
|
|
def main():
|
|
parser = make_parser()
|
|
args = parser.parse_args()
|
|
|
|
b = beaker.Beaker.from_env()
|
|
experiment = b.experiment.get(experiment=args.experiment_id)
|
|
|
|
metrics_all = {}
|
|
metrics_summary = {}
|
|
|
|
for job in experiment.jobs:
|
|
# Skip unfinished jobs.
|
|
eval_task = job.name.replace(args.job_suffix, "").replace(
|
|
"open_instruct_eval_", ""
|
|
)
|
|
|
|
if not job.is_done:
|
|
print(f"Eval for {eval_task} not finished. Skipping.")
|
|
continue
|
|
|
|
metrics = b.job.metrics(job.id)
|
|
if metrics is None:
|
|
# Case where no metrics are availble.
|
|
continue
|
|
|
|
metrics_all[eval_task] = metrics
|
|
|
|
summary_metric, full_name = get_summary_metric(metrics, eval_task)
|
|
if summary_metric is not None:
|
|
metrics_summary[full_name] = summary_metric
|
|
|
|
metrics_all["summary"] = metrics_summary
|
|
if args.print_table or args.table_file:
|
|
summary_table = make_summary_table(metrics_all["summary"], args)
|
|
|
|
if args.print_table:
|
|
print(summary_table)
|
|
if args.table_file is not None:
|
|
summary_table.to_csv(
|
|
args.table_file, sep="\t", index=True, float_format="%0.4f"
|
|
)
|
|
|
|
if args.output_file is not None:
|
|
json.dump(metrics_all, open(args.output_file, "w"), indent=2)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|