分享一篇来自ASE' 20的文章,题目为Evaluating Representation Learning of Code Changes for Predicting Patch Correctness in Program Repair。实验相关代码和数据已开源:https://github.com/TruX-DTF/DL4PatchCorrectness。
在程序缺陷自动修复领域,Weimer等人认为,“如果一个打了补丁的程序能够通过测试套件中的所有测试用例,则认为该补丁是可接受的”[1]。然而,自动生成的代码补丁可能存在过拟合的问题,即:一个给定的补丁被合成以通过测试套件,但相对于预期的程序规范是不正确的。换句话说,由于有限的测试套件只能很弱地近似程序规范,所以打了补丁的程序虽然可以满足测试用例中编码的要求,并呈现出那些测试之外的行为,但这些行为与开发人员最初预期的行为有很大不同。因此,APR(Automated Program Repair)中的一个挑战是对补丁过拟合的验证。
目前针对补丁正确性识别的state-of-art工作主要是基于计算测试用例执行轨迹的相似性来实现的。Ye等人[2]的研究表明,在语法级别静态提取的代码特征可以用于预测过拟合补丁。然而,当把可推广(我理解可能就是扩展性很强的项目吧?)的方法当做目标时,这种方法的特征工程工作量会很大。为此,Csuvik等人[3]提出了一种基于预训练自然语言句子嵌入模型的方法,能够在QuixBugs数据集[4](划重点,数据集!!!)中过滤掉为40个bug生成的45%的错误补丁。
**本文的研究工作为:**研究了利用深度表示学习的进步来产生适合正确性推理的嵌入的可行性,具体如下:
(1)研究了适用于自然语言标记和更专门用于代码更改的源代码标记的不同表示学习模型,考虑了预训练模型和模型的再训练;
(2)实证了通过学习表示,正确补丁引起的最小变化的假设是否仍然有效:进行实验来检查正确补丁和不正确补丁产生的相似性得分之间的统计差异;
(3)进行了探索性实验,评估在错误代码和修补代码片段的学习表示之间选择临界相似性分数的可能性,以启发式地过滤出不正确的补丁;
(4)研究了深度学习特征在分类训练管道中的判别能力,该分类训练管道旨在学习预测补丁正确性。
本文主要研究如下3个问题:
RQ1:不同的表示学习模型是否会在错误代码和补丁代码之间产生相似性值的可比较分布?
RQ2:相似性分布可以推广到什么程度以推断出一个截止值来过滤掉不正确的补丁?
RQ3:能否通过代码嵌入输入训练分类器来预测补丁正确性?
本文所用数据集如下:
对于图1所示的样本,需要将其分别转换成图2和图3所示的缺陷代码和补丁代码。同时,由于表示学习模型,如:BERT、Doc2Vec和CC2Vec,要求每个输入样本都在一行上,因此需要将多行代码片段扁平化(这个词用得妙呀)为一行。
本文选择BERT、Doc2Vec、Code2Vec和CC2Vec分别作为嵌入模型,进行了如图4和图5所示的bug代码和补丁代码嵌入流程。其中,BERT(Scenario 1: 用文本数据训练文本表示模型)是在维基百科语料库上预训练的24层模型,Doc2Vec是在包含36364个补丁代码的数据集上基于Doc2Vec(Scenario 2: 用代码数据训练文本表示模型)训练的模型,Code2Vec(Scenario 3: 用代码数据训练的代码表示模型)是在约1400万个Java代码实例上训练的模型,CC2Vec(Scenario 4: 用代码变更数据集训练的代码表示模型)是基于代码变更数据预训练的模型。
这篇文章的实验部分标题和格式很新奇呀,是我从未接触过的船新版本。
回归正题,本文研究了
(1)不同的学习嵌入捕获代码片段之间相似性/不相似性的能力,旨在回答
RQ-1.1:正确的代码实际上类似于基于学习嵌入的错误代码?
RQ-1.2:有bug的代码在多大程度上更类似于正确打补丁的代码,而不是错误打补丁的代码?
实验1:使用上述4种嵌入模型生成了与表2所示的五个基准测试中的36k个补丁相关的有bug和修补过的代码片段的嵌入。需要注意,修补的代码片段表示正确的代码,因为它们来自标记的基准测试数据(通常指开发人员修复的补丁)。给定嵌入向量(即代码表示向量),计算表示错误代码片段的向量和表示修补代码片段的向量之间的余弦相似度。
实验2:将带有正确补丁的数据集与带有错误补丁的数据集相结合,依赖于Liu等人发布的数据集[5]:从这个数据集中考虑了由16个修复工具为184个Defects4J错误生成的674个合理但不正确的补丁。这674个不正确的补丁是从一个更大的不正确补丁集中选择出来的,方法是通过添加一个约束,即:不正确的补丁应该更改与基准测试中开发人员提供的补丁相同的代码位置。这种不正确的补丁案例可能确实是最难以用启发式方法识别的。
在每个实验的最后对RQ进行回答,这种方式爱了!
Answer to RQ-1.1:错误和正确代码片段的学习表示表现出高余弦相似性分数,预训练的BERT自然语言模型比专门用于代码更改的CC2Vec模型捕获更多的相似性变化。
Answer to RQ-1.2:使用BERT、CC2Vec和Doc2Vec的代码片段的学习表示产生相似性分数,在给定错误代码的情况下,该分数在正确代码和不正确代码之间有很大不同。这一结果表明,相似性分数可以用来区分正确的补丁和不正确的补丁。
(2)基于相似性阈值过滤不正确的补丁
考虑来自上述实验的相似性分数的分布,使用例如第一个四分位数值作为推断的阈值。
Answer to RQ2:基于余弦相似性分数,代码片段嵌入可以帮助过滤掉31.5%的CC2Vec和94.9%的BERT中的不正确补丁。虽然BERT实现了过滤不正确补丁的最高召回率,但它产生的嵌入导致识别正确补丁的较低召回率(5.5%)。
(3)基于有监督学习的正确补丁分类
遵循Hoang等人[6]的方法:当补丁代码片段和错误代码片段的特征交叉在一起时,分类模型表现最佳。因此,作者在本文中提出了一种如图9所示的分类模型,使用减法、乘法、余弦相似性和欧几里德相似性来捕获错误代码向量和修补代码向量之间的交叉特征,从而完成给定补丁的特征提取。
Answer to RQ-3.1:基于BERT嵌入的逻辑回归模型在补丁正确性预测上产生非常有希望的性能。Answer to RQ-3.2:基于表征学习的机器学习预测器比依赖于动态信息的最新PATCH-SIM方法表现稍差。另一方面,深层代码表示似乎是对为ODS[2]设计的手工特性的补充。
这篇文章所做的工作其实概括为:向量余弦相似性,基于阈值的过滤,嵌入模型,深度学习特征与代码静态特征互补。
参考文献
[1] Weimer W, Nguyen T V, Le Goues C, et al. Automatically finding patches using genetic programming[C]//2009 IEEE 31st International Conference on Software Engineering. IEEE, 2009: 364-374.
[2] Ye H, Gu J, Martinez M, et al. Automated classification of overfitting patches with statically extracted code features[J]. IEEE Transactions on Software Engineering, 2021, 48(8): 2920-2938.
[3] Csuvik V, Horváth D, Horváth F, et al. Utilizing source code embeddings to identify correct patches[C]//2020 IEEE 2nd International Workshop on Intelligent Bug Fixing (IBF). IEEE, 2020: 18-25.
[4] Ye H, Martinez M, Durieux T, et al. A comprehensive study of automatic program repair on the QuixBugs benchmark[J]. Journal of Systems and Software, 2021, 171: 110825.
[5] Liu K, Wang S, Koyuncu A, et al. On the efficiency of test suite based program repair: A systematic assessment of 16 automated repair systems for java programs[C]//Proceedings of the ACM/IEEE 42nd International Conference on Software Engineering. 2020: 615-627.
[6] Hoang T, Kang H J, Lo D, et al. CC2Vec: Distributed representations of code changes[C]//Proceedings of the ACM/IEEE 42nd International Conference on Software Engineering. 2020: 518-529.