Large Language Models for Test-Free Fault Localization

基本信息

这是24年2月发表在ICSE `24会议(CCF A)的一篇文章,作者团队来自美国卡内基梅隆大学。

博客创建者

武松

作者

Aidan Z.H. Yang,Claire Le Goues,Ruben Martins,Vincent J. Hellendoorn

标签

软件错误定位、大语言模型、深度学习、神经网络模型

1 摘要

软件错误定位 (Fault Localization,FL) 旨在自动定位有错误的代码位置,这是许多手动和自动调试任务中的第一步。一般的 FL 技术需要提供测试用例,并且通常需要大量的程序分析、程序检测或数据预处理。近年来涌现出一些将大型语言模型 (Large Language Model,LLM)用于代码相关工作的方法,比如代码生成、代码总结等任务,LLM表现出强大的性能和泛化能力。受此启发,文章研究了 LLM 在语句级别(Statement-levelLine-level)进行错误定位的有效性。文章主要有以下几个贡献:

  • 第一种基于大语言模型的错误定位方法,可在没有任何测试信息的情况下定位有缺陷的代码行;
  • 第一种能够在语句级别检测代码安全风险的方法;
  • 发现错误定位能力随着LLM规模的变大而提高。

1.1 相关工作

  • SBFL:基于频域的错误定位(Spectrum-based FL),利用程序执行多个失败的测试用例的覆盖信息计算语句怀疑度,然后进行排名。某个语句在失败的测试中执行的频率越高,在通过的测试中执行的频率越低,该元素的可疑程度就越高。SBFL存在并列排名的情况,如下图中,if语句块中的代码行实际上不能被覆盖信息区分出差异,因此其怀疑度分数是相同的,而真正出错行第7行则无法被准确定位出来。
SBFL失效的例子
  • MBFL:基于变异的错误定位(Mutation-based FL),来源于软件测试中的变异测试。变异测试的思想是使用测试用例执行变异体,测试用例执行结果与源程序执行结果不同,则称该测试用例被该变异体杀死(killed)。被杀死变异体数量与变异体总数的比值为该测试用例的变异分数,变异分数越高,则说明该测试用例更有效。将变异测试用于软件错误定位,基于思想:错误语句容易通过某种简单的变异方式被修复,变异被修复的比例越大,则该语句为错误语句的概率越高。MBFL的局限性在于有的语句可能无法生成变异体,以及执行效率过低的问题(一个程序要为每个语句生成多个变异体,并且要为每个变异体执行多个测试用例,因此该方法定位一个程序的错误行的复杂度为 O ( n 3 ) O(n^3) O(n3))。

  • MLFL:基于机器学习的错误定位(Mechaine Learning-based FL)。早期的机器学习称为Learning-to-Rank的方法,都基于代码信息和代码测试信息训练机器学习模型并预测语句怀疑度,从而进行排名。最近的深度学习方法将这些信息进一步融合、编码和提取特征,并结合一些其他的模型(如GNN、CNN)提升特征提取的效果。

  • LLMs for code:近年的LLMs通常用于代码表征、代码合成等领域,但由于大模型输出的不确定性,以及无法直接用于错误定位(需要prompt),目前还少由工作将LLM用于错误定位。

2. 方法

2.1 方法架构图

方法架构图

2.2 方法描述

2.2.1 Left-to-right Language Models(即大模型)

如各种用于编程领域的代码生成语言大模型,其模型架构都是基于自回归的自左向右的生成模型,也即decoder-only的transformer结构网络模型。这种模型架构适用于生成任务,例如常见的代码生成模型,如下图所示:

代码生成语言模型示例

图a中给定一个具有代码上文的片段,以及功能注释,可以让语言模型据此生成接下来的内容。文章方法主要是利用代码生成大模型提取代码特征,由于代码大模型基于大规模代码数据集训练,其已经具备了较好的代码理解能力。因此文章没有对大模型进行微调,直接使用了现有的代码生成大模型: C o d e G e n CodeGen CodeGen,这是目前效果较好的一个代码大模型。

2.2.2 Bidirectional Adapter(双向注意力适配器)

作者认为Left-to-right的代码生成大模型只能与先前的代码进行交互(单向注意力),对代码行之间的语义考虑不够充分,效果不够好。因此在大模型之后增加了几层Transformer encoder层,以进行双向注意力计算,由此使得每个句子可以与前后的句子都能交互信息。整体训练步骤如下图所示:

细节执行流程
  • 首先输入代码文本被序列化为一串代码 t o k e n s tokens tokens,记为 C = [ c 0 , c 1 , . . . , c N ] C = [c0, c1, . . . , cN ] C=[c0c1...cN] 。将代码 t o k e n s tokens tokens输入一个因果预训练(causally pretrained,即left to right)的 Transformer 模型(LLM,CodeGen),以将它们转换为向量表示,这些向量表示的维度为 S ∈ R N × D S∈\mathbb{R}^{N×D} SRN×D ,其中 D D D 表示预训练模型的每一个隐层输出的维度(即 d m o d e l d_{model} dmodel )。
  • 进而用每一行代码末尾的换行符的向量代表该行代码,此时每一行的向量表示即为 S N L ∈ R M × D = S [ c i = \ n ] S_{NL}∈R^{M×D}=S[c_i=\verb|\| n] SNLRM×D=S[ci=\n] ,其中 M M M 表示原始代码中的换行符数量, M M M<< N N N。作者认为该换行符向量可以准确而合理地捕捉到前一句的信息。
  • 对于 CodeGen 模型,16B版本模型的隐层维度 D 的高达 6144。然而由于文章所加入的适配器层仅基于少量数据训练,适配器的维度d远小于D,文章所使用的 d d d 维度为 d ∈ { 256 , 512 , 1024 } d∈{\{}{256,512,1024}{\}} d{256,512,1024}。因此为了将CodeGen的维度与适配器对接,使用一个全连接层将二者连接起来。文章中形式化表述为:“将原来的 S N L S_{NL} SNL约简为 R N L ∈ R M × d = S N L W d R_{NL}∈\mathbb{R}^{M×d}=S_{NL}W_d RNLRM×d=SNLWd,其中 W d ∈ R D × d W_d∈\mathbb{R}^{D×d} WdRD×d 是一个可学习的权重,相当于一个全连接层”。
  • 由此训练获得的适配器最终获得每一行的向量表示 A N L ∈ R M × d A_{NL}∈\mathbb{R}^{M×d} ANLRM×d 。适配器使用两层Transformer encoder层。最终使用Sigmoid激活函数将每行的表示向量转换为犯错概率估计值。使用二值交叉熵计算该概率值和ground truth之间的损失,即 L C E = T l n B + ( 1 − T ) l n ( 1 − B ) \mathcal{L}_{CE}=T {\rm{ln}} B+(1-T){\rm{ln}}(1-B) LCE=TlnB+(1T)ln(1B)

3. 实验

3.1 数据集

  • Defects4J V1.2.0:一个 Java 基准数据集,其中包含来自 6 个 Java 项目的 395 个 bug 。对于大多数基准测试,使用 V1.2.0 而不是最新版本 (V2.0.0),以便与大多数先前的 FL 技术在同一数据集上进行比较。
  • Defects4J V2.0.0:一个 Java 基准数据集,与 Defects4J V1.2.0 [21] 相比存在其他错误。这个数据集是为了证明我们的方法可以推广到其他未参与训练的数据集上。
  • BugsInPy:一个 Python 基准测试,其中包含来自 17 个不同项目的 493 个错误。
  • Devign:一个来自两个开源项目的 5,260 个 C 语言的benchmark。最初的Devign数据集包含来自四个不同项目的15,512个安全漏洞。

所有数据集都包含与每个故障相对应的修复提交。遵循先前的方法,文章将错误语句识别为在与每次提交相关的 git diff 中更改的语句。

3.2 基准方法

  • DeepFL:通过简单的多层神经网络融合多种测试信息提取代码行的表征然后预测错误概率;
  • DeepRL4FL:通过CNN融合多种测试信息、代码执行信息和代码表示信息;
  • TRANSFER-FL:也是融合多种测试信息和语义信息然后MLP做分类,但引入了迁移学习的概念,构建开源代码数据集训练语义提取器,然后用于错误定位代码的语义信息提取;
  • SBFL(Ochiai)。

3.3 评价指标

  • Top-N:测量在前 N 个位置 (N=1, 3, 5) 内至少有一个故障单元的故障数量。
  • AUC面积(Area Under the ROC Curve,AUC):即ROC 曲线下的面积,用于测试模型的有效性。AUC 是介于 0 和 1 之间的数字,越接近1越好。

3.4 结果分析

3.4.1 对比实验

由于文章针对语句级别(statement-level)的错误定位,而DeepFL是方法级别(method-level)的,因此遵循先前方法,DeepFL选取只利用覆盖信息和变异信息的版本进行对比。对比实验仅在Defects4J V1.2.0数据集上开展,针对java语言。
文章没有对比MBFL方法,原因可能是因为有的代码行无法进行变异。

图3.1 对比实验结果

实验结果显示该方法超越了之前的所有深度学习方法,以及SBFL方法。

3.4.2 cross-project验证(对新的项目代码的泛化性)

前面的对比实验测试集和训练集数据来自同一数据集,其分布相同,采用项目内的交叉验证。而cross-project验证将在未见过的项目上进行测试,性能都会较前者有所降低。cross-project验证在Defects4J V2.0.0数据集上进行,因为Defects4J V2.0.0包括了Defects4J V1.2.0没有涵盖的新的项目代码。

文中说明对比之前的深度学习方法DeepRL4FL和TRANSFER-FL,包括GRACE,性能都有所下降。从图3.1可以看出(new projects),本文方法也有相当程度的下降。但文中表明本文方法优势在于无需为新的项目重新训练模型,而其他模型的交叉验证要么重新训练了模型,要么只能在方法级别定位错误,因此本文方法泛化能力好更,计算成本更低。

3.4.3 消融实验结果

从上图的Ablation部分可以看出,大模型的预训练以及本文所加入的适配器起到了重要作用。
另外,未加入适配器的CodeGen尽管是一个生成模型(目标并非针对于文本理解任务),但其也具有相当于SBFL水平的代码错误理解能力,效果与SBFL相当(仅训练一层MLP接在大模型的输出用于分类)。但对比加入适配器后效果大大提升,说明所加入的双向适配器的有效性,也进一步证明作者考虑到的双向注意力的重要性。

3.4.4 对其他语言和领域的泛化性(generalization)

作者还评估了该方法在不同语言(other languages)和不同领域(other domains)上的错误定位能力,主要是在python数据集BugsInPy,以及C语言的风险预测Devign数据集上进行。其中,BugsInPy用于验证该方法对不同语言的泛化性,Devign用于验证对新的领域数据集上的泛化性,因为Devign是一个进行风险监测的数据集,没有测试信息作为数据输入,因此先前的基于测试信息的方法就不能适用了。

图3.2 Devign数据集的一个例子

实验结果:

图3.3 语言泛化性实验结果
图3.4 领域泛化性实验结果

实验结果表明:

  • LLMAO能泛化到其他的语言数据集上;
  • LLMAO的性能随着训练数据集大小的增加而提高;
  • LLMAO对于在测试用例不可用的 C 语言中查找安全漏洞特别有效;
  • LLMAO的性能随着CodeGen模型规模大小的增加而提高。

4. 总结

4.1 亮点

  • 利用了大模型的代码理解能力,并加入具有双向注意力的Tansformer层解决代码生成大模型的单向注意力在代码山下文理解上的局限性,相当于验证了双向注意力在该任务上的重要性;
  • 解决了传统方法和一般深度学习方法对测试信息的依赖(test-free),降低了数据预处理的成本。说明了代码理解角度直接进行错误定位是可行的。

4.2 不足

  • 在方法对比上没有对比传统方法MBFL;
  • 缺乏可解释性。

4.3 启发

  • 大模型是可以利用的,提取程序语义信息,基于程序和问题理解,进行错误定位。

5. 相关知识链接

  • 论文链接
  • 代码链接
  • BibTex
@inproceedings{yang2024large,title={Large language models for test-free fault localization},author={Yang, Aidan ZH and Le Goues, Claire and Martins, Ruben and Hellendoorn, Vincent},booktitle={Proceedings of the 46th IEEE/ACM International Conference on Software Engineering},pages={1--12},year={2024}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/660800.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网络安全:绕过 MSF 的一次渗透测试

这次渗透的主站是 一个 DiscuzDiscuz!3.4 的搭建 违法招 piao 网站&#xff0c; 配置有宝塔 WAF 用 Discuz!ML 3.X 的漏洞进行攻击&#xff0c;但是没有成功 现主站外链会有一个发卡网&#xff0c;引导人们来这充值&#xff0c;是 某某发卡网&#xff0c;而且域名指向也是主站…

自动驾驶框架 UniAD环境部署

感谢大佬们的开源工作 UniAD-github地址-YYDS更多bev算法部署参考如果您觉得本帖对您有帮助&#xff0c;感谢您一键三连支持一波^_^ 统一自动驾驶框架 (UniAD) &#xff0c;第一个将全栈驾驶任务整合到一个深度神经网络中的框架&#xff0c;并可以发挥每个子任务以及各个模块的…

GZIP格式解析和Deflate静态Huffman解压缩

GZIP是封装了Deflate压缩的格式文件&#xff0c;Deflate使用了无压缩、HuffmanLZ77进行压缩&#xff0c;Huffman包括静态Huffman和动态Huffman。 Java实现了GZIP格式解析&#xff0c;静态Huffman解压缩&#xff0c;CRC32校验 gzip文件格式解析代码&#xff1a; BinaryInputSt…

浅谈 HTTPS

文章目录 HTTPS 简介HTTPS 特点与 HTTP 的区别HTTPS 工作流程1. 服务端生成密钥对2. 服务端申请数字证书3. 服务端发送数字证书4. 客户端验证数字证书5. 客户端解析证书内容6. 客户端传送加密信息7. 服务端解密信息8. 双方协商生成会话密钥并交换9. 使用会话密钥进行通信 总结 …

数据挖掘之基于K近邻算法的原油和纳斯达克股票数据预测分析

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 一、项目背景 在当今日益复杂的金融市场中&#xff0c;准确地预测原油价格和纳斯达克股票市场的走势对于投资者、政…

【STM32】快速使用F407通用定时器输出可变PWM

网上的文章太啰嗦&#xff0c;这里直接开始。 使用的是STM32CubeIDE&#xff0c;HAL。以通用定时器TIM12在 通道2上输出1KHz的PWM为例。 要确定输出的引脚、定时器连接在哪里。 TIM2、3、4、5、12、13、14在APB1上&#xff0c;最大计数频率84M。 TIM1、8、9、10、11在APB2…

【docker 】Windows10安装 Docker

安装 Hyper-V Hyper-V 是微软开发的虚拟机&#xff0c;仅适用于 Windows 10。 按键&#xff1a; win键X &#xff0c;选着程序和功能 在查找设置中输入&#xff1a;启用或关闭Windows功能 选中Hyper-V 点击确定 安装 Docker Desktop for Windows Docker Desktop 官方下载…

vxeTable在vxe-modal提示工具栏无法关联表格

一般情况我们直接在created钩子中去关联工具栏&#xff0c;这样写正常情况下没有问题 const $tableRight this.$refs.tableRefRight;const $toolbarRight this.$refs.toolbarRefRight;if ($tableRight && $toolbarRight) {$tableRight.connect($toolbarRight);}在vxe…

管理能力学习笔记八:Will-Skill矩阵“盘“团队

如何把握带教中的“度”&#xff0c;才能在把事情做好的基础上&#xff0c;又能使员工获得成长呢&#xff1f; 需要做到 合理授权 & 适当辅导 如何做到&#xff1f; 通过使用 意愿-技能矩阵(Will-Skill Matrix) 辨别不同带教方法的适用情形&#xff0c;"盘"…

kube-prometheus部署到 k8s 集群

文章目录 **修改镜像地址****访问配置****修改 Prometheus 的 service****修改 Grafana 的 service****修改 Alertmanager 的 service****安装****Prometheus验证****Alertmanager验证****Grafana验证****卸载****Grafana显示时间问题** 或者配置ingress添加ingress访问grafana…

React复习笔记

基础语法 创建项目 借助脚手架&#xff0c;新建一个React项目(可以使用vite或者cra&#xff0c;这里使用cra) npx create-react-app 项目名 create-react-app是React脚手架的名称 启动项目 npm start 或者 yarn start src是源文件index.js相当于Vue的main.js文件。整个…

Go语言map

map 概念 在Go语言中&#xff0c;map 是一种内建的数据结构&#xff0c;它提供了一种关联式的存储机制&#xff0c;允许你以键值对的形式存储数据。每个键都是唯一的&#xff0c;并且与一个值相关联。你可以通过键来查找、添加、更新和删除值&#xff0c;这类似于其他编程语言…