Abstract

我们提出了CodeBERT,一个用于编程语言(PL)和自然语言(NL)的双模态预训练模型。CodeBERT可以学习通用的表示方法,支持下游NL-PL应用,如自然语言代码搜索、代码文档生成(Code-to-Documentation / Code-to-NL generation)等。

CodeBERT 模型使用基于 Transformer 的神经架构构建而成,训练所用的混合目标函数包括了替换 token 检测(replaced token detection,RTD)预训练任务。RTD 使用从生成器采样的合理替代 token 来替换部分输入 token 从而破坏输入,然后训练一个判别器来预测受损输入中的每个 token 是否被生成器样本替换。

RTD:ELECTRA:将BERT中的MLM任务替换为replaced token detection

这就使得 CodeBERT 模型可利用双模态数据 NL-PL 对和单模态数据,前者为模型训练提供输入 token,后者有助于学得更好的生成器,研究者通过模型调参的方式评估了 CodeBERT 在两个 NL-PL 应用中的性能。

1 Introduction

CodeBERT 可以捕捉自然语言和编程语言之间的语义连接,并输出可广泛支持 NL-PL 理解任务(如自然语言代码搜索)和生成任务(如代码文档生成)的通用表示。

  1. CodeBERT 模型基于多层 Transformer 构建而成。
  2. 为了利用双模态数据实例 NL-PL 对和大量可用单模态代码,研究者使用混合目标函数来训练 CodeBERT,函数包括标准遮蔽语言建模(MLM)和替换 token 检测(RTD),替换 token 检测利用单模态代码学得更好的生成器,从而输出更好的替换 token。

研究使用了 6 种编程语言训练 CodeBERT,其中双模态数据点是具备函数级自然语言文档的代码。CodeBERT 模型的训练设置与多语言 BERT (Pires et al., 2019) 类似,即针对 6 种编程语言学习一个预训练模型,且不使用显式标记来标注输入编程语言。

2 Background

2.1 Pre-Trained Models in NLP

大型预训练模型对几乎所有NLP任务都带来了显著改进,成功的方法是在大规模纯文本上训练具有自监督(self-supervised)学习目标的深度神经网络。

self-supervised是指用于前期训练的监督是自动从原始数据中收集的,不需要人工标注。主要的学习目标是语言建模及其变体。

  • GPT:学习目标是语言建模,即给定前面的语境词 { w 1 , w 2 , . . . , w k − 1 } \left \{ w1,w2,...,w_{k-1} \right \} {w1w2...wk1},预测下一个词 w k w_k wk
  • BERT:使用掩蔽语言建模目标,它学习预测“给定周围上下文的随机掩蔽词序列的”掩蔽词。考虑前面和后面的语境,更好地学习通用语境表征。

2.2 多模态Pre-Trained Model

多模态预训练模型可以学习不同模态输入之间的隐性对齐。这些模型通常是从双模态数据中学习的,如语言图像对或语言视频对。本文将NL和PL视为不同的模式。与之前的工作不同在于,模型训练的数据不仅包括NL-PL对的双模态数据,还包括更大量的单模态数据,如没有配对文档的代码。

3 CodeBERT

3.1 Model Architecture

CodeBERT基于多层双向Transformer。具体而言,CodeBERT 的模型架构与 RoBERTa-base 基本一致,包括 12 个层,每一层有 12 个自注意力头,每个自注意力头的大小为 64。隐藏维度为 768,前馈层的内部隐藏层大小为 3072。模型参数总量为 1.25 亿。

3.2 Input/Output 表示

在预训练阶段,研究者将输入设置为两个片段和一个特殊分隔符的组合,即 [ C L S ] , w 1 , w 2 , . . w n , [ S E P ] , c 1 , c 2 , . . . , c m , [ E O S ] [CLS], w_1, w_2, ..w_n, [SEP], c_1, c_2, ..., c_m, [EOS] [CLS],w1,w2,..wn,[SEP],c1,c2,...,cm,[EOS]其中一个片段是自然语言文本,另一个则是以某种编程语言写成的代码。

CodeBERT 的输出包括:

  1. 每个 token 的语境向量表示(适用于自然语言和代码)
  2. [CLS] 的表示,作为聚合序列表示(aggregated sequence representation)。

3.3 Pre-Training Data

  • 双模态数据,即自然语言-代码对平行数据。
  • 单模态数据,即不具备平行自然语言文本的代码和不具备对应代码的自然语言。

NL-PL对数据样例,其中NL是一个函数的文档(黑色虚线)的第一段(红色填充):

3.4 Pre-Training CodeBERT

本节将介绍训练 CodeBERT 使用的两个目标函数。

  • 目标1:掩码语言模型(MLM)—— 双模态数据
    将NL-PL对作为输入,随机为NL和PL选择位置进行掩码,然后用特殊的掩码Token进行替换。掩码语言模型的目标是预测出原始的token。

  • 目标2:替换 token 检测(RTD)—— 单模态数据
    先分别用单模的自然语言和代码数据各自训练一个数据生成器,用于为随机掩码位置生成合理的备选方案。另外,还有一个判别器学习自然语言和代码之间的融合表示,来检测一个词是否为原词。判别器实际上一个二元分类器,如果生成器产生正确的Token,则该Token的标签为真,否则为假。

模型架构如图2所示:

在这里插入图片描述
图 2:RTD 目标图示。NL Generator 和 Code Generator 都是语言模型,它们基于上下文语境为 masked 位置生成合理的 token。NL-Code Discriminator(判别器)是目标预训练模型,它通过检测从NL和PL生成器中采样的“合理替换 token”进行训练。NL-Code Discriminator 用于在调参阶段输出通用表示,而 NL Generator 和 Code Generator 均不出现在调参阶段。

3.5 Fine-Tuning CodeBERT

在下游NL-PL任务中,我们有不同的设置来使用CodeBERT:

  • 自然语言代码搜索:输入方式与预训练阶段一样,使用[CLS]的表示方式来衡量代码与自然语言查询之间的语义相关性;

CLS:BERT的[CLS]有什么用 / Bert [CLS]位的向量是怎么生成的?

  • 代码到文本生成:使用encoder-decoder框架,用CodeBERT初始化生成模型的编码器。

4 Experiment

4.1 自然语言代码检索

给定自然语言作为输入,代码搜索的目标是从一堆代码中找出语义最相关的代码。研究者在 CodeSearchNet 语料库上进行训练。

数据集中包括六种编程语言,各种语言的数据统计如表6所示:

下表 2 展示了不同方法在 CodeSearchNet 语料库上的性能结果:

表2.自然语言代码检索的结果。

4.2 NL-PL Probing(探测)

本实验研究在固定模型参数的情况下,CodeBERT学习到了哪些类型的知识。即给定一个NL-PL对 ( c , w ) (c,w) (cw),NL-PL探测的目标是测试模型在干扰选项中正确预测/恢复感兴趣的masked token(code token c i c_i ci 或 word token w j w_j wj)的能力。

干扰选项主要有两种类型:

  1. 一个是用于掩蔽语言建模目标的整个目标词汇表;
  2. 另一种是更少的候选词,根据专家对测试能力的理解进行筛选或策划出来的。

本文选取第二种类型,将NL-PL探测制定为一个多选择题的答题任务,其中问题是cloze-style,即其中某个token 被[MASK]代替,并且干扰选项是根据专业知识选取出来的。

cloze-style:一点关于cloze-style问题的简谈

关于python语言的案例研究:

分别应用NL(蓝色)和PL(黄色)的masked token。给出了RoBERTa和CodeBERT的预测概率。

4.3 代码文档生成

本节涉及 code-to-NL 生成任务,报告了在 CodeSearchNet 语料库上六种编程语言的文档生成任务结果。

下表 4 展示了不同模型的代码-文档生成任务结果:

CodeBERT在所有编程语言类别上均获得最好的效果。

4.4 在未训练的编程语言上的泛化能力

在 C# 编程语言上进行了测试。我们选择了CodeNN数据集,这是一个包含StackOverflow自动收集的66015对问题和答案的数据集,并采取了和原论文同样的设置进行实验。

结果如表5所示:

相比RoBERTa,我们的模型能够取得更好的结果。但是,我们的模型效果略低于Code2Seq,这可能是因为该模型有效使用了代码中的抽象语法树(AST)信息

5 Conclusion

本文提出了CodeBERT是第一个针对自然语言和编程语言的大型双模态预训练模型。我们在双模态和单模态数据上训练CodeBERT,并表明微调CodeBERT在下游任务上实现了最先进的性能。

这个领域的进一步研究有很多潜在的方向:

  1. 首先,我们可以利用双模态evidence或者更复杂的神经架构学习更好的生成器,以提高被替换的token检测目标;
  2. 其次,CodeBERT的损失函数主要针对NL-PL理解任务。虽然CodeBERT在代码到文档的生成上取得了很强的BLEU分数,但CodeBERT本身还可以通过生成相关的学习目标进一步提高。如何将AST成功地融入到预训练步骤中,也是一个很有吸引力的方向。
Logo

尧米是由西云算力与CSDN联合运营的AI算力和模型开源社区品牌,为基于DaModel智算平台的AI应用企业和泛AI开发者提供技术交流与成果转化平台。

更多推荐