用于搜索的深度神经网络代码、工具

2021-1-11 17:19 1585 44

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

研究人员已经提出了许多代码搜索方法,其中大多数是基于信息检索(IR)技术。基于 IR 的代码搜索的一个基本问题是自然语言查询中反映的高级意图与源代码中的低级实现细节之间的不匹配。源代码和自然语言查询是异构的。它们可能不共享常见的词汇标记、同义词或语言结构。 相反,它们可能只是语义上的相关。例如,查询“从 XML 读取对象”的相关片段可以如下:

深度代码搜索

现有的方法可能无法返回此代码片段,因为它不包含关键字,如读取和对象或它们的同义词(加载和实例)。因此,有效的代码搜索引擎需要在代码和自然语言查询之间进行更高层次的语义映射。 此外,现有的方法在查询理解方面存在困难。它们不能有效地处理查询中不相关/噪声关键字。 因此,一个有效的代码搜索引擎也应该能够理解自然语言查询和源代码的语义含义,以提高代码搜索的准确性。

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

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

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

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

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

在现有联合嵌入技术的启发下,我们提出了一种新的深度神经网络 CODEnn(代码描述嵌入神经网络)来解决代码搜索问题。自然语言查询和代码片段是异构的,不能很容易地根据它们的词汇标记进行匹配。为了弥补这一点,CODEnn 将代码片段和自然语言描述联合嵌入到一个统一的向量空间中,以便将查询和相应的代码片段嵌入到附近的向量中,并可以通过向量相似性来匹配。

2.1 结构

联合嵌入模型需要三个组件:嵌入函数 ϕ:X→Rd 和 ψ:Y→Rd,以及相似性度量 J。 CODEnn 用深度神经网络实现这些组件。

图 4 显示了 CODEnn 的总体架构。 神经网络由三个模块组成,每个模块对应于联合嵌入的一个组件:

(1) 代码嵌入网络(CoN)将源代码嵌入到向量中。

(2) 描述嵌入网络(DeN)将自然语言描述嵌入到向量中。

(3) 相似性度量模块,它度量代码和描述之间的相似性

深度代码搜索

2.1.1 代码嵌入网络

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

2.1.2 描述嵌入网络

描述嵌入网络(DeN)使用 RNN 和 maxpooling 将自然语言描述嵌入到向量中。

2.1.3 相似性度量模块

我们将代码和描述分别映射到了向量。由于我们希望代码和描述的向量被联合嵌入,所以我们测量了两个向量之间的相似性。使用余弦相似度进行测量,相似性越高,代码与描述的相关性越大。

2.2 模型训练

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

在训练时,我们将每个训练实例构造一个三元组<C,D,D->:对于每个代码段 C,有一个正的描述 D(正确的描述 C)以及一个负的描述 D-随机从所有 D 的池中选择。当在 C、D、D-三元集合上训练时,CODEnn 预测 C、D 和 C、D 对的余弦相似性,并将排序损失最小化。直观地说,排名损失鼓励代码片段与其正确描述之间的余弦相似性上升,代码片段与不正确描述之间的余弦相似性下降。

3. DeepCS:基于深度学习的代码搜索工具

在这一部分中,我们描述了基于所提出的 CODEnn 模型的代码搜索工具 DeepCS。DeepCS 为给定的自然语言查询推荐前 K 个最相关的代码片段。 图 5 显示了总体架构。 它包括三个主要阶段:线下训练、线下代码嵌入和在线代码搜索。

深度代码搜索

我们首先收集一个大规模的代码片段语料库,即具有相应描述的 Java 方法。我们从方法中提取子元素(包括方法名称、token 和 API 序列。然后,我们使用语料库来训练 CODEnn 模型(离线训练阶段)。 对于给定的代码库,用户希望从中搜索代码片段,DeepCS 提取搜索代码库中每个 Java 方法的代码元素,并使用经过训练的 CODEnn 模型(离线嵌入阶段)的 CoNN 模块计算代码向量。最后,当用户查询时,DeepCS 首先使用 CODEnn 模型的 DeNN 模块计算查询的向量表示,然后返回向量接近查询向量的代码片段(在线代码搜索阶段)。

3.1 收集训练语料库

CODEnn 模型需要一个包含代码元素和相应描述的大规模培训语料库,即<方法名称、API 序列、token、描述>元组。

我们使用 Java 方法构建培训元组,这些方法具有来自 GitHub 上开源项目的文档注释。对于每个 Java 方法,我们使用方法声明作为代码元素,使用其文档注释的第一句作为它的自然语言描述。根据 Javadoc 指南,第一句通常是方法的总结。为了准备数据,我们从 2008 年 8 月至 2016 年 6 月创建的 GitHub 下载 Java 项目。为了删除玩具或实验程序,我们排除任何没有星标的项目。我们只从下载的项目中选择具有文档注释的 Java 方法。最后,我们得到了一个包含 18,233,872 个注释 Java 方法的语料库。

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

(1)方法名称提取:对于每个 Java 方法,我们提取它的名称,并根据驼峰命名法将名称解析为一系列 token。例如,方法名称列表文件将被解析为 token 列表和文件。

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

(3)token 提取:为了从 Java 方法中收集 token,我们对方法主体进行 token 化,根据驼峰命名法拆分每个 token,并删除重复的 token。 我们还删除了停止词(例如 the 和 in)和 Java 关键字,因为它们经常出现在源代码中,并且不是区分性的。

(4)描述提取:为了提取文档注释,我们使用 EclipseJDT 编译器从 Java 方法中解析 AST,并从 AST 中提取 JavaDoc 注释。

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

深度代码搜索

3.2 训练 CODEnn 模型

我们使用上一节中描述的大规模语料库来训练 CODEnn 模型。我们使用双向 LSTM,一种最先进的 RNN 实现。所有 LSTM 在每个方向都有 200 个隐藏单元。我们将单词嵌入的维度设置为 100。该 CODEnn 有两种类型的 MLP,用于嵌入单个 token 的嵌入 MLP 和融合 MLP,用于组合不同方面的嵌入。我们将嵌入 MLP 的隐藏单元数设置为 100,融合 MLP 的隐藏单元数设置为 400。

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

我们在 Keras 和 Theano 这两个开源深度学习框架上构建了我们的模型。我们在配备了一个 Nvidia K40 GPU 的服务器上训练我们的模型。训练时间大约 50 小时,总共有 500 轮。

3.3 搜索代码片段

给定用户的自由文本查询,DeepCS 通过经过训练的 CODEnn 模型返回相关的代码片段。它首先计算搜索代码库中每个代码片段(即 Java 方法)的代码向量。然后,它选择并返回具有与查询向量最近的 K 个代码片段。更特别的是,在搜索开始之前,DeepCS 将代码库中的所有代码片段以离线方式嵌入到向量中,使用经过训练的 CODEnn 模块。在在线搜索过程中,当开发人员输入自然语言查询时,DeepCS 首先使用经过训练的 CODEnn 模块将查询嵌入到向量中。然后,利用方程 11 估计查询向量与所有代码向量之间的余弦相似性。最后,返回向量与查询向量最相似的 K 个代码片段作为搜索结果。

4. 结论

本文提出了一种新的深度神经网络 CODEnn 用于代码搜索。CODEnn 学习源代码和自然语言查询的统一向量表示而不是匹配文本相似性,以便根据它们的向量检索与查询语义相关的代码片段。为了证明其可用性,基于所提出的 CODEnn 模型实现了一个代码搜索工具 DeepCS。我们的实验研究表明,该方法是有效的,优于相关的方法。 源代码和数据可在https://github.com/guxd/deep-code-search获取。

在未来,我们将研究源代码的更多方面,如控制流,以更好地表示源代码的高级语义。我们设计的深度神经网络也可能有利于其他软件工程问题,如 bug 定位。

推荐阅读
电路故障分析,电压表、电流表判断电路 2019-11-20 09:21
iPhone 11 电源电力测评,绿色版开箱分享 2019-09-23 17:24
物联网 (IoT) 使用多协议射频接口、多频段无线 SoC 部署 2020-06-09 12:12
夏普打造世界第一款全面屏到沦落为洋垃圾,各大厂商仍在突破前进 2020-07-17 17:12
数据驱动软件工程大规模下加速源代码分析 2020-07-27 10:58