程序员失业第一步?斯坦福研究员用AI从编译器反馈中学习改Bug

  • 2020 年 11 月 18 日
  • AI

作者 | 陈大鑫

众所周知,程序员是一份“光鲜亮丽”、“有福报”、“永不加班”的好工作,程序员每天就是程序代码嘛,理想中的工作日常是这样:
而现实中的工作日常却是这样:
其实无论是对于初学者还是对于专业开发人员,编程这件事,都需要花费大量时间调试或修复代码错误,或称为改Bug。
程序员日常编程的过程基本就是:写代码、编译或执行程序,如果有报错,根据收到的编译器报错反馈修复程序,然后整个过程循环下去直到程序成功运行。
那么,人们可以通过AI来建模和解决这个问题吗?
在ICML 2020上发表的一项最新工作中,来自斯坦福大学的两位研究员研究了如何使用AI来自动修复程序,以期未来程序修复自动化可以大大提高编程和学习编程的效率。
1

论文介绍

论文名称:《Graph-based, Self-Supervised Program Repair from Diagnostic Feedback》。
论文链接://arxiv.org/pdf/2005.10636.pdf
假设我们有一个有Bug的C ++程序(左上图),第5行char 的位置实际上应该是string。当编译程序时,程序将会如图右上报错:“第9行a的类型是char”。
从此信息中,程序员可以注意到程序报错与变量a的类型有关,跟踪a在源代码中的使用或声明方式,到达第5行,然后编辑该行以更正错误。
因此,我们希望我们的机器学习模型要解决的具体任务是,给定有Bug的代码(左图)和报错信息(右上图),定位错误行(第5行)并生成其修复版本(“string” tmp,a,b;”)(上图右下方)。
挑战:
此任务带来两个主要挑战。
1、在建模方面,需要通过两种方式(程序和报错信息)进行连接和共同推理:例如,如上例所示,跟踪导致代码报错的变量。
2、在训练数据方面,需要有效的数据源,以提供监督学习来纠正含Bug的程序。
不幸的是,现有的带有<broken code, fixed code>对的标记数据集比较小且难以获取,并且无法有效地扩展。

2

模型方法

在本文中,作者通过以下两种方式提出了有效的解决方案:
1、使用程序反馈图对程序修复(改Bug)进行建模;
2、引入使用未标记程序的自监督训练方案。

建模方法:程序反馈图

为有效地连接程序和报错信息两种方式并执行修复代码所需要的推理,作者引入了程序反馈图,这是一个连接图的表示,该图将整个程序中的代码符号与报错信息连接在一起。
例如,示例中的编译器消息提到a,size和char,因此我们可以将这些符号连接到源代码中它们出现的位置,以捕获对应语法响应。
这样,我们就可以在共享语法空间中处理这两种模态而不是分开地处理这两种模态,然后使用图注意力( graph attention)机制对这个空间中的符号进行推理 。
下图是本文的模型架构,它建立在NLP中常用的编码器-解码器框架上,该框架对输入序列(在下图中为程序和报错信息)进行编码,然后对输出进行解码,并在架构的中间层(图中)将图注意力模块应用于程序反馈图中。

模型架构图拆解:

训练方法:自监督学习

本文使用的另外一种技术是自监督学习。
带标签的程序Bug修复数据集很小,但在互联网上有大量未带标签的程序代码可用。
例如,GitHub上拥有超过3000万个公共存储仓库。使用大量免费的可用代码来改善学习程序的Bug修复,将大大增强系统的可伸缩性和稳定可靠性。
本文的步骤如下:
1、从GitHub和Codeforce等在线资源中收集未带标签的有效程序(上图 左)。
2、设计随机程序破坏程序代码(例如,删除/插入/替换token),并破坏未标记程序(上图 中)。
3、损坏的程序会报错(上图 右)。
这样,人们就可以创建许多新的程序修复示例<broken code, error message, fixed code>

程序Bug修复模型

本文在两个基准任务上应用和评估的修复模型(称为DrRepair):
  • 纠正学生编写的C程序(DeepFix数据集)
  • 纠正C ++程序合成的输出(SPoC数据集)
结果如下图所示:

3

应用

应用于DeepFix(修正学生程序)
在DeepFix中,任务是更正学生在入门编程课中编写的C程序,以便它们能通过编译。输入程序可能有多行报错,因此需要迭代应用修复模型,一次解决一个报错。   
例如,上图显示了DeepFix中的示例程序,该程序有一个编译器错误,指出“i未声明”
这时应用修复模型DrRepair就派上用场了,它通过插入以下声明来修复此错误:i在第5行中。
完成此修复后,还有另外一个错误,该错误为
再次应用修复模型:这次,DrRepair模型在第12行中插入了分号,程序编译成功!
这种方法也即是迭代优化的思想:逐步运行修复模型并逐步修复报错。
使用报错信息,程序反馈图和自监督的预训练有什么影响?
在DeepFix上研究的现有修复系统未使用编译器报错信息,它们旨在直接将有Bug的代码转换为固定代码。
为了首先查看使用报错信息的效果,本文尝试从系统中删除所有技术:使用编译器消息,程序反馈图和预训练。
下图中没有编译器的模型版本在DeepFix上实现了34%的修复精度,与现有系统相当。现在将编译器提示信息添加到输入中,作者发现该模型实现了更好的性能提升和泛化性(准确度为62.5%)。
这表明,通过访问报错信息,模型可以基于反馈学习正确的归纳偏差来修复代码。
接下来,作者添加了程序反馈图和自监督的预训练。作者发现这两者都作出了进一步的性能提升(“ours: base+graph” 以及“ours: base+graph+pretrain”),并且本文的最终系统可以修复DeepFix中68.2%的含Bug程序!
应用于SPoC(自然语言编码)
程序合成,特别是可以将自然语言描述(例如英语)转换为代码(例如Python,C ++)的系统是很有用的,因为它们可以帮助更多的人使用编程语言。
在SPoC(伪代码-to-代码)中,任务是从伪代码(程序的自然语言描述)合成C ++代码实现。
但是,现有合成器(应用于SPoC的机器翻译模型)遇到的一个挑战是它们倾向于输出不一致的代码,这些代码无法编译,例如,在上图中,变量i在合成代码中被声明了两次。
作者发现可以将程序修复模型应用于此无效代码,并将其修复为正确的代码,从而帮助完成程序合成任务。
在对SPoC的评估中,使用本文的修复模型可使最终合成成功率从现有系统的34%提高到37.6%。
4

总结

在这项工作中,作者研究了如何使用机器学习来修复报错信息中的程序,并提出了三个主要见解:
  1. 报错信息对学习程序Bug修复而言至关重要。
  2. 程序反馈图(代码和错误消息的共同表示)有助于对修复的原因进行建模(例如,跟踪引起报错的变量)。
  3. 自监督学习使人们能够将免费获取的、未标记的程序(例如GitHub开放代码)转换成有用的程序修复训练示例。
这项工作还提供了一个“从反馈中学习”的通用框架,该框架具有各种应用程序:基于注释编辑文档,在交互对话框中向用户学习等。
本文GitHub上源代码/数据链接:
//github.com/michiyasunaga/DrRepair
最后需要指出的是,本文只是AI从编译器反馈中学习修改代码Bug的一项研究工作,还远远不能用于实际生产环境开发中。
这只是程序员开发AI程序让自己失业的远大理想的第一步~
参考链接://ai.stanford.edu/blog/DrRepair/
文末附上两种祖传无Bug的秘法:
秘法1:佛祖保佑~
秘法2:神兽保佑~


点击阅读原文,直达NeurIPS小组~