如何写最高端的代码Facebook教你怎样用机器学习做代码搜索工具

ag百家乐网址

来自Facebook AI博客

作者:Sonia Kim,Hongyu Li,Satish Chandra

机器的核心编译

参与:道,一鸣,思源

如何快速获取基于文本查询的代码示例对工程师来说是一个非常有影响力的事情。 Facebook最近推出了一种新的代码搜索工具,即神经代码搜索(NCS)和UNIF,它们分别基于无监督和监督方法提供快速有效的代码检索。

当工程师可以轻松获取代码示例并指导他们完成特定的编程任务时,他们的工作效率将显着提高例如,对于诸如“如何以编程方式关闭或隐藏Android软键盘?”之类的问题,工程师可以从Stack Overflow等热门网站获取信息。但是当问题涉及专有代码或API(或用编程语言中不常用的语言编写的代码)时,工程师需要不同的解决方案,因为他们可能无法在一个共同的论坛中找到答案。

为了满足这一需求,Facebook开发了一种代码搜索工具,即神经代码搜索(NCS),它使用本地语言处理(NLP)和信息检索(IR)技术来直接处理源代码文本。该工具将自然语言作为查询接收,并返回直接从代码库中检索的相关代码段。这里的前提是你可以获得一个庞大的代码库,这使得它更有可能搜索与开发人员提出的查询相关的代码片段。

Facebook推出了两款可用型号:

NCS:结合自然语言处理和信息检索技术的无监督模型; UNIF:NCS扩展,当训练期间有良好的监测数据时,UNIF使用监督神经网络模型来提高性能。

使用Facebook AI开源工具(包括fastText,FAISS,PyTorch),NCS和UNIF将自然语言查询和代码段表示为向量,然后训练网络,以便语义上相似的代码段和查询向量表示在向量中彼此接近空间。使用这些模型,我们能够直接从代码库中找到代码段,以有效地解决工程师的问题。为了评估NCS和UNIF,Facebook使用新创建的数据集(包含Stack Overflow上的公共查询和相应的代码片段答案)。结果表明,这两个模型可以正确回答数据集中的问题,例如:

如何关闭/隐藏Android软键盘?如何在Android中将位图转换为drawable?如何删除整个文件夹及其内容?如何处理后退按钮?

NCS的性能表明,相对简单的方法可以很好地处理源代码; UNIF的表现表明,简单的监督学习方法可以在可用的注释数据时提供显着的额外好处。当与其他Facebook构建系统(如Aroma和Getafix)结合使用时,该项目为工程师提供了可扩展且不断增长的ML工具包,以帮助他们更有效地编写代码和管理代码。

NCS如何使用嵌入向量

NCS模型使用嵌入(连续向量表示)来捕获程序语义(即,代码段的意图)。当进行适当的计算时,这些嵌入使具有相似语义的实体在向量空间中更紧密地结合在一起。

如下面的示例所示,有两种不同的方法可以关闭/隐藏Android软键盘。因为它们共享相似的语义,即使它们的代码行不相同,它们在向量空间中的位置也彼此接近。

0a531ab62a7f4dababd9cc4be1b5943b

上图显示具有相似语义的代码段在向量空间中更接近。

Facebook使用这个概念来构建NCS模型。通常,每个代码段都嵌入在模型生成过程中的方法级别的向量空间中。构建模型后,给定的查询将映射到相同的向量空间,向量距离可用于估计代码段与查询的相关程度。

下图显示了模型生成和搜索检索过程:

b42f969134d246e4b12a8d77748eba93

上图显示了NCS的整个模型生成和搜索检索过程。

模型生成

要生成模型,NCS必须提取单词,构建单词嵌入,然后构建文档嵌入。 (这里,“文档”指的是方法体。)

提取单词

031e3118a75d4aa98d81766c3a75b11a

NCS从源代码中提取单词并执行分词以生成单词的线性序列。

为了生成表示方法主体的向量,Facebook将源代码视为文本,从以下语法类中提取单词:方法名称,方法调用,枚举值,字符串文字和注释。然后根据标准英语规范(例如空格,标点符号)和与代码相关的标点符号(带下划线的命名法和驼峰命名法)执行分词。例如,在上图中,对于方法体(或方法名称)“pxToDp”,源代码可以用作以下单词的集合:“将dp px中的像素转换为dp获取资源获取显示度量”。

对于代码库中的每个方法体,我们可以使用此方法对源代码执行分词,并学习每个单词的嵌入。从每个方法体提取的单词列表则类似于自然语言文档。

构建单词嵌入

Facebook使用fastText为词汇语料库中的所有单词构建单词嵌入。 fastText使用双层神经网络来计算可以在大型语料库上以无人监督的方式训练的矢量表示。具体而言,Facebook使用skip-gram模型来利用目标令牌的嵌入来预测以固定窗口大小嵌入上下文令牌。如上例所示,给出了令牌“dp”的嵌入,并且窗口大小为2,并且skip-gram模型学习预测令牌的嵌入“像素”,“in”,“px, “ 并。”目标是学习嵌入式矩阵

4a4c27b48def4072887abd692c6be10c

,其中| V_c |表示语料库大小,d表示嵌入单词的维度,T中的第k行表示第k个单词在V_c中的嵌入。

在该矩阵中,如果两个向量指示相应的单词经常出现在类似的上下文中,则两个向量表示更近的距离。 Facebook使用命题的逆命题来帮助定义语义关系:具有近距离向量的词应该具有更高的语义相关性。这在自然语言处理中被称为“分布假设”,源文本同样适用于该概念。

构建文档嵌入向量

下一步是使用方法体中的单词来表达其总体意图。为此,研究人员计算了方法体中所有单词的嵌入向量的加权平均值。这称为文档嵌入。

713b81965f75499ba2515603ce202c28

在公式中,d表示方法体中的单词集,v_w是单词w的单词嵌入,使用fastText处理。 C是包含所有文档的语料库,u是规范化函数。

研究人员使用词频逆文档频率(TF-IDF)为给定文档中的给定单词分配权重。此步骤旨在强调文档中最重要的单词,即,如果一个单词经常出现在文档中,其权重很高,但如果它出现在语料库中的多个文档中,则词汇表将受到惩罚。

在此步骤之后,研究人员为语料库中的每个方法体提供文档向量的索引号。模型生成完成。

搜索和搜索

搜索查询可以用自然语言表示,例如“关闭/隐藏软键盘”或“如何创建没有标题的对话框”。研究人员以相同的方式对查询和源代码进行分词,并使用相同的fastText字嵌入矩阵T.研究人员简单地计算了单词矢量表示的平均值,创建了嵌入查询中的文档,并丢弃了词汇表之外的单词。该研究使用标准相似性搜索算法FAISS来查找与查询具有最接近的余弦相似性的文档向量,并返回前n个结果。 (除了一些训练后的排序,请参阅:https://dl.acm.org/citation.cfm?id=3211353)

883bac7e78ad4198ba564a8c2a60b695

两个方法体和查询映射在相同的向量空间中,并且位于更靠近的位置。这表明查询和两种方法在语义上相似且相关。

实验结果

研究人员使用Stack Overflow问题来测试NCS的性能。使用标题作为查询,并将答案中的代码段作为理想的代码答案。给定一个查询,研究人员评估模型是否可以从前面的1,5或10个响应中的GitHub存储库集合中提取正确的代码段。研究人员还提供了一个平均等级倒数(MRR)分数,用于衡量NCS是否可以在第n个结果中返回正确的答案。

在287个问题中,NCS能够正确回答前10个结果中的175个问题,这大约是整个数据集的60%。研究人员还比较了NCS和其他传统信息检索算法(如BM25)的性能。如下图所示,NCS的性能优于BM25。

7d0cce7562b646e9867a9ecd7a8c625f

以下是NCS的一个很好的答案示例:“从应用程序打开Android Market”,NCS返回的第一个答案如下:

私有空show showMarketAppIn(){

尝试{

startActivity(new Intent(Intent.ACTION_VIEW,Uri.parse('market: //details?id='+ BuildConfig.APPLICATION_ID)));

} catch(ActivityNotFoundException e){

startActivity(new Intent(Intent.ACTION_VIEW,Uri.parse('http://play.google.com/store/apps/details?id='

+ BuildConfig.APPLICATION_ID)));

}}

UNIF:监督方法

NCS的关键是字嵌入。由于NCS是无监督模型,因此具有许多优点。首先,它可以直接从搜索语料库中学习,训练非常快速而且非常简单。 NCS假定查询中的单词与从源代码中提取的单词具有相同的字段,因为查询和代码段映射在同一向量空间中。但事实并非总是如此。

例如,在“在内存中获取可用空间”中,以下代码段中不会出现任何单词。研究人员想要实现的是将查询词“自由空间”映射到以下代码中的“可用”一词。

文件路径=Environment.getDataDirectory();

StatFs stat=new StatFs(path.getPath());

长blockSize=stat.getBlockSize();

long availableBlocks=stat.getAvailableBlocks();

返回Formatter.formatFileSize(this,availableBlocks * blockSize);

基于包含14,005 Stack Overflow帖子的数据集,Facebook研究人员分析了查询术语和源代码中术语的重叠。他们发现查询中有13,972个唯一单词,其中不到一半(6072个单词)出现在源代码中。这意味着如果查询包含不在源代码中的单词,则NCS模型无法有效地检索正确的方法。这一结果促使研究人员进一步探索监督学习模型,将查询术语映射到源代码中。

4813c167983e4c39bb3d329fa3d0203e

Facebook研究员决定尝试UNIF。这是一个监督模型,具有基于NCS的小扩展,用于连接自然语言和源代码。在该模型中,研究人员使用监督学习训练词嵌入矩阵T,并分别生成两个嵌入矩阵T_c和T_q,分别对应于代码令牌和查询令牌。此外,研究人员用基于注意力的加权机制取代了代码令牌嵌入向量的TF-IDF加权机制。

UNIF模型如何运作

研究人员在与训练NCS相同的(c,q)数据点集中训练UNIF,其中c和q分别代表代码令牌和查询令牌。模型架构表示如下:

T_q∈R^ | V_q |×d和T_c∈R^ | Vc |×d是将每个自然语言描述词和代码令牌映射到向量的两个嵌入矩阵,向量长度为d(V_q是自然语言查询语料库) ),V_c是代码语料库)。这两个矩阵用相同的初始权重T初始化并在训练中单独修改(对应于fastText)。

为了将离散代码令牌向量组合成单个文档向量,研究人员使用注意机制来计算加权平均值。注意权重a_c∈R^ d,是从训练中学习并替换原始TF-IDF权重的d维向量。给定代码字包嵌入向量{e_1,.e_n},每个e_i的注意权重a_i如下:

a7edc8a0671e48cbbad78ba8d84f6c4c

通过单词嵌入向量乘以注意权重来添加文档向量:

d378680b615b4a0d96dc055b33ca9268

为了创建查询文档向量e_q,研究人员找到每个查询字的嵌入向量的平均值,这与NCS方法相同。在训练过程中,模型从标准反向传播中学习参数T_q,T_c,a_c。

87b9e4aa4ac84541898f35b56093229a

UNIF网络结构图。

搜索工作与NCS一致。给定查询,使用上述方法将其表示为文档向量,然后使用FAISS查找与查询具有最接近余弦相似性的文档向量。 (原则上,UNIF可以从后处理排序中受益,就像NCS一样。)

UNIF和NCS效应的比较

研究人员在Stack Overflow测量数据集上比较了NCS和UNIF的性能。评估方法是模型是否可以使用top1,top5,top10结果正确回答此查询,并评估MRR分数的使用。下表显示,与NCS相比,UNIF显着增加了回答的问题数量。

2773263b44334f0c8e7ff5d8df403e8a

如此惊人的搜索性能表明,如果提供合适的训练语料库,监督模型可以完成这项任务。例如,搜索查询是“如何退出应用程序并显示主菜单?”,NCS将返回:

Public void showHomeScreenDialog(View view){

Intent nextScreen=new Intent(getApplicationContext(),HomeScreenActivity.class);

startActivity(nextScreen);}

UNIF提供了更相关的代码:

Public void clickExit(MenuItem item){

Intent intent=new Intent(Intent.ACTION_MAIN);

intent.addCategory(Intent.CATEGORY_HOME);

intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

Metr.stop();

startActivity(意向);

光洁度();}

“如何获得ActionBar的高度?”,NCS模型将返回:

Public int getActionBarHeight(){

返回mActionBarHeight;

}

UNIF返回相关代码:

Public static int getActionBarHeightPixel(Context context){

TypedValue tv=new TypedValue();

如果(context.getTheme()。resolveAttribute(android.R.attr.actionBarSize,tv,true)){

返回TypedValue.complexToDimensionPixelSize(tv.data,

。context.getResources()getDisplayMetrics());

} else if(context.getTheme()。resolveAttribute(R.attr.actionBarSize,tv,true)){

返回TypedValue.complexToDimensionPixelSize(tv.data,

。context.getResources()getDisplayMetrics());

}否则{

返回0;

}}

有关UNIF性能的更多信息,请参阅文章:https://arxiv.org/abs/1905.03813。