返回报告库

AI / Technology

DeepSeek-Coder代码模型为什么要看项目,而不只看单个文件

这篇论文不只是“再训练一个更大的代码模型”。它把三个容易混在一起的改动拆开做:按项目依赖组织训练数据、让模型练习补代码中间的缺口,再把可靠上下文扩到 16K。真正值得理解的是,这三件事各自解决什么问题,又有哪些结果能单独支撑它们。

原论文: DeepSeek-Coder: When the Large Language Model Meets Programming — The Rise of Code Intelligence
作者: Daya Guo 等 · arXiv:2401.14196

只看当前文件,模型可能连函数该传几个参数都不知道

真实项目里,一个文件经常调用另一个文件里的函数。上图用一个最小例子说明这个缺口:如果模型只看到 checkout.py,它看不到 formatter.py 里的函数定义,就可能补出参数数量不匹配的调用。让依赖文件进入上下文后,模型至少拿到了完成这次调用所需的信息。

论文指出,之前的代码模型多以单个文件为训练单位,容易忽略项目内部的跨文件依赖。这里展示的是教学例子,不是论文实验中的原始代码;它说明的是“缺少依赖信息”这一类失败,并不保证模型看到依赖后就一定写对业务逻辑。【论文 §2.2,pp. 3–5;§4.3,p. 14】

项目级预训练先把依赖文件排到调用者前面

DeepSeek-Coder 先从 importincludeusing 等调用关系里解析“谁依赖谁”,再把被依赖的文件排到调用者前面。最后,它给每个文件加上路径,并把排好序的一组文件拼成一条训练样本。这样做没有增加一个新的推理模块;它改变的是模型在预训练时反复看到代码的顺序。

这个顺序为什么可能有用?当 utils.py 总是在调用它的 app.py 之前出现,普通的下一个 token 预测也有机会利用前面已经出现的定义。论文的实现只用正则表达式抽取调用关系,并用修改过的拓扑排序处理循环;它不是完整的程序语义分析,所以仍可能漏掉动态调用或复杂依赖。【论文 §2.2,pp. 3–5】

FIM 改变的不是窗口大小,而是模型拿到上下文的顺序

普通续写只根据左边已经出现的代码预测下一段。Fill-in-the-Middle(FIM)则把一段代码随机切成前文、中间和后文,再把训练顺序改成“前文 → 后文 → 中间”。模型因此能用缺口两边的信息预测中间内容,这更接近编辑器里“在已有代码中间补一段”的任务。

DeepSeek-Coder 采用 PSM 顺序,并在文档级别、打包训练样本之前执行 FIM。16K 是另一项改动:论文另外调整 RoPE 并继续训练 1,000 步,把可靠上下文扩到约 16K。FIM 决定“中间缺口能否同时看两边”,长窗口决定“一次能放进多少上下文”,两者不能压成同一个“看得更多”。【论文 §3.1.2,pp. 7–8;§3.6,p. 9】

论文没有把 FIM 拉到 100%,因为填空和普通续写会互相拉扯

论文用 1.3B 模型和一部分 Python 训练数据做了消融。100% FIM 在 HumanEval-FIM 上最好,却让普通代码续写最弱;50% PSM 又比 50% MSP 的填空效果更好。作者因此没有追求单项最高,而是选择 50% PSM,让一半样本练中间填空,另一半保留普通续写。

图中的长条只表达论文报告的相对关系,不是从曲线里猜出的精确分数。这个消融能支持“训练比例存在取舍”,但它只覆盖小模型、Python 子集和单行填空任务,不能证明 50% 对所有语言、规模和真实编辑场景都最优。【论文 Figure 3;§3.1.2,pp. 7–8】

有因果支撑的是项目级预训练;整套性能仍不能拆开归因

CrossCodeEval 是这里最接近因果检验的一组结果:在同一个 6.7B 模型、同样使用 BM25 检索的设置下,保留项目级预训练后,Python、Java、TypeScript 和 C# 的精确匹配率分别提高 0.12、1.08、0.80 和 1.75 个百分点。提升不算巨大,也不是每种语言一样大,但方向一致,说明依赖排序训练确实贡献了一部分跨文件能力。【论文 Table 7;§4.3,p. 14】

整体成绩更强,但不能全归给这一项。33B 基础模型在多语言 HumanEval 平均为 50.3%,MBPP 为 66.0%;同表中的 CodeLlama-Base 34B 分别是 41.0% 和 55.2%。33B 指令模型的多语言 HumanEval 平均为 69.2%,高于表中的 GPT-3.5-Turbo 64.9%,但 MBPP 是 70.0%,略低于 GPT-3.5-Turbo 的 70.8%。这些结果来自数据清洗、项目级组织、模型规模、FIM、长上下文和指令微调共同作用,论文没有把总提升完整拆到每个组件上。【论文 Table 3;§4.1,p. 11】

研究附录

一页结论

  • 论文发布了 1.3B、6.7B 和 33B 三种规模的 Base 与 Instruct 模型,从零训练 2 万亿 tokens,覆盖 87 种编程语言。
  • 数据由 87% 源代码、10% 英文代码相关自然语言和 3% 中文自然语言组成。
  • 论文最有辨识度的贡献不是“2 万亿”这个规模,而是把仓库内依赖关系带进预训练样本,并用 CrossCodeEval 做了组件对照。
  • FIM 的证据显示填空与普通续写之间有取舍;论文选 50% PSM,而不是把所有样本都改成填空。
  • 长上下文调整理论上可到 64K,但作者明确说可靠输出主要在 16K 内;正文没有给出一组隔离 16K 改动的完整任务消融。

关键实验数字

问题对照结果能说明什么
同规模基础模型代码生成DeepSeek-Coder-Base 33B vs CodeLlama-Base 34B多语言 HumanEval 50.3% vs 41.0%;MBPP 66.0% vs 55.2%整套基础模型训练方案更强,不能只归因于项目级数据
指令模型与闭源基线DeepSeek-Coder-Instruct 33B vs GPT-3.5-Turbo多语言 HumanEval 69.2% vs 64.9%;MBPP 70.0% vs 70.8%“超过 GPT-3.5”取决于具体任务,不能写成全面领先
中间填空DeepSeek-Coder-Base 6.7B / 33B三语言平均精确匹配率 80.7% / 81.2%FIM 能力强;规模增加后的提升有限
项目级预训练消融保留 vs 去掉项目级预训练四种语言精确匹配率均提高 0.12–1.75 个百分点直接支持项目级数据组织对跨文件补全有贡献

实验边界

CrossCodeEval 的比较把最大输入长度设为 2,048 tokens,跨文件检索上下文最多 512 tokens,输出最多 50 tokens。因此,它检验的是“检索到跨文件片段后,模型能否更好利用”,并不是把整个仓库一次塞进 16K 窗口。

论文自建的 LeetCode Contest 基准包含 2023 年 7 月到 2024 年 1 月的 180 道题,每题 100 个测试用例。作者仍提醒,GPT-4-Turbo 和 DeepSeek-Coder 在较早月份得分更高,不能完全排除数据污染。

来源

关于这篇论文的三个关键问题

DeepSeek-Coder:代码模型为什么要看项目,而不只看单个文件 解决了什么问题?

这篇论文不只是“再训练一个更大的代码模型”。它把三个容易混在一起的改动拆开做:按项目依赖组织训练数据、让模型练习补代码中间的缺口,再把可靠上下文扩到 16K。真正值得理解的是,这三件事各自解决什么问题,又有哪些结果能单独支撑它们。

DeepSeek-Coder:代码模型为什么要看项目,而不只看单个文件 的核心结论有哪些证据?

CrossCodeEval 是这里最接近因果检验的一组结果:在同一个 6.7B 模型、同样使用 BM25 检索的设置下,保留项目级预训练后,Python、Java、TypeScript 和 C# 的精确匹配率分别提高 0.12、1.08、0.80 和 1.75 个百分点。提升不算巨大,也不是每种语言一样大,但方向一致,说明依赖排序训练确实贡献了一部分跨文件能力。【论文 Table 7;§4.3,p. 14】

阅读 DeepSeek-Coder:代码模型为什么要看项目,而不只看单个文件 时最需要注意什么局限?

整体成绩更强,但不能全归给这一项。33B 基础模型在多语言 HumanEval 平均为 50.3%,MBPP 为 66.0%;同表中的 CodeLlama-Base 34B 分别是 41.0% 和 55.2%。33B 指令模型的多语言 HumanEval 平均为 69.2%,高于表中的 GPT-3.5-Turbo 64.9%,但 MBPP 是 70.0%,略低于 GPT-3.5-Turbo 的 70.8%。这些结果来自数据清洗、项目级组织、模型规模、FIM、长上下文和指令微调共同作用,论文没有把总提升完整拆到每个组件上。【论文 Table 3;§4.1,p. 11】

今天还可免费读 2 篇新报告订阅 Pro 后无限阅读,并获得每月 10 篇新论文生成额度。升级 Pro