论文笔记:InCoder A Generative Mod

导语

1 简介

最近,大型的语言模型在代码生成等相关领域取得了令人印象深刻的进展。然而,这些left-to-right的自回归式模型不太直接适用于许多普遍存在的代码编辑任务,例如修复错误、添加注释或重命名变量。为了解决这个问题,本文提出InCoder模型,该模型通过学习使用一个sential token随机替换一段代码并将它们移动到序列的末尾来填充(这就是本文最核心的创新点,该灵感来源于CM3: A causal masked multimodal model of the Internet.),如图1所示。

image.png

在模型推理阶段,可以任意使用sential token来mask掉一段文本来让模型预测。同时,该模型也可以在没有sential token的情况下进行简单的生成,所以InCoder将程序合成(通过从左到右生成)和编辑(通过填充)任务完成了统一。

本文评估了一系列zero-shot的代码填充任务的性能,如类型预测、变量重命名、注释生成和完成缺失的代码行。实验发现:使用双向上下文的zero-shot填充在很大程度上优于基于仅从左到右模型的方法,并且在一些任务上获得了与在任务上经过微调的最先进模型相当的性能。 InCoder在现有的从左到右的程序合成任务上也取得了出色的表现,尽管它的训练目标更一般,但它与在类似规模下训练的现有代码语言模型相匹配。

模型在 sites.google.com/view/incode… 上公布。

2 通过Causal Masking的填充和合成

用于代码生成的神经模型要么利用了从左到右(因果)的自回归语言建模目标,要么像BERT那样,使用了掩蔽语言建模目标。这两种方法各有优缺点。因果模型只对所生成的标记左侧的上下文设置条件,从而防止填充,但它们可以自回归地生成整个文档。另一方面,遮罩语言模型可以同时使用左右上下文来填充屏蔽区域,但是,它们的训练目标通常仅限于生成文档的15%左右。在本文中,我们采用了最近提出的因果遮罩目标(causal masking objective),该目标旨在结合因果语言模型和掩蔽语言模型的优点。

2.1 训练

在训练时,首先在每个文档中采样一系列连续token来进行掩码(图1,左上)。为此,需要确定两个数字:

  • span的数目;
  • 每个span的长度(即遮盖的token个数)。

对于span的数目,本文从泊松分布中选取span的数量,设置均值为1,并截断值为256,因此通常存在少量的span(约50%的情况为1个span),但分布具有长尾(最多256个span)。

对于span的长度,本文从文档的长度中进行统一采样,如果有span重叠,则重新采样。

一旦span被采样,每个spankspan_kspank将被一个特殊的sential token Mask:kMask:kMask:k取代。然后将span中的token序列移动到文档的末尾(图1,右上),前置掩码sential token Mask:kMask:kMask:k和一个特殊的掩码结束token < EOS >。换句话说,当一个mask token第一次以从左到右的顺序出现时,它标记了span被移除的位置;当它第二次出现时,它标志着移动的span文本的开始。然后,我们最大化概率:

image.png

如果对多个span进行采样,则每个span将类似地按顺序追加到文档的末尾。与标准的从左到右生成语言建模一样,我们计算序列自回归的概率,并在除Mask:kMask:kMask:k;之外的所有标记上使用交叉熵损失来训练模型,以便模型在推理过程中不会生成这些token。

2.2 推理

在推断过程中,模型可以用标准的方式从左到右生成(通过从模型中进行自回归抽样,不使用任何特殊标记),也可以在现有文档的任意位置插入代码,方法是插入 Mask:kMask:kMask:k 标记在所需的位置,并在文档的末尾继续生成。为了简便起见,假设我们只想在单个位置插入文本,我们通过从分布中自回归抽样标记,生成一个span来插入该位置的左右上下文序列

image.png

直到< EOS >生成或实现任务相关的停止条件。一种更加通用的表示形式是多个mask,那么整个预测序列将表示为:[A;Mask:0;C;Mask:1;E;Mask:2;Mask:0;B;;Mask:1;D;][A; Mask:0; C; Mask:1; E; Mask:2; Mask:0; B; < EOM >; Mask:1; D; < EOM >][A;Mask:0;C;Mask:1;E;Mask:2;Mask:0;B;;Mask:1;D;],其中区域B和D是需要被填充的。

这里有一个脚注,即在实践中,作者从分布P(⋅∣[Left;Mask:0;Right;Mask:1;Mask:0]P(⋅∣[Left; Mask:0; Right; Mask:1; Mask:0]P(⋅∣[Left;Mask:0;Right;Mask:1;Mask:0] 中插入一个Mask:1Mask:1Mask:1token。如果不插入Mask:1Mask:1Mask:1,则会给模型一个隐式的大小提示,即Mask:0Mask:0Mask:0token应该展开以填充2048令牌上下文窗口的其余部分。相反,插入一个Mask:1Mask:1Mask:1token向模型表明在正确的上下文之后省略了文档的一部分。作者发现,使用这一点大大提高了模型预测。

当应用于代码时,这允许我们以零目标的方式执行从双向上下文中受益的任务,如图1底部所示,作者展示了四种情况下如何进行推理:

  • Type Inference
  • Variable Name Prediction
  • Docstring Generation
  • Multi-Region Infilling

3 训练数据

我们在一个语料库上训练我们的模型:

  1. 具有许可的、非copyleft的、开源许可的公共代码和
  2. StackOverflow问题、答案和注释。

数据量统计如下:

image.png

3.1 代码

代码源

代码数据主要来自于GitHub/GitLab,大约67万个公共非fork存储库,主要包含Python、JavaScript或Jupyter Notebook文件,并具有MIT、Apache 2.0、BSD-2或BSD-3条款许可。

去重

最近的研究表明,训练中的重复数据删除可以提高模型性能,并降低记忆训练数据的风险。作者也进行了去重操作。

排除训练数据

为了防止数据泄露,作者删除了CodeSearchNet的验证和测试集中包含的所有存储库,因为这些存储库用于为CodeXGLUE中的几个任务构建验证和测试集。

过滤

过滤掉一些过长或过短的文件。

3.2 StackOverflow

语料库的第二个组件由来自StackOverflow的问题、答案和评论组成。The Pile数据集(参考:juejin.cn/post/718390… )也包含这些问题和答案,但不包含注释。定性地说,作者发现注释,以及InCoder模型具备的填充能力,使其具有一些在语言指导下进行交互式代码编辑的能力(如下图11)。

image.png

3.3 Metadata

作者还保留了一些文件或者StackOverflow的元数据,例如文件名、拓展名、来源、StackOverflow的主题、标签等信息。为了允许该元数据在执行模型的从左到右提示时是可选的,作者以50%的概率将每个属性插入其文档的开头(允许模型学习元数据调节);否则,将其插入到文档的末尾(允许元数据预测)。

image.png

3.4 Tokenization

为了增加模型所依赖的上下文数量、模型可以生成的文档长度以及训练和推理的效率,作者训练了BPE Tokenizer,允许token跨越空格(不包括换行符)进行扩展,这样常见的代码习惯用法(例如,import numpy as np)在词汇表中表示为单个token。这极大地提高了标记器的效率——相对于GPT-2的字节级BPE标记器和词汇表,将编码训练语料库所需的token总数减少了45%。

4 训练

本文提出的主要模型是InCoder-6.7B,在248张V100上训练了24天。同时,也训练了一个1.3B版本的小模型。

image.png

5 填充实验

作者的主要评估实验是不同的编程任务的zero-shot实验。
为了评估InCoder在生成填充时如何从双向上下文中获益,作者比较了三种不同的推断方法:第2节中描述的因果掩蔽推断过程,标准的从左到右生成方法(left-to-right single),以及从左到右生成和重排序方法(left-to-right reranking)。

Left-to-right single

该Baseline根本不使用被mask位置右侧的上下文。它通过对左侧上下文进行条件处理,并从模型P(⋅∣left)P(⋅∣left)P(⋅∣left)中自回归采样token,直到达到特定于任务的停止条件(例如,对于注释生成,产生注释结束分隔符;对于多行填充,将生成指定的行数)。

Left-to-right reranking

该Baseline仅使用左侧上下文来给出填充空白的候选语句,但同时使用左侧和右侧上下文在这些候选语句中进行选择。

具体来说,首先为mask区域生成K=10种可能的补全,跨度为1。然后,通过将每个候选人代入空白并对完成的文档进行评分来评估每个候选人。我们使用完成文档的总日志概率logP([Left;Spank;Right])log P([Left; Span_k; Righ_t])logP([Left;Spank;Right]),或者使用完整文档的平均对数概率。

5.1 Infilling Lines of Code (HumanEval)

作者从HumanEval数据集为完整的代码行创建一个填充实验的基准,从HumanEval数据集构建了两个不同的填充任务,用于单行和多行:

  • 单行填充:即遮盖掉N行内容的某一行,让模型预测该行内容,共进行N次实验;
  • 多行填充:即遮盖掉若干行内容,让模型预测多行内容,共进行N(N+1)/2次实验(即CN+12C_{N+1}^2CN+12).

预测结果如下表所示:

image.png

同时,作者还比较了被mask掉的部分的右侧的上下文的多少对于实验结果的影响,结果如下图所示:

image.png

InCoder方法比L-R baseline有更大的改进,因为右侧有更多的上下文可用(即,当空白区域出现在函数的早期时)。

5.2 Docstring generation (CodeXGLUE)

接下来,作者展示了在CodeXGLUE(参考:)上的Docstring Generation任务的表现,InCoder模型在Zero-shot的条件下取得了和CodeBERT(参考:)类似的性能表现。

image.png

5.3 Code Cloze (CodeXGLUE)

在完形填空任务上的主要结果如下表所示。使用带有单个标记(包含min/max)作为屏蔽区域的模型比仅使用左侧上下文执行得更好,但不如从左到右对整个序列进行评分。屏蔽一个更大的区域(CM填充区域),其执行与对整个序列进行评分相当。填充区域长度和标记化可以影响性能。

image.png

5.4 Return Type Prediction

image.png

5.5 Variable Name Prediction

image.png

6 模型对比

6.1 Comparison to Left-to-Right Generative Models on Code Synthesis

所有模型都是Decoder-only模型,其在HumanEval和MBPP上的实验结果如下表:

image.png

可以看到,InCoder模型在HumanEval指标上实现了与CodeGen-Multi大致相当的性能,CodeGen-Multi也是一个用大致相同数量的Python代码训练的∼6B参数模型。

作者还进行了消融实验,比较从本文的训练语料库以及HumanEval和MBPP基准测试中获得的验证集的Python部分的模型性能。实验结果如下表所示:

image.png

7 Qualitative Examples

一些实验示例结果如下图:

image.png

image.png

image.png

8 相关工作

9 总结

本文证明了在训练生成式代码模型时使用因果掩蔽目标(causal masking objective)可以在许多具有挑战性和实用的代码填充和编辑任务中实现强大的Zero-shot性能。该模型的额外填充能力似乎并没有损害其进行标准的从左到右生成的能力:消融实验表明,InCoder模型在标准的从左到右语言到代码合成基准上具有与相似资源模型相当的性能。

展望未来,作者希望通过更多的参数、数据和训练步骤,使得模型性能继续提高。此外,微调将使InCoder能够更好地适应自然语言指令和人类意图的其他迹象。最后,本文为未来通过模型微调进行监督填充和编辑以及执行迭代解码的工作奠定了基础,其中模型可用于改进自己的输出。

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%