深度学习深度代码搜索

2020-7-24 18:22 1470 52

为了实现程序功能,开发人员可以通过搜索大规模的代码库来重用以前编写的代码片段。多年来,许多代码搜索工具被提出以期来帮助开发人员。现有的方法通常将源代码视为文本文档,并利用信息检索模型检索与给定查询匹配的相关代码片段。这些方法主要依赖于源代码和自然语言查询之间的文本相似性。他们缺乏对查询和源代码语义的深入理解。

本文提出了一种新的深度神经网络 CODEnn(Code-Description Embedding Neural Network)。CODEnn 不匹配文本相似度,而是将代码片段和自然语言描述共同嵌入到一个高维向量空间中,使得代码片段与其对应的描述具有相似的向量。使用统一的向量表示,可以根据它们的向量检索与自然语言查询相关的代码片段。语义相关的单词也可以被识别,查询中的无关/噪音关键字也可以被处理。

作为概念验证应用,我们使用所提出的 CODEnn 模型实现了一个名为 DeepCS 的代码搜索工具。我们对从 GitHub 收集的大规模代码库进行了实证评估。实验结果表明,我们的方法能够有效地检索相关的代码片段,并优于以往的技术。

1 引言

代码搜索是软件开发实践中非常常见的活动。为了实现某种功能,例如解析 XML 文件,开发人员通常通过在大规模的代码库上执行自由文本查询来搜索和重用以前编写的代码。

许多代码搜索方法已经提出了,其中大多数是基于信息检索(IR)技术的。例如,Linstead 等人提出了 Sourcerer,一种基于信息检索的代码搜索工具,它将程序的文本内容与结构信息结合起来。McMillan 等人提出的 Portfolio,通过关键字匹配和 PageRank 返回函数链。Lu 等人使用从 WordNet 获得的同义词展开查询,然后执行方法签名的关键字匹配。Lv 等人提出了 CodeHow,它通过扩展的布尔模型将文本相似性和 API 匹配结合起来。

基于 IR 的代码搜索的一个基本问题是自然语言查询中反映的高级意图与源代码中低级实现细节之间的不匹配。源代码和自然语言查询是异构的。它们可能不共享共同的词汇标记、同义词或语言结构。相反,它们可能只在语义上相关。

现有方法可能无法返回此代码段,因为它不包含诸如 read 和 object 之类的关键字或它们的

同义词(如 load 和 instance)。因此,一个有效的代码搜索引擎需要在代码和自然语言查询之间建立更高层次的语义映射。此外,现有的方法在查询理解方面存在困难。它们不能有效地处理查询中不相关/嘈杂的关键字。因此,一个有效的代码搜索引擎也应该能够理解自然语言查询和源代码的语义意义,以提高代码搜索的准确性。

在我们之前的工作中,我们介绍了 DeepAPI 框架,这是一种基于深度学习的方法,可以学习查询的语义和相应的 API 序列。然而,搜索源代码要比生成 API 困难得多,因为代码片段的语义不仅与 API 序列有关,还与其他源代码方面(如令牌和方法名称)相关。例如,Deep API 可以为将图像保存为 png 的查询返回相同的 API Image IO.write,并将图像保存为 jpg。然而,用于回答这两个查询的实际代码片段在源代码令牌方面是不同的。因此,代码搜索问题需要能够利用源代码更多方面的模型。

本文提出了一种新的深层神经网络 CODEnn。为了弥补查询与源代码之间的词法鸿沟,CODEnn 将代码片段和自 然语言描述联合嵌入到高维向量空间中,从而使代码片段 及其相应的描述具有相似的向量。通过统一的向量表示,可以根据向量检索与自然语言查询语义相关的代码片段。还可以识别语义相关词,并处理查询中不相关/有噪声的关键字。

使用 CODEnn,我们实现了一个代码搜索工具 DeepCS,作为概念证明。DeepCS 在 GitHub 的 1820 万个 Java 代码片段(以注释方法的形式)的语料库上训练 CODEnn 模型。然后,它从代码库中读取代码片段,并使用经过训练的 CODEnn 模型将其嵌入到向量中。最后,当用户查询到达时,DeepCS 会找到与查询向量最近的向量的代码片段,并返回它们。

为了评估 DeepCS 的有效性,我们使用从堆栈溢出获得的 50 个实际查询在搜索代码库上执行代码搜索。我们的结果表明 DeepCS 返回的相关代码片段比两种相关的方法(即 CodeHow 和传统的基于 Lucene 的代码搜索工具)返回更多相关的代码片段。平均而言,DeepCS 返回的第一个相关代码片段排名 3.5,而 CodeHow 和 Lucene 返回的第一个相关结果分别排名 5.5 和 6.0。对于 76%的查询,相关的代码片段可以在返回的前 5 个结果中找到。评价结果证实了 DeepCS 的有效性。

2 用于代码搜索的深层神经网络

受现有联合嵌入技术的启发,我们提出了一种新的深度神经网络 CODEnn(CodeDescription embedding neural network)来解决代码搜索问题。自然语言查询和代码片段是异构的,不能根据它们的词法标记轻松匹配。为了弥补这一差距,CODEnn 将代码片段和自然语言描述联合嵌入到统一的向量空间中,以便将查询和相应的代码片段嵌入到邻近的向量中,并通过度量向量相似度来匹配。

2.1 结构

代码嵌入网络将源代码嵌入到向量中。源代码不是简单的纯文本。它包含多个方面的信息,如令牌、控制流和 API。在我们的模型中,我们考虑源代码的三个方面:方法名、API 调用序列和源代码中包含的令牌。它们通常用于现有的代码搜索方法。对于每个代码片段(在方法级别),我们提取这三个方面的信息。每一个单独嵌入,然后组合成一个代表整个代码的向量。描述嵌入网络(DeN)将自然语言描述嵌入到向量中。

我们描述了将代码和描述映射到向量(即 c 和 d 的转换)。由于我们希望代码和描述的向量被联合嵌入,所以我们度量两个向量之间的相似性,我们使用余弦相似度进行测量。

总的来说,总体上,CODEnn 以一个代码、描述对作为输入,并预测它们的余弦相似性 cos(c,d)。

2.2 训练模型

现在我们介绍如何训练 CODEnn 模型将代码和描述都嵌入到统一的向量空间中。联合嵌入的高级目标是:如果代码片段和描述具有相似的语义,则它们的嵌入向量应该彼此接近。换句话说,给定一个任意的代码片段 C 和一个任意的描述 D,我们希望它预测一个高相似性,如果 D 是正确的描述 C,而不是一个小的相似性。

在训练时,我们将每个训练实例构造为三元组:对于每个代码片段 C 都有一个正确的描述 D+,以及从所有 D+的池中随机选择的否定描述(C 的不正确描述)D-。当在三元组上训练时,CODEnn 预测和的余弦相似性,并将最小化排序损失。

3 DEEPCS:基于深度学习的代码搜索

3.1 收集训练语料库

如第 3 节所述,CODEnn 模型需要一个包含代码元素和相应描述(即方法名、API 序列、标记、描述元组)的大规模训练语料库。图 6 显示了训练语料库的摘录。

我们使用 Java 方法构建训练元组,这些方法包含 GitHub 上开源项目的文档注释。对于每个 Java 方法,我们使用方法声明作为代码元素,并使用其文档注释的第一句话作为其自然语言描述。根据 Javadoc 指南,第一句话通常是方法的摘要。为了准备数据,我们从 2008 年 8 月至 2016 年 6 月创建的 GitHub 下载 Java 项目。我们只选择从下载的项目中有文档注释的 Java 方法。最后,我们得到了一个包含 18233872 个带注释的 Java 方法的语料库。

在收集了注释代码片段的语料库之后,我们提取了<方法名、API 序列、令牌、描述>元组,如下所示:

方法名提取:对于每个 Java 方法,我们提取其名称,并根据 camel case 将名称解析为一系列标记。例如,方法名 listFiles 将被解析为 tokens 列表和文件。

API 序列提取: 我们使用 DeepAPI 中描述的相同过程从每个 Java 方法中提取 API 序列-使用 EclipseJDT 编译器解析 AST 并遍历 AST。

图 7 显示了从 Apache commons-lang 库中的 Java 方法 Date Utils.to Calendar3 中提取的代码元素和文档注释的示例。

深度代码搜索

深度代码搜索

3.2 训练 CODEnn 模型

CODEnn 模型的具体实现如下:我们使用双向 LSTM,这是 用于 RNN 实现的 RNN 的最新子类。所有 LSTM 在每个方向都有 200 个隐藏单元。我们将单词嵌入的维度设置为 100。CODEnn 有两种类型的 MLP,即嵌入单个标记的嵌入 MLP 和融合 MLP,以结合不同方面的嵌入. 我们将嵌入 MLP 的隐藏单元数设置为 100,融合 MLP 的隐藏单元数设置为 400。

CODEnn 模型通过小批量 Adam 算法进行训练。我们将批大小(即每个批的实例数)设置为 128。为了训练神经网络,我们将词汇表的大小限制在训练数据集中 最常用的 10,000 个单词。

我们在 Keras 和 Theano 这两个开源深度学习框架上构建了我们的模型。我们用一个 NvidiaK40GPU 在服务器上训练我们的模型。训练持续 50 小时,共 500 个周期。

3.3 搜索代码片段

给定用户的自由文本查询,DeepCS 通过训练的 CODEnn 模型返回相关的代码片段。它首先计算搜索代码库中每个代码片段(即 Java 方法)的代码向量。然后,它选择并返回最接近查询向量的前 K 个向量的代码片段。

更特别的是,在搜索开始之前,DeepCS 使用 CODEnn 的 CoNN 模块以离线方式将代码库中的所有代码片段嵌入到向量中。在在线搜索过程中,当开发人员输入一个自然语言查询时,DeepCS 首先使用 CODEnn 的 DeNN 模块将查询嵌入到一个向量中。然后,使用等式 11 计算查询向量和所有代码向量之间的余弦相似性。最后,返回向量与查询向量最相似的前 K 个代码片段作为搜索结果返回。在我们的实验中 K 设置为 10。

4 评估

4.1 结果

表 1 显示了 DeepCS 对基准中每个查询的评估结果和相关方法。列 Question ID 显示显示查询来自的堆栈溢出中问题的原始 ID。FRank 列显示了每种方法的结果。符号“NF”表示未找到,这意味着在顶部 K 结果(K=10)中没有返回相关结果。

深度代码搜索

结果表明,DeepCS 通常比 Lucene 和 CodeHow 产生更相关的结果。图 8a 显示了三种方法的 FRank 的统计摘要。符号“+”表示每种方法实现的平均 FRank 值。对于在前 10 个返回结果中未能获得相关结果的查询,我们保守地将 FRank 视为 11。我们观察到,DeepCS 以 3.5 的平均 FRank 获得了更相关的结果,这小于 CodeHow(5.5)和 Lucene(6.0)获得的平均 FRank。DeepCS 的 FRank 值集中在 1 到 4 之间,而 CodeHow 和 Lucene 产生更大的方差和许多不太相关的结果。图 8b,8c 和 8d 分别显示了 k 分别为 1,5 和 10 时三种方法的精度@k 的统计量。我们观察到,DeepCS 比 CodeHow 和 Lucene 的工具获得了更好的整体精度值。

为了检验统计学意义,我们应用 Wilcoxon-Signedrank 秩检验(p<0.05)来比较 FRank 和精度@k 在 DeepCS 和两个相关的查询方法之间。对于在前 10 个返回结果中未能获得相关结果的查询,我们保守地将 FRank 视为 11。DeepCS 与 Lucene 和 CodeHow 的比较 p 值均小于 0.05,表明 DeepCS 相对于相关方法的改进具有统计学意义。

深度代码搜索

深度代码搜索

表 2 显示了这三种方法的总体性能,以成功率@k、精度@k 和 MRR 衡量。列 R@1、R@5 和 R@10 分别显示当 k 为 1、5 和 10 时成功率@k 的结果。列 P@1、P@5 和 P@10 分别显示了当 k 分别为 1、5 和 10 时所有查询的平均精度@k 的结果。列 MRR 显示了这三种方法的 MRR 值。结果表明,DeepCS 比 Code How 和 Lucene 返回更多相关的代码片段。例如,R@5 值为 0.76,这意味着对于 76%的查询,可以在前 5 个返回结果中找到相关的代码片段。其中 P@5 值为 0.5,这意味着前 5 名结果的 50%被认为是准确的。对于成功率@k,对 CodeHow 的改进分别为 21%、31%和 30%。对于精度@k,对 CodeHow 的改进分别为 21%、72%和 75%。对于 MRR,对 CodeHow 的改进为 33%。总的来说,我们的方法提高了相关技术对所有度量的准确性。

4.3 代码搜索结果示例

我们现在提供具体的代码搜索结果的例子,以证明深度 DeepCS 的优势。

图 9a 和 9b 显示了两个查询的结果:将要在线程上运行的事件队列和在线程队列上运行的事件队列。这两个查询具有相同的关键字集,具有不同的单词序列。两个查询中的关键字队列具有不同的含义,基于 IR 的方法很难区分。尽管如此, DeepCS 仍然可以理解这两个查询的含义并返回相关的片段。显然,DeepCS 具有识别查询语义的能力。

查询理解能力使 DeepCS 能够执行更健壮的代码搜索。其搜索结果受无关或嘈杂的关键词影响较小。另一方面,DeepCS 可以成功地识别不同关键字的重要性并理解查询的关键点(图 10)。

DeepCS 的另一个优点是关联搜索。也就是说,它不仅查找具有匹配关键字的片段,而且还推荐那些没有匹配关键字但语义相关的片段。这一点很重要,因为它显著地增加了搜索范围,特别是当代码库很小的时候。关联搜索提供了更多的代码片段选项供开发人员学习。图 11a 显示了从 xml 文件读取对象的查询的第一个结果。如第 1 节所述,传统的基于 IR 的方法可能只匹配包含 xml、object 和 read 等关键字的片段。但是,如图所示,DeepCS 成功地识别了查询语义并返回了 xml 反序列化的结果,甚至结果中不存在关键字。相比之下,CodeHow 只返回包含 read、object 和 xml 的片段,缩小搜索范围。这个例子表明 DeepCS 通过理解语义而不是仅仅匹配关键字来搜索代码。图 11b 显示了关联搜索的另一个示例。搜索时播放一首歌。DeepCS 不仅返回具有匹配关键字的片段,而且还还推荐与语义相关的单词(如音频和语音)的结果。

深度代码搜索

深度代码搜索

深度代码搜索


推荐阅读
5G NSA和SA是什么意思,怎么区别出来它们 2020-08-24 10:51
华强北Airpods洛达低配和高配耳机真光感鉴别方法 2021-01-29 16:44
语义源代码检索的多模态注意力网络学习 2020-07-24 18:06
FPGA! SignalTap II 软件调试-新建工程图解 2019-11-13 14:59
MODE:基于状态差分分析和输入选择的自动化神经网络模型调试 2020-06-19 11:21