编程语言是软件开发行业的主要工具。自20世纪40年代以来,已经出现了数百种编程语言,并且每天都有大量的各种编程语言的代码被推送到代码库中。

我们认为,根据代码识别编程语言的源代码分类器将是一个非常有用的工具,因为它可用于在线自动语法高亮和标签建议,比如可用在StackOverflow和技术维基网站上。这个想法促使我们根据最新的AI技术编写一个对代码片段依据编程语言进行分类的模型。

我们使用GitHub API从GitHub上收集了数十万个源代码文件。在训练模型之前,必须处理原始数据以消除和减少一些不需要的特征。最终完成的分类器的性能非常得好,你可以在本文结尾找到相关的结果,以及有关模型决策的一些解释。

数据

我们根据编程语言的受欢迎程度选择了其中的一部分。图1显示了2014年第四季度GitHub上最常用的49种语言[1]。此分析仅考虑活跃的代码库,即在此期间至少有一行代码被推送进去的存储库。我们也将**HTML**和**XML**添加到列表中,虽然人们可能并不认为它们是编程语言,但毕竟它们是与软件开发项目相关的。基于同样的原因,我们也添加了SQL。

1.png 比人工还准确!看深度学习如何对源码进行分类 AI教程 第1张
图表1 - 活跃代码库(点击查看原图

我们使用GitHub API来抓取代码库。下图显示了经过几天抓取后的数据形状。我们抓取了数千个代码库,但忽略了大小超过100MB的,以避免花费太多的时间进行下载和预处理。我们使用文件扩展名来标记每个样本所用的编程语言(例如,file.php是PHP源文件)。 C#是代码量最多的编程语言,而Arduino在我们爬取的资源中是最少的。为了避免训练集的不平衡,每个种类我们最多使用了一万个例子。

2.png 比人工还准确!看深度学习如何对源码进行分类 AI教程 第2张
图表2 - 抓取的文件(点击查看原图

混杂的源代码

仔细看一下原始数据,我们发现一些令人深思的行为和特征,这并不令人惊讶,因为这些数据是从实际的代码库中抓取的。最常见的情况是单个文件混杂了多个语言,这在网络应用程序中很常见(如、HTML、CSS、PHP和ASP)。下面这段从.asp源文件中提取出来的ASP代码说明了这种情况。

3.png 比人工还准确!看深度学习如何对源码进行分类 AI教程 第3张
图1 - 混杂的语言

在这个例子中,我们只想为每个文档分配一个种类。因此,对于在单个源代码文件中使用混合语言,我们只保留该文件主要语言的代码片段(从其扩展名推断),并删去其他语言的所有内容。为此,我们对于每种语言使用已知的保留词和表达式。例如,我们知道<%php%>之间的所有内容都是php代码,所以如果是.php文件,我们只保留这些内容,并删除其他的内容。通过同样的方法,我们可以使用正则表达式或Python中的内置解析器从代码中剥离HTML标签。

这些文档中另一个常见的特征是嵌入式代码片段。例如,在下面的脚本中,引号之间嵌入了C代码段。这是另一种非常常见的混合代码。我们通过用占位符替换引号之间的所有内容来化这个问题(在这个例子中,我们使用strv作为字符串占位符)。

4.png 比人工还准确!看深度学习如何对源码进行分类 AI教程 第4张
图2 - 代码段中嵌入了“隐藏的”C代码

符号化

在预处理之后,源代码中仍然包括了转义的换行符和制表符,因此,我们需要对所有文本进行符号化。在这个步骤中,我们必须保留代码所有的语法信息。我们使用正则表达式[\w']+|[""!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~""\\]来提取符号。完成这一步之后,这些数据就可以进行训练了。

Python

print "This is using getsize"for root, dirs, files in os.walk('/tmp'):    print root, "consumes"

符号化之后

print strv \n for root, dirs, files in os.walk(strv):\n\t print root, strv

预处理完成后

['print',  'strv',  'for',  'root',  ',',  'dirs',  ',',  'files',  'in',  'os',  '.',  'walk',  '(', 'strv', ')',  ':',  'print',  'root,',  '"',  'strv']

模型

近来,卷积神经网络(CNN)正受到越来越多的NLP项目的青睐。特别是在文本分类方面,深度学习模型取得了显着的成果[2,3]。我们的模型使用了一个单词嵌入层,然后是一个带有多个过滤器的卷积层、一个最大池层,最后是一个softmax层(图3)。我们使用了一个非静态并且随机初始化的嵌入层,因此需要从头开始训练矢量。

5.png 比人工还准确!看深度学习如何对源码进行分类 AI教程 第5张
图3 - 卷积神经网络模型

结果

我们对10%的数据进行了测试,并计算出每个标签的准确性、精度、回调率和f1评分。总体结果分别为97%、96%、96%和96%。每个标签的成绩也相当得高(图3)。

6.png 比人工还准确!看深度学习如何对源码进行分类 AI教程 第6张
图表3 - 每个种类的结果(点击查看原图

结果看起来还不错,让我们来看一下预测的解释说明来检查分类器是如何做出决策的。我们使用LIME生成“解释说明”,该“解释说明”高亮了与每个标签最相关的单词。这样,我们就知道了模型为什么选择这个标签而不是另一个标签。

Scala代码片段:

object HelloWorld {  def main(args: Array[String]) {
    println("Hello, world!")
   }
}

结果说明:

7.png 比人工还准确!看深度学习如何对源码进行分类 AI教程 第7张

Java代码片段:

BufferedWriter out = null;try {   out = new BufferedWriter(new FileWriter("filename", true));   out.write("aString");
} catch (IOException e) {// error processing code} finally {   if (out != null) {      out.close();
   }
}

说明:

8.png 比人工还准确!看深度学习如何对源码进行分类 AI教程 第8张

OCaml代码片段:

# let average a b =    let sum = a +. b in
    sum /. 2.0;;val average : float -> float -> float =

9.png 比人工还准确!看深度学习如何对源码进行分类 AI教程 第9张

未来的方向

虽然分类器的性能很高,但仍有改进的空间。例如,尝试着使用直接从字符学习的字符级模型,这样就用不着单词嵌入层了[4]。此外,可以试着获取每种编程语言的版本数据,这样就能给源代码添加特定版本号了。

参考资料

  1. Githut – http://githut.info/

  2. Kim, Y. (2014). 用于语句分类的卷积神经网络。 有关2014届自然语言处理会议的经验方法 (EMNLP 2014), 1746–1751.

  3. Wang, P., Xu, J., Xu, B., Liu, C., Zhang, H., Wang, F., & Hao, H. (2015). 基于语义聚类和卷积神经网络的短文本分类。 Proceedings ACL 2015, 352–357.

  4. Zhang, X., Zhao, J., & LeCun, Y. (2015). 用于文本分类的字符级卷积网络, 1–9.

文章原标题《Source Code Classification Using Deep Learning》,作者:Robson Montenegro,译者:夏天,审校:主题曲。

文章为简译,更为详细的内容,请查看原文