chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,154 @@
|
||||
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()
|
||||
|
||||
"""
|
||||
>>>
|
||||
"""
|
||||
@@ -0,0 +1,189 @@
|
||||
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.
|
||||
|
||||
|
||||
Note:
|
||||
1. Sometimes the pseudo test cases can include some extremely large cases, leading to out-of-memory error.
|
||||
"""
|
||||
|
||||
|
||||
def counting_partial_response_value(full_res):
|
||||
pass_num = []
|
||||
for pred_res in full_res:
|
||||
if len(pred_res) == 0:
|
||||
pass_num.append(0)
|
||||
# elif pred_res[0] == -1: # FIXME: This line is commented since 2024/09/25. Seems no difference.
|
||||
# pass_num.append(0)
|
||||
else:
|
||||
pass_num.append(sum([1 for x in pred_res if x is True]))
|
||||
|
||||
return pass_num
|
||||
|
||||
|
||||
def annotate(file, exclude: str = ""):
|
||||
exclude = exclude.split(",")
|
||||
if any([e and e in file for e in exclude]):
|
||||
print(f"Excluding {file}")
|
||||
return []
|
||||
return json.load(open(file, encoding="utf-8"))
|
||||
|
||||
|
||||
def multiprocessing_loading(files, exclude: str = "", num_workers: int = 8):
|
||||
_annotate = partial(annotate, exclude=exclude)
|
||||
|
||||
# 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 += _annotate(file)
|
||||
return data
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--input_file", type=str)
|
||||
parser.add_argument("--output_file", type=str)
|
||||
parser.add_argument("--pass_case_margin", type=float, default=1)
|
||||
parser.add_argument("--pass_case_lower_bound", type=float, default=0.5)
|
||||
parser.add_argument("--test_case_field", type=str, default="pseudo_input_output")
|
||||
parser.add_argument("--num_workers", type=int, default=8)
|
||||
parser.add_argument("--reduction", type=str, default="max")
|
||||
parser.add_argument("--exclude", type=str, default="")
|
||||
args = parser.parse_args()
|
||||
|
||||
print("Collecting data...")
|
||||
if os.path.exists(args.input_file):
|
||||
data = json.load(open(args.input_file))
|
||||
else:
|
||||
files = glob(args.input_file)
|
||||
files = sorted(files)
|
||||
print(len(files))
|
||||
print(files)
|
||||
data = multiprocessing_loading(files, args.exclude)
|
||||
|
||||
print(len(data))
|
||||
|
||||
num_prefixes = 0
|
||||
val_cnt = collections.Counter()
|
||||
outputs = []
|
||||
p_id2prefixes = collections.defaultdict(list)
|
||||
preference_pairs = []
|
||||
missing = 0
|
||||
missing_test_cases = 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
|
||||
|
||||
if args.test_case_field not in item or (not isinstance(item[args.test_case_field], dict)) or "inputs" not in item[args.test_case_field]:
|
||||
missing_test_cases += 1
|
||||
continue
|
||||
|
||||
test_case_num = len(item[args.test_case_field]["inputs"])
|
||||
if test_case_num == 0:
|
||||
missing_test_cases += 1
|
||||
continue
|
||||
|
||||
pass_num = counting_partial_response_value(item["full_res"])
|
||||
if args.reduction == "max":
|
||||
max_pass_num = max(pass_num)
|
||||
elif args.reduction == "avg":
|
||||
max_pass_num = sum(pass_num) / len(pass_num)
|
||||
else:
|
||||
raise NotImplementedError
|
||||
|
||||
outputs.append({
|
||||
"problem_id": problem_id,
|
||||
"prefix": prefix,
|
||||
"pass_num": pass_num,
|
||||
"max_pass_num": max_pass_num,
|
||||
"test_case_num": test_case_num,
|
||||
})
|
||||
num_prefixes += 1
|
||||
val_cnt.update(pass_num)
|
||||
|
||||
p_id2prefixes[problem_id].append(outputs[-1])
|
||||
|
||||
for problem_id, all_prefixes in tqdm(p_id2prefixes.items()):
|
||||
max_pass_num2prefixes = collections.defaultdict(list)
|
||||
for prefix in all_prefixes:
|
||||
max_pass_num2prefixes[prefix["max_pass_num"]].append(prefix)
|
||||
max_pass_num2prefixes = sorted(max_pass_num2prefixes.items(), key=lambda x: x[0])
|
||||
|
||||
pos_prefixes = []
|
||||
neg_prefixes = []
|
||||
for p in all_prefixes:
|
||||
pass_ratio = p["max_pass_num"] / p["test_case_num"]
|
||||
if pass_ratio < args.pass_case_lower_bound:
|
||||
continue
|
||||
neg_upper_pass_num = p["max_pass_num"] - args.pass_case_margin
|
||||
|
||||
target_neg = []
|
||||
for pass_num, prefixes in max_pass_num2prefixes:
|
||||
if pass_num < neg_upper_pass_num:
|
||||
target_neg.extend([x["prefix"] for x in prefixes])
|
||||
else:
|
||||
break
|
||||
|
||||
pos_prefixes.append(p["prefix"])
|
||||
neg_prefixes.append(target_neg)
|
||||
|
||||
preference_pairs.append({
|
||||
"problem_id": problem_id,
|
||||
"pos": pos_prefixes,
|
||||
"neg": neg_prefixes
|
||||
})
|
||||
|
||||
print(f"Missing: {missing}")
|
||||
print(f"Missing test cases: {missing_test_cases}")
|
||||
print(val_cnt)
|
||||
print(f"Processed {num_prefixes} prefixes.")
|
||||
print(f"Averaged {num_prefixes / len(data)} prefixes per problem.")
|
||||
print(f"Processed {len(preference_pairs)} problems.")
|
||||
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", f"_low{args.pass_case_lower_bound}_m{args.pass_case_margin}_{args.reduction}.json"),
|
||||
"w", encoding="utf-8"), indent=2, ensure_ascii=False)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
"""
|
||||
>>> python scripts/apps/prm/construct_process_rm_sample_fix.py \
|
||||
--input_file "/mnt/fangkai_blob/reward_modeling//experiments/deepseek-coder-v1.5-ins.7b.apps.r2c.gpt4o.distil.V100.w8.v3.1.dp4.tp4.s42/apps/checkpoint-200/train.tem1.0.n10.prefix.upper0.8.r0.3.completion.tem1.0.n5.v2.0.[0-9]*-of-256.pseudo_test_case.exec.json" \
|
||||
--output_file /mnt/fangkai_blob/reward_modeling//experiments/deepseek-coder-v1.5-ins.7b.apps.r2c.gpt4o.distil.V100.w8.v3.1.dp4.tp4.s42/apps/checkpoint-200/train.tem1.0.n10.prefix.upper0.8.r0.3.completion.tem1.0.n5.v2.0.pseudo_test_case.prefix_pass_num.fix.json \
|
||||
--pass_case_lower_bound 0.8 --pass_case_margin 4 --test_case_field pseudo_input_output
|
||||
|
||||
|
||||
>>> python scripts/apps/prm/construct_process_rm_sample_fix.py \
|
||||
--input_file "${OUTPUT_PREFIX_PATH}/experiments/deepseek-coder-v1.5-ins.7b.apps.r2c.sft_ps_test_case.process-dpo.V100.tp8dp16.v4.9.s42/oss-instruct-apps-train/checkpoint-700/train.tem1.0.n10.prefix.upper0.8.r0.3.sample20_per.completion.tem1.0.n3.pseudo_input_output.exec.*-of-256.json" \
|
||||
--output_file ${OUTPUT_PREFIX_PATH}/experiments/deepseek-coder-v1.5-ins.7b.apps.r2c.sft_ps_test_case.process-dpo.V100.tp8dp16.v4.9.s42/oss-instruct-apps-train/checkpoint-700/train.tem1.0.n10.prefix.upper0.8.r0.3.sample20_per.completion.tem1.0.n3.pseudo_input_output.prefix_pass_num.fix.json \
|
||||
--pass_case_lower_bound 0.5 --pass_case_margin 4 --test_case_field pseudo_input_output --reduction avg --test_case_field input_output --exclude "204-of-256,225-of-256"
|
||||
|
||||
Missing: 0
|
||||
Missing test cases: 0
|
||||
Counter({10: 448824, 0: 153053, 9: 25420, 1: 23469, 8: 16718, 5: 15115, 2: 14803, 3: 12821, 4: 12253, 7: 12053, 6: 11947, 11: 724, 20: 112, 16: 3}) # TODO: This should be a problem. Why there are some problems have more than 10 test cases?
|
||||
Processed 249105 prefixes.
|
||||
Averaged 1.0 prefixes per problem.
|
||||
"""
|
||||
@@ -0,0 +1,152 @@
|
||||
import json
|
||||
import argparse
|
||||
import os
|
||||
from glob import glob
|
||||
import sys
|
||||
import random
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.set_int_max_str_digits(0)
|
||||
|
||||
from post_processors.code.clean import get as get_code_cleaner
|
||||
|
||||
|
||||
def sample_step(response: str, code: str, upper_step_ratio: float, sample_ratio: float):
|
||||
if code:
|
||||
assert code in response, (code, "\n\n========================\n\n", response)
|
||||
end_of_response = response.find(code) + len(code)
|
||||
response = response[:end_of_response]
|
||||
|
||||
orig_lines = response.split("\n")
|
||||
lines = [(i, line) for i, line in enumerate(orig_lines)]
|
||||
lines = [(i, line) for i, line in lines if line.strip()]
|
||||
|
||||
if len(lines) < 5:
|
||||
return []
|
||||
|
||||
upper_step = int(len(lines) * upper_step_ratio)
|
||||
if upper_step == 0:
|
||||
return []
|
||||
|
||||
sample_step_num = int(upper_step * sample_ratio)
|
||||
if sample_step_num == 0:
|
||||
return []
|
||||
|
||||
sample_steps = random.sample(lines[:upper_step], sample_step_num)
|
||||
if len(sample_steps) == 0:
|
||||
return []
|
||||
|
||||
step_prefixes = []
|
||||
for i, line in sample_steps:
|
||||
step_prefixes.append("\n".join(orig_lines[:(i + 1)]))
|
||||
|
||||
return step_prefixes
|
||||
|
||||
|
||||
def load_files(file_path):
|
||||
data = []
|
||||
if os.path.exists(file_path):
|
||||
print(f"Loading pseudo test cases from {file_path}")
|
||||
if file_path.endswith(".json"):
|
||||
data.extend(json.load(open(file_path)))
|
||||
else:
|
||||
data.extend([json.loads(line) for line in open(file_path).readlines()])
|
||||
else:
|
||||
for file in glob(file_path):
|
||||
print(file)
|
||||
if file.endswith(".json"):
|
||||
data.extend(json.load(open(file)))
|
||||
else:
|
||||
data.extend([json.loads(line) for line in open(file).readlines()])
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def merge_key(item, value):
|
||||
assert isinstance(item, list)
|
||||
if isinstance(value, list):
|
||||
item = item + value
|
||||
else:
|
||||
item.append(value)
|
||||
return item
|
||||
|
||||
|
||||
def merge_seed_sampled_data(data):
|
||||
id2data = {}
|
||||
large_mem = 0
|
||||
for item in data:
|
||||
if isinstance(item["response"], str):
|
||||
item["response"] = [item["response"]]
|
||||
assert isinstance(item["pred"], str) or item["pred"] is None
|
||||
item["pred"] = [item["pred"]]
|
||||
|
||||
if item["id"] not in id2data:
|
||||
id2data[item["id"]] = item
|
||||
continue
|
||||
|
||||
tmp = id2data[item["id"]]
|
||||
|
||||
tmp["response"] = merge_key(tmp["response"], item["response"])
|
||||
tmp["pred"] = merge_key(tmp["pred"], item["pred"])
|
||||
assert isinstance(tmp["pred"], list), tmp["pred"]
|
||||
id2data[item["id"]] = tmp
|
||||
|
||||
print(f"Too large outputs: {large_mem}")
|
||||
return list(id2data.values())
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--input_file", type=str, )
|
||||
parser.add_argument("--output_file", type=str, )
|
||||
parser.add_argument("--upper_step_ratio", type=float)
|
||||
parser.add_argument("--sample_ratio", type=float)
|
||||
parser.add_argument("--filter_all_correct", action="store_true")
|
||||
parser.add_argument("--sample_over_p", type=int, default=-1)
|
||||
args = parser.parse_args()
|
||||
|
||||
data = load_files(args.input_file)
|
||||
data = merge_seed_sampled_data(data)
|
||||
|
||||
outputs = []
|
||||
num = 0
|
||||
for item in data:
|
||||
if args.filter_all_correct and all(item["res"]):
|
||||
continue
|
||||
|
||||
prefixes = []
|
||||
prefix_ids = []
|
||||
if not item["response"]:
|
||||
item["prefix"] = []
|
||||
continue
|
||||
|
||||
for resp_id, resp in enumerate(item["response"]):
|
||||
response_prefixes = sample_step(resp, item["pred"][resp_id], args.upper_step_ratio, args.sample_ratio)
|
||||
prefixes.extend(response_prefixes)
|
||||
prefix_ids.extend([f"{item['id']}_{resp_id}_{i}" for i in range(len(response_prefixes))])
|
||||
|
||||
if args.sample_over_p > 0:
|
||||
if len(prefixes) > args.sample_over_p:
|
||||
prefixes = random.sample(prefixes, args.sample_over_p)
|
||||
prefix_ids = random.sample(prefix_ids, args.sample_over_p)
|
||||
|
||||
item["prefix"] = prefixes
|
||||
item["prefix_id"] = prefix_ids
|
||||
outputs.append(item)
|
||||
num += len(prefixes)
|
||||
|
||||
json.dump(outputs, open(args.output_file, "w", encoding="utf-8"), indent=2, ensure_ascii=False)
|
||||
print(f"Total number of samples: {num}")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
"""
|
||||
>>> python scripts/apps/prm/sample_steps.py \
|
||||
--input_file "../msranlpintern/reward_modeling/experiments/deepseek-coder-v1.5-ins.7b.apps.r2c.gpt4o.distil.V100.w8.v3.1.dp4.tp4.s42/apps/checkpoint-200/train.0shot.tem1.0.n10.?-of-4.v2.0.json" \
|
||||
--upper_step_ratio 0.8 --sample_ratio 0.3 \
|
||||
--output_file ../msranlpintern/reward_modeling/experiments/deepseek-coder-v1.5-ins.7b.apps.r2c.gpt4o.distil.V100.w8.v3.1.dp4.tp4.s42/apps/checkpoint-200/train.0shot.tem1.0.n10.prefix.upper0.8.r0.3.json
|
||||
|
||||
Total number of samples: 470010
|
||||
"""
|
||||
Reference in New Issue
Block a user