当前位置: 首页 > 科技观察

自动检索并修复Python代码bug,微软推出DeepDebug

时间:2023-03-19 21:34:42 科技观察

你还在为不断调试代码而烦恼吗?定位错误和修复程序是软件开发过程中的一项重要任务。在本文中,微软Cloud+AI部门的研究人员介绍了DeepDebug,这是一种使用大型预训练模型转换器进行自动调试的方法。首先,研究人员根据200,000个库中的函数训练了一个反向翻译模型。接下来,他们将注意力转向了可以运行测试的10,000个库,并为那些已通过测试的库中的所有函数创建了有缺陷的版本。这种丰富的调试信息,例如堆栈跟踪和打印语句,可用于微调已在原始源代码上预训练的模型。最后,我们通过将上下文窗口扩展到buggy函数本身之外并添加一个由函数的父类、导入、签名、文档字符串、方法体组成的框架(按优先级顺序排列)来扩充所有模型。在QuixBugs基准测试中,研究人员将错误修复总数提高了50%以上,同时将误报率从35%降低到5%,并将超时时间从6小时减少到1分钟。根据微软自己的可执行测试基准,该模型在没有跟踪的情况下第一次修复了68%的错误,在添加跟踪后第一次尝试修复了75%的错误。为了评估可执行测试,作者接下来开源了框架和验证集。论文链接:https://arxiv.org/pdf/2105.09352.pdf简介自动程序修复的主要范例是“生成和验证”方法。研究人员遵循这种方法,假设一组可以识别错误存在的测试函数,然后定位错误并考虑候选修复,直到找到一个满足测试的。在整个实验过程中,研究人员使用合成错误,其错误已定位到单个错误方法,将其作为其他上下文的输入(例如函数文件中的上下文和暴露错误函数的堆栈跟踪),并将该输入组合提供给尝试生成固定函数的序列到序列转换器。研究人员还尝试使用堆栈跟踪来定位其部署场景中的错误。目前,研究人员基于开发人员自己的代码行的堆栈跟踪应用简单的启发式方法,因为最近调用的代码行最可疑。将来,作者也有兴趣使用编码器变换器改进启发式,编码器变换器可以为给定的堆栈跟踪重新排序方法。如下图所示,研究人员利用广泛预训练的转换器,使用了与微调PyMT5相同的DeepDev-py序列到序列模型。他们首先使用提交数据来训练基线错误修复模型和错误创建模型。bug-creator模型为DeepDebug(反向翻译)提供20倍的数据量。最后,研究人员通过使用可执行测试和生成的跟踪对函数中的神经错误模型进行微调,获得了最终的DeepDebug(跟踪)。培训管道。模型研究人员重新使用了具有4.06亿参数的序列到序列转换器,该转换器具有12个编码器层和12个解码器层。在使用堆栈跟踪进行实验时,他们为代码帧分配了1024个标记,为跟踪分配了多达896个标记,并且为了适应这个更大的上下文,转换器的位置嵌入矩阵也需要扩展。为此,研究人员使用受改革者启发的轴向嵌入,复制现有1024个位置嵌入中的前896个,生成随机轴向向量,并将此向量添加到所有896个重复嵌入中。在初步实验中,该方法优于随机初始化的嵌入。数据科学家使用四种不同的训练数据集:用于预训练的原始Python代码;提交用于训练神经错误创建和错误修补的数据;从原始代码中提取的方法,其中插入了神经错误以训练更强大的错误修复;通过可执行测试。对于最后一个数据集,研究人员还获得了每个测试执行的行列表,并通过重新插入合成错误并重新运行通过测试获得了另一个错误补丁数据集,允许他们分析堆栈跟踪、错误消息、小调整打印语句上的错误补丁。研究人员还尝试为bugfix模型提供一个“骨架”,其中包含有针对性的bug方法或整个文件,以便对函数签名等数据进行优先排序。预训练在DeepDevtransformer平台上,研究人员重用了来自FaceBook的BART模型热启动的4.06亿参数的DeepDevPythontransformer,然后使用Spanmasking目标对其进行了预训练。预训练数据包括200,000个五星级公共Python库,在DGX-2盒子上预训练了三周。DeepDev的令牌生成器附加空白令牌,例如四空格和八空格令牌,提高吞吐量和有效上下文长度。为了将泄漏的风险降到最低,研究人员总是将验证和测试库限制在同一范围内,尤其是CodeSearchNet中使用的库。提交数据研究人员遍历过滤到至少10星Python库的100,000个提交的历史,并进一步过滤所有在其消息中包含“修复”一词的提交,大约占所有提交的五分之一。根据对示例的检查,研究人员发现这个简单的过滤器似乎与使用“补丁错误”或“修复错误”等短语的限制性过滤器一样准确。但是,数据仍然很嘈杂。Commit数据使研究人员可以做两件事:首先,它可以让他们训练一个偏向于建设性的、bug修复的编辑模型,让研究人员可以直接在bug修复上评估这样的模型,或者进一步过滤就可以了-调整了图层的错误数据。其次,研究人员可以反转输入和输出,并训练偏向于破坏性、引发错误的编辑模型。研究人员可以使用这个模型来创建神经错误,从而大大增加训练数据。这种反向翻译方法已被证明在NLP中很有用。合成错误由于研究人员对通过合成错误进行数据扩充感兴趣,因此使用了GitHub上的大量无错误代码。与仅使用从错误修复提交中提取的函数相比,这样做有可能将目标方法的数据集扩展20倍。此外,研究人员通过为每种方法创建多个错误版本来任意扩大规模。在本文中,他们将规模限制为来自10,000个库的130万个函数(几乎等于提交数据),并通过反向翻译扩展到1800万个错误修复。研究人员在模型注入中观察到以下类型的错误:将点访问器替换为方括号访问器;链接函数调用被截断;删除返回线;将返回值包装在元组和字典等对象中,然后忘记包装对象;用ValueError等不同的错误替换IndexError等确切的错误;错误命名变量,如self.result而不是self._result;错误地按引用而不是按值进行复制。研究人员应用了之前文献中报道的几乎所有启发式错误。术语“启发式错误”用于指代使用简单规则手动创建的合成错误,例如删除一行或在函数调用中交换两个参数,替换二元运算符(使用!=而不是==),使用错误变量,忘记“自我”。存取器或删除代码。术语“神经错误”用于指代使用神经编辑模型创建的合成错误,例如那些经过训练可以将错误修复恢复到已提交错误的错误。使用神经错误的数据扩充具有许多吸引人的特性。灵活的神经模型几乎可以从开发人员实际犯错的分布中任意生成编辑。例如,神经编辑模型可以将get_key与get_value交换,而简单的启发式可能会进行随机交换,例如从get_key切换到reverse_list。此外,这种方法几乎与语言无关,因为研究人员可以重用框架来挖掘提交,只需要一个解析器来提取类和方法,以及组成代码框架所需的部分。上表显示了在测试集中训练两个transformer时使用的交叉熵损失,一个用于提交数据,一个用于反向提交。两种模型都在使用和不使用代码框架的情况下进行前向和后向编辑评估。由于编辑任务相对容易,交叉熵损失比通常报告的生成Python代码的性能提高了五倍。此外,反向编辑的损失比正向编辑低三分之一。正向模型在正向编辑方面比反向模型好6%,反向模型在反向编辑方面好6%。与仅聚焦相比,使用该框架的两种模型的性能均优于2%。如上所示,错误创建模型将kwargs.pop替换为kwargs.get,将.startwith(self.name)替换为==self.name,并删除了break。可执行测试的方法事实上,有很多机会调试实际执行的代码,特别是如果有伴随测试来验证正确执行。典型的调试会话包括借助堆栈跟踪查找可疑代码块、在近二进制搜索中插入打印语句和断点、修改和执行代码片段、在StackOverflow中搜索错误消息的解释以及API使用示例。相比之下,baseline神经模型的机会主义较少,在每次写入令牌之前盯着一段代码几秒钟。由可执行测试启用的“构建和验证”方法可以有多种机会来提高性能。例如,在短Java方法领域,研究人员见证了top-20准确率是top-1准确率的三倍。尽管之前的工作表明这些编辑可能会过度拟合,但真正的随机编辑可确保进行足够的试验以通过测试集。研究人员主要使用三种方法:跟踪:除了使用测试对不正确的编辑进行分类外,来自测试的信息还以三种不同的方式集成到训练中:错误消息附加到错误方法,另外附加堆栈跟踪,并进一步使用测试框架Pytest在故障时提供所有局部变量值;收集通过测试方法:以训练规模收集可执行测试,从200,000个库开始进行预训练,过滤到35k个包含测试和setup.py或requirements.txt文件的库。对于这些库中的每一个,在一个独特的容器中执行Pytest,并最终从10,000个库中收集通过的测试;合成错误测试方法:过滤掉通过可执行测试的函数并插入神经错误后,重新运行测试以收集pytest跟踪并过滤掉仍然通过测试的已编辑函数,因此实际上不是错误。实验和结果研究人员对训练反向翻译数据、添加框架、添加Pytest堆栈跟踪进行了实验,得到了以下结果。反向翻译数据在第一个实验中,研究人员将前向提交数据的训练与反向翻译产生的合成错误进行了比较,并使用交叉熵对保留数据进行了评估。如下表所示,与正向提交数据相比,DeepDebug(反向翻译)的损失减少了10%。令人惊讶的是,反向翻译模型实际上在反向提交数据上表现更差。总的来说,DeepDebug比以前的技术要强大得多。QuixBugs挑战是40种经典算法的基准测试,这些算法具有小的合成错误以及几乎相同的Python和Java版本。最初的QuixBugs挑战要求开发人员在一分钟内修复尽可能多的错误。下表报告了模型挑战QuixBugs的结果。研究人员通过随机抽样限制模型生成100个补丁,这大约是在一分钟内可以生成和评估的数量。这随后将现有错误数量增加了50%以上,同时将误报率从35%降低到5%。值得注意的是,由于这项任务的复杂度较低,所有模型都产生了很多重复编辑,表明采样方面仍有改进的空间。考虑到先前模型的超时以及提供的附加信息,这些结果更加令人印象深刻。例如,CoCoNuT被明确告知哪一行包含错误,并允许六小时找到补丁;五个非神经工具为最长递增子序列算法找到了122个补丁,并进行了数千次尝试。添加帧在第二个实验中,研究人员比较了仅使用焦点函数作为输入和使用整个帧作为输入的训练和评估。如下表所示,在对神经错误进行评估时,使用该框架时神经错误补丁损失减少了25%。事实上,在提交数据上使用框架时,神经错误补丁的性能更差,因为提交通常会编辑多个函数。Pytest堆栈跟踪在第三个实验中,研究人员将Pytest堆栈跟踪附加到错误输入,使用轴向嵌入来扩展上下文窗口以容纳额外的标记。在计划开源的验证集中筛选了100个库中的523个神经错误的基准。他们观察到令人印象深刻的性能,与交叉熵结果形成对比,使用迹线极大地提高了性能。如下表所示,DeepDebug(反向翻译)top10patch成功率为90%,而DeepDebug(tracing)top10patch成功率为97%。