利用迁移学习完成代码相关任务

互联不一般哥 2024-07-03 03:20:54

引用

Mastropaolo A, Cooper N, Palacio D N, et al. Using transfer learning for code-related tasks[J]. IEEE Transactions on Software Engineering, 2022, 49(4): 1580-1598.

论文:https://arxiv.org/pdf/2206.08574

摘要

深度学习(DL)技术已被用于支持多种与代码相关的任务,如代码摘要和错误修复。特别是,由于在自然语言处理(NLP)任务中取得了优异的结果,预训练的变压器模型正在兴起。这些模型背后的基本思想是首先在通用数据集上使用自监督任务(例如,填充句子中的掩蔽词)对它们进行预训练。然后,这些模型被微调以支持感兴趣的具体任务(例如,语言翻译)。一个单一模型可以微调以支持多个任务,可能利用迁移学习的优势。这意味着为了解决一个特定任务(例如,语言翻译)而获得的知识可能对提高另一个任务(例如,情感分类)的性能有所帮助。虽然迁移学习在NLP中的益处已被广泛研究,但在代码相关任务方面,有限的实证证据可用。在本文中,我们评估了文本到文本传输转换器(T5)模型在支持四个不同代码相关任务方面的性能:(i)自动错误修复,(ii)代码变异体的注入,(iii)断言语句的生成,以及(iv)代码摘要。我们特别关注研究预训练和多任务微调对模型性能的影响。我们展示了(i)T5可以取得比现有最新基线更好的性能;以及(ii)虽然预训练有助于模型,但并非所有任务都能从多任务微调中受益。

1 引言

研究人员利用深度学习(DL)技术自动化了许多与代码相关的任务。这些研究大多定制了自然语言处理(NLP)领域提出的DL模型,以支持代码相关任务,并且大多数研究有一个共同特点:它们将当前的问题形成为文本到文本的转换,其中模型的输入和输出都是文本字符串。输入和输出都表示为一串标记(即文本格式),输入是提交审查的代码,输出是实施了可能在代码审查过程中要求的更改的修订代码。类似的方法适用于自动化错误修复、学习通用代码更改、支持代码迁移、代码摘要、代码审查、伪代码生成、代码反混淆、代码变异注入、生成断言语句、克隆检测、可追溯性和代码补全。

近年来,迁移学习在自然语言处理领域崛起。其基本思想是首先使用自监督任务在一个大型通用数据集上预训练模型,例如,遮蔽字符串中的标记并让模型猜测被遮蔽的标记。然后,在较小且专门的数据集上对训练好的模型进行微调,每个数据集都针对特定任务。在这种背景下,Raffel等人提出了T5(文本到文本的转换Transformer)模型,该模型在大型自然语言语料库上进行预训练,并微调以在许多任务上实现最先进的性能,这些任务都以文本到文本的转换为特征。

在我们最近的工作中,我们通过实证研究了T5模型在预训练和微调以支持四个同样以文本到文本转换为特征的代码相关任务时的潜力。具体来说,我们首先使用包含499,618个英文句子和1,569,889个源代码组件(即Java方法)的大型数据集预训练了T5模型。然后,我们使用先前工作中的四个数据集对模型进行了微调,旨在支持四个代码相关任务:

自动化错误修复。我们使用了Tufano等人提供的数据集,其中“输入字符串”表示一个有缺陷的Java方法,“输出字符串”是相同方法的修复版本。代码变异注入。这个数据集同样由Tufano等人提供,其特征是输入输出字符串与自动化错误修复相反(即输入是一个修复后的方法,而输出是其有缺陷的版本)。模型必须学习如何在代码中注入错误(变异)而不是修复错误。在测试方法中生成断言语句。我们使用了Watson等人提供的数据集,其中“输入字符串”是一个没有断言语句的测试方法及其测试的焦点方法(即主要的生产方法),而“输出字符串”是为输入测试方法生成的适当断言语句。代码摘要。我们使用了Haque等人提供的数据集,其中输入字符串是一些Java方法的表示形式,输出字符串是文本摘要。

我们在所有四个任务上对单个预训练的T5模型进行了多任务设置的微调,并显示它在所有任务上都比四个基准模型取得了更好的结果。然而,由于我们只在多任务设置中对预训练模型进行了实验,迁移学习所带来的实际优势问题仍未得到解答。在这项工作中,我们旨在克服这种限制,这在使用现成预训练模型(如T5)来支持代码相关任务的其他许多研究中也是典型的。实际上,关于迁移学习在处理代码相关任务时带来的实际好处(如果有的话)的理解还很少。这种观察适用于(i)预训练阶段,它应该为模型提供与任务核心相关的语言(例如Java)的一般知识(例如错误修复);以及(ii)多任务微调,它应该允许模型利用在为特定任务(例如错误修复)训练时获得的知识来自动化其他任务(例如生成断言语句),从而可能提高所有任务的整体性能。除了对性能预期的积极影响外,预训练和多任务微调在训练数据稀缺的实际场景中也很有用(例如,当需要手动标记实例时)。在无监督设置中预训练模型和/或在其他相关任务上微调它,对于那些训练数据稀缺的任务也可能解锁使用深度学习模型的可能性。

我们的研究包括了以下任务:(i) 转换输入代码以改变其行为(错误修复和变异注入);(ii) “理解代码”以验证其行为(断言生成);以及 (iii) “理解代码”以用自然语言总结它(代码摘要)。此外,遵循前人研究中的原始数据集,这四个任务涉及抽象的源代码(错误修复、变异注入和断言生成)、原始源代码(断言生成和代码摘要)以及自然语言(代码摘要)。这种任务的混合有助于提高我们研究发现的普遍性。

我们还对数据集进行了新的分析,旨在通过查看训练集和测试集之间的数据窥探水平来评估模型的泛化能力。结果证实,T5模型可以显著提升所有四个代码相关任务的性能。

2 方法

我们使用了最简单的T5模型,将其作为实验对象,对其进行预训练与微调。

2.1 预处理阶段方法

在预训练阶段,我们使用了与Raffel等人类似的自监督任务,即对自然语言句子中的标记进行掩码处理,并要求模型猜测被掩码的标记。然而,我们并未仅使用自然语言句子进行预训练,因为我们针对的所有任务都涉及源代码。为了获得预训练数据集,我们使用了CodeSearchNet数据集,一个由自然语言(即代码注释)和源代码组成的数据集,该数据集提供了来自开源代码的600万个函数。因为我们支持的四个任务都与Java代码相关,我们只关注其中用Java编写的大约150万个方法,并且在方法级粒度上工作。

接下来,由于我们支持的四个任务中的三个(即自动错误修复、断言生成和代码变异注入)的原始论文作者使用了抽象版本的源代码,我们使用Tufano的src2abs工具来创建每个挖掘到的Java方法的抽象版本。在抽象过程中,特殊标记用于表示输入方法的标识符和字面量。基本上,抽象方法由语言关键词(例如,for,if)、分隔符(例如,“(”,“;”,“}”)和表示标识符及字面量的特殊标记组成。在抽象过程中,会移除注释和注解。请注意,由于工具是在Java方法的隔离状态下运行的(即未提供其所属项目的全部代码),在约150万个方法中,src2abs在约60万个方法上引发了解析错误(例如,由于缺少引用),最后我们剩下约90万个抽象方法。

我们使用CodeSearchNet数据集中的docstring_tokens字段提取了相关文档,获得了499,618个所考虑的方法。我们将这些句子添加到预训练数据集中。整个过程产生了总共2,984,627个预训练实例,包括原始源代码方法、抽象方法和代码注释句子。在获得的数据集中可能存在重复:(i) 不同的原始方法在抽象后变得相同,(ii) 不同方法之间复用的注释。因此,我们去除了重复项,最终得到2,672,423个实例,如表1所示。这是我们用于预训练T5模型的数据集,使用了Raffel等人在其实验中使用的BERT风格目标函数,随机掩码15%的标记(即注释中的单词和原始及抽象代码中的代码标记)。

最后,由于我们在特定软件数据集上对模型进行预训练和微调,我们创建了一个新的SentencePiece模型(即用于神经文本处理的分词器),通过在整个预训练数据集上进行训练,使T5模型能够正确处理Java语言及其抽象。该模型实现了子词单元(例如,字节对编码BPE)和单字语言模型,以缓解神经机器翻译中的开放词汇问题。

2.2 微调阶段方法

在微调阶段,我们分别对数据集与模型进行了微调。

2.2.1 数据集微调

其中,在数据集微调的过程中,我们使用了不同的方法完成对以下四个任务的微调:

自动错误修复:我们使用了Tufano等人的数据集,该数据集由三元组组成,其中和分别是Java方法的有错误和修复版本的抽象版本,M表示抽象标记与原始代码标记之间的映射,该映射允许追踪模型输出到源代码。我们训练模型在给定错误版本的情况下预测修复版本。由于存在两个数据集,我们将BF任务分为两个子任务,和,具体使用哪个取决于所涉及方法的大小。

代码变异注入:我们利用了Tufano等人提供的两个数据集之一:和。在这两个数据集中,每个实例都由三元组表示,类似于BF数据集,和分别是代码片段的错误和修复版本,M表示抽象标记与代码标记之间的映射。第一个数据集表示最一般(也是最具挑战性)的情况,其中变异版本可以包含输入版本中未包含的新标记。则只包含变异版本包含非变异代码中的标记子集的样本。

测试方法中的断言生成:我们使用了Watson等人提供的数据集,包含三元组,其中T是给定的测试用例,是T测试的焦点方法,即在断言之前T中调用的最后一个方法,A是必须生成的断言(输出)。

代码摘要:我们利用了Haque等人提供的数据集,包含2149120个实例,每个实例由四元组表示,其中S表示方法的原始源代码,是其AST表示,是同一文件中其他方法的代码,D是方法的摘要,即模型应生成的文本描述。对于此特定任务,我们考虑了原始数据集的一个变体,使其与所执行的预训练更加一致。我们的数据集实例由四元组表示:我们训练模型在仅给定S的情况下预测D。

2.2.2 模型微调

由于我们用于微调的数据集大小各不相同,其中代码摘要的数据集规模远大于其他数据集。这可能导致模型在不同任务上的效果不平衡。在我们的情况下,模型可能在代码摘要方面非常有效,而在其他三个任务上效果较差。然而,正如Arivazhagan等人指出的那样,在训练多任务模型时,选择平衡策略没有“免费午餐”,每种策略都有其优缺点(例如,过度采样较少的代表性数据集会对最具代表性的任务性能产生负面影响)。因此,我们决定对两种策略进行实验。

在第一种策略中,我们在创建每个批次时遵循真实数据分布。换句话说,我们按训练数据集的大小比例,从任务中抽样实例,使得每个批次在训练期间包含的样本数量成比例。对于第二种策略,我们使用平衡采样策略训练一个多任务预训练模型。换句话说,我们向T5模型提供数据批次,每个任务的样本数量完全相同,这些样本在微调期间随机选择。

我们获得的结果证实了Arivazhagan等人的发现。特别是,当使用第一种训练采样策略(即比例采样)时,具有大规模训练数据集的任务(即AG abs、AG raw、CS)的性能有所提升。相反,当使用第二种策略(即平衡采样)时,训练数据集较小的任务性能有所提高,但其他三个任务的性能有所下降。不过,由于观察到的性能差异并不显著,而且每种策略都有其优缺点,我们决定在本文中讨论使用比例采样方案获得的结果,就像我们在中所做的那样。

3 实验评估

研究问题:在本文中,我们研究以下研究问题:

• RQ1: T5模型在支持代码相关任务时的表现如何?

在RQ1的背景下,我们还将探讨迁移学习对性能的影响:

RQ1.1:预训练对T5模型在代码相关任务上的性能有何影响?

RQ1.2:多任务学习对T5模型在代码相关任务上的性能有何影响?

• RQ2: T5与最先进基线模型相比的表现如何?

实验设置:该实验在一台配备2.3GHz 8核第9代Intel Core i9处理器和16GB RAM的笔记本电脑上进行,使用CPU运行深度学习模型。我们针对不同的光束搜索大小(K ∈ {1, 5, 10, 25, 50})进行了实验。对于每个K,我们报告每个任务所有实例的平均推理时间(以秒为单位)。此外,我们还报告了本研究中涉及的九种不同模型的训练时间(以小时为单位),即无预训练(四个模型,每个任务一个),预训练单任务(+4个模型),以及预训练多任务(一个模型,进行四个任务的预训练和微调)。训练时,我们使用Google Colab的2x2 TPU拓扑结构(8个核心),批次大小为128,序列长度(输入和目标)为512个标记。最后,我们讨论了由T5和基线生成的预测的定性示例,以便让读者更好地了解这些模型在支持四个与代码相关的任务方面的能力。

实现细节:我们对T5的不同变体进行了实验:(i) 无预训练(即每个任务各训练一个模型,未进行预训练);(ii) 预训练单任务(即每个任务各训练一个模型,进行了预训练);以及(iii) 预训练多任务(即一个模型同时进行四个任务的预训练和微调)。这些模型都在我们四个基线研究中提供的测试集上运行。一旦获得T5模型在四个任务相关测试集上的预测结果,我们就计算报告的评估指标。之后,我们引入了我们基线的论文中报告的指标:

1) Accuracy@K:度量模型预测序列与参考序列(即完美预测)相等的情况(即测试集中的实例)百分比。

2) BLEU得分(双语评估替代):衡量候选(预测)文本和参考(oracle)文本的相似程度。

3) ROUGE(面向召回的摘要评估):用于评估自动文本摘要和机器翻译技术的指标。

基线设置:本次分析中表现最好的模型输出被用于比较最佳T5模型与四个基线模型,采用报告的性能指标。此外,我们还使用前面描述的相同程序(即McNemar检验和OR效应量)对T5和基线模型的Accuracy@1进行了统计比较。我们还进行了互补性分析:我们定义T5(PP T5 d)和基线模型(PP BLd)在光束大小为K=1时生成的完美预测集。然后,对于每个任务和数据集,我们计算三个指标:Sharedd衡量在数据集d上两种方法共享的完美预测百分比,而OnlyT5 d和OnlyBLd分别衡量在数据集d上只有T5或基线生成完美预测的百分比。我们还进行了一项“推理时间”分析:我们计算了T5在给定输入上运行所需的时间。

3.1 Answer to RQ1(包括RQ1.1与RQ1.2)

表1展示了我们实验的不同T5模型变体所达到的性能。对于每个任务(例如,自动错误修复)和每个数据集(例如,BFsmall),报告了三种采用的训练策略(即,无预训练、单任务预训练和多任务预训练)的性能指标。为了便于阅读,我们只报告了BLEU-A分数,但其他BLEU分数(例如,BLEU-4)的结果可以被找到。

表1 T5 模型在各项任务中取得的总体结果

表2报告了我们使用McNemar检验进行的统计分析结果,以确定在使用不同训练策略时Accuracy@1方面是否存在统计差异。从Accuracy@1可以看到,没有一种训练策略在所有任务和数据集上都是最优的。具体来说:无预训练策略在自动错误修复的BFsmall数据集上表现更好;单任务预训练策略在自动错误修复的BFmedium数据集上表现更好,在生成断言语句的两个数据集上,以及在代码摘要任务上表现更好;最后,多任务预训练策略在代码突变注入任务上表现更好。总体而言,单任务预训练策略似乎是表现最好的策略。即使它不是某个特定任务/数据集的首选,它也是第二最佳的训练策略。

此外,通过查看表2,我们可以观察到:

1) 当单任务预训练是最佳策略时,其Accuracy@1的性能显著优于第二最佳策略(p-value < 0.001>,OR从1.13(对于CS)到3.39(AGraw)。这意味着使用这种策略获得完美预测的机会比使用第二选择时高出13%到339%。

2) 当单任务预训练不是最佳策略而是第二选择时,与多任务预训练相比,在MGident任务上Accuracy@1的差异不显著。唯一显著的差异是有利于在BFsmall上无预训练的策略,OR为0.77。

表2 McNemar 检验(辅助 p 值和 OR),仅将Accuracy@1的匹配视为正确预测

3.2 Answer to RQ2

图1 T5 模型与实验基线的性能对比

我们将T5模型在使用单任务预训练策略时取得的结果与每个任务的基线进行比较(见表3)。比较结果如图1所示,我们分类在四个任务上进行了对比。接下来,我们将分别介绍在这四个任务下的具体效果。

表3 各项任务的基线和评估指标

3.2.1 自动错误修复

如表4所示,T5模型在BFsmall数据集上实现了15%的完美预测,相比之下基线模型实现了9%,提高了6个百分点。而在最具挑战性的场景(即BFmedium),我们的模型比基线模型提高了8个百分点(11% vs 3%)。这些改进在统计上显著,具有2.39(BFsmall)和6.88(BFmedium)的优势比,表明使用T5比基线模型更有可能实现完美预测。值得注意的是,随着波束宽度的增加,T5和基线模型的性能变得更加接近,在K=25和K=50时,基线模型在BFsmall上表现更好。鉴于前面讨论的T5的优越性能,预期会看到T5更频繁地正确执行所需的AST操作。然而,有趣的是,基线模型未能学习某些特定类型的操作,而T5却成功实现了这些操作。尤其是在较不流行的操作(如插入操作)上,这些操作需要合成输入AST中不存在的新节点。在BFmedium中,基线模型从未应用前五名的AST插入操作中的四种(见表7)。类似的结果也适用于更新操作,而在错误修复主要需要删除现有AST节点时,两种模型的表现相似。

表4 McNemer 检验,考虑 T5 模型和基线在两种技术下的预测准确率

3.2.2 代码变异注入

从图1可以看出,使用T5生成变异代码比基线模型能够取得更准确的结果,Accuracy@1提高了12个百分点,增加了1,336个完美预测。平均BLEU分数也在基线模型已经取得的良好结果(即0.77)的基础上提高了约0.02。尽管BLEU分数的微小提升仍然表明生成解决方案质量的重大进步。同样,如表4所示,在Accuracy@1方面的差异在统计上显著,T5模型比基线方法更有可能生成正确的解决方案(OR=2.95)。

表5 T5 模型和基线生成的正确预测的重叠度量

与错误修复任务不同,对于代码变异的注入,完美预测的共享百分比(表5)略高(33%),但T5是唯一生成50.52%完美预测的模型,相比之下基线模型只生成了16.48%的完美预测。

表6 在数据集中注入突变体所需的前 20 种 AST 操作以及它们在 T5 和基线上的预测结果

类似于错误修复任务的情况,表6报告了在我们的数据集中正确注入变异所需的前20种AST级操作。需要注意的是,与错误修复任务观察到的情况不同,注入变异主要需要插入新的AST节点。我们观察到的趋势,如预期的那样,与错误修复任务的结果相反,因为任务相同但输入/输出相反。实际上,基线模型似乎能正确预测AST中最流行的插入操作,而几乎忽略了较为罕见的删除操作。相反,T5覆盖了所有前20种操作。

3.2.3 测试方法中的断言生成

如图1所示,在这个任务中,T5相比基线模型表现得更好。无论是使用代码抽象(AGabs)还是不使用代码抽象(AGraw),两者之间的差距都很大。使用抽象时,T5在K=1时的准确率为56%,而ATLAS的准确率为31%。当两种方法被要求生成多个断言语句时(即K=5, 10, 25, 50),性能差距在13到25个百分点之间。使用更具挑战性的未抽象数据集AGraw时,T5的表现甚至更好。在这种情况下,当T5被要求生成一个断言语句(K=1)时,其报告的准确率比基线模型高出51个百分点,而对于更大的K值,性能差距在51到53个百分点之间。McNemar检验确认了两种技术之间的巨大性能差距,OR值在6.19(AGabs)到43.12(AGraw)之间。

在重叠性方面,我们发现了与前面讨论的任务(变异注入)类似的趋势:在AGabs上,34.92%的完美预测是由两种方法共享的,而剩余的实例分布在仅由T5预测的(58.87%)和仅由基线模型预测的(6.21%)之间。在AGraw数据集上,重叠性要小得多,仅有9.56%的实例被两种方法正确预测,89.65%的实例仅由T5正确预测,而只有0.79%的实例仅由基线模型正确预测。

3.2.4 代码摘要

如图1所示,在这个任务中,与基线相比,T5的BLEU分数显著提高。当考虑平均BLEU(BLEU-A)时,改进约为5个百分点。另一方面,可以注意到,使用T5时获得的ROUGE-LCS分数低于基线(在F-measure分数上低约5个百分点)。因此,从这些指标来看,没有明确的优胜者,但T5至少似乎与基线相媲美。为了得到更容易解释的结果,我们比较了两种方法在生成完美预测方面的表现,尽管这种指标在原始论文中并未使用。这意味着计算一种技术生成的注释,这些注释与人类手动编写的完全相同。T5设法生成了12.02%的完美预测(10,929个实例),而基线技术只有3.4%(3,048个)(超过3倍)。与先前的结果一样,这项任务的大多数完美预测只能通过T5完成(93.79%)。少部分完美预测是共享的(4.79%),而只有少数实例可以通过基线预测(1.42%)。McNemar检验突出显示了Accuracy@1方面的统计显着性,OR值为35.56。

转述:何家伟

0 阅读:10

互联不一般哥

简介:感谢大家的关注