PFPO 如何用 GPT-4o 合成解法并在 APPs 数据上完成代码 SFT?
【免费下载链接】unilmLarge-scale Self-supervised Pre-training Across Tasks, Languages, and Modalities项目地址: https://gitcode.com/GitHub_Trending/un/unilm
如果你要给一个 7B 级的代码模型补强算法题能力,直接拿 GPT-4o 的输出做蒸馏数据有个明显风险:模型生成的解法里混着错误代码。PFPO(Preference Optimization for Reasoning with Pseudo Feedback,ICLR 2025,代码位于本仓库PFPO/目录)的代码实验采用了一条“先合成、后用官方测试用例过滤、再 SFT”的路径:以deepseek-coder-7b-instruct-v1.5为底模,用 GPT-4o 按 APPs 题目批量生成解法,只保留能通过 APPs 自带input_output测试用例的解法,然后启动 SFT 训练。下面按这条路径还原仓库中给出的完整操作步骤与验证方式。
准备环境
PFPO/README.md 给出的依赖安装方式:
- 大部分依赖列在 requirements.txt,按该文件安装即可;
- flash-attention 需要单独自行安装(
pip install,需要匹配的 CUDA/PyTorch 环境); - 官方也提供 docker 镜像,一条命令拉取:
docker pull jiaofangkai/normal:torch-2.5.1-vllm-0.6.4.post1-eval-1206注意:拉取镜像只完成环境准备,不替代后续任何步骤。合成解法和过滤脚本需要网络执行环境(见下文 sandbox 说明),SFT 训练需要多机 GPU 资源(仓库中的配置按 2 台 8xV100 节点编写)。
第一步:从 APPs 训练集生成 GPT-4o 提示词
README 在 “SFT on APPs” 小节中说明,团队用一种特殊格式从 GPT-4o 收集 SFT 数据,提示词模板的生成入口是:
python scripts/apps/pp_solution_gen_inputs.py阅读 pp_solution_gen_inputs.py 可以看到它的具体行为:
- 从 HuggingFace 加载
codeparrot/apps数据集的train分片(可用--split参数更换); - 对每条数据,把
question字段填入内置的vanilla提示词模板(要求模型按“先分析复杂度、再逐步设计算法、最后写出 Python 程序”的顺序作答,并把代码放在<BEGIN>和<END>标签之间); - 结果写入一个 JSON Lines 文件,每行在原 APPs 字段(含
question、problem_id、input_output等)之外多出一个prompt字段。
这里有一个 README 命令中没有写出的必选参数:脚本的--output_file是required=True,实际执行时必须指定,例如:
python scripts/apps/pp_solution_gen_inputs.py --output_file outputs/apps/apps.train.r2c.vanilla.gpt-4o.prompts.jsonl--prompt_type默认为vanilla,当前仓库中只有这一种模板,无需修改。
生成好带prompt的请求文件后,将请求发给 GPT-4o 服务获取解法。仓库提供了两个 API 调用入口:openai_api_caller_v1.py(OpenAI API 推理入口,基于 Hydra 配置)和 service_api_caller_v1.py(服务化 API 入口)。两者都是标准的@hydra.main(config_path="conf", config_name="config")程序,用-cp/-cn指定PFPO/conf/下的配置目录与配置名来驱动。README 没有给出合成 APPs 解法这一环节对应的具体配置名,执行前请在PFPO/conf/下确认你使用的 GPT-4o 服务版本,并把产出保存为下文过滤脚本所需的 completion 文件。
第二步:用 APPs 官方测试用例过滤 GPT-4o 解法
拿到 completion 文件(GPT-4o 的原始输出)后,运行 README 给出的过滤命令:
python scripts/apps/solution_fail_extract.py --completion_file $completion_file --output_file $output_file --num_workers 16$completion_file是上一步的 GPT-4o 输出文件,也支持 glob 模式(脚本会按problem_id去重合并多个分片文件);$output_file是过滤结果的保存路径。
阅读 solution_fail_extract.py 可以确认它的判定逻辑,这也是“可核对”的关键:
- 用正则
<BEGIN>(.*?)<END>从每条 completion 中提取代码,提取失败的解法直接判为不可用(results记为False); - 对提取成功的代码,调用 utils_execute.py 中的
check_correctness,在 APPs 数据自带的input_output测试用例上逐条执行(超时 10 秒); - 某解法全部测试用例通过时才记
True,只要有任一用例失败即为False; - 结果写入
$output_file,每个条目带pred(提取出的解法)、res(各 completion 是否全部通过)、full_res(逐用例结果)、outputs、errors等字段。
脚本跑完后会在终端打印三行统计,这是本步骤的验证信号:
Missing: {missing / len(outputs)} Correct: {corr / len(outputs)} Correct at k: {corr_at_k / len(outputs)}这是文档示例形式的输出模板,具体数值取决于你的 completion 数据。Missing表示无法从输出中提取出代码的比例,Correct表示首个 completion 通过全部测试用例的比例,Correct at k表示至少一个 completion 通过的比例。若Missing偏高,说明 GPT-4o 输出没有稳定遵守<BEGIN>/<END>标签格式,需要回到提示词或服务配置环节检查。
过滤产出的文件同时承担了下一个步骤的“正样本表”:SFT 配置通过extra_file从中按problem_id取出通过测试的解法。
第三步:配置并启动 SFT 训练
训练入口是trainer_base_ds_mul_fs_tp.py,README 给出的 APPs SFT 启动命令为:
torchrun --nnodes 2 --nproc_per_node 8 --node_rank $NODE_RANK --master_addr $MASTER_ADDR --master_port $MASTER_PORT trainer_base_ds_mul_fs_tp.py \ -cp conf/exp/apps/r2c_generation/deepseek_coder/sft/ -cn gpt4o-distil-v3.1-v100$NODE_RANK、$MASTER_ADDR、$MASTER_PORT是两节点分布式训练的环境变量,在各节点上按你的集群设置导出。README 明确该实验运行在 2 台 8xV100 节点上;GPU 更少时,按 README 中数学部分给出的方法相应调大配置里的gradient_accumulation_steps。
对应配置文件是 gpt4o-distil-v3.1-v100.yaml,其中与“GPT-4o 解法 SFT”直接相关的字段:
train_file: "hf:codeparrot/apps":从 HuggingFace 加载 APPs 训练集,由data.apps.APPsWithFunctionName读取(apps.py),train_sub_split: train表示先按 apps_train_sub_val_ids.json 剔除留出验证子集,use_starter_code: True表示把题目自带的 starter code 拼进question;extra_file: ${data_path_prefix}outputs/apps/apps.train.r2c.vanilla.gpt-4o.tem1.0.n11.exec.dpo_v1.0.json:这就是第二步过滤结果文件的路径(通过field_extract_aligner按problem_id提取pos字段,即通过测试的 GPT-4o 解法,再经recompose_template拼入训练样本)。你的实际产物路径不同时,需要在这里改成自己的文件;prompt指向 r2c_prompt_0shot_v1.0.txt,与第一步的 vanilla 模板一致(要求把代码写在<BEGIN>与<END>之间);model_name_or_path: ${model_path_prefix}/deepseek-coder-7b-instruct-v1.5,model_path_prefix默认为../pretrained-models/:底模 deepseek-coder-7b-instruct-v1.5 需放在该相对路径下,或修改前缀指向你的模型目录;- 训练超参:
learning_rate: 1e-5、per_gpu_train_batch_size: 1、gradient_accumulation_steps: 16、max_steps: 500、max_seq_length: 3072(collator 内)、fp16: True、save_steps: 100; - 输出目录:
${output_path_prefix}experiments/${exp_name},exp_name形如deepseek-coder-v1.5-ins.7b.apps.r2c.gpt4o.distil.V100.w8.v3.1.dp4.tp4.s42,checkpoint 按save_steps周期性落盘。
训练启动后以 loss 日志(logging_steps: 5)与experiments/<exp_name>/apps/checkpoint-*目录下产出 checkpoint 作为进行中的检查点;本配置中do_eval: False,训练过程不含验证集评估。
一个需要在启动前确认的限制:该配置tp_size: 4,即启用了基于 FairScale 的张量并行(模型加载走models.llama_tp.LlamaForCausalLM.from_pretrained)。README 的 “Enable Tensor Parallel based on FairScale” 小节说明,启用张量并行前需要用scripts/model_converter/convert_llama_to_llama_tp.py把原始模型转换为张量并行格式,且该脚本目前只支持Llama、Qwen和Mistral系列;当前仓库PFPO/scripts/model_converts/下并未包含这个转换脚本(只有llama_hf_mp_split.py和pad_model_embedding.py)。因此如果你的底模不在上述受支持系列内,不能直接照搬该配置,需要先解决张量并行模型的转换问题,或参照 README 数学部分的说明把tp_size置 1 并另行处理并行配置。
结果验证:用仓库评测配置跑 SFT 模型
训练结束后,README 的 “Evaluation Configs” 小节给出的评测方式是:python vllm_inference.py -cp $config_path -cn $config_name,评测包含在推理过程中,不需要单独的评估命令。代码任务对应的配置文件:
- APPs:
conf/api/vllm/apps/deepseek_coder/r2c/dev_v2_0.yaml - HumanEval:
conf/api/vllm/human_eval/ds_coder/r2c/test_v2_2_local.yaml - MBPP-257:
conf/api/vllm/mbpp_sanitized/r2c/test_v1_0_local.yaml
README 的 APPs 结果表中列出了这条 SFT 路径的参考成绩(deepseek-coder-7B-v1.5底模):
| 阶段 | APPs Overall | HumanEval | MBPP |
|---|---|---|---|
| 底模 Instruct | 14.3 | 75.6 | 73.9 |
| w/ SFT (APPs) | 15.4 | 72.0 | 72.8 |
这是论文实验值,作为判断你复现结果是否落在合理区间的参考,而不是固定预期。
边界与下一步
- 整条链路里 GPT-4o 解法的合法性完全由 APPs 自带测试用例保证(
check_correctness全通过才保留),不要把未过滤的原始 completion 直接喂给 SFT 配置; solution_fail_extract.py会在本地多线程执行模型生成的 Python 代码(每条用例 10 秒超时),README 在类似的伪测试用例执行环节明确建议“in sandbox”运行,本步骤执行任意生成代码前请同样做好隔离;- 完成 SFT 后,README “DPO on APPs based Ground-truth Test Cases” 一节给出了下一步:用 SFT checkpoint 跑
vllm_inference.py(配置conf/api/vllm/apps/deepseek_coder/r2c/train_v2_0)采样完整轨迹,再用 construct_prefer_pair.py 依据测试用例结果构造偏好对,做 DPO 训练。这属于 PFPO 偏好优化阶段,与本文的 SFT 任务是独立环节,按需参考。
【免费下载链接】unilmLarge-scale Self-supervised Pre-training Across Tasks, Languages, and Modalities项目地址: https://gitcode.com/GitHub_Trending/un/unilm
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考