141 lines
16 KiB
Markdown
141 lines
16 KiB
Markdown
# CodeI/O:通过代码输入-输出预测凝练推理模式
|
||
|
||
> **原文标题**:CodeI/O: Condensing Reasoning Patterns via Code Input-Output Prediction
|
||
> **arXiv**:[2502.07316](https://arxiv.org/abs/2502.07316) | **发布**:2025-02-11(v1),最后修订 2025-05-21(v4)
|
||
> **作者/机构**:Junlong Li(上海交通大学,于 DeepSeek-AI 实习期间完成)、Daya Guo、Dejian Yang、Runxin Xu、Yu Wu(DeepSeek-AI / 深度求索)、Junxian He(HKUST)
|
||
> **原文 PDF**:[03-CodeIO-2502.07316.pdf](./03-CodeIO-2502.07316.pdf)
|
||
|
||
## 一、摘要(全文翻译)
|
||
|
||
推理是大语言模型(Large Language Model, LLM)的一项基础能力。尽管此前的研究主要聚焦于增强数学或代码生成这类较窄的技能,但由于训练数据稀疏且碎片化,提升许多其他推理任务的性能仍然充满挑战。为解决这一问题,我们提出 **CodeI/O**,一种新方法:它把原始代码转化为「代码输入-输出预测」格式,从而系统性地凝练(condense)那些本就内嵌于有上下文语境的代码(contextually-grounded code)之中的多样化推理模式。通过训练模型在给定代码与测试用例的情况下、完全以自然语言作为思维链(Chain-of-Thought, CoT)推理过程来预测输入/输出,我们让模型接触到通用的推理原语——例如逻辑流程规划、状态空间搜索、决策树遍历与模块化分解——同时将结构化推理与代码特有的语法解耦,并保留过程的严谨性。实验结果表明,CodeI/O 在符号推理、科学推理、逻辑推理、数学与数值推理以及常识推理任务上都带来了一致的提升。通过将预测结果与已有标准答案比对,或使用预测出的输入重新执行代码,我们可以验证每一条预测,并通过多轮修订进一步增强 CoT,由此得到 CodeI/O++,并取得更高的性能。我们的数据与模型发布于 https://github.com/hkust-nlp/CodeIO 。
|
||
|
||
## 二、核心贡献
|
||
|
||
1. **提出「代码输入-输出预测」任务**:把原始代码改写为可执行函数,让模型完全以自然语言 CoT 预测「给定输入的输出」或「给定输出的可行输入」,将推理流程从代码语法中剥离而不失严谨。
|
||
2. **构建可扩展数据集 CodeI/O**:由约 810.5K 个代码文件筛出 454.9K 个可执行函数,执行代码自动生成输入-输出对,再由 DeepSeek-V2.5 合成 CoT,得到 3.5M 条样本(输入/输出预测约各半)。
|
||
3. **CodeI/O++ 兑现代码可验证性**:对第一轮预测错误的回答追加执行反馈并要求重写,把两轮回答与反馈拼接为更长响应,不丢弃任何错误样本即提升数据质量。
|
||
4. **跨模型、跨领域普适增益**:四个 7B–30B 基座、14 个基准上的平均分全面超过单阶段指令微调基线,以及 WebInstruct、OpenMathInstruct2、OpenCoder-SFT-Stage1、Python-Edu 等强基线。
|
||
5. **均衡而非偏科**:其他数据集常在某任务领先、别处回退,CodeI/O 几乎全基准一致提升,说明收益来自学到推理模式而非数据量堆积。
|
||
6. **系统性分析**:消融证明输入预测与输出预测缺一不可、拒绝采样反而有害;13-gram 泄漏检测表明提升不能归因于数据泄漏。
|
||
|
||
## 三、方法与技术要点
|
||
|
||
### 3.1 动机:为什么做「代码输入-输出预测」
|
||
|
||
论文指出的悖论是:数学解题与代码生成已有充足的结构化数据,而逻辑推导、科学推断、符号推理等领域只有稀疏、碎片化的监督。真实代码天然汇聚多样推理模式,但两条常规路径都不理想:在原始代码上做持续预训练(continual pre-training)时推理信号隐式且与噪声纠缠;文本到代码生成虽目标更干净,却被迫产出代码特有语法,难以迁移到代码之外。因此作者「逆用」代码:给定函数与文字 query,让模型用自然语言推理出输出或可行输入。其价值在于**解耦**——推理流程脱离语法外壳——与**重复暴露**:原代码的多样语境让模型反复接触逻辑流程编排、状态空间探索、递归分解、决策等基础技能,从而内化。该任务与代码持续预训练类似,被置于通用指令微调之前。
|
||
|
||
### 3.2 原始代码收集(§2.1)
|
||
|
||
三大来源各有侧重,共计约 810.5K 个代码文件(见下表):CodeMix 补充算法内容,PyEdu-R 刻意剔除算法类文件以与其错开,其他来源提供高质量难题与竞赛代码。
|
||
|
||
| 数据源 | 筛选方式 | 文件数 |
|
||
|---|---|---|
|
||
| CodeMix | 取自内部代码预训练语料,用 DeepSeek-Coder-V2-Lite-Inst 做函数补全,保留成功率 10%–90% 的文件(滤除过简/过难) | 约 427K |
|
||
| PyEdu-R(reasoning) | Python-Edu 子集,先分类为算法/逻辑谜题/数学/科学计算/系统建模/其他复杂推理/非推理,剔除算法与非推理以避免与 CodeMix 重叠 | 约 369K |
|
||
| 其他来源 | 综合算法仓库(TheAlgorithms/Python)、Project Euler、LeetCode、CodeWars、Edabit、Codeforces、AtCoder、CodeChef | 约 14.5K |
|
||
|
||
### 3.3 转换为统一格式(§2.2)
|
||
|
||
原始代码缺少结构、难以自包含执行,故用 DeepSeek-V2.5 重构为五部分:①**清洗后的参考代码**——核心逻辑抽取为函数,剔除绘图(print、plot)与文件读写;②**主入口函数**——概括整体逻辑,可调用其他函数或导入外部库,须有非空输入与有意义的返回值,且输入输出均可 JSON 序列化;③**输入/输出描述**——明确数据类型、约束(如输出范围)或更复杂的要求(如字典的键);④**输入生成器**——不直接产出测试用例,而是生成基于规则的 Python 函数,在约束下引入随机性以可扩展地产出「非平凡」输入;⑤**Query**——描述代码预期功能的简洁问题陈述。
|
||
|
||
### 3.4 采集输入-输出对(§2.3)
|
||
|
||
对每个函数采样多个输入并执行代码取得真实输出;为保证确定性,含随机性的函数(如使用 `import random`)全部跳过。执行约束见下表(附录 A),对象复杂度检查递归作用于所有子对象,以确保结果落在通用 LLM 可预测的范围内。
|
||
|
||
| 约束项 | 阈值 |
|
||
|---|---|
|
||
| 单样本运行时限 | 5 秒 |
|
||
| 输入/输出对象总大小 | < 1024 字节 |
|
||
| 列表 / 字典长度 | < 20 |
|
||
| 字符串长度 | ≤ 100 字符 |
|
||
| 其他类型对象大小 | ≤ 128 字节 |
|
||
|
||
过滤不可执行、超时与超复杂度样本后,得到来自 454.9K 个代码文件的 3.5M 条实例,输入/输出预测大致均衡(50%/50%)。各来源采样密度不同(附录 C.2):CodeMix 每函数至多 3 对(300K 样本,平均 2.78/2.80,共 1,674,345 条);PyEdu-R 至多 6 对(141K 样本,平均 5.77/5.79,共 1,630,716 条);其他来源至多 10 对(13.9K 样本,平均 7.70/7.87,共 216,159 条)。
|
||
|
||
### 3.5 构建训练样本:CodeI/O 与 CodeI/O++(§2.4)
|
||
|
||
每条样本由 prompt 与 response 组成:prompt 用模板组合函数、query、参考代码与一个具体输入或输出;response 应是自然语言 CoT,说明如何推出正确输出或可行输入。作者未用自动执行轨迹作答案:输入预测无法得到确定性的「逆函数」,且模板化轨迹缺乏自由语言推理的表达力与泛化性。故全部响应由 DeepSeek-V2.5 合成(性能顶级、成本低),这构成 **CodeI/O**。
|
||
|
||
**CodeI/O++** 放弃常见的拒绝采样:既然能重新执行代码验证回答,本可丢弃错误预测,但实测性能反而次优(§4.1)。作者改为把执行反馈作为第二轮输入追加并要求重写:输出预测只告知答案错误;输入预测额外给出「基于错误输入实际执行得到的输出」;执行失败(格式错误、参数不匹配或其他运行时错误)也显式告知。最终响应拼接为「第一轮回答 + 第一轮反馈 + 第二轮回答 + 第二轮反馈」;第一轮已正确时反馈仅为「Success」且无第二轮内容。第一轮约 50% 回答正确,错误回答中约 10% 可在第二轮修正;对错一律保留。
|
||
|
||
### 3.6 两阶段训练策略(§3.1)
|
||
|
||
第一阶段在 CodeI/O(++) 上训练,第二阶段在约 1.18M 条内部指令数据(多领域、多语言)上做通用指令微调。之所以分阶段而非直接混合:CodeI/O(++) 样本量远大于指令数据,混合会造成分布偏置、令指令跟随能力学习不足。超参数见下表(附录 E)。
|
||
|
||
| 阶段 | 训练量 | 批大小 | 学习率 | 其他 |
|
||
|---|---|---|---|---|
|
||
| 第一阶段 | 1 epoch | 1024 | 1e-5(三个较小模型)/4e-6(Gemma 2 27B),恒定 | 无 warmup,最大序列长度 4096 |
|
||
| 第二阶段 | 700 步(约指令数据 3 epoch) | 1024 | 3e-5/1e-5,余弦调度衰减至 1e-6/3e-7 | 无 warmup,最大序列长度 4096 |
|
||
|
||
## 四、主要实验结果
|
||
|
||
评测覆盖 14 个基准(名称见下表):其中 LeetCode-O 为自建,只给文字 query 不给函数、中英双语、按问题级准确率计分;BBH-ZH 由 9 个 BBH 子任务翻译而来。除 BBH-EN/-ZH 用 3-shot 外,其余均为零样本、greedy 解码。
|
||
|
||
| 基座模型(平均分 AVG) | 单阶段基线(仅指令微调) | 第一阶段最强对比数据集 | CodeI/O | CodeI/O++ |
|
||
|---|---|---|---|---|
|
||
| Qwen 2.5 Coder 7B | 54.8 | 56.0(OpenMathInstruct2 全量 14.0M) | 57.2 | **57.7** |
|
||
| LLaMA 3.1 8B | 49.3 | 50.6(OpenMathInstruct2 3.5M) | 51.2 | **52.1** |
|
||
| DeepSeek Coder v2 Lite 16B (MoE) | 51.6 | 52.1(Python-Edu 7.7M / OpenMathInstruct2 3.5M) | **53.6** | 53.5 |
|
||
| Gemma 2 27B | 59.5 | 60.4(WebInstruct 3.5M / OpenMathInstruct2 3.5M) | 60.9 | **61.5** |
|
||
|
||
以 Qwen 2.5 Coder 7B 为例的分项对比:
|
||
|
||
| 基准 / 任务 | 单阶段基线 | CodeI/O | CodeI/O++ | 说明 |
|
||
|---|---|---|---|---|
|
||
| WinoGrande | 66.9 | 67.9 | 66.9 | 常识推理,持平 |
|
||
| DROP | 70.7 | 76.4 | **79.1** | 阅读理解中的数值推理,+8.4 |
|
||
| GSM8K | 83.4 | 86.4 | 85.7 | 小学数学,约 +2 |
|
||
| MATH | 71.6 | 71.9 | 72.1 | 竞赛数学,小幅提升 |
|
||
| GPQA | 41.5 | 43.3 | 40.6 | 学科问答,++ 反而回退 |
|
||
| MMLU-STEM | 77.2 | 77.3 | 77.9 | 学科知识,持平 |
|
||
| LeetCode-O | 20.7 | 23.7 | **24.2** | 自建输出预测,+3.5 |
|
||
| CRUXEval-I | 61.3 | 63.6 | 62.5 | 输入预测 |
|
||
| CRUXEval-O | 60.0 | 64.9 | **67.9** | 输出预测,+7.9 |
|
||
| BBH-EN | 68.3 | 69.3 | **71.0** | +2.7 |
|
||
| BBH-ZH | 70.6 | 72.8 | **74.2** | +3.6 |
|
||
| ZebraLogic | 10.9 | 10.7 | 10.7 | 逻辑网格谜题,略降 |
|
||
| KorBench | 38.7 | 44.3 | **45.7** | 规则泛化推理,+7.0 |
|
||
| LiveBench | 26.0 | 28.5 | **29.1** | 综合基准,+3.1 |
|
||
|
||
CodeI/O 在四个基座上普遍带来增益,且增益是「均衡」的:对比数据集常绿红混杂,它却几乎全绿——仅用代码类数据便提升了符号、逻辑、数学、科学与常识任务,说明学到的是可迁移的推理模式。而在原始代码语料(Python-Edu 7.7M)上训练相对基线只有微小甚至负向提升,证明收益不来自数据规模,而来自训练任务的设计。少数任务(如 ZebraLogic)性能几乎不变甚至下降,并非每项必然提升。
|
||
|
||
主要分析结论:
|
||
|
||
| 分析维度 | 结论 |
|
||
|---|---|
|
||
| 输入预测 vs 输出预测 | 单独训练总体相近(各约 56.1/56.4,全量 57.2)。输入预测在 KorBench 更强但略损 GPQA,输出预测更利于 BBH 等符号推理;CRUXEval-I 与 -O 分别偏好输入预测与输出预测。 |
|
||
| 拒绝采样 | 丢弃错误回答会删掉 50% 数据,总体性能下降,作者归因于多样性损失;把错误回答替换为执行得到的真值(无 CoT)虽提升 LeetCode-O/CRUXEval-O,却在别处下降、拉低平均(56.6),且与样本量相当的 ~50% 子集(56.7)相比无优势,故保留全部错误回答。 |
|
||
| 合成模型的影响 | 用 DeepSeek-V2.5 重新合成 3.5M WebInstruct 子集(WebInstruct-DS25)优于原版,但仍不及 CodeI/O,说明收益超出「从强模型蒸馏知识」。 |
|
||
| 规模效应 | 随机采样显示训练实例越多越好;在 I/O 对维度放大(固定代码样本、增加每样本测试用例)也有清晰收益,尤其从 1/6 增至 6/6,说明某些推理模式需多个测试用例才能完整学到。 |
|
||
| 数据格式 | query 与参考代码放 prompt、CoT 放 response 时平均分最高且最均衡;最差格式为 query 在 prompt 而参考代码在 response(类似标准代码生成任务),凸显 CoT 与测试用例扩展的重要性。 |
|
||
| 多轮修订 | 第 0→1 轮提升一致,第 1→2 轮收益极小(LLaMA 3.1 8B 略升、Qwen 2.5 Coder 7B 回退),模型常重复同样的错误 CoT,故主实验止步单轮修订。 |
|
||
| 两阶段 vs 混合 | 所有两阶段变体均优于单阶段混合训练;Qwen 2.5 Coder 7B 上最优为完全分离 CodeI/O 与指令数据,LLaMA 3.1 8B 则混入数据更好,为简化方法主实验采用完全分离。 |
|
||
| 数据泄漏 | 严格 13-gram 检测(去标点、数字、空白后比对)显示多数基准无风险或远低于增益:LeetCode-O 21.5%、KorBench 5.1%、MMLU 0.1%、MATH 0.1%、CRUXEval 0.1%、其余 0.0%。重叠仅为「数独规则」等通用描述或共享描述的姊妹题(Two Sum I/II);完整集与去泄漏子集的样本级增益几乎一致(如 Qwen 在 LeetCode-O 为 3.8/3.9),故提升不是数据泄漏所致。 |
|
||
|
||
## 五、结论、局限与影响
|
||
|
||
- **结论**:论文提出 CodeI/O,让模型用纯自然语言 CoT 预测代码的输入与输出,借代码结构化、可扩展、可执行验证的特性学习符号、逻辑、数学与常识等推理模式。在四个 7B–30B 基座、14 个基准上,CodeI/O 与 CodeI/O++ 一致优于现有基线,跨基准均衡提升而几乎不牺牲任何领域性能。作者强调该方向与推理时扩展(o1、DeepSeek-R1)正交,可为激发 LLM 推理能力提供更好的基础。
|
||
- **局限性**:论文未设专门的 Limitations 章节,但正文与附录自述了若干不足:① 少数任务(如 ZebraLogic、CodeI/O++ 的 GPQA)不升反降,提升并非在所有基准上成立;② 多轮修订第二轮收益甚微、Qwen 上甚至回退,故只做到单轮;③ PyEdu-R 样本多集中于非平凡浮点计算、缺少高层推理流程,模型难以有效学习,提纯该数据源被列为未来工作(附录 C.3);④ 训练数据与测试基准的模式重叠不可避免,只能以 13-gram 检测与去泄漏子集论证影响有限;⑤ 最优数据混合策略尚未确定;⑥ 换成公开指令数据 Tulu-3 时 CodeI/O++ 略逊于 CodeI/O,说明效果依赖指令数据的类型覆盖。
|
||
- **影响**:该工作把代码从「生成目标」转化为**推理监督的来源**,给出不依赖数学/代码标注、可自动扩展与验证的通用推理能力提升路径;「用执行反馈修订而非丢弃数据」与「先强化基座推理、再指令微调」的配方亦具借鉴意义。
|
||
|
||
## 六、关键术语对照表
|
||
|
||
| English | 中文 |
|
||
|---|---|
|
||
| Code Input-Output Prediction | 代码输入-输出预测 |
|
||
| Reasoning Pattern | 推理模式 |
|
||
| Chain-of-Thought (CoT) | 思维链 |
|
||
| Contextually-grounded Code | 有上下文语境的代码 |
|
||
| Input / Output Prediction | 输入预测/输出预测 |
|
||
| Main Entrypoint Function | 主入口函数 |
|
||
| Input Generator | 输入生成器 |
|
||
| Unified Format | 统一格式 |
|
||
| Rejection Sampling | 拒绝采样 |
|
||
| Multi-turn Revision | 多轮修订 |
|
||
| Execution Feedback | 执行反馈 |
|
||
| Code Execution Verification | 代码执行验证 |
|
||
| Continual Pre-training | 持续预训练 |
|
||
| Two-stage Training | 两阶段训练 |
|
||
| Instruction Tuning | 指令微调 |
|
||
| Data Leakage (13-gram overlap) | 数据泄漏(13-gram 重叠) |
|