Hamel's modelhtml
如何实现semantic search?在已有数据库的基础上,衡量一个句子和每段代码的相关性再进行排序,选出最优代码片断便可实现一个通用的code search接口。为了计算code和nlp的类似度,咱们须要创建一个代码空间和语言空间共享的向量空间,以下图git
分别把code和天然语言映射到这个向量空间,就能够对比{text, code}的类似度从而选择类似度最高的进行匹配。因此咱们输入天然语言text来搜索代码时,将该语言片断转换成共享空间重点vector,再从code构造的vector数据库中寻找类似度最高的进行匹配并返回。github
整个过程可分为五步:docker
数据预处理,从数据库中提取出代码(函数)、docstring及代码路径。经过代码创建一个词汇表,将代码转化成向量,接下来要做为encoder的输入。docstring是代码的comment,也用词汇表转化成向量做为监督训练encoder的label。保存代码路径是为了查找匹配成功时索引到源码返回给用户。数据库
这里使用了Seq2Seq模型,而且采用了teacher forcing的训练策略。什么是teacher forcing呢?RNN模型一般在预测下一个step T时,是将前面T-1个step的输出看成输入来预测,但teacher forcing策略将前T-1个step的Ground Truth做为当前输入。网络
Seq2Seq模型采用了一个Encoder和decoder结构,并采用GRU来构建。框架
使用fast.ai中的AMD_LSTM模型,输入docstring来训练,预测句子中的下一个单词。训练好的模型迁移到编码短词组或句子上。什么是AMD_LSTM模型呢?AMD_LSTM是当前最早进的语言模型之一,在字符模型上也展示了突出的成功。一个简单描述就是,它使用了一些正则化方法、DropConnect策略以及NT-SGD优化器等方式改进了传统的LSTM网络使得它拥有了更好的泛化语言的能力。函数
在预训练好的Seq2Seq模型基础上,用code向量为输入及上一步训练好的language model的输出为监督,对上上步的Code encoder进行fine-tuning,使之将code向量映射到共享空间。工具
该模型提供了一种通用的code2nlp的双向转换方式,而且每一步都有很大的可扩展性,而且采用了迁移学习来获得共享的向量空间。可是也存在一些改进空间:性能
咱们复现的是项目Semantic Code Search,主要参考的是博客How To Create Natural Language Semantic Search For Arbitrary Objects With Deep Learning
因为项目环境配置过程过于复杂,咱们使用了做者推荐的Docker容器: hamelsmu/ml-gpu。咱们的机器配置,硬件为12核的Intel Core i9 CPU,2块NVIDIA RTX 2080 Ti,系统为Ubuntu 16.04,CUDA版本为10.1,使用Python3.6。
从BigQuery中下载数据,其数据格式以下图所示:
使用AST库存,将这些数据首先解析为(code, docstring)对,结果以下:
将上表中的pair
项中的数据展开为function_name
, lineno
等,接着对数据进行去重,并根据有无docstring
(至少3个单词)对数据进行划分,接着对有docstring
的数据分别按照0.87, 0.82的比例对数据进行train,test,valid,获得的结果以下所示:
最后讲划分的数据每一类按照function
, docstring
, linage
存储。这一步花费的时间很长,为了节省时间,咱们只处理了一部分数据,后面使用的都是做者提供的数据。
在这一步中,会训练一个Seq2Seq的模型,这个模型能够预测给定代码段的docstring
。
对该模型进行训练,因为咱们的卡不是很强,咱们修改了batchsize
和迭代的次数
对训练的模型进行测试
讲训练好的模型保存再本地,以备使用
这个模型的做用是能够用docstring
生成embedding
。
首先处理该模型须要的数据,将数据存在本地。这里直接使用了做者提供的接口。利用这些数据训练一个Fast.AI模型,
使用训练好的模型处理Docstring
,这里的时间太长了,咱们中途中止了处理,后面直接使用做者处理好的。
Code
映射到Embeding
空间中的模型这里须要使用到前面训练好的Seq2Seq
模型中的decoder和前面的docstring-embeding
模型。
首先加载Seq2Seq
中的encoder
在其后面加上Dense
获得Code2Emd
模型
加载docstring-embeding
模型,命名为fastailm_emb
,在训练Code2Emd
模型时使用它
前面咱们先将encoder
固定住来训练该模型,此时在对整个模型进行一些训练,以便使模型在该数据上表现更好。
在训练好以后,使用该模型将全部的Code
生成Embedding
.
使用做者提供的search_enigne类
进行测试
因为做者提供了完整的代码,可是因为咱们在硬件上的限制,在训练次数上要比做者少,并且一些很耗时间的refine也没有作,因此咱们的模型效果比起原来的应该要略差一点。
复现中的难点有两个,一个是数据的处理,另外一个就是环境的配置。载数据的处理上若是稍不留神,那么咱们的模型就根本不可能训练好,所以在实现过程当中使用了不少断言来保证数据的正确性。起初咱们是在一个新的Anaconda环境下实现的,可是项目中的各类库和依赖配置起来太耗费时间和经历,因此中途转到用docker了,复现工做一下进度就上来了。而模型原理中最重要的部分其实是迁移学习的步骤,也就是对seq2seq模型的fine-tuning。
咱们的改进动机是提升Code Summarizer在将代码映射到向量空间的性能,这就须要咱们利用代码中更多固有的先验知识,具体想法是将代码表示成树的结构。
在baseline中,Code Summarizer 对代码的处理是比较暴力的,将代码也看成天然语言进行处理,虽然能够获得合理的结果,但这个步骤从直觉上存在很大的提高空间,实际上代码的做者在其文中提到了这个summarizer自己就能够是一个很酷的项目,并建议读者在此引入优化。
从做业给出的参考连接的code2vec中能够获得启发,将function或者method转换成语义树的结构应该比直接将代码parse成词汇能保留更多的语义信息,应该能够提升编码器的性能。
code2vec工具中对code的表示:
Code Summarizer以代码树做为输入须要引入基于树的LSTM (tree-lstm)(一种图神经网络),区别于sentence-lstm。
改进的Code Summarizer以下
咱们小组三我的一开始就有明确的分工,分别负责阅读基线模型原理和代码、配置运行环境与实验、阅读其余模型,以后发现基线模型对于code的representation很是简单,与实际的代码组织方式相比还不够贴切。分工以后,伙伴们都对本身的工做作的比较好,可是可能由于有其余的工做要忙,须要沟通的时候回复不太及时,常常把开会时间定的很 晚:)。对小伙伴的建议就是,团队项目仍是赶早不赶晚,先开会商量好分工就不会那么盲目了。