文献阅读笔记 # CodeBERT: A Pre-Trained Model for Programming and Natural Languages

news2024/11/17 8:19:40
  • 《CodeBERT: A Pre-Trained Model for Programming and Natural Languages》EMNLP 2020 (CCF-B)
  • 作者主要是来自哈工大、中山大学的 MSRA 实习生和 MSRA、哈工大的研究员。
  • 资源:code | pdf
  • 相关资源:RoBERTa-base | CodeNN
  • 词汇: bimodal: 双模态/双模;unimodal: 本文应该要理解为单模态;

Abstract

本文提出用于程序语言(PL)和自然语言(NL)的双模态预训练模型 CodeBERT。CodeBERT 学习支持下游任务(如: natural language code search, code documentation generation)的通用表示,然后基于混合的目标函数对其进行训练,该目标函数包含预训练任务和 replaced token detection(detect plausible alternatives sampled from generators) 任务。这使得我们能利用 NL-PL 对的 “bimodal” data 和 “unimodal” data。前者为模型训练提供 input tokens,后者用来帮助学习更好的 generators。评估:

  • 在 natural language code search, code documentation generation 任务中取得了 2020 年 SOTA。
  • 在 zero-shot setting 和 fix model params 的条件下,在本文构建的 NL-PL probing dataset 上测试取得 2020 年 SOTA。

【个人理解】这里的 RTD 任务类似 GAN,数据是 mask 的数据,然后通过 generator 生成可能的候选方案,然后再用 discriminator 判断候选方案是否正确。

1 Introduction

大规模预训练模型,如 ELMo、GPT、BERT、XLNet、RoBERTa 等模型,极大提高了各种 NLP 任务的 SOTA。这些预训练模型通过自监督目标在大规模无标签的文本中学习有效的上下文表示,如 masked language modeling 从人工屏蔽的输入序列中预测原始词。预训练模型的成功也推动了多模态预训练模型的发展,如 ViLBERT、VideoBERT 等。

本文提出的 NL-PL 双模态预训练模型 CodeBERT 在包含6种编程语言的数据中进行预训练,其中的双模态数据是指代码和其对应的函数级别的自然语言形式的文档。模型训练在类似多语言 BERT 的设置下进行,输入的时候不会特别说明程序语言的类型。

本文主要贡献:1)首个面向多编程语言的 NL-PL 预训练大模型;2)CodeBERT 在自然语言代码搜索和代码文档生成任务中都取得了当前(2020年) SOTA。3)创建了用于研究代码预训练模型的 probing 能力的数据集。

2 Background

2.1 Pre-Trained Models in NLP

  • self-supervised:无需人工标注自动获得用于预训练的监督信息;

  • 主要的学习目标是 language modeling and its variations

    • GPT:给定前文 { w 1 , w 2 , . . . , w k − 1 } \{w_1,w_2,...,w_{k-1}\} {w1,w2,...,wk1} 预测下一个词 w k w_k wk
  • 由于预训练的最终目标不是训练一个好的语言模型,因此最好同时考虑前后文,以学习更好的通用上下文表示。这导致 BERT 采用了 masked language modeling objective。
    【说实话,论文这里的表述方式我觉得很怪,这里真的有因果关系?怎么去定义“好”的语言模型?为什么不是为了得到“好”的语言模型就要考虑前后文?好的语言模型是指能预测下文的能力才叫好吗?】

2.2 Multi-Modal Pre-Trained Models

多模态预训练模型:学习不同模态输入之间的隐式对齐。本文不但包含 NL-PL 的双模态数据,还包括大量的单模态数据(不带文档的代码);

  • ViLBERT
    • 数据: image caption data(language-image);
    • 自监督任务:reconstructing categories of masked image region or masked words 同时预测标题是否描述了图像的内容;
  • VideoBERT
    • 数据:language-video;
    • 自监督任务:trained by video and text masked token prediction;

同期一项工作:采用 masked language modeling 和 next sentence prediction 作为训练 BERT 的目标,并在 Python 源码上训练模型。 这里的 sentence 指:Python 标准定义的 logical code line。在预训练过程上 CodeBERT 与上述工作的差异是:1)CodeBERT 以跨模态方式进行训练,同时利用双模态 NL-PL 数据和单模态 PL/NL 数据;2)CodeBERT 在6种编程语言上进行预训练;3)CodeBERT 基于一种新的 replaced token detection 目标进行训练。

3 CodeBERT

3.1 Model Architecture

CodeBERT: multi-layer bidirectional Transformer,结构与 RoBERTa-base 完全相同,因此不再赘述,模型参数共 125M。

3.2 Input/Output Representations

预训练阶段的输入: [ 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];(NL Text + PL Code)

  • [ C L S ] [CLS] [CLS] 开头特殊标记,其 hidden representation 通常被认为是用于分类或排序的 aggregated sequence representation;
  • 按照 Transformer 处理文本的方式,将 NL 视为单词序列,将其切分为 WordPiece;此处将一段代码看作 token sequence;

输出:1)对 NL/PL 输出每个 token 的 contextual vector representation;2) [ C L S ] [CLS] [CLS] token 作为 aggregated sequence representation;

3.3 Pre-Training Data

分别用 bimodal/unimodal data 训练 CodeBERT;

  • bimodal:parallel data of natural language-code pairs
  • unimodal:codes without paired natural language texts and natural language without paired codes

数据:datapoints from Github Repos

  • bimodal datapoint:带有对应注释的函数
  • unimodal code:不带注释的函数


用于预训练的数据集的构造方法 爬取公开非 fork 的 github repo,根据下述规则过滤:1)至少被一个别的项目使用;2)each documentation is truncated to the first paragraph(看下面的图);3)注释不能少于 3 tokens;4)函数不能小于三行;5)函数名不能带有 test;

3.4 Pre-Training CodeBERT

使用了两个预训练任务来预训练 CodeBERT:

  • masked language modeling (MLM):应用于 bimodal data of NL-PL pairs;
  • replaced token detection (RTD):使用大量 unimodal data,如无注释的代码;

Objective #1: Masked Language Modeling (MLM)
输入: datapoint of NL-PL pair x = { w , c } x=\{w,c\} x={w,c} w w w:NL words sequence; c c c:PL tokens sequence;
首先为 NL、PL 随机选择约 ~15% 的 token 替换为 [ M A S K ] [MASK] [MASK]

MLM 的目标是预测 masked position 处的 original token,下面的 p D 1 p^{D_1} pD1 是判别器 discriminator,从大量的词汇表中预测出一个 token:

Objective #2: Replaced Token Detection (RTD)

RTD 目标最初是用于高效学习自然语言预训练模型。本文同时采用双模态和单模态数据用 RTD objective 进行训练。这里有两个 generators:NL generator p G w p^{G_w} pGw,PL generator p G c p^{G_c} pGc 都用于对 masked positions 生成 plausible alternatives。

判别器 discriminator 被训练来判断一个词是否是原始词,这是一个二分类问题。对输入的每个位置,都应用 RTD objective,这与 GAN 的区别是:如果 generator 恰好生成了正确的 token,该 token 的 label 是 “real” 而不是 “fake”。【因为 GAN 里是通过 generator 和 discriminator 左右互搏,造 fake 和 鉴别 fake 来实现模型的提升,所以 generator 的目标是生成 fake 数据】

δ ( i ) \delta(i) δ(i):指示函数; p D 2 p^{D_2} pD2:预测 i-th word 是原始词的概率的判别器。

有很多方式实现 generator,本文实现了2个具有 bidirectional contexts 的 n-gram 语言模型,分别用于 NL、PL,也分别从相应的数据点学习。这个方法也很容易推广到学习双模态生成器以一种联合方式使用像基于 Transformer 这样的神经架构的复杂生成器,这部分作为未来可以拓展的工作

当前的 PL 训练数据是单模态代码数据,NL 训练数据来自双模态数据中的代码文档。最终的 Loss 函数:

3.5 Fine-Tuning CodeBERT

将 CodeBERT 应用到下游的 NL-PL 任务:

  • natural language code search:用与预训练相同的方式输入数据,用 [ C L S ] [CLS] [CLS]的表示来度量代码和自然语言查询中的语义相关性。
  • code-to-text generation:使用 encoder-decoder 结构,用 CodeBERT 初始化生成模型的编码器。

4 Experiment

4.1 Natural Language Code Search

Natural Language Code Search 任务:通过输入的自然语言查询代码集合中语义最相似的代码;

  • 数据集:CodeSearchNet corpus
    • 训练数据集和验证数据集都平衡了正负样本。负样本也平衡了随机替换 NL ( c , w ˉ ) (c,\bar{w}) (c,wˉ) 或者随机替换 PL ( c ˉ , w ) (\bar{c},w) (cˉ,w)的两类样本。
  • 评估方式:通过一组固定的 999 distractor codes 来为每对测试数据 ( c , w ) (c,w) (c,w) 计算 Mean Reciprocal Rank (MRR) 指标。然后进一步计算测试数据中的所有编程语言的宏观平均的 MRR 来作为整体评估指标。
    注意:这个指标与原始论文中的 AVG 指标不同,原始论文中的 answer 从6种候选语言中获得。但本文对每种编程语言都微调了特定于语言的模型。使用二分类 loss 训练每个模型,其 softmax 层连接到 [ C L S ] [CLS] [CLS] 的表示层。详细的微调超参数见附录 B.2。

Model Comparisons

上面的模型都通过把代码视为 tokens sequence 来进行预训练。本文也以 MLM 任务只在 code 上训练 RoBERTa。CodeBERT(MLM) 从头开始学习的性能超越了 RoBERTa。用 RoBERTa 初始化 CodeBERT 可以提高性能。

4.2 NL-PL Probing

Task Formulation and Data Construction:在相关研究 NLP probing 实验之后,本文研究 NL-PL probing。由于目前没有面向该问题的工作,因此本文创造了数据集,并形式化该问题。

对给定的 NL-PL 对 ( c , w ) (c,w) (c,w),NL-PL probing 的目标是测试模型在干扰下正确预测/恢复 masked token of interest 的能力(可能是 c i c_i ci,也可能是 w j w_j wj)。干扰有两种:

  • 用于 MLM 目标的整体目标词典;
  • 由专家对被测能力的理解而筛选或设计的少量候选样本(完型填空);

本文采用第二种干扰,将 NL-PL probing 任务设计为有多个选项的 QA 问题。问题是完型填空,一个特定的 token 被 [ M A S K ] [MASK] [MASK] 替换,然后专家设计了一些候选答案。具体而言,本节分别在 NL 侧和 PL 侧进行评估。而为了减少数据构建的工作量,自动从 CodeSearchNet 数据集中的验证集和测试集中的 NL-PL pairs 获取数据(该数据在预训练阶段不可见)。

为了在 NL 方面评估,选择了 NL-PL pairs 中 NL docs 包含6个关键词 (max,maximize,min,minimize,less,greater) 之一的 pair,然后合并1/2关键词和3/4关键词的 pairs,将数据分为4组候选。任务是让预训练模型从4个选项中选择1个正确的选项。即,该设置的输入包括完整的代码和带有 mask 的文档。

对于 PL 方面,选择包含关键字 max 和 min 的代码,并将任务设计为二选一问题。由于代码补全是一个重要的场景,我们想测试模型仅仅基于前文的 PL context 预测正确 token 的能力。因此,此处为 PL 添加了一个额外配置,其输入是完整的 NL 文档和前面的代码。

Model Comparisons:这里采用 CodeBERT(MLM) 因为其输出层自然契合 probing。结果表明在 NL 和 PL probing 上 CodeBERT 都比基线方法更好,只有在 proceding context 设置下更差,这表明 code completion 是一个挑战性的任务,这项研究留给未来的工作

本节进一步的对 NL-PL probing 进行 case study。分别 mask NL token、PL token,然后报告 RoBERTa 和 CodeBERT 的预测概率。我们可以看到 RoBERTa 在下图的两种情况下都失败了,而 CodeBERT 在 NL 和 PL 设置中都做出了正确的预测。

4.3 Code Documentation Generation

CodeBERT 的预训练目标不包括 generation-base objective,但本文想调查 CodeBERT 在生成任务上的扩展能力。本节研究 code-to-NL generation 并报告在 CodeSearchNet Corpus(6种编程语言) 上的文档生成任务的结果。因为生成的文档很短并且 higher order n-grams may not overlap,本节通过使用 smoothed BLEU score 解决了该问题。

Model Comparisons:baselines model 如带有 attention 机制的 RNN 模型、Transformer、RoBERTa 和仅在代码上预训练的模型。为了证明 CodeBERT 在 code-to-NL generation 任务上的有效性,采用了不同的预训练模型作为编码器并保持超参数一致(详细的超参数见附录B.3)。

  • 可以发现在 PL 上预训练的模型效果好于 RoBERTa,这证明在程序语言上预训练的模型可以改善 code-to-NL generation。

4.4 Generalization to Programming Languages NOT in Pre-training

本节评估在预训练中未见过的编程语言上模型的泛化性,选择的任务:natural language summary of a C# code snippet。在 CodeNN 论文中的数据集上进行实验,包含了 66015 个来自 StackOverflow 的 QA 对。这个数据集由于数量级小,因此具有挑战性。采用 smoothed BLEU-4 score 评估模型。


Model Comparisons:但这里效果仅次于 Code2Seq,可能原因是因为 Code2Seq 使用在其 AST 上使用了 compositional paths。但 CodeBERT 只将原始代码作为输入。本文通过按照一定顺序遍历 AST 的树结构来训练 CodeBERT,但这样做并没有对生成任务带来改进。因此结合 AST 来改进 CodeBERT 也是未来研究的一个潜在方向

5 Conclusion

  • 本文提出首个面向 NL-PL 的双模态预训练模型 CodeBERT,并基于 bimodal 和 unimodal 数据共同训练,微调后的模型在自然语言代码搜索、代码文档生成等下游任务中取得了当前的 SOTA。
  • 为了进一步研究预训练模型中蕴含的知识,设计了 NL-PL probing 任务,并创建了用于该任务的数据集。将 probing 任务看作完型填空问题(cloze-style answer selection problem),并对 NL 和 PL 的部分设计了干扰项。结果显示,当模型参数固定不变时,CodeBERT 优于 RoBERTa 和只使用代码 continuously trained 的模型。

潜在研究方向

  • 可以根据 bimodal evidence 学习更好的生成器或者更复杂的神经网络结构来改善 replaced token detection objective。
  • CodeBERT 的 loss 函数主要针对 NL-PL understanding tasks,尽管在 code-to-documentation generation 任务上取得了很高的 BLEU scores,但还可以通过修改为与 generation-related learning 相关的目标函数来提升。
  • 将 AST 纳入预训练也是一个值得探索的方向。
  • 将 CodeBERT 应用到更多的 NL-PL 相关的任务中,扩展到更多编程语言,获得更好的泛化性: 探索灵活和强大的 domain/language adaptation 方法。

Appendix

A Data Statistic

B Train Details

B.1 Pre-training

  • train CodeBERT on one NVIDIA DGX-2 machine using FP16;16 卡 NVIDIA Tesla V100;32GB内存;
  • batchsize: 2048,learning rate:5e-4;Adam Optimizer;warmup steps:10K;max sequence length:512;max training step:100K;

B.2 CodeSearch

  • fine-tuning 时 learning rate:1e-5, batch size: 64, max sequence length: 200, max fine-tuning epoch: 8;
  • Adam Optimizer

B.3 Code Summarization on Six Programming Languages

  • Transformer with 6 layers, 768 dimensional hidden states and 12 attention heads as our decoder in all settings;
  • max length of input and inference as 256 and 64;
  • Adam optimizer, learning rate: 5e-5,batch size: 64;
  • perform early stopping on the development set

B.4 Code Summarization on C#

  • 2-layer GRU with an attention mechanism as our decoder for a comparison
  • fine-tune models using a grid search with the following set of hyper-parameters: batchsize is in {32, 64} and learning rate is in {2e-5, 5e-5}

C Learning Curve of CodeSearch

D Late Fusion

本节分析 CodeBERT 是否适合作为 unified encoder。CodeBERT 首先对 NL 和 PL 分别进行编码,然后通过内积计算相似度,这样代码搜索就相当于在共享向量空间中寻找最近的代码。这样做还有助于预先计算代码表示的线上系统中使用 CodeBERT。在运行时,系统只需要计算 NL 的表示和基于向量的点积。根据以下目标对 CodeBERT 进行微调:最大化 ground truth 的内积,同时让干扰项的内积最小化。

我们只在数据量少的语言上使用了这个设定。可以看到 CodeBERT 比 RoBERTa 和仅用代码预训练的模型表现得更好。late fusion 与 standard 方法效果相当,但更有效,因为这种设定可用于线上系统。

E Case Study



本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/339178.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

嵌入式设备搭建NFS环境(服务器/客户端、源码下载编译、文件系统适配、内核适配)

1、什么是nfs (1)NFS(Network File System)是网络文件系统,能让使用者访问网络上别处的文件就像在使用自己的计算机一样; (2)NFS是基于UDP/IP协议的应用,其实现主要是采用远程过程调用RPC机制,RPC提供了一组与机器、操作系统以及低…

CAS详解.

CAS这个机制就给实现线程安全版本的代码,提供了一个新的思路,之前通过加锁,把多个指令打包成整体,来实现线程安全。现在就可以考虑直接基与CAS来实现一些修改操作,也能保证线程安全(不需要加锁)…

OpenAi-chatgpt注册保姆级全网最详细注册教程2023年2月最新-

废话就不多说了,说多了浪费各位师傅的时间!直接冲,在开始之前需要科学上网,就没其他要求了 1、访问https://chat.openai.com/auth/login 2、点击sign up,输入账号密码,点击Continue 3、之后会来到登陆页面&#xff0…

Oracle Dataguard(主库为 Oracle rac 集群)配置教程(03)—— 创建 dataguard 数据库之前的准备工作

Oracle Dataguard(主库为 Oracle rac 集群)配置教程(03)—— 创建 dataguard 数据库之前的准备工作 / 本专栏详细讲解 Oracle Dataguard(Oracle 版本为11g,主库为双节点 Oracle rac 集群)的配置…

云计算|OpenStack|错误记录和解决方案(不定时更新)

前言: openstack的部署和使用是难度比较大的,难免会出现各种各样的问题,因此,本文将把一些在部署和使用openstack社区版时出现的错误做一个记录,并就每一个错误分析和解决问题。(尽量记录比较经典的错误&a…

微搭低代码从入门到精通10-tab栏组件

在小程序中,如果你的页面是由多个组成的,往往涉及到页面切换的问题。那如何引导用户访问不同的页面呢?微搭中提供了tab栏组件来实现这个功能,本篇我们介绍一下这个组件的使用方法。 首先呢打开我们的应用编辑器,在左侧…

OJ刷题Day2 · 判断根结点是否等于子结点之和 · 删除有序数组中的重复项 · 合并两个有序链表 · 数组中的第K个最大元素(中等题)

一、判断根结点是否等于子结点之和二、删除有序数组中的重复项三、合并两个有序链表四、数组中的第K个最大元素(中等题)一、判断根结点是否等于子结点之和 给你一个 二叉树 的根结点 root,该二叉树由恰好 3 个结点组成:根结点、左…

SpringBoot + kotlin/java + Mybatis-Plus +Sqlite + Gradle多模块项目

前言 我自己的业务项目,先用kotlinspringboot 搭建, 发现gradle支持kts脚本,于是我就搭建试试。我就选用了最流行的Sqlite内嵌数据库,虽然H2也不错,但是Sqlite才是最流行的。orm框架我还是选择了Mybatis-Plus ,为此中…

Spring Boot的创建和使用

目录 一、Spring Boot介绍 1.1 Spring Boot 是什么 1.2 Spring Boot的优点 二、Spring Boot 项目的创建 2.1 使用idea创建 2.1.1 安装Spring Boot Helper插件 2.1.2 创建 Spring Boot 项目 2.1.3 验证项目是否创建成功 2.2 使用网页创建 三、输出 hello world 一、S…

前端如何提升To B产品用户体验

云计算产品发展的早期常以技术为核心吸引客户,功能的实现是这一时期产品优先考虑的因素。经过数十年的发展,云计算行业已经进入了深耕细作的时代,市场的激烈竞争与云产品快速发展的同时,用户对产品的可用性与易用性也有了更高的要…

交换机中的冗余链路管理

一 交换机冗余链路许多交换机或交换机设备组成的网络环境中,通常使用一些备份连接,以提高网络的健全性,稳定性。备份连接也叫备份链路,冗余链路等。为了解决共享式局域网的碰撞问题,采用了交换机构成的交换式局域网&am…

C语言静态库、动态库的封装和注意事项

1、动态库、静态库介绍 参考博客:《静态库和动态库介绍以及Makefile》; 2、代码目录结构和编译脚本 参考博客:《实际工作开发中C语言工程的目录结构分析》; 3、编写库的流程 (1)明确需求:需求是否合理、需求的使用场景、需求可能遇…

chatgpt:人工智能的一次突破,如何正确的创建用户及使用

Chatgpt的正确创建及使用 chatgpt最近在国内也开始有声音了,其实早在去年12月初,该网站就已经可以在国外进行使用,而且很快渗透到了国外各行各业各个年龄段 ,最火的当属国外很多学生用它来生成论文,关键是语句通顺&am…

如何开启多个独立Chrome浏览器

一、简介 作为测试或者开发人员,有些情况下会用到 Chrome 浏览器,但有时是同一个 Chrome 浏览器无法为我们提供隔离开的不同环境。这样 我们就需要清理 cache 、切换账号等,降低了我们的工作效率。今天的主题是如何开启多个独立的 Chrome 浏…

LayUI模板引擎渲染数据

前端模板引擎介绍 接上节Spring boot项目开发实战——(LayUI实现前后端数据交换与定义方法渲染数据) 模板引擎能简化开发,极大提高效率,小编之前使用过JSP和Thymeleaf,以及python的jinja2,这些是后端的模…

spring(二)-----------如何注入bean

我们从第三方框架mybatis为引,看看如何往spring中注入一个bean 1、纯mybatis开发生成一个mapper对象 如果不使用spring的情况下,mybatis想生成一个mapper对象大概需要做下面的操作: 假设我们有了一个TMapper接口,此时获取该map…

12款开源数据资产(元数据)管理平台选型分析(三)

如上,是ChatGPT的百度指数和微信指数,继2022年12月上旬技术圈火热之后,因为微软、谷歌等巨头的推广加持,ChatGPT成为全球大众热源的话题。各大媒体都在消费这波舆论红利,打开微信公众号,劈天盖地各种姿势的…

前后端学习

最近和锴哥想搞一下前后端接口的事儿,但是不会,所以打算再学学前后端的基础知识,之后好抄作业,做缝纫机;达哥觉得我浮躁,这次一定要支棱起来;这次开始,面向openai学习。 前后端学习1…

ChatGPT (可能)是怎么炼成的

学习自李宏毅老师的课https://www.youtube.com/watch?ve0aKI2GGZNg 1.学习文字接龙 学习方式 GPT只需要在网上阅读大量的句子,不需要人工标注即可学习到大量句子接龙的知识 然而实际上,“你好”后面可以接的字有很多。实际上,GPT学的就是…

3、Go基础数据类型

目录一、Go数据类型二、字符串三、强制类型转换一、Go数据类型 基础数据类型 类型长度(字节)默认值说明bool1falsebyte10uint8,取值范围[0,255]rune40Unicode Code Point, int32int, uint4或8032 或 64 位,取决于操作系统int8, uint810-128 ~ 127, 0 ~…