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很是簡單,與實際的代碼組織方式相比還不夠貼切。分工以後,夥伴們都對本身的工做作的比較好,可是可能由於有其餘的工做要忙,須要溝通的時候回覆不太及時,常常把開會時間定的很 晚:)。對小夥伴的建議就是,團隊項目仍是趕早不趕晚,先開會商量好分工就不會那麼盲目了。