CodeDPO: Aligning Code Models with Self Generated and Verified Source Code¶
会议: ACL 2025
arXiv: 2410.05605
代码: https://anonymous.4open.science/r/CodeDPO/
领域: LLM对齐 / 代码生成
关键词: code generation, DPO, self-validation, PageRank, code efficiency
一句话总结¶
提出 CodeDPO,通过 PageRank 启发的自验证评分机制从自生成代码中构造高质量偏好对(93K 正确性 + 21K 效率),DPO 训练后在 8 个代码模型上 HumanEval 平均提升 10+ 分,同时提升代码执行效率 1.25-1.45×。
研究背景与动机¶
- 领域现状:代码生成模型主要通过 SFT 提升。但 SFT 在提升正确代码概率的同时也提升了错误代码的概率,导致性能饱和。DPO 在推理任务中效果好但在代码生成中尚未充分探索。
- 现有痛点:代码 DPO 需要正/负偏好对,但构造可靠偏好对面临两个难题:(1) 自生成测试用例质量参差——低质量测试会误判代码正确性;(2) 仅优化正确性不够,代码效率同样重要。
- 核心矛盾:简单地用"通过测试=正/未通过=负"来构造偏好对会被低质量测试用例污染。需要一种机制来同时评估测试用例和代码的可靠性。
- 本文要解决什么:如何从自生成代码和测试中构造高质量偏好对,同时优化正确性和效率?
- 切入角度:借鉴 PageRank 的互参照思想——通过更多测试的代码更可信,被更多代码通过的测试更可靠。
- 核心 idea 一句话:用 PageRank 式迭代自验证评分取代简单的通过/未通过判定,构造高质量偏好对做 DPO。
方法详解¶
整体框架¶
四步:(1) 从开源代码库提取编程概念生成多样化题目;(2) 对每题生成 15 个代码解 + 15 组测试用例,用 PageRank 式互验证评分排序,取极端对作为正确性偏好对;(3) 在可信测试集上测量执行时间,快/慢配对作为效率偏好对;(4) RPO 格式(加权 SFT + DPO)训练。
关键设计¶
- PageRank 式自验证评分 (Self-Validation Score):
- 做什么:对每道题的 15 个代码和 15 组测试用例,构造二部图——代码节点和测试节点之间的边表示"通过"关系
- 核心思路:迭代更新(T=10 轮,阻尼系数 d=0.85):\(Score_t(c_i) = (1-d) \cdot Score_{t-1}(c_i) + d \cdot \sum_j Score_{t-1}(t_j) \cdot Link(t_j, c_i)\)
-
设计动机:被多个高分代码通过的测试更可信 → 通过更多高分测试的代码更正确,形成正向循环。比简单计数"通过了几个测试"(Spearman r=0.77)相关性更高(r=0.86)
-
双维度偏好对构造:
- 正确性偏好(93K 对):按自验证评分排序,取评分最高和最低的代码配对
- 效率偏好(21K 对):在自验证评分高(正确性有保证)的代码中,按执行时间配对快/慢版本
-
设计动机:正确性和效率是代码质量的两个正交维度,分别构造偏好对各自优化
-
RPO 训练策略:
- 做什么:使用 RPO 格式 loss = 加权 SFT loss + 原始 DPO loss
- 核心思路:SFT loss 确保模型不偏离正确生成模式,DPO loss 拉开正负样本差距
- 设计动机:纯 DPO 可能导致模型行为不稳定,RPO 增加了稳定性
损失函数 / 训练策略¶
RPO 格式 loss,10 epochs,lr=5e-6,线性调度 + warmup,16 × A100,DeepSeekCoder-v2 生成数据,温度 1.5。整个数据集构造成本约 $80。
实验关键数据¶
主实验 (HumanEval / HumanEval+)¶
| 模型 | 基线 | + CodeDPO | 提升 |
|---|---|---|---|
| MagiCoder-S-DS-6.7B | 73.17 / 68.29 | 83.54 / 76.22 | +10.37 / +7.93 |
| DeepSeekCoder-6.7B | 47.60 / 39.60 | 59.75 / 51.83 | +12.15 / +12.23 |
| StarCoder2-7B | 35.40 / 29.90 | 48.17 / 34.15 | +12.77 / +4.25 |
| Phi-2-2.7B | 48.78 / 46.34 | 57.32 / 51.83 | +8.54 / +5.49 |
| DeepSeekCoder-1.3B | 31.53 / 28.65 | 42.07 / 38.04 | +10.54 / +9.39 |
消融实验 (DeepSeekCoder-1.3B)¶
| 偏好对构造方法 | HumanEval | HumanEval+ |
|---|---|---|
| 随机选对 | 21.34 | 18.29 |
| 按通过测试数排序 | 37.19 | 31.09 |
| 用所有测试过滤 | 34.75 | 29.89 |
| CodeDPO (自验证评分) | 42.07 | 38.04 |
关键发现¶
- 自验证评分与真实正确性的 Spearman 相关系数 0.86,显著高于简单计数(0.77)和全测试过滤(0.61)
- 代码效率提升 1.25-1.45× 加速,20-45% 的生成代码至少快 10%
- 在 LiveCodeBench 上也有效(Easy: +12%,Medium: +5.6%),证明泛化性
- DPO 比 KTO 更有效(42.07 vs 40.85 HumanEval),因为 CodeDPO 的偏好对构造天然平衡
- 数据量从 25% 到 100% 持续提升,但增长趋于平缓
- 数据污染检查:与 HumanEval 的平均相似度仅 0.109,低于 Self-Instruct (0.169)
亮点与洞察¶
- PageRank 自验证是最核心的设计:将代码-测试的互验证建模为图上的迭代信誉传播,比简单的通过率计数更准确地反映代码质量。这个思想可迁移到任何需要自动评分的场景。
- 正确性+效率双维度优化很实际:真实编程中不只要求代码"能跑",还要求"跑得快"。分开构造偏好对各自优化是巧妙的解耦策略。
- 极低的数据构造成本(~$80)证明了自生成+自验证范式的经济性。
局限性 / 可改进方向¶
- 未与 RL 方法(如 GRPO、Reinforcement++)对比,可能不如在线 RL 强
- 基于测试用例的正确性评估天然有边界情况遗漏问题——通过所有测试 ≠ 100% 正确
- 未优化代码可读性和安全性维度
- 自验证评分依赖于有足够数量的代码和测试探索空间,题目太简单或太难时可能失效
相关工作与启发¶
- vs AceCoder:AceCoder 侧重于构建专用 RM + RL,CodeDPO 侧重于离线 DPO + 自验证评分。两者互补:CodeDPO 的自验证评分可作为 AceCoder 的偏好对构造方法
- vs RLTF (Liu et al. 2023):RLTF 用编译/执行反馈做 RL,但不做评分——只有通过/不通过。CodeDPO 的 PageRank 评分提供更细粒度的质量排序
- vs CodeRL:CodeRL 用 critic model 做奖励,需要额外训练。CodeDPO 完全自包含,不需要外部 RM
评分¶
- 新颖性: ⭐⭐⭐⭐ PageRank 自验证评分 + 效率优化维度有创意
- 实验充分度: ⭐⭐⭐⭐⭐ 8 个模型 × 4 个基准 + 效率评估 + 详细消融 + 数据扩展分析
- 写作质量: ⭐⭐⭐⭐ 方法叙述清晰,消融实验设计合理
- 价值: ⭐⭐⭐⭐ 低成本高效的代码对齐方法