冷眸

Code LlaMA: 一文详解代码生成SOTA大模型

· 冷眸

1、简介

2023年,Meta AI发布了一系列的Code Llama,这些Code Llama都是基于Llama 2的大型语言模型,专门用于生成代码。该项目提供了多个版本的模型,包括基础模型(Code Llama)、针对Python的专业化模型(Code Llama - Python)以及可以根据指令进行操作的模型(Code Llama - Instruct)。这些模型在开放模型领域提供了最先进的性能、填充能力,能够支持大规模的输入上下文,并具备零样本学习(zero-shot learning)编程任务指令跟随的能力。

2、背景

使用大规模的领域内数据集可以显著提高模型在自然语言和领域特定语言、专业术语等方面的理解能力,进而在程序合成、代码补全、调试和生成文档等方向的应用中取得更好的性能。目前已有的代码大模型方案存在一些问题,而Codellama提供了相应的解决方案。

代码能力训练: 基础模型如AlphaCode、InCoder和StarCoder等模型只在代码数据上进行预训练,而Codex是基于通用语言模型微调而来的。相比于只在代码数据上进行预训练的模型,Codellama基于Llama2在通用数据和代码数据上进行了预训练,实验证明其性能更好。

代码填充/补全: LLMs的自回归训练和微调适用于提示完成,但在考虑完整的上下文情况下填补缺失的文本部分方面存在一定的限制。为了解决这个问题,Codellama采用了多任务训练损失,包括自回归和因果填充预测,使得Codellama可以在源代码编辑器中实现实时补全和文档字符串生成等应用。

长上下文: llama2支持的4096个token输入序列长度在代码领域可能不够。为了解决这个问题,Codellama提出了一个额外的微调阶段,通过修改llama2使用的RoPE位置编码,将序列长度从4096扩展到100,000。

指令微调: 指令微调有助于避免生成不安全、有毒或带有偏见的代码。Codellama的-instruct变种进一步在混合专有指令数据上进行微调,以提高安全性和实用性;通过采用self-instruct的方式生成一个新的数据集,其中llama2用于生成问题,而Code Llama用于生成相应的单元测试和解决方案。

3、Code LlaMA方案

3.1、Code LlaMA系列

image

Code Llama提供了在所有开源模型中的最先进性能、填充能力、支持大输入上下文以及zero-shot编程任务指令跟随能力。它提供了多个版本,以满足不同应用的需求:

  1. 基础模型(Code Llama): 参数为7B,用于通用代码生成任务。
    • 用于代码生成的基础模型,有三种参数大小:7B、13B和34B。
    • 7B和13B模型使用填充目标进行训练,适用于在集成开发环境(IDE)中补全代码等中间任务。
    • 34B模型没有使用填充目标训练。
    • 所有模型都是在Llama2基础上初始化,并使用了500B的训练数据。
    • 经过长文本微调的训练。
  2. Python专业化版本(Code Llama - Python): 参数为13B,针对Python编程的任务进行了优化。
    • 专门用于Python代码生成,有三种大小的模型参数:7B、13B和34B。
    • 旨在研究针对单一编程语言定制的模型与通用代码生成模型在性能上的差异。
    • 所有模型都是从Llama2基础上初始化,并首先进行500B数据的预训练,然后使用100B的Python数据进行专门强化。
    • 所有Code Llama-Python模型都没有使用填充填充目标训。
    • 经过长文本微调的训练。
  3. 指令模型(Code Llama - Instruct): 参数为34B,支持根据指令进行代码生成。
    • 基于Code Llama初始化,经过额外的5B token训练数据微调,以更好地遵循人类指令。

每个版本都在16k token序列上进行训练,并对最多包含100k token的输入进行了长序列改进。7B和13B的Code Llama以及Code Llama - Instruct等变种支持填充补全能力。Code Llama在多个代码基准测试中展现了开放模型中的最先进性能,特别是在HumanEval和MBPP测试中,分数分别达到53%和55%(优于Llama2 70B模型)。而在多语言MultiPL-E测试中,Code Llama的精度也超过了所有开源模型。

最重要的是Code Llama遵循与Llama2相同的开源协议,并允许进行研究和商业用途。

3.2、数据集

Codellama使用了没有重复数据的公开可用代码数据集进行训练的。此外,还从与代码相关的自然语言数据集中获取了8%的样本数据。这个数据集包含了许多关于代码的讨论,其中部分问题或答案中包含了代码片段。为了保持自然语言理解能力,还采样了7%的自然语言数据。

3.3、优化器

  1. 优化器采用的是 AdamW(Loshchilov & Hutter,2019),β1 和 β2 的值分别设为 0.9 和 0.95。
  2. 使用了一个包含1000个预热步骤的余弦调度,并将最终的学习率设置为峰值学习率的1/30
  3. 使用了一个批次大小为 400 万个 token,每个序列为 4096 个token。
  4. 尽管在微调阶段使用比预训阶段低的学习率是标准做法,但论文发现保留 Llama 2 基础模型的原始学习率时获得了最好的结果。作者把这些发现应用到了 13B 和 34B 的模型中,并分别将它们的学习率设置为 3e−4 和 1.5e−4。
  5. 对于 Python 微调,论文将初始学习率设置为 1e−4。对于 Code Llama - Instruct,他们用一个批次大小为 524,288 个 token 进行训练,总共训练了大约 50 亿个 token。

3.4、训练方式(Code LlaMA核心贡献点)

3.4.1、填充训练

代码填充是指在给定周围上下文的情况下预测代码中缺失部分的任务。这个任务在代码集成开发环境(IDE)中具有多种应用,包括代码补全、类型推断和生成代码内部文档等。 为了训练填充模型,Codellama采用了因果掩码(causal masking)的概念,把填充部分被移到序列的末尾,并通过自回归预测的方式来进行训练。 具体来说,训练文档在字符级别上被划分为前缀、中间部分和后缀,并通过独立采样确定划分的位置,且分割操作仅应用于那些没有跨越多个模型上下文的文档。分割后的数据一半采用前缀-中间-后缀(PSM)格式,另一半采用后缀-前缀-中间(SPM)格式,以提高模型的多样性。另外,Codellama扩展了Llama 2的分词器,添加了四个特殊标记,用于标记前缀、中间部分和后缀的开始,以及填充的结束。为了保持自回归训练和填充训练之间的分布一致性,Codellama抑制了SentencePiece分词器在编码中间部分和后缀时添加的隐式前导空格。

3.4.2、长文本训练

在基于Transformer的语言建模中,处理长序列是一个重要的挑战。由于外推问题及注意力传递的二次复杂度,一般的建模方法通常更适用于短到中等长度的输入。为了解决这个问题,Code Llama提出了一个专门的长上下文微调(LCFT)阶段。通过将处理长序列的训练时间限制在微调阶段,Code Llama在不显著增加模型训练成本的情况下,获得了处理长距离序列的能力。 Code Llama的策略类似于最近提出的"Extending context window of large language models via positional interpolation"一文中的位置插值微调,并且Code Llama还修改Llama 2基础模型中使用的旋转位置编码的的旋转频率,Code Llama对RoPE(Rotated Positional Embedding)的基本周期进行了修改:

$$(R_{\Theta,n}^{d})=\begin{matrix}\text{cos}(n\theta_i)&\text{-sin}(n\theta_i) \\ \text{sin}(n\theta_i)&\text{cos}(n\theta_i) \end{matrix}$$

在本文中,基础周期θ从10000增加到1000000,据公式$\theta_i=\theta^{-2i/d}$可知,增加基础周期θ可以让模型更有效地处理长序列。实验证明,Code Llama模型不仅在微调阶段增加的序列长度范围内表现良好,还在长达100,000个token的长序列上展示了稳定的外推能力。

  1. 对于长上下文微调 (LCFT),作者使用了2e−5的学习率
  2. 16384的序列长度,并重置 RoPE 频率,基值为θ = 10^6
  3. 批次大小对于7B和13B的模型大小设置为200万个 token,对于34B的模型大小设置为100万个 token
  4. 默认情况下,训练持续进行10,000个梯度跟新 step,作者观察到某些配置的下游性能存在不稳定性,因此他们将34B模型的梯度步数设置为11,000,将 Code Llama 7B 的梯度步数设置为3,000。

3.4.3、指令微调

主要使用了三种数据来源:

  1. 专有数据集:Code Llama使用了Llama2中的RLHF V5版本数据集。该数据集通过多个强化学习阶段从人类反馈和人类反馈注释中收集而来。数据集中包含数千个监督微调样本和数百万个拒绝抽样样本。
  2. Self-instruct(自我指导):Code Llama还使用了一个自我指导流程生成了14,000个问题-测试-解决方案三元组的数据集。
  • 通过提示 Llama 2 70B 生成 62,000 个面试风格的编程问题。
  • 删除重复项,对问题集进行去重,最终得到大约 52,000 个问题。
  • 对于每一个问题:
    • 提示 Code Llama 7B 生成单元测试
    • 提示 Code Llama 7B 生成十个 Python 解决方案
    • 在十个解决方案上运行单元测试。将第一个通过测试的解决方案(以及其对应的问题和测试)添加到最终的数据集中。
  1. 回放:为了防止Code Llama - Instruct模型在普通编码和语言理解能力方面出现倒退,它还使用了来自代码数据集(6%)和自然语言数据集(2%)的少量数据进行训练。这种方式被称为"Rehearsal"(回放),通过在训练过程中引入先前的数据样本,有助于保持模型在不同任务和领域上的综合能力。