Files
2026-07-13 13:24:13 +08:00

266 lines
9.7 KiB
Python

import argparse
import io
import json
import multiprocessing
import os.path
import sys
from collections import defaultdict, Counter
from concurrent.futures import ThreadPoolExecutor, as_completed
from multiprocessing import Pool
import resource
from tqdm import tqdm
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
from eval.mbpp_eval.execute import time_limit, TimeoutException
# Function to set memory limits (e.g., 100 MB)
def set_memory_limit(memory_limit_mb):
soft, hard = resource.getrlimit(resource.RLIMIT_AS)
resource.setrlimit(resource.RLIMIT_AS, (memory_limit_mb * 1024 * 1024, hard))
def unsafe_execute(check_program, result, timeout):
set_memory_limit(256)
# Create a StringIO stream to capture output
output = io.StringIO()
# Save the current stdout (standard output)
current_stdout = sys.stdout
# Set the stdout to the StringIO stream
sys.stdout = output
# Run program.
try:
exec_globals = {}
# with swallow_io():
with time_limit(timeout):
exec(check_program, exec_globals)
result.append("passed")
except TimeoutException:
result.append("timed out")
except BaseException as e:
result.append(f"failed: {e}")
finally:
# Restore stdout to its original setting
sys.stdout = current_stdout
result.append(output.getvalue())
# def capture_print_output(check_program, timeout=1.0):
# """
# Evaluates the functional correctness of a completion by running the test
# suite provided in the problem.
#
# :param completion_id: an optional completion ID so we can match
# the results later even if execution finishes asynchronously.
# """
# # manager = multiprocessing.Manager()
# # result = manager.list()
# # p = multiprocessing.Process(target=unsafe_execute, args=(check_program, result, timeout))
# # p.start()
# # p.join(timeout=timeout + 1)
# # if p.is_alive():
# # p.kill()
#
# result = []
# unsafe_execute(check_program, result, timeout)
#
# if not result:
# result.append("timed out")
# result.append("")
#
# passed = result[0] == "passed"
# output = result[1]
#
# return output, passed
def capture_print_output(code, timeout=2):
# output_queue = multiprocessing.Queue()
manager = multiprocessing.Manager()
output_queue = manager.list()
process = multiprocessing.Process(target=unsafe_execute, args=(code, output_queue, timeout))
process.start()
process.join(timeout)
if process.is_alive():
process.terminate()
process.join()
return "Error: Timeout", False
if not output_queue or len(output_queue) < 2: # TODO: I don't know the case when the length of `output_queue` is 1.
return "Error: Unknown", False
else:
passed, output = output_queue
return output, passed
def test_single_case(program, test_case):
if "assert" in test_case:
test_case = test_case.replace("assert ", "").strip()
program = program + "\n\n" + f"print({test_case})"
output, passed = capture_print_output(program, timeout=3)
return output, passed
def _worker(_input):
task_id, program_id, case_id, program, test_case = _input
output, passed = test_single_case(program, test_case)
return task_id, program_id, case_id, output, passed
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--program_prediction_file", type=str)
parser.add_argument("--test_cases", type=str)
parser.add_argument("--num_workers", type=int, default=8)
parser.add_argument("--top_k_prog", type=int, default=100)
parser.add_argument("--top_k_case", type=int, default=100)
args = parser.parse_args()
program_predictions = json.load(open(args.program_prediction_file))
programs = {}
for item in program_predictions:
if item["task_id"] not in programs:
programs[item["task_id"]] = {
"task_id": item["task_id"],
"prompt": item["prompt"],
"programs": set(),
}
programs[item["task_id"]]["programs"].add(item["completion"])
test_cases = json.load(open(args.test_cases))
test_cases = {int(task_id): item["aug_cases"][:args.top_k_case] for task_id, item in test_cases.items()}
for task, item in programs.items():
programs[task] = {
"task_id": item["task_id"],
"prompt": item["prompt"],
"programs": list(item["programs"])[:args.top_k_prog],
}
mp_inputs = []
for task in programs:
for program_id, program in enumerate(programs[task]["programs"]):
for case_id, test_case in enumerate(test_cases[task]):
mp_inputs.append((task, program_id, case_id, program, test_case))
pbar = tqdm(mp_inputs, total=len(mp_inputs))
task_results = defaultdict(dict)
# with Pool(args.num_workers) as p:
# # for result in p.imap(_worker, mp_inputs):
# for result in p.imap_unordered(_worker, mp_inputs):
# task_id, program_id, case_id, output, passed = result
# if passed is False:
# continue
# if case_id not in task_results[task_id]:
# task_results[task_id][case_id] = {}
#
# if not output:
# print(f"Warning: empty output with task id {task_id} and case id {case_id}\n\nProgram:\n{programs[task_id]['programs'][program_id]}")
#
# if output not in task_results[task_id][case_id]:
# task_results[task_id][case_id][output] = []
# task_results[task_id][case_id][output].append(program_id)
#
# pbar.update()
with ThreadPoolExecutor(max_workers=args.num_workers) as executor:
futures = []
for _input in pbar:
future = executor.submit(_worker, _input)
futures.append(future)
pbar.update()
for future in tqdm(as_completed(futures), total=len(futures), desc="Collecting results"):
result = future.result()
task_id, program_id, case_id, output, passed = result
if passed is False:
continue
if case_id not in task_results[task_id]:
task_results[task_id][case_id] = {}
if not output:
print(f"Warning: empty output with task id {task_id} and case {test_cases[task_id][case_id]}\n\n"
f"Program:\n{programs[task_id]['programs'][program_id]}\n\nOutput: {output}")
continue
# print(f"Task: {task_id}, Program: {program_id}, Case: {test_cases[task_id][case_id]}, Passed: {passed}")
# print(f"Program: {programs[task_id]['programs'][program_id]}")
# print(f"Output: {output}")
# print("========================================================================")
if output not in task_results[task_id][case_id]:
task_results[task_id][case_id][output] = []
task_results[task_id][case_id][output].append(program_id)
# for _input in pbar:
# result = _worker(_input)
# task_id, program_id, case_id, output, passed = result
# print(f"Task: {task_id}, Program: {program_id}, Case: {case_id}, Passed: {passed}")
# print(f"Program: {programs[task_id]['programs'][program_id]}")
# print(f"Output: {output}")
# if passed is False:
# continue
# if case_id not in task_results[task_id]:
# task_results[task_id][case_id] = {}
#
# if not output:
# print(f"Warning: empty output with task id {task_id} and case id {case_id}\n\nProgram:\n{programs[task_id]['programs'][program_id]}")
#
# if output not in task_results[task_id][case_id]:
# task_results[task_id][case_id][output] = []
# task_results[task_id][case_id][output].append(program_id)
sc_results = []
visited = {}
for task_id, cases in tqdm(task_results.items(), total=len(task_results)):
program_pass_cnt = Counter()
for case_id, outputs in cases.items():
if not outputs:
continue
tmp = sorted([(len(v), k) for k, v in outputs.items()], reverse=True)
maj_program_ids = outputs[tmp[0][1]]
program_pass_cnt.update(maj_program_ids)
if not program_pass_cnt:
continue
best_program_id = program_pass_cnt.most_common(1)[0][0]
sc_results.append({
"task_id": task_id,
"completion": f"[BEGIN]\n{programs[task_id]['programs'][best_program_id]}\n[END]",
})
visited[task_id] = True
cnt = 0
for task, programs in programs.items():
cnt += 1
if task not in visited:
sc_results.append({
"task_id": task,
"completion": f"[BEGIN]\n{programs['programs'][0]}\n[END]",
})
print(f"Missing {cnt} programs.")
print(len(sc_results))
with open(args.program_prediction_file.replace(".json", f"_sc_{args.top_k_prog}_{args.top_k_case}.jsonl"), "w") as f:
for item in sc_results:
f.write(json.dumps(item) + "\n")
json.dump(task_results, open(args.program_prediction_file.replace(".json", f"_sc_{args.top_k_prog}_{args.top_k_case}_outputs.json"), "w"))
if __name__ == "__main__":
main()
"""
python scripts/mbpp/run_test_case_v1.0.py --program_prediction_file ../msranlpintern/instruction_tuning/experiments/h100/oos_sc2_magicdoer_mix/model_lr3e-6_batch512_epochs3_gpus8_linearSchedule/evaluation/open_instruct_results_local/mbpp_257_n100/mbpp_eval_predictions.json --test_cases outputs/mbpp/mbpp_test_case_inputs.w_test.v1.0.compl.gpt-4-32k.tem1.0.combine.json
"""