.

如何写最高端的代码Facebook教你怎

选自FacebookAIBlog

作者:SoniaKim、HongyuLi、SatishChandra

机器之心编译

参与:路、一鸣、思源

如何基于文本查询快速获取代码示例,对于工程师而言是一个很影响效率的事儿。Facebook最近提出了新型代码搜索工具——神经代码搜索(NCS)和UNIF,分别基于无监督和监督的方式提供快速高效的代码检索。

当工程师能够轻松获取代码示例,指导其完成特定编程任务时,他们的工作效率会显著提高。例如,对于「如何以编程方式关闭或隐藏安卓软键盘?」这类问题,工程师可以从StackOverflow等常用网站上获取可用信息。但是当问题涉及专有代码或API(或者用不常用编程语言写的代码)时,工程师需要不同的解决方案,因为在常用论坛上可能找不到这方面的答案。

为了解决这个需求,Facebook开发了一个代码搜索工具——神经代码搜索(NeuralCodeSearch,NCS),该工具使用自然语言处理(NLP)和信息检索(IR)技术直接处理源代码文本。该工具接收自然语言作为查询(query),并返回从代码库中直接检索到的相关代码段。这里的前提是能够获取大型代码库,从而更有可能搜索到与开发者提出的查询相关的代码段。

Facebook介绍了两种可用模型:

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

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

如何关闭/隐藏安卓软键盘?如何在安卓中将位图转换为可画的?如何删除一整个文件夹及其内容?如何处理backbutton?

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

NCS如何使用嵌入向量

NCS模型使用嵌入(连续向量表示)来捕捉程序语义(即代码段的意图)。当进行恰当计算时,这些嵌入能够将语义相近的实体在向量空间中拉近距离。

如下图示例所示,关于如何关闭/隐藏安卓软键盘有两个不同的方法。由于它们共享类似的语义,因此即使它们代码行不完全相同,它们在向量空间中的位置彼此接近。

上图表明语义相近的代码段在向量空间中距离较为接近。

Facebook使用这个概念构建NCS模型。总体而言,在模型生成过程中,每个代码段以方法级粒度嵌入到向量空间中。一旦模型构建完成,给定的查询语句就会映射到同样的向量空间中,那么向量距离就可用于估计代码段与查询的相关程度。

下图展示了模型生成和搜索检索流程:

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

模型生成

为了生成模型,NCS必须抽取单词,构建词嵌入,然后构建文档嵌入。(这里「文档」指方法体(methodbody)。)

抽取单词

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

为了生成能表示方法体的向量,Facebook将源代码看作文本,从以下句法类中抽取单词:方法名称、方法调用、枚举值、字符串文本和注释。然后基于标准英语规范(如空格、标点)和代码相关标点(如下划线命名法和驼峰命名法)执行分词。例如上图中,对于方法体(或方法名)「pxToDp」,源代码可作为以下单词的集合:「convertspixelindppxtodpgetresourcesgetdisplaymetrics」。

对于代码库中的每个方法体,我们都可以用这种方法对源代码执行分词,并为每个词学习一个嵌入。之后,从每个方法体中抽取的单词列表类似一个自然语言文档。

构建词嵌入

Facebook使用fastText为词汇语料库中的所有单词构建词嵌入。fastText使用一个两层神经网络计算向量表示,该网络可以在大型语料库上以无监督方式训练。具体来讲,Facebook使用skip-gram模型,利用目标token的嵌入来预测固定窗口大小中的上下文token的嵌入。如上例所示,给出token「dp」的嵌入、窗口大小为2,skip-gram模型学习预测token「pixel,」、「in,」、「px,」、「to.」的嵌入。其目标是学习嵌入矩阵

,其中

V_c

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

在该矩阵中,如果两个向量表示对应的单词经常出现在相似语境,则这两个向量表示距离较近。Facebook使用该命题的逆命题帮助定义语义关系:向量距离接近的单词应该语义相关性较高。这在自然语言处理中叫作「分布假设」(distributionalhypothesis),源文本同样适用于这一概念。

构建文档嵌入向量

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

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

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

在这一步之后,研究人员给语料库中每个方法体的文档向量表示一个索引数字。模型生成就完成了。

搜索检索

搜索查询可以用自然语言表达,例如「关闭/隐藏软键盘」或「如何建立一个没有标题的对话框」。研究人员使用同样的方式对查询和源代码执行分词,且使用同样的fastText词嵌入矩阵T。研究人员简单地计算了词向量表示的平均值,建立一个查询语句的文档嵌入,词表外的词被舍弃。研究使用标准的相似度搜索算法FAISS,用于寻找和查询的余弦相似度最接近的文档向量,并返回topn个结果。(此外还有一些训练后排序,详情参见:


转载请注明:http://www.abachildren.com/ysty/2406.html