通过大规模预训练自动化代码审查活动

互联不一般哥 2024-06-22 21:06:50

Automating Code Review Activities by Large-Scale Pre-training

Zhiyu Li1, Shuai Lu2, Daya Guo3, Nan Duan2, Shailesh Jannu4, Grant Jenks4, Deep Majumder4, Jared Green4, Alexey Svyatkovskiy5, Shengyu Fu5, Neel Sundaresan5

1Peking University, China

2Microsoft Research Asia, China

3Sun Yat-sen University, China

4LinkedIn, USA

5Microsoft DevDiv, USA

引用

Ibrahimzada A R, Chen Y, Rong R, et al. Automated Bug Generation in the era of Large Language Models[J]. arXiv preprint arXiv:2310.02407, 2023.

论文:https://dl.acm.org/doi/abs/10.1145/3540250.3549081

仓库:https://github.com/microsoft/CodeBERT/tree/master/CodeReviewer

摘要

代码审查是软件开发生命周期中不可或缺的一部分,其目的在于保证代码质量。现代代码审查活动需要开发者查看、理解甚至运行程序,将不得不花费大量时间。因此,自动化代码审查流程的需求非常迫切。本文专注于利用预训练技术处理代码审查场景中的任务,从九种最流行的编程语言的开源项目中收集了大规模的实际代码更改和代码审查数据集。为了更好地理解代码差异和审查,本文提出了CodeReviewer,这是一个预训练模型,它利用了四个专门为代码审查场景定制的预训练任务。CodeReviewer专注于与代码审查活动相关的三个关键任务,包括代码变更质量估计、审查评论生成和代码精炼。此外,本文基于收集的数据为这三项任务建立了一个高质量的基准数据集,并在其上进行了全面的实验。实验结果表明,CodeReviewer在所有任务中都超越了以往最先进的预训练方法。

1 引言

代码审查,一个由团队成员(而非代码作者)手动检查源代码的过程,被认为是软件开发生命周期中的关键部分。研究表明代码审查带来了巨大的好处。与1976年Fagan正式化的传统代码审查过程相比,后者虽然避免了错误和缺陷的引入但过于繁琐,现代代码审查活动涉及较少的正式要求,旨在全面理解代码变更。鉴于其好处,代码审查已广泛应用于开源和工业项目中。正如Yang等人所示,例如在Qt这样的开源项目中,每月有一万次审查活动(在Qt的案例中大约有22k次审查)。然而,要完全利用代码审查的所有优势并非无成本。为了正确判断是否接受拉取请求,开发者必须投入大量时间和努力进行代码审查,从每一个角度检查代码,包括逻辑、功能、复杂性、代码风格、文档等。例如,Yang等人报告称,在Qt项目中,只有1,437名审查者在4年内提交了超过1M次审查。因此,自动化代码审查过程的需求非常迫切。

许多研究者已经探索了帮助审查者和提交者(即代码作者)减轻代码审查过程中工作量的方法,如推荐最佳审查者、推荐或生成可能的审查评论,甚至在提交审查之前修改代码。这篇论文也有同样的目标,即自动化一些与代码审查相关的特定任务。我们针对的是审查者和提交者的三种情境。第一种是代码变更质量估计,旨在预测代码差异是否需要审查评论。它帮助审查者在大量代码块中挑选可能有问题的代码块。第二项任务是审查生成,可以显著减少审查者的时间成本。最后一个情景是针对提交者的,即根据之前的代码和审查者的评论进行代码精炼。

在深度学习(DL)技术在软件工程中广泛应用以及预训练技术快速发展的驱动下,我们利用预训练自动化代码审查活动。近期,研究者们已经提出了许多针对源代码的预训练模型。然而,它们很难处理代码审查过程。Chen等人提出了Codex,一个基于GPT-3的大规模预训练模型。Codex已被证明是代码生成任务中最强大的模型。由于它是基于原始格式的源代码文件训练的,它对代码审查知之甚少。我们的评估显示它在审查生成任务中无法生成任何有意义的评论。Tufano等人试图使用一个预训练模型来自动化代码审查。然而,他们的预训练数据集是从Stack Overflow和CodeSearchNet收集的,这与代码审查过程没有直接关系。此外,他们将源代码的普通形式作为模型输入,忽略了可以帮助模型更好地理解代码变更的代码差异的特殊格式。

为了解决这些问题,我们预训练了CodeReviewer,一个编码器-解码器变换器模型。与Tufano等人的工作不同,CodeReviewer是在代码审查场景的大数据集上预训练的,包括代码差异块和代码审查评论。我们提出了四个预训练任务,包括差异标签预测、代码差异去噪、审查评论去噪和审查评论生成,以使CodeReviewer更好地理解代码差异并生成审查评论。图1显示了我们的CodeReviewer的工作流概览。

图1:CodeReviewer工作流程概览。

为了使CodeReviewer更适合代码审查过程,我们构建了一个大规模的代码变更及其对应审查评论的数据集。这些代码审查数据是从GitHub拉取请求中收集的,涵盖了九种最受欢迎的编程语言的高星级高质量项目。使用GitHub代码审查数据,我们为与代码审查过程相关的三项任务创建了预训练和基准数据集。据我们所知,这是最大的多语言代码审查数据集,包含完整的代码变更和审查信息。我们进一步在我们的基准数据集上评估了我们的CodeReviewer模型。与以往最先进的(SOTA)代码生成模型相比,实验结果显示我们的模型在所有三项任务上都有更好的表现。进一步分析证明了我们提出的预训练任务和多语言高质量数据集的有效性。

本文的显著贡献包括:

第一个在代码审查场景中以代码差异为输入的预训练模型。更好地理解和生成代码变更而设计的新颖预训练任务。一个大规模的与代码审查相关的预训练数据集,以及用于评估九种编程语言的高质量基准数据集。对CodeReviewer及之前最先进(SOTA)模型的全面评估。我们的数据集、代码和模型已发布。

2 代码审查自动化任务

在本节中,我们提供了代码审查流程的格式化描述,给出了从代码审查流程中抽象出的三个关键任务的正式定义,并阐明了任务的数据格式。使用的符号列在表1中。

表1:本文中符号和标记的总结

2.1 代码审查

在代码审查过程中,贡献者(代码变更作者,PC)更新源代码以实现新功能或修复旧版本中的错误。原始代码和更新后的代码分别表示为 C0 和 C1。一旦代码变更(D : C0 →C1)准备好进行审查,这些变更的作者就会创建一个拉取请求以启动代码审查过程。其他同行贡献者(审查者,PR)将审查代码变更,并在必要时提供评论或建议(Rnl)。基于这些评论,作者进行修订,并提供新版本的代码 C2。我们称到目前为止的活动为一轮审查。注意,审查过程尚未结束。审查者可以对修订提出进一步的建议。作者也可能再次修订代码。经过几轮审查后,拉取请求最终会被批准(变更合并到主分支)或被丢弃。

一个拉取请求通常包含多个提交,每个提交可能涉及不同文件中的多个代码变更。因此,建模整个审查过程是困难且具有挑战性的。作为初步步骤,我们专注于自动化单个提交的审查过程。在审查轮中,涉及两个不同的角色——提交代码变更的贡献者PC(D : C0 →C1),以及提供建议和评论的审查者PR(Rnl)。代码审查自动化的目标是帮助减轻他们的工作负担。为此,我们专注于两种不同角色场景中的三个具体代码审查自动化任务。所有三项任务的概览如图2所示。

图2:代码审查自动化任务概览。三个任务分别完成。

2.2 代码变更质量估计

代码变更质量评估任务旨在预测代码变更是否高质量并且准备好在审查过程中被接受。这是一个二分类任务,即 Y = {0, 1}。输入是一个代码变更,即 X = {D(C0,C1)}。如前所述,一个拉取请求通常涉及不同源代码文件中的许多变更。审查者需要花费大量时间来审查所有变更。但结果通常是,大多数变更都是微小的,并不需要评论或建议。为了提高代码审查的效率,我们定义并推进自动化代码变更质量评估任务。根据评估结果,审查者可以优先审查质疑的代码变更,并更加关注它们,从而节省时间和精力。贡献者也可以利用这些评估结果在提交给审查者之前改进低质量的代码变更。

2.3 代码审查生成

代码审查生成是一个序列生成任务。输出是预测的审查评论,即 Y = {w1, · · · ,wn},其中 wi 是自然语言单词,n ∈ N 是评论的长度。输入仍然是代码变更,即 X = {D(C0,C1)},以及其上下文。在一些先前的研究中,研究者使用变更后的代码作为输入,而不是代码差异,没有考虑到审查评论必须关注已变更的部分。不建议审查者对未经修改的代码上下文提出建议。考虑到软件的自然性,语言模型可以捕捉程序的一般统计特性,因为程序往往是重复和可预测的。在代码审查过程中,某些代码变更也存在常见问题。例如,审查者经常写“此方法应为私有”,以建议贡献者为方法添加私有修饰符。这为我们提供了一个机会,学习一般的代码审查模式,并自动生成评论,以减轻审查者的负担。在现实世界场景中,模型生成少量审查评论候选项,审查者可以从中选择一个理想的评论,免于手动编写评论。

2.4 代码精炼

在代码精炼任务中,模型输入包括贡献者编写的原始代码C1和审查者的审查评论Rnl,目标是生成修订后的版本代码C2,实现Rnl中提到的要求。与其他软件开发场景中的代码精炼任务不同,后者只将源代码作为输入,我们专门为代码审查过程设计,利用审查评论作为精炼的指导。代码精炼是为协助贡献者设计的任务。当他们开启拉取请求并作为反馈获得审查评论时,模型帮助根据评论自动修改提交的代码。

2.5 数据格式

所有三个任务都与源代码或代码变更相关。在代码审查过程中,通常涉及多个相关的文件和功能。一个源代码文件或一个函数/方法过大而难以处理,因为可能会有多个审查评论和代码修订分布在一个文件或函数/方法中。因此,我们在差异块级别定义了这三个任务的输入。

在拉取请求中,代码的原始版本和修订版本以特殊格式显示:差异(图2)。差异文件是通过比较变更前后的两个文件生成的。差异工具找到两个文件中都有的行序列,这些行序列间隔着称为块的不同行组。具体来说,一个差异块是一个被几行未改变的代码行包围的源代码行序列。差异块包括从原始文件中删除的行和添加到新文件中的行。差异格式经常被程序员用来清晰地显示代码中的变更。此外,差异格式是表示代码变更的一种高效方式,因为未改变的行只出现一次,并且变更在每行的开头用“-”和“+”标记对齐。在前两个任务中,我们将输入格式化为表示代码变更的差异块。在代码精炼任务中,我们从修订差异块中提取输入行(C1)和输出行(C2)。

3 代码审查数据集

如今,许多开发者不仅使用像GitHub和Gerrit这样的协作软件开发平台来分享他们的代码,还在这些平台上执行代码审查活动。GitHub平台允许贡献者公开所有这些审查细节,包括每个拉取请求中代码变更的确切内容、审查评论及其作者和发生时间,这使得从开源项目中收集和分析代码审查数据成为可能。因此,我们基于从GitHub上开源项目收集的拉取请求数据,建立了我们的CodeReview数据集,涵盖九种编程语言。

3.1 项目选择

为了确保我们数据集的质量,我们从公开可用的高质量开源仓库中收集拉取请求数据。我们首先按“受欢迎程度”排序项目,这一点通过星级的数量来表示。为了提高在我们数据集上训练的模型的泛化能力,我们收集GitHub上九种最受欢迎的编程语言的项目,包括C、C++、C#、Go、Java、JavaScript、PHP、Python和Ruby。然后,我们保留每种编程语言前10,000个项目,并移除那些不明确允许数据再分发的项目。具体来说,所有带有流行许可证的仓库,如Apache-2.0许可证和MIT许可证,都被保留。如果贡献者在许可证文件中写明允许数据再分发,他们的项目也会被收集。为了确保项目质量并尽可能多地获取代码审查数据,我们进一步按拉取请求的数量排序项目,并过滤掉拉取请求少于1,500的项目。这一过程只保留了活跃的、拥有许多贡献者的项目,并移除了那些从其他项目分叉出来的仓库,因为拉取请求的数量不会被继承。然后我们开始爬取这些项目的拉取请求信息。

图3:数据集构建过程的流程图

3.2 审查数据收集

我们使用GitHub REST API从项目中收集拉取请求数据。GitHub API提供了一个基于HTTP请求的API,用于访问仓库信息。通过向GitHub发送HTTP请求,我们可以方便地以Json格式访问分支、提交、拉取请求、代码差异、审查评论等。许多研究者已经使用GitHub API在他们的工作中收集和分析拉取请求数据[20, 35]。为了推动代码审查研究,Heumüller等人[20]开发了ETCR基础设施,用于从任何实践基于拉取请求的开发的GitHub项目中挖掘代码审查数据集。ETCR工具的设置只需要GitHub API密钥和仓库名称。ETCR使用基于Kotlin的网络爬虫,并通过四个阶段工作,通过GitHub API收集拉取请求、提交、评论和源文件的数据。所有数据都存储在关系数据库中,因此可以方便地访问。我们首先使用ETCR工具[20]收集拉取请求和审查评论的元信息,包括与评论相关的git提交哈希和更改文件名。使用元信息,我们可以进一步查询GitHub API以获取与审查评论相对应的代码变更(包括原始文件、新文件和代码差异)。这些代码变更和评论构成了我们的CodeReview数据。到目前为止,我们已经收集了构建三个下游任务数据集所需的所有数据。

3.3 关注分析器

以用预训练数据集是一组带有或不带有审查评论的代码变更。然而,构建三个下游任务的数据集还需要进一步的数据处理:

代码变更质量评估:所有有评论的代码变更被视为引入错误或与代码规范冲突的可疑代码。其他没有评论的代码变更被标记为正确。由于没有评论的代码变更数量约为有评论的代码变更数量的2-3倍,我们对没有审查评论的变更执行随机下采样,以构建平衡的数据集。审查评论生成:带有审查评论的代码变更将用于此任务。我们过滤掉那些由代码变更作者编写的评论。当一个差异块相关的评论多于一个时,我们只保留最早的一个。代码精炼:我们遍历项目中的每个拉取请求。对于每个有评论的代码变更,我们检查此拉取请求中的所有提交,以找出是否有后续提交再次更新了这部分代码。具体来说,当审查者对代码差异D : C0 →C1发表评论,且在后续提交中,C1中修订的源代码行被进一步修改为新版本C2时,我们假设早期变更的评论帮助贡献者进行了后续更新。然后收集三元组(C1, Rnl, C2)以构建代码精炼数据集。在某些情况下,一个评论与多个未来代码修订相关,或者多个评论共同促成了一次修订。所有这些样本都从数据集中删除,因为模拟多个评论与多次变更之间的交互超出了本文的讨论范围。 尽管我们从星级和PR数量高的项目中收集数据,数据集质量仍然存在变化,尤其是在审查评论方面。为了过滤掉低质量的评论,我们根据附录中描述的步骤仔细清理预训练和下游数据集。

3.4 数据分割

我们使用CodeReview数据构建预训练数据集以及三个下游任务的基准数据集。为了防止数据集发生信息泄露,我们在项目级别上分割数据。拥有超过2,500个拉取请求的代码仓库用于构建预训练数据集和基准数据集的训练集。其他拥有[1,500, 2,500)个拉取请求的代码仓库用于构建验证集和测试集。

4 CodeReview

在本节中,我们详细描述了我们的CodeReviewer模型,包括模型架构、模型的输入输出表示,以及为代码审查设计的预训练任务。我们基于变换器(Transformer)开发了CodeReviewer,并设计了四个与代码审查过程相关的预训练任务,以提高模型自动化代码审查活动的能力。

4.1 模型架构

CodeReviewer是基于变换器(Transformer)的编码器-解码器模型。我们采用与文本到文本转换变换器(Text-To-Text-Transfer Transformer, T5)模型相同的架构。CodeReviewer模型由12层变换器编码器和12层解码器组成。每层有12个注意力头,隐藏层大小为768。模型的总参数量为2.23亿。

我们使用CodeT5的参数初始化CodeReviewer。我们进一步使用我们的四个预训练任务对模型进行预训练。一旦预训练完成,CodeReviewer将分别在下游任务上进行微调和评估。

4.2 输入输出表示

CodeReviewer针对不同任务接受不同的输入和输出。对于代码理解任务或评论生成任务,模型以代码差异作为输入。对于代码精炼任务,模型同时接受原始源代码和审查评论作为输入。

遵循变换器中的标准输入处理方式,输入被视为一个标记序列。我们使用与CodeT5相同的RoBERTa[26]分词器来将源代码和审查评论分割成标记。一个特殊标记[CLS]被添加到序列前,形成输入为{[CLS], c1, c2, ···, cn},其中ci是源代码标记,n是序列长度。为了帮助我们的模型更好地理解差异格式,差异文件中表示行删除和行插入的特殊行标记“-”和“+”被替换为特殊标记[DEL]和[ADD]。我们还在每条未更改的行前插入一个[KEEP]标记。当输入中既有源代码标记也有审查评论标记时,将插入一个[MSG]标记来分隔两个序列。因此输入为{[CLS], c1, c2, ···, cn, [MSG], w1, w2, ···, wm}。

模型的输出包括两个部分:来自编码器的标记表示和来自解码器的生成标记序列。对于分类任务,使用[CLS]标记的表示来生成预测。对于序列生成任务,解码器输出预测的标记序列。

4.3 预训练任务

自动化代码审查活动的关键挑战在于理解代码变更和捕捉代码变更与相应审查评论之间的关系。因此,我们设计了四个预训练任务来提高CodeReviewer的能力。

差异标签预测。正如第2.5节中提到的,差异文件是一种包含丰富代码变更信息的特殊格式。与编码原始版本和新版本代码相比,差异格式避免了未更改行的重复。因此,学习将代码差异作为源代码的特殊格式对模型在代码审查场景中至关重要。我们使用DTP任务使模型具备理解代码差异中特殊行标签的能力。请注意,我们将差异行开头的“+”和“-”标签用特殊标签[ADD]、[DEL]替换,并在模型输入中包含[KEEP]。在DTP训练中,这三种特殊标签在模型输入中被[MASK]标记替换。我们训练我们的模型预测相应位置的特殊标记[ADD]、[DEL]或[KEEP]。通过DTP训练,模型学会区分一行是未更改还是已更新。这有助于CodeReviewer理解代码差异格式。

去噪目标。去噪目标是Lewis等人引入的一种无监督预训练目标,用于获取语料的一般理解。原始的去噪目标随机地用15%的损坏率掩盖输入句子中的跨度,并预测这些跨度。通过学习预测掩盖的跨度,模型获得关于语料分布的一般知识。为了更好地理解代码差异和审查评论,我们为CodeReviewer设计了两个去噪目标:去噪代码差异(Denoising Code Diff, DCD)和去噪审查评论(Denoising Review Comment, DRC)。在DCD任务中,我们随机选择15%的代码行并对其进行掩盖。我们在行级而非跨度级上损坏输入,以保持代码差异的完整格式。值得注意的是,为了降低这项任务的难度,行标签([ADD]、[DEL]和[KEEP])被保留,以告知模型一行是更新还是移除。DCD任务旨在帮助模型学习代码变更的分布,增强编码器和解码器。编码器产生更好的代码变更表示对理解和生成任务都有益。在DCD上预训练解码器有助于模型在代码精炼任务中生成更好的源代码。

在去噪审查评论(DRC)任务中,模型接收到一个被损坏的审查评论作为输入,并需要恢复被掩盖的跨度。具体来说,我们随机掩盖跨度,损坏率为20%,并训练解码器生成它们。进行DRC任务的训练预期将有助于与评论相关的任务。对于去噪代码差异(DCD)任务和去噪审查评论(DRC)任务,模型需要预测掩盖的代码差异和审查评论。损失函数用于评估模型预测的代码差异跨度序列和审查评论跨度序列 与真实序列的匹配程度。这些损失通常使用交叉熵损失来实现,帮助模型精确地恢复输入中的被掩盖部分。通过这种方式,CodeReviewer学习从部分信息中恢复完整的代码差异和审查评论,从而提高了处理实际代码审查任务中常见的不完整或损坏数据的能力。这对于实际应用中自动化代码审查和生成有关代码的评论具有重要意义。

生成审查评论。在上述每个预训练任务中,只涉及一种模式,这意味着模型只学习在一个任务中理解源代码或审查评论。然而,代码审查中最具挑战性的部分是捕捉代码变更与审查评论之间的关系。为了使我们的模型具备这一能力,我们在预训练任务中利用双模态数据(编程语言中的代码变更和自然语言中的相关审查评论)。为了通用性,我们使用一个简单的条件生成任务:审查评论生成(RCG)。在RCG中,模型接收代码变更作为输入,并被要求生成人类审查者编写的审查评论。我们使用负对数似然损失。通过这种方式,模型学习根据给定的代码变更生成相应的审查评论,这对于理解和复现人类审查者在实际代码审查中的反馈非常关键。这不仅有助于模型更好地理解代码变更的上下文,还能增强其在自动代码审查中生成有用和相关评论的能力。

4.4 微调

我们将所有下游任务分为分类任务和生成任务。对于像代码变更质量估计这样的分类任务,我们只使用预训练的编码器。特殊标记[CLS]在开始时最后一层的表示ℎ0被输入到一个线性分类器中以产生预测。对于像代码精炼这样的生成任务,使用整个预训练的编码器-解码器模型。标准的标记负对数似然损失被用来优化目标序列的概率。

5 微调

5.1 实验设置

研究问题。为了调查我们的CodeReviewer模型在代码审查任务上的表现,我们进行了一项大规模破破的研究,以回答以下研究问题(RQ):

RQ1:CodeReviewer在代码变更质量评估任务上的表现如何?我们向CodeReviewer提供代码变更D1 : C0 →C1作为输入,并要求模型给出是否需要审查的二元预测。

RQ2:CodeReviewer在审查生成任务上的表现如何?在这个问题中,CodeReviewer同样提供代码变更D1 : C0 →C1,但我们评估CodeReviewer生成审查者可能给出的自然语言评论Rnl的能力。

RQ3:CodeReviewer在代码精炼任务上的表现如何?给定提交代码审查的几行源代码和审查者用自然语言写的反馈,模型需要精炼提交的代码以实现审查评论的要求。

在RQ1-RQ3中,我们评估CodeReviewer在不同的代码审查任务上的表现。为了评休每个预训练任务和我们的多语言数据集的贡献,我们进一步调查RQ4和RQ5。

RQ4:每个预训练任务在CodeReviewer中扮演什么角色?在RQ1-RQ3中,评估的CodeReviewer模型是在应用于下游任务之前预先训练了所有四个预训练任务。我们逐一移除预训练任务,并再次评估生成的模型,以揭示每个预训练任务对不同下游任务的影响。

RQ5:多语言数据集能否提高模型对单一编程语言理解的表现?现有研究表明,与单语言数据集相比,多语言训练数据集可以提高模型在神经机器翻译和代码翻译上的表现,特别是对于低资源语言。我们评估在单语言数据集上预训练和微调的CodeReview的性能,并与在完整数据集上训练的模型进行比较,以展示多语言数据集的影响。

数据集。我们按照第3.3节描述的方法构建了预训练数据集和3个下游任务数据集。表2总结了预训练数据集的统计数据。对于基准数据集,详情显示在表3中。

表2:预训练数据集的统计数据

表3:基准数据集的统计数据

评估指标。代码变更质量评估。这是一个二分类任务。我们使用准确率(accuracy)、精确度(precision)、召回率(recall)和F1分数来评估模型预测。注意,在计算后三个指标时,有问题的代码变更(需要评论和更新)被视为正类。审查评论生成。我们计算预测的双语评估学徒(BLEU)[30]得分。BLEU广泛用于评估自动生成文本的质量,如机器翻译和代码生成等生成任务。我们使用BLEU-4变体,计算生成文本与参考文本之间的1至4个n-gram的重叠。代码精炼。对于这个任务,我们计算生成代码与目标代码之间的BLEU得分和完全匹配(EM)率。BLEU仅评估预测与目标之间的相似性,而源代码的微小变化可能导致编译错误和执行错误。因此,完全匹配是此任务中更重要的指标。只有当预测与目标完全相同时,才被视为正确。

5.2 结果分析

在这一部分,我们根据我们的实验结果回答每个研究问题。我们首先关注三个关于我们模型在各个任务中的表现以及与其他最先进基线模型的比较的研究问题。我们进一步展示了我们的预训练任务和多语言数据集的效果。

RQ1 代码变更质量评估的表现

表4展示了代码变更质量评估任务的结果。从表中可以看出,无论是从头开始训练的基线模型还是预训练模型,CodeReviewer在所有四个指标上均显著优于它们。具体来说,与T5相比,我们的CodeReviewer模型在F1和准确率上分别提高了8.24%和7.07%。与CodeT5相比的改进也超过/约7%,这表明我们的预训练任务帮助CodeReviewer更好地理解代码变更。此外,从头开始训练的Transformer在性能上不如其他三个模型,这表明了预训练的重要性。

表4:代码变更质量评估结果

RQ2 审查评论生成的表现

表5显示了审查评论生成任务的结果。CodeReviewer的BLEU分数高于基线模型。然而,我们模型的BLEU分数仍低于10,表明这是一个难度较大的任务。正如之前提到的,审查评论具有多样性和非唯一性。参考图5中的示例,我们模型的预测传达了与真实情况相似的意图,但他们的措辞差异很大,导致BLEU分数低于Codex。为了更好地调查模型的性能,我们对其预测进行了人工评估。

表5:审查评论生成的结果。人工评估中两项指标的完美得分均为5分

我们首先从测试集中随机选择300个Java和Python样本,并手动挑选出100个具有高质量代码变更和审查评论的样本。对于选定的样本,我们邀请了6名专业的高级程序员按照第5.2节描述的方法对每个模型的参考评论和生成评论进行评分。结果列在表5中。与基线模型相比,我们的模型在生成评论的信息得分和相关性得分方面提高了约20%,这意味着CodeReviewer生成的评论更有用且更充分。T5的表现低于其他模型,包括Transformer基线,因为T5的参数大小(61M)约为其他模型(223M)的1/4。我们推测对于一个小型模型来说,生成审查评论过于具有挑战性。

在这项任务中,我们还对世界上最大的源代码语言模型Codex[7]进行了定性分析,它已被证明是最强大的代码生成模型,并能够进行零样本任务转移。由于我们无法直接访问并微调该模型,我们选择使用由Codex支持的GitHub Copilot[15]作为替代。通过提供几个代码差异和审查评论对作为提示,我们发现Codex无法生成任何有意义的评论,只是复制给定示例中的评论。图5展示了不同模型生成的输出示例,包括Codex。

图5:审查评论生成任务的两个示例。Codex的输出由Copilot获得

RQ3 代码精炼的表现

表6:代码精炼的结果

表6展示了代码精炼任务的结果。Naïve-Copy方法直接复制输入代码作为精炼结果。它产生了一个不错的BLEU得分,但完全匹配(EM)得分为0.00。CodeReviewer成功地在超过30%的案例中生成与真实代码完全相同的修复代码,这是T5结果的两倍,相对于CodeT5多出25%,展示了CodeReviewer理解审查评论并基于它们精炼代码的卓越能力。CodeReviewer的BLEU得分也高于T5和CodeT5。图6展示了我们模型生成的一个完美预测示例。请注意,Transformer模型在10个周期内未能收敛,产生约0的BLEU得分,因此该结果未列在表中。

RQ4 影响预训练任务

我们在RQ1-RQ3中展示了CodeReviewer在不同下游任务上的卓越表现,证明了精心设计的预训练任务有利于自动化代码审查活动。在本研究问题中,我们深入探讨了每个预训练任务的贡献。我们进一步预训练了三个模型,每个模型都移除了一些预训练任务,然后评估它们在代码变更质量评估任务上的表现。模型CodeReviewer w/o DTP、CodeReviewer w/o DCD和CodeReviewer w/o CMT分别代表没有进行差异标签预测任务、去噪代码差异任务和其他两个与评论相关的任务(去噪审查评论和审查评论生成)的CodeReviewer。

表7显示了结果。模型性能的下降证明了预训练任务的重要性。对于代码变更质量评估任务,所有的预训练任务都帮助我们的模型更好地理解代码差异。但差异标签预测任务和去噪代码差异任务更为重要。这些结果与我们在第4.3节中的动机是一致的。

表7:代码变更质量评估的削减研究

RQ5 多语言数据集的影响

表8:多语言数据集在代码变更质量评估任务上的削减研究

在之前的实验中,CodeReviewer是在包含九种编程语言的数据集上训练的。为了研究多语言数据集是否帮助我们的模型更好地理解单一编程语言,我们分别为Java、C#和Ruby语言构建了单语言数据集。Java代表流行语言,而Ruby代表低资源语言,如表2所示。对于这三种语言中的每一种,我们在单语言数据集上预训练和微调CodeReviewer,并将其在代码变更质量评估任务上的表现与在完整多语言数据集上预训练和微调的原始CodeReviewer进行比较。结果列在表8中。

多语言CodeReviewer一致性地优于三个单语言模型,平均准确率提高了2.32%,F1得分提高了1.10%。我们得出结论,我们的多语言数据集显著地有助于CodeReviewer理解特定语言。这揭示了我们的多语言数据集相对于单一编程语言数据集的优越性。它还证明了CodeReviewer在不同编程语言中的广泛适用性。

转述:葛一飞

0 阅读:0

互联不一般哥

简介:感谢大家的关注