代码补全漫谈(1) - 从TabNine说起
前不久,基于GPT-2模型的TabNine横空出世,在程序员界再次引起轰动。此前,国产的aixcoder,还有获得github ceo天使投资的Python编程利器kite等,已经收获了一轮又一轮的眼球。人工智能代替人编写代码的忧虑不时在知乎等网站上出现。
从程序语言处理的近亲 - 自然语言处理NLP的发展来看,这样的乐观不是没有道理的。从进入深度学习时代后,基于RNN的NLP技术不断发展进步,比如Attention机制引入RNN,到仅需要Attention的Transformer模型,到GPT, BERT, XLNet等预训练模型不断刷榜,借鉴NLP的经验,程序语言处理没有道理不取得大进步。TabNine的成功,也是对这种想法的印证。
但是,与外表的光鲜不同,程序语言处理学界却是处于纠结之中。NLP界的论文题目是这样的《Attention is all you need》,而程序语言的论文是这样的《Are Deep Nerual Networks the Best Choice for Modeling Source Code?》
Are Deep Neural Networks the Best Choice for Modeling Source Code?
就在这篇《Are Deep Neural Networks the Best Choice for Modeling Source Code?》中,作者Vincent J. Hellendoorn和Premkumar Devanbu认为,在程序语言处理方面,早日封神的深度神经网络的效果还不如基于传统统计方法的效果。
究其原因,他们提出三点:
第一,开发人员特别能造新词。这也没办法,变量名是造新词,函数名是造新词,面向对象设计方法就是造新词的助推器。这与自然语言完全不同,只有学术作品里才充满了术语,大部分人正常交流的词汇表非常有限,而且更新很慢。因为新词造出来没有用,得流行起来才有用,这个门槛可不低。而开发人员造词太容易了。但是,词造太多了,其实对人来说也同样是挑战,比如接手别人的代码,或者使用别人发明的API,都是令人头疼的事。
第二,开发人员造的新词局部性很强,出了一定范围重名很正常,然后每个人的风格还不一样。这也是自然语言中非常少见的情况,但是在写代码太正常了,新词有作用域,跨文件,跨模块都不一样。这是为了避免全局变量重名的一个重要手段,比如每个类中可以有局部变量,公有变量可以通过不同的类来区分,类重名可以用包来区分,如果包名加类名都一样,还可以加个容器来隔离各用各的。这样的要求,确实难为神经网络了。
第三,造词数量不但多,如果一次性批量造出来可以做训练也可以,但是随着代码编写,这是一个动态的过程。代码还可能错了重新修改。这样对于计算的实时性要求很高。这导致了基于大型NLP模型的改进算法,基本上没有能在程序员本机上运行的,都需要远程服务器的支持。
听起来是不是很有道理?确实是有道理的,我们将来介绍更多的背景知识后大家就会觉得更有道理。于是,两位作者提出了自己的解决方案,细节我们后面再讲,论文在这里:https://vhellendoorn.github.io/PDF/fse2017.pdf,代码在这里:https://github.com/SLP-Team/SLP-Core
以上的三个问题,我们总结一下给它起个名字,OOV(Out Of Vocabulary)问题.
Maybe Deep Neural Networks are the Best Choice for Modeling Source Code
不过,硬币总是有两面的。《Are Deep Neural Networks the Best Choice for Modeling Source Code?》发表于2017年,2年后,隔空应答的论文《Maybe Deep Neural Networks are the Best Choice for Modeling Source Code》发表了。
该文作者Rafael-Michael Karampatsis和Charles Sutton承认OOV是个问题。不过他们认为,对于罕见词的处理也是机器翻译中的老问题了,2015年的论文《Neural Machine Translation of Rare Words with Subword Units》已经开始讨论采用subword的办法来解决这样的问题。
于是,Karampatsis和Sutton实现了一套基于开放词典的神经网络系统,有兴趣的同学可以关注下他们的代码实现:https://github.com/mast-group/OpenVocabCodeNLM
为了详细说明程序语言处理中遇到的问题和前人的解法,我们还是回到故事的起点,从代码的自然性说起。
代码的自然性
如果同学们对于源代码处理的技术想有一个整体的概念的话,不妨可以先读一篇综述论文:《A Survey of Machine Learning for Big Code and Naturalness
)》。
所谓的"Big Code",论文中原文是这么讲的『The scale of available data is massive: billions of tokens of code and millions of instances of meta-data, such as changes, bug-fixes, and code reviews (“big code”).』,也就是说,元数据,如代码修改的记录,bug修复的记录,代码评审的记录等等。
而Naturalness自然性,我们需要看另一篇论文《On the naturalness of software》。
这篇文章的主旨是说,虽然语言可以千变万化,但是落实到日常生活中,由于认知的限制和实际的需要,我们日常交流所有的语言是重复性的,有规律的,可预测的。这个统计上的结果,导致了统计机器学习方法在语音识别、机器翻译等领域的巨大成功。于是这篇论文的作者们假设程序代码也是自然的,因为它们也是人类在工作中创建的,受到硬件的软件的各方面的限制,它们也应该是有其统计规律的。
作者们研究的成果是非常正面的,他们证明,代码不但是有自然性的,而且比自然语言的自然性还要好。为此,他们实现了一套基于统计方法的代码补全系统,并成功应用于eclipse IDE中。
从那时起,各种对编程语言模型的研究百发齐放,如2013年Allamanis和Sutton的《Mining Source Code Repositories at Massive Scale Using Language Modeling》,2013年Nguyen的《A Statistical Semantic Language Model for Source Code》,2014年Tu, Su和Devanbu的《On the localness of software》,2016年Bielik等人的《PHOG: Probabilistic Model for Code》,Dam等人的《A deep language model for software code》等。
有了理论之后,大家迅速将其应用于解决自己手头的问题:
比如2014年《Code Completion with Statistical Language Models》用于代码提示与补全;
2014年的《Learning Natural Coding Conventions》和2015年的《Predicting Program Properties from "Big Code"》用于提升代码可读性;
2016年的《On the "Naturalness" of Buggy Code》用于bug修复;
2015年的《Suggesting Accurate Method and Class Names》用于推荐方法名和类名;
2016年的《A Convolutional Attention Network for Extreme Summarization of Source Code》和《Summarizing Source Code using a Neural Attention Model》用于源代码总结;
2018年的《DeepBugs: A Learning Approach to Name-based Bug Detection》用于预测bug;
2016年的《Deep Learning Code Fragments for Code Clone Detection》用于查找代码克隆;
2018年的《Deep Code Comment Generation》用于自动为代码生成注释;
2015年的《DeepFix: A Fully Convolutional Neural Network for predicting Human Eye Fixations》用于语法错误修复;
2018年提《A Deep Learning-Based Approach to Infer Natural Variable Names from Usage Contexts》用于反混淆;等等
正在看起来岁月静好的时候,Vincent J. Hellendoorn和Premkumar Devanbu发表了《Are Deep Neural Networks the Best Choice for Modeling Source Code?》,认为OOV问题导致深度学习处理程序语言的效果还不如传统机器学习方法。
P. Devanbu是加州大学戴维斯分校的老师。他参与了上面介绍的多篇论文的发表,如《On the "Naturalness" of software》《On the Localness of Software》《On the "Naturalness" of Buggy Code》《A Survey of Machine Learning for Big Code and Naturalness》。
Vincent Hellondoorn是Devandu老师的博士生。他今年的另外两篇论文《Deep Learning Type Inference》和《When Code Completion Fails: a Case Study on Real-World Completions》也是我们这一系列文章的主角。