本人对AI发展有着浓厚的兴趣, 也参加过一些大模型相关的大赛,在考研之余会研究一些前沿AI的paper作为兴趣,想着把我自己的研究和思考发发csdn分享一下,内容是由我自己的研究理解、paper原文和与AI深度交流过后的一些精选内容组成,本人只是一个ai爱好者,内容请大家理性甄别,欢迎沟通讨论(不喜勿喷)

一、论文要解决什么问题?  

问题背景:

        假设你是一个程序员,想用AI写代码,但发现现有的工具(比如GitHub Copilot)虽然强大,但闭源(无法自由修改和研究)。而开源的模型(比如CodeLlama)虽然免费,但效果不够好,尤其在处理复杂项目或跨文件的代码时容易出错。

论文的目标:

        开发一个开源的代码生成模型(DeepSeek Coder),性能接近闭源模型(如GPT 3.5),甚至超过它们。让模型能理解整个项目的结构(而不仅仅是单个文件),并能处理长代码和复杂任务。

 二、核心创新点

1. 项目级数据构建

        传统方法的问题:

        假设你学做菜,但只学了“切洋葱”和“煎牛排”两个步骤,却不知道如何把这些步骤组合成一道完整的菜。这就是传统模型的问题——它们只学单个文件的代码,但不知道文件之间的依赖关系(比如一个文件用到了另一个文件的函数)。

        DeepSeek Coder的解决方案:

        像整理整个厨房一样整理代码,模型在训练时会把整个项目的文件按逻辑顺序拼接成一个样本。例如:

        文件A导入了文件B的函数,训练时会先放文件B的代码,再放文件A的代码。这样模型就能理解“为什么A要用到B的函数”,就像知道“煎牛排前必须先切牛排”一样。

        假设项目中有两个文件:  `math_utils.py`(工具函数,比如加法函数)  `main.py`(调用加法函数)  训练时,模型会把这两个文件按顺序拼接,确保`main.py`知道`math_utils.py`的存在,避免写代码时找不到函数。

 2.Fill in the Middle(FIM)训练  

        我们模型的第二个训练目标称为 fil-in-the-middle。在代码预训练场景中,通常需要根据给定的上下文和后续文本生成相应的插入内容。由于编程语言中的特定依赖关系,仅依靠 next token:预测不足以学习这种填充中间人功能。因此,几种方法(Bavarian et al.,2022;Li et al..2023)提出了 Fill-in-the-Midlle(FIM)的预训练方法。这种方法包括将文本随机分为三个部分,然后打乱这些部分的顺序并用特殊字符将它们连接起来。该方法旨在在训练过程中加入填空预训练任务。在 FIM 方法中,采用两种不同的模式:PSM(Prefix-Suffix-Middle)和 SPM(Sufix-Prefix-Middle)。在 PSM 模式下,训练语料库按 Pre fix、Su ffix、Middle 的顺序进行组织,以中间段两侧带有前缀和后缀的方式对齐文本。相反SPM 模式将段排列为 Su ffix、Pre fix、Middle,提出了不同的结构挑战。这些模式有助于增强模型处理代码中各种结构安排的能力,为高级代码预测任务提供强大的训练框架。(机翻原文)

        传统方法的问题:  

        模型像“填空游戏”,但只能从左到右补全。比如,如果句子是“我今天去__公园,看到了__”,模型只能补全“公园”后面的内容,但无法补全中间的空格。

         FIM的改进:  

        像玩拼图一样训练模型:将代码随机分成三段,打乱顺序后让模型还原。例如:  原始代码:`def add(a,b): return a + b`  。挖空后:`def add(a,b): <fim_hole> return`(中间挖空)。模型需要根据前后文补全`return a + b`。

         这样做模型能更好地处理  中间代码缺失  的情况,比如补全一个函数的中间逻辑,而不仅仅是续写。

 3.长上下文支持(16K上下文窗口) 

        为了增强 DeepSeek-Coder 处理扩展上下文的能力,特别是对于存储库级代码处理等场景,我们重新配置了 RoPE (Su et a., 2023) 参数以扩展默认上下文窗口。遵循以前的做法(Chen et al..2023;kaiokendev, 2023),我们采用了线性缩放策略,将缩放因子从1增加到 4,并将基本频率从10000 更改为 100000。该模型还进行了额外的 1000 个训练步骤,使用批量大小 512 和序列长度 16K学习率与最后的预训练阶段一样保持不变。从理论上讲,这些修改使我们的模型能够在上下文中处理多达64K个令牌。然而,实证观察表明,该模型在 16K 标记范围内提供了最可靠的输出。未来的研究将继续改进和评估长上下文适应方法,旨在进一步提高 DeepSeek-Coder 在处理扩展上下文方面的效率和用户友好性。 (机翻原文)

        问题:  

         想写一个超长的代码文件(比如1万行),但模型只能记住前面几百行,后面就“健忘”了。

        解决方案:  

        像记忆一本长篇小说一样记住代码,通过调整模型的参数(比如位置编码),让模型能处理长达16,384行的代码,理解更复杂的逻辑。

        例子:  

        写一个大型游戏程序时,模型能同时记住角色设定、关卡逻辑和输入控制,而不会混淆或遗漏关键步骤。

4.指令调优(让模型听懂自然语言)  

        通过使用高质量数据进行基于指令的微调来增强DeepSeek-Coder-Base 来开发 DeepSeek-Coder- Instruct。这些数据包括有用且公正的人工指令,由 Alpaca Instruction 格式构建(Taori et al., 2023)。为了划分每个对话回合,我们采用了一个独特的分隔符标记 <|EOT|> 来表示每个片段的结论。对于训练,我们使用具有 100 个热身步骤和初始学习率 1e-5 的余弦时间表。我们还总共使用 4M 令牌和 2B 令牌的批量大小。(机翻原文)

        问题:  

        你告诉模型“写一个贪吃蛇游戏”,但它可能完全不知道怎么开始,或者生成的代码有错误。

         下图描述了使用 DeepSeek-Coder-instruct 348 的示例。此示例是用于构建贪吃蛇游戏的多回合对话场景。最初,我们要求模型使用 pygame 编写一条游戏蛇。该模型成功地创建了一个基本的贪吃蛇游戏,它可以无错误地运行。为了改进游戏,我们进一步要求在左上角添加一个计分系统。然后,该模型引入了“score” 变量和一个“display score” 函数,并解释了如何集成这些功能。此示例说明了DeepSeek-Coderinstruct 在多轮次对话设置中提供完整的解决方案的能力。(机翻原文)

        解决方案: 

        像教小学生写作业一样训练模型,用大量人类写的“指令+代码”示例微调模型。例如:

        人类指令:“用Pygame写一个贪吃蛇游戏,并添加计分系统。”  

        模型学习后,能根据指令一步步生成代码,甚至先规划步骤再写代码(比如先画界面,再写移动逻辑)。

        例子:  

        用户输入:“帮我写一个计算器程序,支持加减乘除。”  

       模型会先生成代码框架,再逐个实现功能,而不是乱写一气。

三、训练过程:如何让模型变聪明?  

 1. 数据收集与清洗  

        数据来源  :  

        从GitHub上爬取87种语言的代码(比如Python、Java、C++),再加上自然语言文档(比如英文的StackExchange问答、中文的技术文章)。

       筛选规则  :  

      去掉垃圾代码(比如超长行、乱码),保留高质量代码,就像整理图书馆时只保留好书。

  2. 依赖解析与拓扑排序  

        比喻:    

        想做一道菜,但食材和步骤散落在不同地方。模型需要先整理所有步骤的顺序,确保先切菜再炒菜。

        具体操作:    

        分析代码文件间的依赖关系(比如文件A用到了文件B的函数)。  

        用算法(拓扑排序)确定文件拼接的顺序,确保依赖的文件先出现。

3. FIM训练策略 

        分三步训练:    

        1. 把代码分成三段:`前半段`、`中间段`、`后半段`。  

        2. 打乱顺序,比如变成`前半段 <空> 后半段`,模型需要补全中间段。  

        3. 同时练习“逐行写代码”和“填空”,平衡两种能力。

        例子:    

        原始代码:`for i in range(10): print(i)`  

        FIM训练时可能变成:`for i in range(10): <fim_hole>`,模型要补全`print(i)`。

 四、模型效果:为什么它比其他模型好?   

 1. 代码生成能力(HumanEval基准)  

         HumanEval  :测试模型能否写出通过测试用例的代码。  

         结果  :  

         DeepSeek Coder 33B在Python任务中通过率56.1%,比CodeLlama 34B(48.2%)更好。   小模型(6.7B)甚至比大模型(CodeLlama 34B)表现更好,说明数据质量很重要。

 2. 跨文件代码补全  

        问题  :  

        写一个Java程序,但需要用到另一个文件的类,模型能否正确引用?  

        结果  :  

       DeepSeek Coder在跨文件任务中的准确率比CodeLlama高5 8%,说明它更懂“项目整体结构”。

 3. 数学题解决能力(LeetCode)  

        例子  :  

        让模型解一道数学题:“找出最强的球队(没有比它更强的对手)”。  

        模型表现  :  

       DeepSeek Coder Instruct 33B的通过率27.8%,接近GPT 3.5(23.3%),远超其他开源模型。

 五、通俗总结:DeepSeek Coder是怎么做到的?  

1.   数据更聪明    

     不仅学单个文件,还学整个项目的结构,就像学做菜时知道所有步骤的顺序。  

     去掉重复和低质数据,只保留精华。

2.   训练方法创新  

       FIM训练  :像玩填空游戏,让模型学会补全中间代码,而不是只会续写。  

       长上下文  :能记住超长代码,处理复杂项目。

3.   理解自然语言  

     你可以说“写个登录页面”,模型能生成带验证的完整代码,而不需要复杂的指令。

4.   开源且强大  

     免费使用,性能接近闭源模型(如GPT 3.5),填补了开源代码模型的空白。

  六、关键指标解释(小白也能懂!)  

  1. HumanEval Pass@1(通过率)  

           简单解释  :  

           给模型一个编程任务(比如写一个函数),它一次写出正确代码的概率。  

          比如HumanEval的Python任务,DeepSeek Coder 33B通过率56.1%,意味着它有56%的概率一次写出正确的代码。

 2. LeetCode Pass@1  

           简单解释  :  

           在LeetCode的难题(比如算法题)中,模型一次写出能通过所有测试用例的代码的概率。  

           DeepSeek Coder 33B的通过率27.8%,说明它能解决较复杂的问题。

 3. FIM任务(填空能力)  

        简单解释  :  

        像玩填空游戏,模型补全中间代码的准确率。  

        DeepSeek Coder在Python的填空任务中准确率81.2%,比其他模型高。

七、为什么这些创新重要?  

        项目级数据是为了让模型理解代码的“全局视角”,比如一个函数可能依赖另一个文件,而不会“只见树木,不见森林”。FIM训练是为了类似人类写文章时需要补全中间段落,模型能处理更复杂的逻辑漏洞。而长上下文可以写一个包含多个函数的程序时,模型不会“健忘”,记得所有定义和逻辑。指令调优,你不用学复杂的代码提示,直接说“写个XXX程序”就行,模型能听懂并执行。

        DeepSeek Coder的优势我觉得是:

        像程序员一样思考,能理解项目结构,补全中间代码,处理长程序。  

        像助手一样听话,你用自然语言描述需求,它能生成可运行的代码。  

        开源免费,比闭源模型(如GitHub Copilot)更自由,适合开发者和研究者。

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐