Paper name
Code Llama: Open Foundation Models for Code
Paper Reading Note
Paper URL: https://ai.meta.com/research/publications/code-llama-open-foundation-models-for-code/
Project URL: https://about.fb.com/news/2023/08/code-llama-ai-for-coding/
Blog URL: https://ai.meta.com/blog/code-llama-large-language-model-coding/
Code URL: https://github.com/facebookresearch/codellama
TL;DR
- 2023 年 meta 出品的代码大模型文章,发布了 Code Llama,基于 Llama 2 的一系列大型代码语言模型,提供了在开放模型中的最先进性能、填充能力、支持大输入上下文以及 zero-shot 编程任务指令跟随能力。
Introduction
背景
- 使用大规模的领域内(in-domain)数据集,可以使得训练的模型在需要自然语言和领域特定语言以及专业术语理解相结合的应用中得到极大的性能提高
- 比如程序合成、代码补全、调试和生成文档等方向
- 目前已有的代码大模型方案的问题及对应的 codellama 解决方案
- 基础模型的代码训练:AlphaCode、InCoder、StarCoder 等模型下只在 code 数据上预训练过,Codex 是基于一个通用语言模型微调得到
- codellama 从 llama2 预训练模型基础上得到,因为 llama2 预训练有通用数据和代码数据,实验证明比只有 code 预训练的模型性能好
- 填充:LLMs的自回归训练和微调适用于提示完成,但不能在考虑完整周围上下文的情况下填补缺失的文本部分。
- codellama 采用了多任务训练损失(自回归和因果填充预测),使得 codellama 能够应用与源代码编辑器中的实时完成或文档字符串生成等应用
- 长输入上下文:llama2 支持的 4096 个 token 输入的序列长度在代码领域可能不够用
- codellama 提出了一个额外的微调阶段,通过修改 llama2 使用的 RoPE 位置编码,将序列长度从 4096 扩充到 100000
- 指令微调:大语言模型的指令微调有助于防止不安全、有毒或带有偏见的生成
- codellama - instruct 变种进一步在混合专有指令数据上进行微调,提高安全性和实用性;基于 self-instruct 方式生成了一个新的数据集,其中 llama2 用于生成代码问题,code llama 用于生成对应的单元测试和解决方案
- 基础模型的代码训练:AlphaCode、InCoder、StarCoder 等模型下只在 code 数据上预训练过,Codex 是基于一个通用语言模型微调得到
本文方案
- 发布了 Code Llama,基于 Llama 2 的一系列大型代码语言模型,提供了在开放模型中的最先进性能、填充能力、支持大输入上下文以及零-shot编程任务指令跟随能力。
- 提供多个版本以涵盖各种应用:
- 基础模型(Code Llama)
- Python 专业化版本(Code Llama - Python)
- 指令跟随模型(Code Llama - Instruct)
- 每个版本分别具有 7B、13B 和 34B 参数,所有模型都是在 16k token 序列上训练的,并在最多包含 100k token 的输入上进行长序列改进。
- 7B 和 13B 的 Code Llama 以及 Code Llama - Instruct 变种支持基于周围内容的填充。
- Code Llama 在多个代码基准测试中达到了开放模型中的最先进性能,分别在 HumanEval 和 MBPP 上取得了高达 53% 和 55% 的分数(优于 Llama2 70B),MultiPL-E 上精度优于所有开源模型
- 重点是和 Llama2 开源协议一样,Code Llama 开源并允许进行研究和商业用途
- 提供多个版本以涵盖各种应用:
- code llama 各系列模型训练流程如下:
- code llama - instruct 的使用样例如下,它展示了该模型如何解释自然语言以确定命令行程序的合适选项,并提供解决方案的说明:
Methods
code llama 系列模型
- code llama:
- 用于代码生成的基础模型。它们有三种模型大小:7B、13B和34B参数。
- 7B和13B模型使用填充目标进行训练,适合在集成开发环境(IDE)中用于在文件中间完成代码等用途
- 34B模型则是在没有填充目标的情况下进行训练的
- 所有系列模型都是从 llama2 基础上初始化
- 训练数据量为 500B
- 经过长文本微调
- 用于代码生成的基础模型。它们有三种模型大小:7B、13B和34B参数。
- code llama-python:
- 专门用于Python代码生成,有7B、13B和34B参数大小。旨在研究针对单一编程语言定制的模型与通用代码生成模型相比的性能。
- 所有系列模型都是从 llama2 基础上初始化 ,先进行 500B 数据预训练,然后使用 100B python 数据进行专门强化
- 所有 code llama python 模型都没有使用填充的训练损失
- 使用长文本微调
- code llama-instruct
- 基于 code llama 初始化,经过了额外的 5B token 训练数据微调,以更好遵循人类指令
训练数据集
- codellama 模型在几乎没有重复数据的公开可用代码数据集进行训练。另外还从与代码相关的自然语言数据集中获取了 8% 的样本数据。这个数据集包含许多关于代码的讨论,其中包括自然语言问题或答案中包含的代码片段。为了保持自然语言理解能力,也采样了 7% 自然语言数据
- codellama tokenizer 使用和 llama2 一样的
- 自然语言数据集的使用提升了 MBPP 上的性能
填充
- 代码填充是指在给定周围上下文的情况下预测程序中缺失部分的任务。应用包括在代码集成开发环境(IDE)中在光标位置进行代码补全、类型推断和生成代码内文档
- 按照因果掩码(causal masking)的概念来训练填充模型,其中训练序列的部分被移到末尾,重新排序后的序列是自回归地预测的
- 具体来说,将训练文档在字符级别分成前缀、中间部分和后缀,分割位置从文档长度上独立采样,采样概率为 0.9,只对没有跨越多个模型上下文的文档应用此转换。随机将一半的分割以前缀-中间-后缀(PSM)格式格式化,将另一半以 Efficient Training of Language Models to Fill in the Middle 论文中描述的兼容后缀-前缀-中间(SPM)格式格式化。扩展了Llama 2的分词器,增加了四个特殊标记,用于标记前缀、中间部分或后缀的开始,以及填充范围的结束。为了限制自回归训练和填充训练之间的分布变化,抑制了 SentencePiece 分词器在编码中间部分和后缀时添加的隐式前导空格。在 SPM 格式中,在编码之前将前缀和中间部分连接起来。请注意,本文的模型在SPM 格式中不会遇到分割的子 token,而在 PSM 格式中会遇到
长文本微调
- 在基于 Transformer 的语言建模中,有效处理长序列是一个重要的研究课题。基本的建模挑战包括外推,即在超出训练时见到的序列长度上进行操作,以及注意力传递的二次复杂度。所以一般偏向于对短至中等长度的输入进行训练
- 对于Code Llama,提出了一个专门的长上下文微调(LCFT)阶段,在这个阶段,模型被呈现出16,384 个 token 的序列,而不是 Llama 2 和我们的初始代码训练阶段所使用的 4,096 个 token。通过将处理长序列的训练时间限制在微调阶段,我们在不显著增加模型训练成本的情况下获得了处理长距离序列的能力
- 我们的策略类似于 Extending context window of large language models via positional interpolation 文章最近提出的位置插值微调,并且我们确认了修改 Llama 2 基础模型中使用的旋转位置嵌入的旋转频率的重要性。与上面提到论文中的线性降低频率不同,本文改变了 RoPE 的基础周期
其中n 表示位置,d 表示 embedding 维度,选择频率计算为:
θ i = θ − 2 i / d \theta_{i}=\theta^{-2i/d} θi=θ−2i/d
本文将基础周期 θ \theta θ 由 10000 提升到 1000000 用于微调。这个增加允许处理更大的序列,并减少了对短距离关注的偏见。实验证实,Code Llama模型不仅在微调期间使用的增加的序列长度内表现出效果,还展示了外推能力,并在长达100,000个 token 的非常长序列上表现稳定
指令微调
- 主要有三种数据来源
- 专有数据集:llama2 中的 RLHF V5 版本数据集,该数据集通过多个强化学习阶段从人类反馈和人类反馈注释中收集。该数据集结合了数千个监督微调示例和数百万个拒绝抽样示例。每个示例由用户和助手之间的多轮对话组成。对于拒绝抽样,输出是根据奖励模型从多个生成中选择的。最终的数据集包含了实用性和安全性数据。这使得Code Llama能够继承Llama 2的指令遵循和安全性属性。
- self instruct:14,000个问题-测试-解决方案三元组,基于以下流程生成
- 提示 Llama 2 70B 生成 62,000 个面试编程问题
- 通过删除完全相同的重复项,对问题集进行去重,结果是大约52,000个问题
- 对于这些问题中的每一个:
-
(a) 通过提示Code Llama 7B生成单元测试
-
(b) 通过提示Code Llama 7B生成十个Python解决方案
-
© 在这十个解决方案上运行单元测试。将通过测试的第一个解决方案(以及相应的问题和测试)添加到自我指导数据集中。
-
- 提示 Llama 2 70B 生成 62,000 个面试编程问题
- 复述数据集:
- 为了防止模型在一般编码和语言理解能力上出现倒退,Code Llama - Instruct 还使用来自代码数据集(6%)和自然语言数据集(2%)的少量数据进行训练
训练细节
- 优化器相关
- adamw
- 余弦学习率
- warmup 1000
- 不用降低学习率,保持Llama 2基础模型的原始学习率时获得了最佳结果
- 长上下文微调
- 学习率为2e−5,序列长度为16,384
- RoPE频率重置为基本值θ = 10^6
Experiments
- 评测数据集
- python 相关:HumanEval、MBPP、APPS
- 多语言(C++/Java/PHP/C#/TypeScript/BASH): MultiPL-E
- 数学推理能力:GSM8K
python 相关
HumanEval 和 MBPP 上的结果
-
评测参数:
- pass@1 使用 greedy decoding 测试,pass@10 和 pass@100 使用 nucleus sampling,topp=0.95,temperature=0.8
- humaneval 使用 zero-shot 评测,MBPP 使用 3-shot
-
实验结果分析:
- codellama 7b 结果优于 llama2 70b
- 在 python 数据上单独进一步训练的精度更高,HumanEval pass@1的增益在4.3个百分点到8.3个百分点之间,MBPP pass@1的增益在1.2个百分点到6.4个百分点之间。Code Llama - Python 7B能够在MBPP和HumanEval上胜过甚至Code Llama 13B
- 证明了在代码数据集上进一步训练对于代码任务有好处
- 参数量提升对于精度提升很重要:Code Llama从7B参数扩展到13B参数,MBPP pass@1增加了5.6个百分点,扩展到34B参数时再增加8个百分点
- 精度低于 GPT-4 的 zeroshot 版本,和 GPT4 还是有明显差距的
- 其中 unnatural model 在 15000 unnatural 指令数据(数据类似 Unnatural Instructions: Tuning Language Models with (Almost) No Human Labor 论文介绍,基于 self instruct 生成)上微调 Code Llama - Python 34B 得到的,在 HumanEval 和 MBPP 上精度有显著提升,证明小规模高质量数据有助于精度提升(该模型没有开源)
-
温度值的选取来源于以下实验
- 随着温度提升,pass@1 掉点,pass@10 和 pass@100 涨点
- 所以 pass@1 直接使用 greedy decoding 就行,pass@10/pass@100 使用 temperature 0.8,开 topp
APPS 结果
- 没有展示 pass@1 指标,只有 5,10,100 上的指标,使用 2-shot 测试方法,topp=0.95,temperature=0.6
多语言评测
MultiPL-E 评测结果
-
基本结论和 python 评测结果类似。Code Llama模型在任何语言上的代码生成方面都明显优于相同规模的Llama 2模型,甚至Code Llama 7B的性能超过了Llama2 70B
-
为了更好地理解多语言预训练的影响,我们测量了每种语言评测结果之间的相关性:
- 模型在C++、C#、Java和PHP上的性能之间存在很高的相关性
- Python和Bash上的性能之间存在很强的相关性
- 正如预期的那样,模型规模越大、表达能力越强,跨所有不同语言的性能之间的相关性越高
填充训练的评估
- 如果使用填充目标对7B模型进行训练,它的平均性能在HumanEval和MBPP pass@1、pass@10和pass@100分数上下降了0.6个百分点,而13B模型下降了1.1个百分点。由于性能的这种适度下降以及具有填充功能的模型的广泛适用性,我们决定以这种配置发布Code Llama 7B和13B。
- SPM(后缀-前缀-中间) 在多语言评测中精度更高
长上下文序列评估
- 外推期间的困惑度分析:在图4a中,我们计算了从代码数据集中的 4M 个 token 的困惑度,使用了我们验证数据的一个子集,其中包括大型源文件(≥50KB)。对于所有模型尺寸,我们观察到在16384个 token 之后,困惑度稳步下降,这是我们用于长上下文微调的序列长度。在100K个 token 之后,迷惑度仅略微增加
- 关键检索:在图4b中,我们研究了合成任务中的关键检索性能。提示包含大量语法有效的 Python 代码,其中包括在指定位置插入一个返回标量的函数。模型被要求使用插入函数的返回值完成一个assert语句。除了 7B 在将函数放置在开头时性能不佳,其他模型都没有问题。
- 单行完成:测试了在单行代码完成任务中处理长上下文尺寸的能力的好处。基于Long Code Completion(LCC)基准。LCC测试集偏向于较短的文件,因此我们从LCC的验证和测试集中采样了一组新的例子,以在文件大小上进行均衡分布。
- 对短上下文的性能影响:尽管我们的模型在长序列上有效,但我们观察到LCFT微调对包含短序列的标准代码合成基准的性能略有影响。我们观察到在HumanEval pass@1和MBPP的pass@1指标上平均减少了0.52个百分点,对于MBPP的pass@1指标减少了1.9个百分点。然而,许多实际应用情况不能通过这些基准来捕捉,我们认为处理长序列的潜力远大于此代价。因此,我们选择发布所有具有长上下文功能的Code Llama、Code Llama - Python和Code Llama - Instruct模型。
消融实验
从头训练对比从 llama2 基础上训练
- 将7B参数模型与从头开始在相同数据混合上进行训练的相同模型进行了比较。在训练结束时,从头开始训练的模型的损失等于Code Llama 7B模型在其训练的一半左右(少了240B的训练令牌)的损失。此外,随着时间的推移,这个差距会变得更大。
指令微调
- General helpfulness vs. coding ability:如上图 c 所示,codellama 提升了编码能力,同时保留了 llama2 的 general helpfulness。这个结果应该持保留态度,因为我们将自动评估限制为使用Llama 2奖励模型对模型的答案进行评分
- self-instruct 数据有利于精度提升
Thoughts
- 非常详尽介绍了 codallama 全流程,开源可商用很良心
- 其中为了实现某些性能所做的 trade off 操作带来的掉点或许有进一步优化的空间,比如长序列上下文微调对于 humaneval 等测试集上有一定掉点,以及填充训练带来的一定掉点