code2vec 令牌嵌入的泛化能力评估

2020-7-27 17:59 2618 79

词嵌入模型的开发使许多自然语言处理(NLP)任务(例如情感分析或语法分析)受益匪浅。特别地,无论训练算法如何,学习到的嵌入常常被证明可推广到不同的 NLP 任务。相比之下,尽管最近在源代码的词嵌入方面有了发展势头,但是除了经过培训的示例任务以外,文献还没有证据表明它们具有泛化能力。

在这篇经验文章中,我们确定了可以应用源代码令牌嵌入模型的 3 个潜在的下游任务,即代码注释生成,代码作者身份标识和代码克隆检测。我们根据经验评估了最近提出的代码令牌嵌入模型,即 code2vec 的令牌嵌入。Code2vec 在预测方法名称的任务上接受了训练,尽管有可能在其他任务上使用它学习的向量,但文献中尚未对此进行探讨。因此,我们通过专注于已确定任务的泛化能力来填补这一空白。最终,我们证明了源代码令牌嵌入不能轻易地用于下游任务。我们的实验甚至表明,我们尝试使用它们不会导致较不复杂的方法有任何改进。我们要求对有效和泛化使用代码嵌入进行更多研究。

1. 介绍

软件工程领域的许多研究方向都提出了训练代码嵌入的新方法。但是,通常仅根据训练的单个任务对它们进行评估。与词嵌入在下游任务中有用的大量证据相反,几乎没有证据表明代码嵌入可在各种软件工程任务中使用。考虑到代码嵌入的希望,我们的工作是由这种需求来填补的,以填补确认代码嵌入模型的泛化能力的空白。将 code2vec 视为代码嵌入的代表,我们的研究调查了它是否可以成功地用于预测方法名称之外的各种软件工程任务中。

在本文中,我们评估了 code2vec 提出的令牌嵌入,以便在几个不同的软件工程下游任务中提供适当的源代码表示形式,即可以帮助学习代码嵌入的任务。这些任务与其原始的预测方法名称的培训任务没有直接关系。具体而言,我们建议使用源代码令牌嵌入来增强现有模型,以执行代码注释生成,代码作者身份识别和代码克隆检测等任务。然后,我们根据基准评估这些模型的性能

最初为考虑的任务设计的模型。我们提供了我们工作的复制包。本文做出了以下贡献:

  • 我们研究了 code2vec 为下游软件工程任务学习的令牌嵌入的泛化能力。据我们所知,这是文献中朝着这个方向的第一步。
  • 我们通过实验证明了 code2vec 的令牌嵌入可能无法推广:它们并不总是有助于显着提高每个软件工程任务的模型性能。
  • 我们对代码嵌入的通用性进行了全面的讨论,并激发了进一步研究可用于各种下游任务的新颖的源代码嵌入模型的需求。

2. 基础知识

我们的研究旨在回答一个研究问题:源代码令牌的嵌入是否可以泛化用于未经培训的任务?

我们研究的主要内容如下:

l 代码嵌入模型。在文献中,AST 的结构信息已被广泛用于构建模型。特别是,它已用于训练用于预测方法名称的源代码表示,这是软件工程文献中的常见任务。由于 code2vec 处于代码表示研究的这两个趋势的交汇处,因此我们选择它作为嵌入式模型中最有代表性的技术。在训练过程中,Code2vec 将整个代码段嵌入到单个向量中。但是,我们的工作重点是令牌训练所产生的令牌嵌入,因为它的粒度与词嵌入中使用的词令牌相似,并且词汇量更广,我们认为这可以使其更具通用性。

l 词嵌入模型。除了 code2vec 专用于源代码令牌之外,我们还考虑使用通用 NLP 词嵌入来建立比较基准。为此,我们将 GloVe 视为代表性的词嵌入技术,通过将源代码视为自然语言文本,在与 code2vec 类似的数据集上进行训练。

l 下游任务。我们确定了代码注释生成,代码作者身份标识和代码克隆检测的三个下游任务。对于每个任务,我们选择一种使用源代码令牌作为其输入一部分的现有方法。我们从最近的工作中选择模型或使用知名模型。对于代码注释生成和代码作者身份识别,我们使用 Hu 等人的最新著作。和 Abuhamad 等。分别。对于代码克隆检测,我们使用有据可查的基线模型 SourcererCC。我们尝试使用源代码令牌的嵌入来扩充这些模型。最后,我们将使用嵌入的模型的性能与较简单的模型作为基准进行比较。与 Fu 和 Menzies 在对软件工程中的机器学习方法进行比较研究中提供的建议相同,我们使用的第一个基准是不使用代码嵌入的更简单的基本模型。其次,我们将 code2vec 扩充模型与以相同方式扩充的模型进行比较,但是这次使用的是通过源代码令牌训练的 GloVe 向量。

3. 下游任务评估

在本研究中,我们考虑了针对可在嵌入中编码的源代码的不同属性的三个下游软件工程任务:(1)代码注释生成,(2)代码作者身份识别和(3)代码克隆检测。现在,我们简要描述每个任务的目标,我们使用的数据集以及评估过程。

为了评估代码嵌入,我们尝试使用代码嵌入来扩展现有模型,并观察所得的模型是否会导致性能提高。对于每个任务,我们从最近的论文中选择一个模型。每当不明显如何使用嵌入来增强现有模型时,我们都会提出一种新方法来将嵌入合并到其中。我们专注于使用基于令牌的技术,以使其易于通过代码嵌入来扩展模型。我们在这些任务中使用的技术也有所不同。三分之二的任务使用基于神经网络的方法,而最后一项任务则利用矢量空间计算来比较两个矢量的相似性。在这项研究中,我们不关注这些技术的整体有效性。相反,我们评估使用代码嵌入是否可以提高这些技术的性能。对于每个任务,我们选择数据集并使用类似于文献报道的实验设置。

A. 代码注释生成

我们的首要任务是代码注释生成。当我们将工作重点放在方法的粒度上时,此任务涉及从方法主体自动生成方法级别的注释。生成的方法注释应以描述性,高级自然语言语句的形式总结该方法提供的功能。该任务对软件维护和程序理解具有影响。为此任务开发的技术可以为开发人员带来广泛的好处,包括帮助软件重用,重新文档化和概念定位。最近的一些著作已经使用神经网络从源代码合成自然语言。

方法:对于此任务,有几种使用深度学习方法的技术。我们使用 Hu 等人提出的最新方法。在他们的方法中,他们将问题视为机器翻译任务。当将表示方法主体的代码片段中的数据预处理成表示 AST 节点的标记序列时,他们的方法会合并并保留 AST 的结构信息。基于递归神经网络的 Seq2Seq 语言模型用于将这些序列转换为自然语言代码注释。我们选择这种方法是因为它使用了神经网络方法,并使用了可以使用我们的代码嵌入的嵌入层。此外,他们的模型还提供了最新的结果。因此,我们遵循 Hu 等人描述的方法。

与 Hu 等人所做的预处理类似,我们仅采用 Javadoc 方法注释的第一句话,因为该第一句话通常是对基于 Javadoc 约定的方法提供的功能的描述。像 Hu 等人一样,我们从数据集中滤除了简单案例。如果注释为空或仅包含一个单词,我们将省略一对代码段和注释。此外,还将省略 getter,setter,构造函数和测试方法。

code2vec 令牌嵌入的泛化能力评估

我们显示了此任务的样本输入,摘自 Hu 等人的工作中的表 5。在清单 1 中。在这个示例中,事实输出将是 Javadoc 注释的第一句话(在本例中为唯一),概括了该方法。

指标 BLEU 用于衡量所生成评论的质量。这通常用于评估自然语言的机器翻译的性能,并衡量翻译与人工翻译的接近程度。BLEU 将生成的翻译和参考翻译作为输入,并输出介于 0 和 100 之间的百分比值,分数接近 100 表示质量更高。

事实证明,BLEU 量度与人类对翻译质量的认知高度相关。在软件工程文献中,这已用于评估多个任务,包括注释生成。BLEU 有几种变体,取决于 N 的值。在此任务中,由于 Hu 等人使用了 BLEU-4(即 N = 4),因此我们使用 BLEU-4。评估生成评论的质量。

为了准确地总结使用高级自然语言的方法,将需要一种技术来推断源代码的语义属性。因此,此任务可能对代码嵌入的编码语义信息的能力敏感。

训练:我们使用 OpenNMT 训练了一个基于递归神经网络的 Seq2Seq 语言模型。该模型由一个编码器-解码器网络组成。在编码器和解码器上,我们使用 2 个长期短期记忆(LSTM)层,每层中有 500 个隐藏单元。我们将学习率设置为 0.5,dropout 设置为 0.5,并将其训练 50 个 epoch。训练数据中总共有 330,000 种方法,我们将验证和测试数据限制为 5000 种方法。

该模型由一个嵌入层组成。当不使用 code2vec 和 GloVe 嵌入时,将使用随机初始化的矢量代替,类似于 Hu 等人的工作。我们有 2 个设置用于此任务的实验。由于来自 code2vec 的令牌全部为小写字母,因此我们对提取的 AST 树中的标识符进行了小写转换,并且还创建了 GloVe 矢量的版本,其令牌被小写了。为了进行更全面的评估,我们在上述 Java 大数据集中训练了一组新的 code2vec 嵌入。在这组嵌入中,单词不小写。

结果:我们将结果报告在表 I 中。由于 SBT 遍历为模型增加了结构信息,因此我们希望进行调查,否则会影响模型的性能。因此,我们展示了运行 seq2seq 模型而没有执行 SBT 遍历的预处理结果。在这种情况下,如果不对源代码中的稀有令牌进行处理,则存在超过 300,000 个在 code2vec 向量中未表示的令牌。表 II 给出了在注释生成中不使用 AST 节点信息的结果

code2vec 令牌嵌入的泛化能力评估

code2vec 令牌嵌入的泛化能力评估

发现:基于结果,似乎使用预先训练的嵌入并不能改善序列到序列的模型。最佳性能配置不使用其他代码 2vec 或 GloVe。但是,code2vec 令牌向量在每种设置下都优于 GloVe 向量,这表明结构信息在训练代码嵌入期间可能很有价值。这些结果表明,这种生成代码注释的方法不能利用在 GloVe 或 code2vec 向量中编码的任何语义信息来提高性能。

B. 代码作者身份识别

我们的第二个任务是确定简短程序的作者。虽然已经对自然语言文档的确定作者进行了广泛研究,但在源代码上进行这种工作的工作却很少。

此任务对隐私和安全性问题有很多影响。例如,有关此任务的技术可能被用来侵犯程序员的隐私。它们可能用于取消匿名化希望隐藏身份的程序员,例如比特币的创建者。这种技术的其他用途包括侵犯版权或抄袭。识别代码片段作者的过程对于识别恶意软件和其他恶意程序的作者也可能有用。

为了成功地识别作者,方法必须能够区分程序员代码中的编码风格。此任务中使用的技术利用了表达程序员编程风格的功能,例如布局和词汇功能。先前的工作已经发现,使用包含 unigram,bigrams 和 trigram 的 TF-IDF 功能的机器学习可用于高精度地识别程序。

方法:受 Abuhamad 等人工作的启发,我们提出了一个类似的神经网络。作为基准,我们将我们的方法与使用 TF-IDF 功能的模型进行了比较,Abuhamad 等人证明这是有效的。该网络由 2 个具有 1024 个节点的隐藏的全连接层组成。我们使用 dropout 进行正则化并将其设置为 0.6。我们使用前 1000 个 TF-IDF 功能,这些功能是通过使用每个功能和作者之间的 ANOVA F 值进行功能选择来确定的。而阿布哈马德等人的工作使用基于他们的神经网络中间输出的随机森林分类器,如果没有我们自己的修改,我们就无法在基于他们描述的体系结构的神经网络上复制好的结果。因此,我们对神经网络进行了一些修改,以使其能够产生相对准确的预测。由于我们的目标是评估代码嵌入而不是拥有一个先进的系统,因此,一旦我们在模型上取得了良好的性能,我们就不会使用将神经网络结果传递给随机森林分类器的第二步。

尽管我们的目标是评估代码嵌入,但我们无法用它们成功替换 TF-IDF 功能。我们尝试使用程序中代码矢量的平均值,并用一维平均代码矢量替换每个 TF-IDF 功能。这将产生 128 个特征(每个特征对应于代码矢量的一维)。但是,我们发现这会导致性能下降。进一步调整模型的超参数并没有改善其性能。

code2vec 令牌嵌入的泛化能力评估

由于我们的代码向量中有 1000 个 TF-IDF 特征,而只有 128 个维,因此输入特征的数量从 1000 个减少到 128 个。因此,不良的性能可能归因于特征数量的减少。我们试图训练一组新的 1000 维维度的 code2vec 向量。但是,这并没有提高模型的性能。因此,为了进一步评估在此任务上嵌入代码的可能性,我们使用了另一个使用 LSTM 层的神经网络。LSTM 神经网络具有允许输入可变长度的优点,因此我们可以将整个代码段输入到模型中。该神经网络包括 2 个隐藏的 LSTM 层,然后是一个完全连接的层。我们在图 2 中说明了神经网络。

我们将研究限于使用 Java 编写的程序,该程序使用与 code2vec 和 GloVe 向量相同的语言进行训练。对于 LSTM 神经网络,我们同时使用预训练的嵌入和随机初始化的嵌入。我们将精度表示为 0 到 100 之间的数字,其中 100 表示完美精度。对于每个模型,我们训练到 50 个 epoch。

结果:从表 III 中,我们看到同时使用 code2vec 和 GloVe 嵌入来初始化 LSTM 神经网络的性能低于随机初始化的嵌入层。此外,使用带有代码嵌入的 LSTM 神经网络的性能不及使用 TF-IDF 功能的完全连接的神经网络。当仅在完全连接的层的神经网络中使用代码嵌入时,我们获得的精度接近 0。

发现:比较 code2vec 向量和 GloVe 向量,GloVe 向量比 code2vec 向量具有更高的精度。这意味着 GloVe 嵌入可能比 code2vec 令牌嵌入更好地编码语法关系。但是,GloVe 和 code2vec 令牌嵌入的效果都优于随机初始化的一组嵌入。这表明 code2vec 令牌嵌入不能推广到代码作者身份识别的任务。最后,具有 TF-IDF 功能的模型是我们实验中性能最好的模型。使用 code2vec 令牌嵌入的性能

code2vec 令牌嵌入的泛化能力评估

code2vec 令牌嵌入的泛化能力评估

较差,表明它们无法区分代码作者的语法差异和 TF-IDF 功能。

C. 克隆代码检测

最后,我们的最后一个任务是检测代码克隆。代码克隆检测是确定一对代码片段是否彼此相似的任务。该任务在文献中受到了很多关注。检测代码克隆对软件开发和维护有很多影响。例如,代码克隆可能会增加维护成本,使软件设计复杂化,并且从长远来看,很难引入较小的更改。代码克隆也很可能导致错误通过软件系统中的复制粘贴行为传播。

方法:从技术角度来看,我们使用 SourcererCC(基于令牌的模型),该模型为 Type-1 至 Type-3 克隆提供了近乎最新的性能,作为我们工作的基础。SourcererCC 比较代码片段对中包含的令牌。为了高效地执行此操作,SourcererCC 使用它们识别出的几种属性和启发式方法来实施复杂的算法,以减少要执行的比较次数。但是,确定两个代码片段是否为代码克隆的主要标准是基于两个代码片段中都存在的令牌数量。给定 2 个代码片段 Bx 和 By,以确定它们是否为代码克隆,它将计算两个代码片段中重叠的令牌的数量,计算其重叠相似度,并将其与可配置的阈值 θ 进行比较,以识别这些片段是否为代码克隆。

为了使 SourcererCC 能够使用源代码令牌的向量,我们更改了标准,以确定一对代码片段是否为代码克隆。我们的标准不是基于标记之间重叠的基于计数的度量,而是基于 2 个代码片段的标记向量平均值的余弦相似性。先前的工作表明,自然语言和源代码的平均向量都可以用来表示较大的令牌片段。

因此,在我们对 SourcererCC 的改编中,对于两个代码片段 Bx 和 By,要被视为代码克隆,它们必须共享至少一个令牌,并且它们之间的余弦相似度应超过阈值 θ(在这项工作中,使用默认值 θ= 0.8)。出于可伸缩性的原因,要求共享至少一个令牌。如果没有此附加标准,则需要比较所有成对的代码片段,这对于我们的实验来说将是非常庞大的。对于代码片段中的标记而不是嵌入词汇中的标记,我们使用零向量。基于平均包含在 Bx 和 By 中的所有令牌向量,计算两个代码片段的余弦相似度。对令牌向量进行平均后,我们得到 X 和 Y,这是两个代码段中令牌向量的平均值,它们是 n 维空间中的向量。令 Xi 表示向量 X 的第 i 维值。

结果:如前所述,我们在两个数据集 BigCloneBench 和 OJClone 上评估了对 SourcererCC 的适应性。在 BigCloneBench 上的实验中,我们仅考虑大于 6 行和 50 个令牌的克隆。这是用于测量召回率的标准配置。如前所述,BigCloneBench 不提供评估精度的过程。表 IV 显示了我们对每种克隆类型的分析方法。为了便于解释,我们提供了文献中广泛使用的克隆类型分类的定义:

  • Type-1:相同的代码片段,其中空格,注释不同
  • Type-2:相同的代码片段,其标识符名称或文字值不同
  • Type-3:添加,修改或删除了语句的代码片段

*Type-4:在语义上几乎没有语法相似性地执行相同计算的代码片段。

可以基于语法相似性水平进一步拆分 Type-3 克隆。强 Type-3 克隆是指语法上相似的 Type-3 克隆,而弱 Type-3 克隆在语法上是相似的。

在 BigCloneBench 上评估 SourcererCC 的结果表明,代码嵌入的使用可改善在语法上不太相似的克隆类型(Type-3 和 Type-4)上对 SourcererCC 的调用,但可能会导致 Type-1 和 Type- 2 个克隆要删除。但是,尚不清楚其对精度的影响。

code2vec 令牌嵌入的泛化能力评估

code2vec 令牌嵌入的泛化能力评估

为了评估方法的精度,我们使用了第二个数据集 OJClone。我们使用了数据集中的所有 104 个编程竞赛问题,并将结果显示在表 V 中。由于该数据集中大约 1%的代码片段对是克隆对,因此我们引入了另一个基线,在该基线中我们随机接受一对代码片段作为代码 1%的时间会克隆。

OJClone 数据集中的克隆以前被认为是 Type-3 及以上类型。我们看到的召回率增加与我们在 BigCloneBench 基准测试中对 Type-3 和 Type-4 克隆观察到的一致。另一方面,结果表明我们的方法导致 SourcererCC 的精度下降。由于对 SourcererCC 的召回不佳,使用代码嵌入的方法的总体 F1 略高于单独使用 SourcererCC 时的 F1。

一种假设是,代码嵌入精度不佳是由任务数据集中遇到的大量令牌造成的,这些令牌在嵌入过程中语无伦次(OOV)。我们计算了我们的方法尝试检索代码向量的次数,以及该方法未能检索令牌的次数。计数示于表 VI。我们看到超过 95%的时间,我们的方法可以成功地检索程序片段中标记的向量。因此,语无伦次的标记并不是导致我们模型性能不佳的原因。

发现:结果:尽管使用嵌入的方法似乎可以改善 F1 的总体得分,但提高幅度很小。令人信服的是,使用代码嵌入的方法具有检测代码克隆所必需的代码片段的编码语义质量。总体而言,所有方法的召回率都很低,并且增强嵌入的方法会导致精度急剧下降(0.87 到小于 0.1)。因此,我们不能得出这样的结论:嵌入技术已成功提高 SourcererCC 检测克隆的能力。

从实际的角度来看,我们对 SourcererCC 的扩充也导致速度大幅下降,因为我们无法使用 SourcererCC 所采用的启发式方法来减少要比较的克隆对的数量。检测代码克隆的可伸缩性是实际使用中的一个关键问题,我们注意到我们的技术仅用于评估代码嵌入,并且由于缺乏可伸缩性,我们的技术可能不适合实际使用。

D. 经验

从上面的 3 个任务中,我们看到代码嵌入不能轻易用于改进简单模型。实际上,在三分之二的任务中,使用嵌入会降低添加到其中的模型的性能。在执行代码作者任务的情况下,诸如 TF-IDF 之类的简单方法要优于通过源代码令牌的嵌入而增强的模型。代码向量不会导致性能下降的唯一任务是检测代码克隆的任务。即使在此任务中,似乎也可以使用嵌入来交换 SourcererCC 的高精度以实现更高的查全率,同时保持相似的 F1 分数。

我们的发现支持 Fu 和 Menzies 的观察,即较简单的基准运行速度更快,并且可能优于复杂的技术,因此应将它们用作基准。我们看到,在代码作者身份识别的任务上,代码嵌入的使用表现不及使用简单 TF-IDF 功能的简单方法。同样,使用代码嵌入并不能提高 SourcererCC 的性能。简而言之,代码令牌的连续表示可能不一定比将代码令牌简单地视为符号的简单基准更好。

代码嵌入可能不是提高深度学习模型性能的灵丹妙药;其他考虑因素可能会产生更大的影响。例如,我们发现对数据进行预处理会对模型的性能产生重大影响。在软件工程领域有效使用神经网络的一个障碍是语音令牌不足的问题。 Hellendoorn 和 Devanbu 在之前就提出了这个问题,并在他们的工作中建议深度学习技术与大量的源代码词汇作斗争。他们通过非深度学习模型展示了自己的观点,该模型可以更新和扩展其词汇表,优于具有固定词汇表的深度学习模型。我们的实验验证了对代码注释生成任务进行预处理的重要性,其中,Hu 等人提出的将稀有令牌转换为 AST 节点类型的技术。从而提高了性能。另一方面,在代码克隆检测和代码作者任务中,尽管语音令牌似乎并不是这些任务上的问题,但我们的性能却很差。在代码作者身份识别任务中,仅 1000 个 TF-IDF 功能的基线功能就足以实现良好的性能。

源代码令牌嵌入的组成需要进一步研究。在自然语言的领域中,已经提出通过求和,平均或级联来组合标记的构造对于表示标记的较大片段可能是有用的。但是,在代码克隆检测任务中,这些运算符构成的源代码令牌似乎并不足够有意义地代表有效地检测代码克隆的令牌主体。我们认为,这一结果应能激发对其他操作员或组成代码嵌入的方法的研究。

我们发现缺乏代码嵌入的可解释性是这项工作中困难的根源。 SourcererCC 测量代码令牌重叠的标准既简单又易于解释,另一方面,我们的方法对代码向量进行平均会导致难以调试的表示形式。另外,我们的方法有实际的影响。原始 SourcererCC 具有基于基于计数的标准的启发式方法,可在较短的时间内运行并获得可比的 F 值。

最后,由于缺乏成功,我们面临着尝试使用代码嵌入来改进模型的尝试,这可能表明通过源代码学习的令牌嵌入可能无法编码大量可用于不同下游任务的语义或句法信息。我们无法在我们确定的 3 个下游任务中有效地使用 code2vec 或 GloVe 嵌入,这可能表明令牌嵌入的通用性不足。

我们认为,我们的发现将激励人们在寻找代码令牌的良好表示形式方面进行更多的工作,并且未来在代码表示方面的工作应旨在解决在下游任务上使用代码嵌入的困难。

致谢

本文由南京大学软件学院 2020 级博士生虞圣呈翻译转述。

推荐阅读
为什么华为愿出售5G技术,任正非采访回答全文 2019-09-17 11:10
比苹果还热的口罩生产设备【图纸学习】 2020-04-16 11:39
什么是晶振,电子表晶振为什么都是32.768K 2020-01-21 15:30
PCB挠性电路设计指南(性价比高的挠性电路互连方案) 2020-06-05 11:26
微型FM无线话筒电路图分析原理 2020-08-04 14:19