使用BERT快速基于变更集的Bug定位

互联不一般哥 2024-04-11 00:57:05

Fast Changeset-based Bug Localization with BERT

Agnieszka Ciborowska, Kostadin Damevski

Virginia Commonwealth University

Department of Computer Science

Richmond, VA, USA

引用

Ciborowska A , Damevski K .Fast Changeset-based Bug Localization with BERT[J]. 2021.DOI:10.48550/arXiv.2112.14169.

论文:http://arxiv.org/pdf/2112.14169v2.pdf

摘要

本研究描述了如何使BERT变得足够快,从而适用于基于变更集的bug本地化。我们还探讨了为此目的使用BERT时的几个设计决策,包括如何最好地对变更集进行编码,以及如何将错误报告与单个变更相匹配以提高准确性。我们将模型的准确性和性能与非上下文基线和以前在软件工程中使用的基于bert的体系结构进行比较。我们的评估结果证明了与基线相比,使用提议的BERT模型的优势,特别是对于缺乏任何相关代码元素提示的bug报告。

1 引言

本文将BERT应用于基于变更集的错误定位问题,目标是提高检索质量,特别是在直接文本相似度不够的错误报告中。我们描述了一种利用BERT而不影响检索速度和响应时间的IR体系结构。此外,我们还研究了一些设计决策,这些决策有助于利用类似bert的模型进行bug定位,包括如何最好地编码变更集及其独特的结构。

我们的实验结果表明,所提出的方法在流行的错误定位技术的基础上得到了改进,例如,对于没有或有限数量的定位提示的错误报告,检索准确率提高了5.5%至20.6%。我们注意到,使用整个变更集作为输入粒度会极大地阻碍模型的性能,而利用更细粒度的输入数据,比如大块,会产生最高的检索质量。我们还观察到,搜索空间的大小(即项目中变更集的数量)显着影响不同基于bert的模型的检索延迟,尽管在所提出的模型中影响较小。

本文的主要贡献有:

1. 将BERT应用于bug定位问题的方法(具体地说,是定位引起bug的变更集),它比最先进的方法更准确

2. 改进了其他最近提出的针对变更集检索的基于BERT的体系结构,在检索速度方面显示出显著的优势

3. 在将BERT应用于变更集时对关键设计选择的评估和建议(例如,代码更改编码,数据粒度)。

本文提出的基于bert的技术可以对软件工件(特别是变更集)进行语义检索,以进行错误定位,这超出了(并且可以补充)当前流行的最先进技术中的精确术语匹配。相对于最近类似的基于bert的技术,我们提供了一种显著提高检索速度的方法,以一种支持现实世界使用的方式,同时也提高了检索质量。

2 技术介绍

2.1 BERT用于bug定位

BERT的体系结构由多层转换编码器组成,这是一种抽象,旨在利用自关注对序列数据建模;注意的概念是对序列中的特定术语进行不同的加权,即,从序列中的每个术语到剩余的语义上最相关的术语之间编码更强的关系。正如Mills等所指出的那样,通过智能查询构建,即通过仔细选择bug报告的哪些部分用于比较,可以显著改进bug定位的检索技术。因此,利用使用注意力来强调某些单词关系的模型有可能显著改进先前最先进的bug定位技术。

使用BERT模型进行缺陷定位(或其他类似目的)包括三个基本步骤:(1)使用大量通用软件工程相关数据对模型进行预训练,(2)微调BERT模型以进行缺陷定位,最后,在BERT被完全训练之后,(3)为新报告的缺陷检索相关的引起缺陷的更改集。

在最简单的变更集检索场景中,如图1a所示,每个新到达的bug报告都与项目历史中的每个变更集相关联。然后,对它们进行BERT处理,生成嵌入矩阵,通过聚合层将其转换为向量。最后,向量被传递到一个分类层,该层在bug报告和变更集之间产生相关性评分。更改集根据它们的分数排序,以产生排序的结果集。这种用于信息检索的BERT架构通常被称为单BERT。在另一种检索架构中,称为Siamese BERT,如图1b所示,bug报告和变更集是分开处理的,首先通过BERT,然后通过聚合层。结果,bug报告和变更集被转换成独立的向量,这些向量随后被连接并馈送到分类层,以产生相关性评分。Siamese BERT相对于Single BERT的优势在于Siamese BERT支持离线预计算变更集表示,因为不需要将变更集与bug报告连接起来以便检索。然而,Siamese BERT仍然需要将bug报告与每个变更集进行比较,这在大量变更集的情况下会导致显著的检索延迟。

图1:用于变更集检索的基于bert的体系结构

2.2 快速Bug定位BERT

基于Khattab等人的ColBERT的FBL-BERT架构避免了嵌入矩阵的聚合,而是通过利用整个矩阵来构建相关性评分,从而实现更完整、更细粒度的比较。更具体地说,bug报告br和变更集c分别由BERT处理,分别创建嵌入矩阵br和c。为了计算br与c之间的相关性分数,对于bug报告vbr∈br中的每个词嵌入,我们找到变更集vc∈c的词嵌入之间的最大余弦相似度,并通过求和将最大余弦相似度组合起来,如图1c所示。

因此,模型学习如何将bug报告中的单词与变更集中的令牌关联起来,并考虑到它们出现的上下文。考虑到我们处理的两种不同类型的数据,即bug报告和变更集,我们通过增加BERT编码器层的数量来修改ColBERT。更具体地说,虽然ColBERT使用最后一个BERT编码器的输出,但我们采用最后4个编码器的输出。这种修改是由于先前的研究观察到不同的BERT层编码不同粒度的语义信息。请注意,FBL-BERT中的线性层并不等同于前面讨论的聚合层,而是用于减少BERT产生的词嵌入的大小,以压缩形式保留所有词嵌入,以便更快地进行下游处理。

为了阐明FBL-BERT是如何操作基于变更集的错误定位的,请考虑图2所示的管道。首先,如图2的模型训练部分所示,FBL-BERT模型在由bug报告和bug诱导变更集组成的项目特定数据集上进行了微调。在下一步(离线索引)中,项目存储库中的所有变更集都通过FBL-BERT进行编码,并存储在支持高效向量相似性搜索的索引中。为此,我们使用了在Faiss库中实现的IVFPQ(倒置文件与产品量化)索引。IVFPQ索引使用k-means算法将嵌入空间划分为< 0.05(例如,< 0.05 = 300)个分区,并随后将每个词嵌入分配给其最近的聚类。为了方便高效的搜索,在发出查询时,首先将查询与分区的质心进行比较,以找到最近的分区,然后仅在这些分区中继续搜索到实例级。注意Faiss索引包含所有变更集中的词嵌入。完成此步骤后,检索系统就可以部署了。

图2:FBL-BERT用于基于变更集的bug本地化管道。

当一个新的bug报告到达时,它首先通过FBL-BERT编码,产生一个嵌入矩阵。接下来,对于嵌入矩阵中的每个词嵌入,我们查询Faiss索引来识别存储在所有变更集嵌入中的最相似的嵌入在Faiss指数中。由于在大多数相似的嵌入中,有些可能指向相同的变更集,因此最后我们得到了全部的唯一的候选变更集。最后,我们使用FBL-BERT对候选变更集重新排序并生成最终排名。

2.3 变更集编码策略

随着时间的推移,软件的发展被记录在存储库中,作为更改集的时间顺序序列。每个变更集包括一条日志消息(提供解释修改目标的简短基本原理)和一组源代码变更。根据软件项目中使用的版本控制系统和diff算法,源代码更改的表示可能会有所不同。在本文中,我们关注的是git diff命令的输出格式,其中添加的代码行用+注释,删除的代码行用-注释,所有修改的代码行都被3行上下文未修改的代码行包围。虽然存在更先进的基于树的代码差异算法(例如,GumTreeDiff),但向机器学习模型提供详细的代码更改信息可能会对模型产生负面影响,因此我们选择基于文本的方法。变更集可以封装跨一个或多个源代码文件的代码变更,并且对每个文件的修改可以分成大块——由未更改(上下文)行包围的修改(添加或删除)行组。鉴于这种特定的格式,我们从两个角度探索如何最好地利用变更集的属性来构建BERT输入:(1)编码代码修改的特征,例如添加或删除;(2)变更集中的粒度级。

提供给BERT模型的输入需要遵循一定的规则。首先,一个文档(例如,一个变更集或一个bug报告)需要被标记化,并且每个标记被其唯一的标记id替换。预训练的BERT模型提供自己的BERT标记器,这些标记器针对模型预训练的语料库进行优化。BERT标记器使用WordPiece算法进行训练。BERT标记器的主要优点是通过将未知单词划分为词汇表中存在的最大子词来避免词汇表外的单词,这在我们的设置中可能是有益的,因为软件项目可能具有非常具体的词汇表,在其他地方不太可能观察到。其次,BERT使用一组预定义的特殊令牌。一般来说,由于BERT的训练方式,该模型要求每个令牌序列以特殊分类令牌[CLS]开始,以分隔令牌[SEP]结束,而其他特殊令牌,如填充[PAD]在必要时使用。特殊标记可以传递有关数据结构的信息,从而允许BERT区分输入的各个部分,因此我们将探讨如何最好地利用特殊标记对更改集进行编码。为此,我们提出以下编码策略,如图3所示。

图3:变更集编码策略。

D:变更集被认为是提供给模型的单个文档。为了通知模型变更集序列开始了,我们在代码序列的开始处定义并预先附加了特殊的标记[D]。由于此策略不利用代码更改的特定特征,因此它可以作为与其他策略进行比较的基线。

ARC:在这种编码中,一个变更集被分成几行,这些行随后根据它们是否被添加、删除或提供上下文进行分组,正如它们的初始字符所示:

+表示添加,-表示删除,并为上下文行留出空白。每组中的行被连接以创建一个序列,我们在其上预先附加一个特殊的标记:[a]用于添加的行序列,[R]用于删除的行序列,[C]用于上下文行序列。最后,将所有序列连接在一起以创建模型的输入。通过分组不同的部分基于其特征的变更集,我们的目标是调查是否任何特定类型的修改比其他修改更有益。使用ARC策略,模型有机会学习如何组合不同类型的信息,如果有必要,如果它对性能有不良影响,则决定忽略其中的一部分。

ARCL:与ARC类似,一个变更集被分成几行,但是ARCL编码不会对这些行进行分组。相反,它保留了更改集中的行顺序,这样在修改类型发生变化的地方预先添加了特殊的标记[a], [R]或[C]。虽然与ARC相比,此策略可以获得更准确的数据表示,但对于模型来说,ARCL也更具挑战性,因为特殊令牌会在多个位置多次出现。

假设bug报告和变更集是分开编码的,那么模型必须区分这两种类型的文档。为此,在编码错误报告时,我们定义了一个特殊的令牌[Q],它预先附加到查询中,即错误报告。

选择如何最好地编码变更集的另一个方面与它们的粒度有关,即,使用整个变更集或将变更集分离为文件级或块级。利用块作为IR模型中的主要数据维度有几个优点。

首先,已经观察到的bug通常是由小段代码引起的,因此,与整个源代码文件相比,大块固有的细粒度使它们不太容易受到噪声的影响。其次,将变更集划分为块可以缓解因提交纠结而引起的问题。考虑到块通常很小并且集中在代码的封闭部分,BERT不受远程令牌依赖的影响,这是一个通常影响源代码的问题。最后,较短的输入文档不太可能超过BERT接受的最大序列长度,而较长的文档必须被截断,这可能会对结果产生负面影响。然而,尽管在变更集中很容易获得较小的数据粒度,但到目前为止,大多数努力都集中在利用整个变更集上。

3 实验评估

3.1 研究问题

RQ1:与(1)基于VSM的最先进技术和(2)相关的基于bert的架构相比,FBL-BERT的有效性如何?

使用FBL-BERT的主要机会是在检索引起错误的更改集时结合额外的上下文和语义,这应该提供比最新技术更高的准确性,特别是对于提供高级错误描述而缺乏显式本地化提示的错误报告。研究人员已经发现,相当数量的bug报告已经包含了本地化提示,也就是说,它们提到了与修复bug相关的类名或方法名,而最近的一些bug本地化方法认为,只有缺乏广泛本地化提示的bug报告才应该在评估中考虑。我们遵循Kochhar等提出的方法,根据bug报告提供的本地化提示的完整性将其分为3组,并分别对每个bug报告组的性能进行评估。我们还研究了利用细粒度匹配的FBL-BERT的运行时性能与其他依赖于嵌入聚合并跨整个搜索空间执行检索的基于bert的体系结构相比。作为基准,我们使用(1)Locus,这是一种基于VSM的最先进的方法,用于定位引起bug的变更集,以及(2)TBERT-Single和TBERT-Siamese方法,它们利用最近为软件工程提出的基于bert的聚合表示。

RQ2:哪种变更集编码策略是最有利可图的?使用大块、变更集文件或整个变更集作为主要数据维度有什么优势吗?

在这个RQ中,我们首先研究了关于变更集每行修改类型的编码信息是否可以提高FBL-BERT模型的性能。我们评估了编码变更集语义的两种选择,ARC, ARCL,以及忽略变更相关信息的基线方法D。其次,我们研究输入数据的粒度如何影响模型性能,以及在模型中利用变更集、变更集文件或块的好处和挑战是什么。为了回答这个RQ,我们分别针对每种编码策略和每种输入数据粒度对FBL-BERT进行微调,从而在每个软件项目中产生9个评估配置,测量模型在检索相关变更集方面的性能。

3.2 数据集和基线

为了回答研究问题,我们利用Wen等人收集并手动验证的bug数据集及其诱导变更集;手动验证的数据集消除了SZZ算法可能引入的错误,该算法将bug修复映射到诱导提交。该数据集包括6个软件项目,分别是AspectJ、JDT、PDE、SWT、Tomcat和ZXing(描述性统计如表1所示)。为了创建每个项目的训练集,我们选择项目中按bug开放日期排序的bug报告和bug诱导变更集的前一半作为训练集,剩下的一半作为测试集。对于训练集中的每一对,我们还通过随机选择一个不属于诱导更改集的代码更改来创建一个负样本,本质上形成bug报告,bug诱导更改集,非bug诱导更改集的三元组。我们通过选择一个语法相似的不会引起错误的更改集来选择负样本,但我们没有观察到检索准确性的显着变化。由于这种产生负样本的类型需要大量的计算成本来收集,因此我们选择使用随机抽样。最后,对于每个项目,我们得到了一个正反例数量相等的平衡训练集。请注意,尽管训练集不包括所有可用的代码更改,但在错误定位期间,模型会跨特定项目的所有可用代码更改执行检索。为了研究不同的变更集数据粒度对基于bert的模型的影响,我们为每种类型的粒度创建了一个单独的数据集,即变更集、变更集文件和块。为此,对于变更集-文件和块粒度,我们将引起错误的变更集划分为文件级别或块级别的代码更改,这样一个错误报告就会从其各自的引起更改集创建多个文件或块对。

表1:评估数据集中的项目。

我们将该模型的性能与Locus进行了比较,后者是一种利用块级的无监督模型粒度和VSM,根据bug报告、块和日志消息之间获得的最大相似度评分来定位相关的更改集。请注意,FBL-BERT不使用日志消息,因为我们的目标是探索从bug报告中的自然语言到代码更改的映射。虽然编写良好的日志消息可以通过提高某些更改集的分数来对结果产生积极的影响,但并不是所有相关的代码更改都伴随着高质量的日志。作为第二组基线,我们采用Lin等人最近提出的TBERT架构进行软件工件检索。在Lin等人研究的三种架构中,我们选择了TBERT-Single和TBERT-Siamese作为我们的基线,拒绝了TBERT-Twin,因为它在准确性和时间方面的性能明显超过了其他两种。一般来说,除了使用更高级的嵌入聚合操作符之外,这两种架构都与图1中所示的架构非常相似。

3.3 实验结果

RQ1:检索性能

检索精度。表2对比了FBL-BERT模型与三种不同类型bug报告的基线方法的检索性能:未本地化、部分本地化或完全本地化。如果一个bug报告没有提到相关的类,它被归类为未本地化(BRNL);当报告中出现一些相关类时,该bug被归类为部分本地化(BRPL);如果提供了所有相关类名,则bug报告是完全本地化的(BRFL)。请注意,在FBL-BERT的情况下,我们使用使用ARCL编码训练的模型的结果,因为平均而言,它在评估项目中提供了最佳性能。

表2:针对不同类型的bug报告,基于变更集的BL技术的平均互惠等级(MRR)。

检索时间。FBLBERT的关键特性之一是在大型语料库中执行有效的检索。这将允许它利用细粒度的数据,如变更集文件或块,它们被观察到提供最佳的检索准确性,同时保持合理的检索延迟。在图4中,我们将每个bug报告的平均检索时间与搜索空间中增加的文档数量进行比较,例如,变更集、变更集文件和块。一般而言,FBL-BERT检索相关文档的速度比两种TBERT模型都快,检索时间差距随着搜索空间的增大而增大。

图4:使用不同大小的搜索空间(TBERT-Single、TBERT-Siamese、FBL-BERT),每个bug报告的平均检索时间。

误差分析。为了更深入地了解对FBL-BERT检索准确性产生负面影响的因素,我们手动分析了模型最难以解决的错误报告。更具体地说,我们选择了所有在FBL-BERT中排名50或更低的bug报告。这使作者独立分析的20个bug报告,将检索到的数据块与真正会导致bug的数据块进行对比,从而设计出一组导致检索准确率较低的常见问题。作者还检查了检索到的和黄金集块中最相似的术语(及其权重),特别关注两者之间最大差异的来源。最后,作者讨论了他们独立的观察结果,并就三种常见的错误类别达成了一致:堆栈跟踪/代码片段、注释和代码令牌分割,其中单个错误报告可以属于多个错误类别。

RQ2:变更集编码策略

表3显示了使用不同的变更集编码策略和输入数据粒度训练和评估的FBL-BERT检索性能。对于每个项目,突出显示了三个性能最好的配置,例如深绿色标志着具有最高检索性能的配置,而绿色和黄色对应于第二和第三个最佳配置。总的来说,我们注意到,使用整个变更集作为输入的粒度,到目前为止,在所有评估项目的所有调查配置中,性能是最差的。我们可以将这一结果归因于:(1)由于BERT模型的输入长度限制,变更集被截断;(2)单个变更集中的复杂变更,这些变更可能会通过不相关的代码修改引入噪声来影响模型。另一方面,虽然基于块或变更集文件的模型并非没有这些问题,但更精细的数据粒度允许它部分地克服这些问题。例如,在复杂更改的情况下,将整个更改集划分为块或更改集文件将创建多个新的数据点,这限制了与错误不太相关的实例引入的噪声。在使用块和变更集文件作为输入数据之间,在所有度量中检索准确性的差异很小,每个项目的差异从1%到12.2%不等。这个结果表明,利用大块和变更集文件执行相似,并且对影响变更集的问题都具有弹性。

表3:不同配置FBL-BERT的检索性能。

转述:王凌杰

0 阅读:0

互联不一般哥

简介:感谢大家的关注