目前,在GitHub上的代码搜索主要依赖于关键词搜索。这种方式依赖于用户对语法的理解或对注释中可能存在的关键词的预期。我们的机器学习专家正在研究一种能够进行代码语义搜索的方法。
如果读者希望更好地理解语义搜索的概念,可以考虑以下搜索请求:“ping REST API 并返回结果”。请注意,即使搜索请求和实际代码之间没有共同的关键词(代码和注释中并未出现“Ping”、“REST”或“API”),我们的语义搜索算法仍能提供有意义的结果。这种语义搜索的能力对于提升新软件工程师的效率和增加代码的可见性具有重要意义。
在本文中,我们将介绍如何利用深度学习技术在自然语言语义搜索方面取得进展,并分享一个开源示例以及实现这些结果所需的代码和数据。
目前,对代码仓库、代码、问题单、文件和用户等实体的表示学习是GitHub上正在进行的重要机器学习研究方向之一。通过学习代码和文本共享同一向量空间的表示方法,我们在促进语义搜索方面取得了显著进展。下面是一个示例:
在上述示例中,Text 2(蓝色)是对代码的合理描述,而Text 1(红色)则与代码完全无关。我们的目标是使表示相同概念的文本和代码对彼此靠近,而不相关的文本和代码对则远离。通过在相同的向量空间中表示代码和文本,我们可以将用户的搜索查询转化为向量,并找到最接近代码表示的向量。
为此,我们采取了以下四个步骤:
1. 学习代码的表示
为了学习代码的表示,我们训练了一个序列到序列(Seq2Seq)模型,该模型可以学会对代码进行总结。在Python环境中,我们可以通过提供(代码,文档字符串)对来实现这一目标,其中文档字符串是模型试图预测的目标变量。我们还在特定领域(如基于树结构的LSTM、门控图网络以及语法感知的分词处理)进行了一些优化研究。下面是一个代码总结模型的例子:在这个例子中,模型接收两个Python函数作为输入,并输出相应的代码总结。
需要注意的是,在上述例子中,模型通过整个代码块而不是仅仅函数名称来生成代码总结。我们还可以利用这个模型的编码器作为代码的通用特征提取器,进而建立代码到自然语言的向量空间映射。
我们可以使用BLEU得分来评估模型的性能。目前,我们已经能够使用fairseq-py代码库构建Seq2Seq模型,并在Python代码验证集上获得13.5的BLEU得分。
2. 学习短文本的表示
除了学习代码的表示外,我们还需要找到合适的短文本(例如,来自Python文档字符串的句子)的表示。起初,我们尝试使用通用的句子编码器,这是一种可以从TensorFlow Hub获取的预训练文本编码器。虽然目前的嵌入技术表现良好,但我们发现针对软件开发领域的词汇和语义进行专门学习仍然有益。目前的研究方向是评估不同特定领域语料库的效果,这些语料库包括从GitHub问题单到第三方数据集。
为了学习短文本的表示,我们使用fast.ai库训练了一个神经语言模型。该库允许我们轻松使用最先进的架构,如AWD LSTM,并采用随机重启的周期性学习率等技术。我们使用《Universal Language Model Fine-tuning for Text Classification》中提出的级联池化技术来抽取短文本的表示。
评估这些嵌入质量的一个挑战是建立下游监督任务,这可以帮助我们客观评估嵌入质量。同时,我们还通过人工检查相似短文本之间的相似度来验证嵌入效果。
3. 将代码表示映射到文本的向量空间
接下来,我们需要将从代码总结模型中学到的代码表示映射到文本的向量空间。我们通过对模型的编码器进行微调来实现这一点。该模型的输入仍然是代码块,但目标变量现在变成了文档字符串的向量化版本。这些文档字符串使用上一部分介绍的方法进行了向量化处理。
具体来说,我们使用余弦近似损失(即预测值与真实标签的余弦距离平均值的相反数)进行多维回归,将编码器的隐藏状态带入与文本相同的向量空间。我们正在积极研究直接学习代码和自然语言的联合向量空间的方法,借鉴了《Efficient Natural Language Response Suggestion for Smart Reply》中的部分思路。
4. 创建语义搜索系统
最后,在成功创建了一个可以将代码向量化到与文本相同向量空间的模型之后,我们可以构建一个语义搜索机制。最简单的方式是在数据库中存储所有代码的向量化版本,并对向量化搜索查询执行最近邻查找。
我们还在研究如何将语义搜索结果与现有的关键字搜索相结合,以及如何引入上下文语境和相关性等额外信息。此外,我们正在探索如何评估搜索结果的质量,以便在这一问题上快速迭代开发。我们计划在未来继续讨论这些话题。
总结
下面的示意图总结了我们当前语义搜索工作流程的所有步骤:
我们正在探索如何改进这种方法的几乎所有组成部分,包括数据准备、模型架构、评估过程以及整体系统设计。本文介绍的内容只是一个初步示例。