Files
microsoft--unilm/PFPO/scripts/apps/prm/construct_process_rm_sample.py
2026-07-13 13:24:13 +08:00

155 lines
4.4 KiB
Python

import json
import argparse
from glob import glob
import os
import sys
import collections
from multiprocessing import Pool
from tqdm import tqdm
from functools import partial
sys.set_int_max_str_digits(0)
"""
For self-consistency based input-output pairs, first copy the pseudo test cases into the prefix data, run `prefix_fail_extract_pseudo_label.py`,
and the run this script.
This script is incorrect for pseudo test cases since we cannot ensure the correctness of each test case, but it is appropriate for ground-truth test cases,
serving as hard limit, i.e., if there is one completion for some prefix has passed all test cases, then it is a gold prefix.
"""
def counting_partial_response_value(res):
return sum([1 if x else 0 for x in res])
def parse_value(v, binary: bool):
if binary:
return 1 if v > 0 else 0
return v
def _process_trajectories_worker(item, top_k: int, binary: bool):
item_id, trajectories = item
outputs = {
"idx": item_id
}
for i in range(top_k):
level_trajectories = [(traj["vs"][i], traj["prefix"]) for traj in trajectories if len(traj["vs"]) > i]
if len(level_trajectories) == 0:
continue
prefix_vis = set()
level_values = []
level_prefixes = []
for v, prefix in level_trajectories:
if prefix in prefix_vis:
continue
level_values.append(parse_value(v, binary))
level_prefixes.append(prefix)
prefix_vis.add(prefix)
outputs[f"traj_level_{i}_values"] = level_values
outputs[f"traj_level_{i}_prefixes"] = level_prefixes
return outputs
def _annotate(file):
return json.load(open(file, encoding="utf-8"))
def multiprocessing_loading(files, num_workers: int = 8):
with Pool(num_workers) as p:
data = list(tqdm(p.imap(_annotate, files), total=len(files)))
all_data = []
for d in data:
all_data.extend(d)
return all_data
# data = []
# for file in tqdm(files):
# data += json.load(open(file, encoding="utf-8"))
# return data
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--input_file", type=str)
parser.add_argument("--output_file", type=str)
parser.add_argument("--binary", default=False, action="store_true")
parser.add_argument("--num_workers", type=int, default=8)
args = parser.parse_args()
print("Collecting data...")
if os.path.exists(args.input_file):
data = json.load(open(args.input_file))
else:
# data = []
# for file in glob(args.input_file):
# print(file)
# data += json.load(open(file))
files = glob(args.input_file)
files = sorted(files)
print(len(files))
print(files)
data = multiprocessing_loading(files)
print(len(data))
num_prefixes = 0
val_cnt = collections.Counter()
outputs = []
preference_pairs = dict()
missing = 0
for item in tqdm(data):
problem_id, resp_id, prefix_id = item["prefix_id"].split("_")
prefix = item["prefix"]
problem_id = int(problem_id)
if "res" not in item:
missing += 1
continue
v = counting_partial_response_value(item["res"])
v = parse_value(v, args.binary)
outputs.append({
"problem_id": problem_id,
"prefix": prefix,
"value": v,
})
num_prefixes += 1
val_cnt[v] += 1
if problem_id not in preference_pairs:
preference_pairs[problem_id] = {
"pos": [],
"neg": [],
}
if v > 0:
preference_pairs[problem_id]["pos"].append(prefix)
else:
preference_pairs[problem_id]["neg"].append(prefix)
preference_pairs = [
{
"problem_id": problem_id,
"pos": pair["pos"],
"neg": pair["neg"],
}
for problem_id, pair in preference_pairs.items()
]
print(f"Missing: {missing}")
print(val_cnt)
print(f"Processed {num_prefixes} prefixes.")
print(f"Averaged {num_prefixes / len(data)} prefixes per problem.")
json.dump(outputs, open(args.output_file, "w", encoding="utf-8"), indent=2, ensure_ascii=False)
json.dump(preference_pairs, open(args.output_file.replace(".json", "_pairs.json"), "w", encoding="utf-8"), indent=2, ensure_ascii=False)
if __name__ == '__main__':
main()
"""
>>>
"""