【论文精度】CodeBERT——基于自然语言和编程语言的预训练模型

CodeBERT

论文地址:https://arxiv.org/abs/2002.08155

【论文精度】CodeBERT——基于自然语言和编程语言的预训练模型_第1张图片

Abstract

​ 提出了一种用于编程语言(PL)和自然语言(NL)的双模态预训练模型CodeBERT,CodeBERT学习了通用表示,支持自然语言代码搜索、代码文档生成等下游NL-PL任务。本文利用基于Transformer的神经架构开发了CodeBERT,使用**混合目标函数(hybrid objective function)**对其进行训练,该混合目标函数包含了替换token检测的预训练任务,即检测从生成器中采样的可行替代方案,这使我们能够利用NL-PL对的双模态数据以及单模态数据,前者为模型训练提供输入tokens;后者有助于学习更好的生成器。

​ 在实验方面,通过微调模型参数在两个NL-PL应用上评估CodeBERT,结果表明CodeBERT在自然语言代码搜索和代码文档生成任务上都达到了SOTA性能;此外,为了研究在CodeBERT中学习了什么类型的知识,论文构造了一个用于NL-PL探测(NL-PL probing)的数据集,并在一个zero-shot设置中进行评估,其中预训练模型的参数中固定的,结果表明CodeBERT模型在NL-PL探测方面的性能优于之前的预训练模型。

1. Introduction

​ ELMo(2018)/GPT(2018)/BERT(2018)/XLNet(2019)/RoBERTa(2019)等预训练模型在各种NLP任务上显著地提高了最先进的技术,这些预训练模型从大量自监督目标优化的未标记文本学习有效的上下文表示,例如掩码语言建模从一个人工掩码输入序列中预测原始被掩码的词。预训练模型在NLP领域的成功也推动了多模态预训练模型的激增,例如ViLBERT(用于语言-图像)、VideoBERT(用于语言-视频),他们从双模态数据(如带有双模态自监督目标的语言-图像对)中进行学习。

​ 本论文提出了CodeBERT,是一个用于自然语言(NL)与像Python、java、JavaScript等编程语言(PL)的双模态预训练模型。CodeBERT捕获了自然语言和编程语言的语义联系,生成了通用的(general-purpose)表示,广泛支持NL-PL理解任务(例如自然语言代码搜索)和生成式任务(例如代码文档生成)。CodeBERT使用多层Transformer进行开发,为了充分利用NL-PL对的双模态实例以及大量单模态代码,采用一个**混合目标函数(hybrid objective function)**对CodeBERT进行训练,包含了标准的masked language modeling 与 replaces token detection,淡漠太代码可以帮助学习更好的生成器,生成器能够为后一个训练目标产生更好的可替代tokens。

​ 从包含6中编程语言的GitHub代码仓库中训练CodeBERT,其中双模态数据点是与函数级自然语言文档配对的代码,训练是在类似于多语言BERT(multilingual BERT)的设置下进行的,一个预训练模型是在6中编程语言学习的,没有使用显式标记来表示输入的编程语言。

  • 在两个下游NL-PL任务上对CodeBERT进行评估,包括自然语言代码检索与代码文档生成。结果表明对CoBERT进行参数微调后再两个任务都获得了SOTA性能。
  • 为了进一步探索CodeBERT学习了什么类型的知识,论文构造了一个用于NL-PL探索的数据集,在zero-shot场景(比如,没有对参数进行微调)下对CodeBERT进行测试,发现CodeBERT性能始终优于RoBERTa(一个单纯基于自然语言的预训练模型)。

论文的贡献主要包括:

  • CodeBERT是第一个为多种编程语言预训练的大型NL-PL模型;
  • 实验结果表明,CodeBERT在代码搜索与代码到文本生成任务上都是有效的;
  • 进一步构造了一个数据集,这是第一个用于测试基于代码的预训练模型的探测能力(probing ability)的数据集。

2. Background

2.1 NLP中的预训练模型

​ 很多成功的方法在具有自监督学习目标的大规模纯文本上训练神经网络,最具有代表性的架构为Transformer,它包含多层self-attention层,并且可以以端到端方式以梯度下降的方式进行常规学习,因为每个部分都是可微的(differentiable)。“自监督”的意思是用于预训练的监督是自动从原始数据(raw data)中收集的。主要的学习目标是语言模型及其变体,例如,在GPT中学习目标是语言模型,即根据某个词wk前面的文本{w1,w2,…,wk-1}去预测词wk,这里只考虑了上文;对于BERT,使用了掩码语言建模目标,学习在给定的上下文情况下预测被随机掩码词序列的掩码词。掩码语言建模被用于CodeBERT训练的一个学习目标。

2.2 多模态(Multi-Modal)预训练模型

​ 预训练模型在NLP中的显著成功推动了多模态预训练模型的发展,学习不同模态数据的隐式对齐(implicit alignment),这些模型通常是从双模态数据中学习的,例如语言-图像对或者语言-视频对,例如,ViLBERT从图像说明数据(image caption data)中进行学习,模型通过给定观察到的输入重建掩码图像区域或掩码词的类别进行学习,同时预测说明是否描述了图像内容;VideoBERT从语言-视频数据中学习,通过预测掩码视频或文本进行训练。

​ 本文工作中,将NL与PL视为两种模态,与以往研究不同的是,模型的训练数据不仅包括NL-PL对的双模态数据,还包括大量的单模态数据(如没有配对文档的代码)。

​ 一个同样的研究(Kanade et al., 2019)使用掩码语言模型和下句预测作为目标,在Python源代码上训练一个BERT模型,其中一个句子是一个Python标准定义的逻辑代码行。在预训练过程上,CodeBERT与其他研究的不同点在于:(1)CodeBERT采用跨模态的方式(cross-modal style)进行训练,同时利用了双模态NL-PL数据和单模态PL/NL数据;(2)CodeBERT采用了6中编程语言进行预训练;(3)CodeBERT使用一个新的基于replaces token detection训练目标进行训练。

3. CodeBERT

这一部分介绍:模型结构、输入输出表示、用于CodeBERT训练的目标与数据、如何对CodeBERT进行微调。

3.1 模型架构

​ 遵循BERT、RoBERTa,使用多层的双向Transformer作为CodeBERT的模型架构,使用与RoBERTa-base完全相同的模型架构开发CodeBERT,模型参数总数为125M。

3.2 输入/输出表示

​ 在预训练阶段,将输入设置为带有特殊分隔符的两个片段的拼接,即:[CLS], w1, w2, …wn, [SEP], c1, c2, …, cm, [EOS]. 一个片段是自然语言文本,另一个是来自特定编程语言的代码;[CLS]是在两个片段开头的特殊token,其最终隐藏层表示被认为是聚合的序列表示,用于分类或排序。遵循在Transformer中处理文本的标准方式,将一个自然语言文本视为一个单词序列,并将其拆分为WordPiece;将一段代码视为一个token序列。

​ CodeBERT的输出包括:(1)自然语言和代码中每个token的上下文向量表示;(2)作为聚合序列表示的[CLS]的表示。

3.3 预训练数据

​ 同时使用双模态数据(自然语言-代码对)和单模态数据(无配对自然语言文本的代码或者无配对代码的自然语言)训练CodeBERT。

​ 使用来自GitHub仓库的数据点,其中每个双模态数据点是一个单独的带有配对文档的函数、每个单模态代码是一个没有配对文档的函数。具体来说,使用了一个最近的大型数据集,包含2.1M的双模态数据点和6.4M的单模态代码,跨越6中编程语言(Python、java、JavaScript、PHP、Ruby、Go),具体如表1所示:

【论文精度】CodeBERT——基于自然语言和编程语言的预训练模型_第2张图片

​ 数据来自公开的开源GitHub仓库,通过一组约束和规则进行过滤。例如:(1)每个项目应该至少被一个其他项目使用;(2)每个文档被截断到第一段;(3)短语三个token的文档被删除;(4)短语三行的函数被删除;(5)带有子字符串"test"的函数名被删除。具体样例如图1所示:

【论文精度】CodeBERT——基于自然语言和编程语言的预训练模型_第3张图片

3.4 预训练CodeBERT

训练CodeBERT的过程基于两个目标:①MLM:MLM在文献(Devlin et al., 2018; Liu et al.,2019; Sun et al., 2019).中被证明是有效的,对NL-PL对的双模态数据进行了掩码语言建模;②RTD:该目标进一步利用了大量的单模态数据(例如没有配对自然语言文本的代码)。

3.4.1 MLM (Masked Language Modeling)

给定NL-PL对的一个数据点(x={w,c})作为输入,其中w是NL单词序列,c是PL token序列,首先为NL何PL选择一个随机的位置集合进行掩码(分别为mw和mc),然后将选中的位置替换为[MASK] token,x中15%的tokens被掩码。

【论文精度】CodeBERT——基于自然语言和编程语言的预训练模型_第4张图片

MLM目标是预测被掩码的原始token,公式如下,其中pD1是从一个大词汇表中预测一个token的鉴别器 在这里插入图片描述

3.4.2 RTD (Replaces Token Detection)

在MLM目标中,只有双模态数据被用于训练。
【论文精度】CodeBERT——基于自然语言和编程语言的预训练模型_第5张图片

有两种数据生成器:NL生成器pGw和GL生成器pGc,用于为随机masked 位置集生成可用的替代。

【论文精度】CodeBERT——基于自然语言和编程语言的预训练模型_第6张图片

鉴别器被训练与判断一个词是否为原词,这是一个二分类问题。值得注意的是,RTD目标应用与输入中的每个位置,它与GAN(生成对抗网络,generative adversarial network)的不同之处在于,如果生成器碰巧产生了正确的token,该token的标签的"real"而不是"fake"。RTD关于θ参数化鉴别器的损失函数如下:(其中, δ(i)为一个指示函数;pD2是鉴别器,预测第i个词是原词的概率)

【论文精度】CodeBERT——基于自然语言和编程语言的预训练模型_第7张图片

实现了两种有效的双向上下文n-gram语言模型,一个用于NL、一个用于PL,并分别从相应的单模态数据点学习它们,该方法很容易推广到学习双模态生成器或使用更复杂的生成器,如以联合方式学习的基于Transformer的神经架构。PL训练数据是表1所示的单模态代码,NL训练数据来自双模态数据中的文档,我们可以很容易地将这两个训练数据集扩展到更大的量,最终损失函数如下所示:
m i θ n   L M I N ( θ ) + L R T D ( θ ) m \underset θ in \ L_{MIN}(θ) + L_{RTD}(θ) mθin LMIN(θ)+LRTD(θ)

3.5 CodeBERT微调

在下游NL-PL任务中使用CodeBERT时有不同的设置,例如,

  • 在自然语言代码搜索中,与预训练阶段相同的方式输入,使用[CLS]表示来衡量代码和自然语言查询之间的语义相关性;
  • 在代码文档生成任务中,基于encoder-decoder框架,使用CodeBERT生成模型来初始化encoder。

4. Experiment

4.1 自然语言代码搜索

给定一个自然语言作为输入,代码搜索的目标是从代码集中找出语义最接近的代码。在CodeSearchNet语料库中进行实验,在999个扰乱的(distractor)代码集中,遵循官方评估指标为每对测试数据(c, w)计算MRR(Mean Reciprocal Rank),进一步计算了所有编程语言的宏观平均MRR作为整体评估指标。值得注意的是,这个指标与原始论文中的AVG指标不同,AVG指标六种语言的候选语言中检索得到的。为每种编程语言微调得到特定的语言模型,对于每种模型,使用一个二进制分类损失函数进行训练,其中softmax层连接到[CLS]的表示。训练和测试集都是以正负样本平衡的方式进行创建,负样本由随机替换的NL和PL的样本平衡数量组成。

  • Model Comparisons:表2展示了在CodeSearchNet语料库上不同方法的结果。

【论文精度】CodeBERT——基于自然语言和编程语言的预训练模型_第8张图片

前四行结果为Husain et al.的结果,是NL和PL的联合嵌入(joint embedding)。NBOW表示neural bag-of-words;CNN/GIRNN/SELFATT分别表示1D卷积神经网络、双向基于GRU的循环神经网络、多头注意力。

对于其他结果,将代码视为token序列对所有预训练模型进行训练;还基于掩码语言建模对RoBERTa进行训练,训练仅使用CodeSearchNet中的代码。

实验表明:

  • CodeBERT稳定优于RoBERTa和仅用代码预训练的模型;
  • 从零开始学习的CodeBERT(MLM)比RoBERTa性能要优;
  • 使用RoBERTa初始化CodeBERT可以提升性能。

4.2 NL-PL探测 (NL-PL Probing)

进一步研究在没有修改参数的情况下CodeBERT学习了什么样的知识。

(1)Task Formulation and Data Construction:由于目前没有相关研究工作,因此论文将NL-PL探测问题形式化,并创建数据集。

给定一个NL-PL对(c, w),NL-PL探测的目标是测试模型在干扰点(distractors)之间正确预测/恢复masked token的能力(一个code token ci或者word token wj),有两中主要类型的干扰:①用于掩码语言建模目标的整个目标词汇表;②根据专家对被测能力的理解过滤或策划的更少的候选词汇表。论文遵循第二个类型,将NL-PL探测定义为一个多选项问题的问答任务,其中的问题是完型类问题,特定token被[MASK]替代,并基于专业知识策划扰乱的候选答案(distractor candidate answers)。

特别地,论文分别在NL侧和PL侧进行评估。为了减轻数据收集的工作量,从Code-SearchNet的验证集和测试集中自动收集NL-PL对的数据,这两者在预训练阶段都是看不到的。

  • 对于NL方面的评估:选择NL文档中包含6个关键字(max, maximize, min, minimize, less, greater)之一的NL-PL对,通过合并前两个关键字和中间两个关键字将其分组为4个候选关键字。任务目标是要求预训练的模型选择正确的一共,而不是其他三个选项。即:输入包括完整的代码和被掩码的NL文档,目标是从四个候选者中选择正确答案;
  • 对于PL方面的评估:选择包含关键字max和min的代码,将任务表述为二选答案选择问题。输入包括完整的NL文档和被掩码的PL代码,目标是从两个候选答案中选择正确答案。由于代码补全是一个重要的场景,我们希望测试模型仅基于先前的PL context(preceding PL context)预测正确token的能力,因此,为PL方面添加了一个额外的设置,其中的输入包括完整的NL文档和先前的PL代码。

结果如表3所示:

【论文精度】CodeBERT——基于自然语言和编程语言的预训练模型_第9张图片

(2)Model Comparisons:结果如表3所示,报告了每种编程语言的准确性(即正确预测实例的数量除以所有实例的数量),由于不同编程语言的数据集是及其不平衡的,用相同的方式报告了累积的衡量。这里使用CodeBERT(MLM)是因为其输出层自然地适合用于探测。

实验结果表明:CodeBERT在NL和PL探测上几乎在所有语言的性能都优于基线,只有preceding context only的结果要比bidirectional context的结果要查,这表明代码补全是具有挑战性的。

进一步给出了PL-NL探测的案例研究:分别掩码NL token与PL token,然后报告RoBERTa和CodeBERT的预测概率。

【论文精度】CodeBERT——基于自然语言和编程语言的预训练模型_第10张图片

如图3所示,可以看到CodeBERT在NL与PL预测中都得到了正确的预测结果,显著优于RoBERTa.

4.3 代码文档生成

尽管CodeBERT的预训练目标不包含基于生成的目标,这里仍然测试CodeBERT在生成任务上的性能表现,特别地,测试了code-to-NL生成任务,报告了在六种编程语言下,基于CodeSearchNet语料库的文档生成任务的结果。由于生成的文档较短,更高阶的n-gram可能不会重叠,我们通过使用平滑的BLEU评分来解决这个问题。

  • Model Comparisons:将CodeBERRT与几个基线模型进行比较,包括一个带有attention机制的基于RNN的模型、Transformer、RoBERTa、以及只在代码上预训练的模型。为了验证CodeBERT在code-to-NL生成任务中的有效性,采用了多种预训练模型作为编码器,并保持超参数的一致性。结果如表4所示:

【论文精度】CodeBERT——基于自然语言和编程语言的预训练模型_第11张图片

可以看到:

  • 在编程语言预训练的模型显著优于RoBERTa,这表明在编程语言进行预训练可以提升code-to-NL生成任务的性能;
  • CodeBERT通过RTD和MLM目标进行预训练,总体上比RoBERTa获得了1.3BLEU score增益,并达到了SOTA性能。

4.4 泛化性:测试在预训练期间没有使用的编程语言类型

研究了生成C#代码片段的自然语言摘要任务,在CodeNN数据集上进行实验,该数据集由StackOverflow自动收集的66015个问题-答案对组成,其规模比CodeSearchNet语料库小一个数量级,具有挑战性。使用平滑的BLEU-4 score对模型进行评估。

  • Model Comparisons

【论文精度】CodeBERT——基于自然语言和编程语言的预训练模型_第12张图片

如表5所示,CodeBERT比大多数模型获得了更优的性能,这表明CodeBERT可以更好地推广到其他预训练期间未使用的编程语言。然而结果略低于Code2Seq,其主要原因可能是Code2Seq在其抽象语法树(AST)中使用了组合路径,而CodeBERT仅使用原始代码作为输入。论文作者通过按照一定的顺序遍历AST的树结构训练了另一个版本的CodeBERT,但应用该模型并没有改善生成任务,这显示了通过合并AST来改进CodeBERT的潜在方向。

5. Conclusion

  • 提出了CodeBERT模型,这是第一个针对自然语言和编程语言的大规模双模态预训练模型,在双模态和单模态数据上训练CodeBERT。
  • 结果表明,微调CodeBERT在自然语言搜索和代码文档生成等下游任务上取得了SOTA性能。
  • 为进一步研究预训练模型中蕴含的知识,论文定义了NL-PL探测任务并创建了探测数据集,将探测任务视为完型答案选择问题,为NL与PL策划干扰选项。结果表明,在模型参数固定的情况下,CodeBERT模型的性能优于RoBERTa模型和仅使用代码预训练的模型。
  • 在这一领域还有许多潜在研究方向。①可以学习具有双模态数据、或使用更复杂的神经架构,得到更好的生成器,以改善RTD目标;②CodeBERT损失函数主要针对NL-PL理解任务,虽然CodeBERT在代码文档生成方面取得了较好的BLEU分数,但通过使用与生成相关的学习目标,CodeBERT本身可以进一步提高;如何将AST融入到预训练步骤中也是一个很有吸引力的方向;③计划将CodeBERT应用到更多的NL-PL相关的任务中,并将其扩展到更多的编程语言中,灵活而强大的领域/语言适应方法对于模型的泛化是很有必要的。

你可能感兴趣的:(自动代码生成,神经代码智能预训练模型,深度学习,人工智能,python,语言模型)