當深度學習遇上代碼搜索

當深度學習遇上代碼搜索

引用

Jose Cambronero and Hongyu Li and Seohyun Kim and Koushik Sen and Satish Chandra. When deep learning met code search. In Proceedings of the 18th Joint Meeting on European Software Engineering Conference and Symposium on the Foundations of Software Engineering, 2019, 964-974.

摘要

近來很多人提議將深度神經網絡運用到使用自然語言的代碼搜索中。這些提議共同的思路是將代碼和自然語言查詢嵌入為實數向量,然後使用向量間的距離來近似代碼與查詢間的語義相關性。目前有多種技術可以學習這些嵌入,包括只依賴代碼案例語料庫的無監督技術和使用了成對代碼和自然語言描述的對齊語料庫的監督技術。監督的目的是為查詢及其所對應的期望的代碼塊產生更加相似的嵌入。

顯然,在是否使用有監督技術與使用何種技術來進行監督訓練上存在多種選擇。這篇論文首次對這些選擇進行了系統地評估。為此,我們收集幾種最先進技術的實現以運行在相同的平臺、訓練和評估語料庫上。為了探索在網絡複雜性的設計空間,我們還引入了一個新的設計,即對現有的無監督技術進行最小監督擴展。

我們的評估表明:1. 儘管不是必須的,但是對現有的無監督技術增加監督能夠提高性能。2. 在代碼搜索方面,用於監督的簡單神經網絡能夠比複雜的、基於序列的神經網絡表現得更加有效。3. 儘管在進行監督學習時用的往往是文檔字符串,但在效率方面,其與更加適用於查詢的監督語料庫間仍存在很大差距。

介紹

代碼搜索的目的在於通過自然語言從語料庫中檢索出最符合開發者期望的代碼片段。目前從 Github 等公開的代碼倉庫直接檢索代碼變得越來越困難,尤其是一些公司專有代碼倉庫中的特定的 API 和庫無法直接從 Google、StackOverflow 等渠道檢索到。但是,近期學術界和產業界已經著手將代碼搜索與深度學習相結合,我們將這樣的方法稱為神經代碼搜索。

當深度學習遇上代碼搜索

圖 1 展示了神經代碼搜索的大體框架並概括了幾種不同的技術。神經代碼搜索的關鍵抽象是嵌入(embeding)這一概念,他將輸入表示為同一向量空間的不同向量,並通過計算向量間的相似度來搜索與查詢在語義上相關的代碼片段。如圖 1 所示,用來學習這些向量表示的模型可以大致分為無監督的和有監督的。在本文的實驗中,作者先是使用了 NCS,這是一種高效的、無監督的神經代碼搜索技術。然後作者將 NCS 的結果作為基準,對幾種近期較有潛力的有監督神經代碼搜索技術進行了評估,包括 CODEnn 和 SCS,並觀察模型設計上的提高是否帶來了結果上的改善。

在如此多的神經代碼搜索技術中,如何做出明智的選擇?有監督技術帶來的提升能否彌補獲得監督學習的數據帶來的開銷?複雜網絡帶來的價值是否值得參數數量的增加?在此次實驗中,作者試圖對此做出定量的權衡。為此,作者為以上提到的神經代碼搜索技術設計了實驗,實驗中使用的是開源的語料庫,之後會介紹。表 1 展示了一些代碼搜索的結果:

當深度學習遇上代碼搜索

技術簡介

NCS (Neural Code Search):NCS 的嵌入函數 Ec (嵌入代碼)和 Eq(嵌入查詢)通過結合 fastText 和傳統的信息檢索技術 IF-IDF 實現,該模型沒有使用深度神經網絡和有監督技術。在 NCS 中代碼片段和查詢片段共用一個嵌入矩陣。

UNIF(Embedding Unification):UNIF 在 NCS 的基礎上增加了有監督技術,不同於 NCS,UNIF 使用兩個不同的嵌入矩陣 Tq 和 Tc,這兩個矩陣在訓練前為相同的矩陣 T,但通過分別訓練進行不同的演化。除此之外,UNIF 還將 NCS 中的 IF-IDF 賦權策略替換為訓練好的基於注意力的賦權策略。

CODEnn(Code Description Embedding Neural Network)、SCS(Semantic Code Search):相比於前兩個模型,CODEnn 與 SCS 的網絡結構更加複雜且層數更多,並且不再將代碼片段作為記號袋輸入。其中 CODEnn 將輸入(代碼片段)分為方法名序列、API 調用序列和記號袋分別提取並處理,方法名可以通過駝峰或蛇形命名法的規則提取。CODEnn 採用 LSTM 處理序列,而對於記號袋,採用多層前向神經網絡進行處理,最後的結果皆進行最大池化。SCS 將模型分為三個獨立的訓練模塊:GRU 模塊(sequence-to-sequence gated recurrent unit)學習將代碼序列轉換為文檔字符串序列、LSTM 模塊學習嵌入自然語言、最終模塊利用學習根據代碼序列預測一個自然語言查詢。SCS 模型將訓練好的 GRU 模塊作為 Ec,LSTM 模塊作為 Eq。

表 2 是對三種技術的彙總:

當深度學習遇上代碼搜索

語料庫介紹

實驗中使用了幾種不同的數據集和基準集:

訓練語料庫

訓練期間使用三種訓練語料庫:

  • CODEnn-Java-Train:CODEnn 的作者公開發布的數據集,由 1600 萬個預處理過的 Java 方法及其文檔字符串組成。該數據集有四種基本輸入類型,包括方法名序列、API 序列、方法體的記號袋以及文檔字符串序列,除此之外作者將方法名與 API 序列相連接,這種衍生的輸入專門用於訓練 UNIF 和 SCS。
  • GitHub-Android-Train:安卓專用的語料庫,包含作者從 Github 中越 26109 個標有安卓 tag 的倉庫中收集的方法及其文檔字符串,一共大約 787000 個,其基本輸入類型與 CODEnn-Java-Train 完全一致。
  • StackOverflow-Android-Train:同樣是安卓專用的語料庫,其內容來源於 Stack Overflow 上的提問及篩選過的代碼回答片段。其目的在於構造一個相對理想化的訓練語料庫,通過在這個語料庫上訓練,可以發現一些可能的性能提升空間,而這些通過傳統的以文檔字符串為自然語言的語料庫是很難發現的。

搜索語料庫

評估期間使用兩種搜索語料庫:

  • CODEnn-Java-Search:包含 400 萬個 Java 方法,由 CODEnn 的作者公開發布。
  • Github-Android-Search:包含 550 萬個 Github 上的安卓方法,來源於構造 GitHub-Android-Train 其語料庫的 Github 倉庫,中包括一些不含文檔字符串的方法。

基準查詢

實驗中使用了兩套查詢集作為模型評估的基準。在兩個基準集中,每一個查詢都對應 Stack Overflow 上的標題,並且其標準回答來源於對應帖子下被採納的或是點贊數最多的回答。這兩套基準集包括:

  • Java-50:包含 50 個查詢,其來源於 Stack Overflow 上票數最多的前 50 個 Java 編程問題,當使用這套基準集時,模型需要在 CODEnn-Java-Train 語料庫上訓練。
  • Android-518:包含個 518 安卓相關的查詢,當使用這套基準集時,模型需在 GitHub-Android-Train 上進行訓練。

表 3 是對這些語料庫的彙總:

當深度學習遇上代碼搜索

實驗設計

當深度學習遇上代碼搜索

由於人工評估搜索結果的方法可幾乎無複用性可言,作者設計了一種自動化評估管道。該管道採用相似性測度,其值記錄了查詢搜索結果與標準代碼片段的相似度,並用來評估一個查詢是否被正確回答。實驗中的標準查詢結果來源於 Stack Overflow 上的代碼回答。圖 6 顯示了該評估管道的結構。

為了判斷一個查詢是否被正確回答,該自動化管道需要設立一個相似度閾值。為此,兩位作者人工評估了 Java-50 基準查詢集在 CODEnn 和 UNIF 模型上獲得的前 10 個搜索結果與查詢的關聯程度,這一步驟是兩位作者分別進行的,並且過程中產生的分歧都通過了交叉驗證與重新評估,最終決定了一組關聯程度最高的搜索結果。接著作者根據標準結果進行了相似性測度,得出的數值近似滿足正態分佈,取其均值作為評估的相似度閾值。

在評估過程中,作者記錄下了在前 k 個結果中被成功回答的問題數量。實驗中只考慮前 1、5、10 個結果,對應的被成功解決的問題數記為 Answered@1、5、10。

實驗結果

問題 1:用基於查詢和代碼對的監督訓練拓展無監督技術是否能夠改善性能?

相比於 NCS 模型,UNIF 模型在其訓練過程中引入了有監督技術,並用注意力機制替換了 TF-IDF。表 4 顯示 UNIF 改善了在 Android-518 基準集上前 5 和前 10 個搜索結果中成功回答的問題數量,但是在第一的回答解決的問題數量上略顯不足,作者認為使用有監督技術拓展無監督技術能夠提高代碼搜索性能,但並不是在他們的所有數據集上都有此規律。

當深度學習遇上代碼搜索

問題 2:更加複雜的網絡是否能改善有監督神經代碼搜索的性能?

本文通過回答正確的查詢數量以及推斷速度來回答這個問題。首先,對於回答正確的查詢數量,表 5 顯示使用簡單詞袋方法的 UNIF 在所有基準查詢集上表現得都比 CODEnn 和 SCS 好,而 CODEnn 表現比 SCS 更好。其次,在推斷速度上,複雜的網絡需要維護更多的中間狀態,儘管嵌入代碼片段的時間可以忽略不計(因為可以離線處理),但嵌入自然語言片段的時間卻直接影響到神經代碼搜索系統的響應時間,因此會明顯更慢。實驗中計算了在各模型中嵌入代碼以及 CODEnn-Java-Train 中的自然語言描述所需的時間,其中代碼以 1000 個為單位,查詢以 1 個為單位,表 6 中展示的結果是 CODEnn 和 SCS 相比於 UNIF 的速率,可見基於序列的網絡開銷遠大於 UNIF。

當深度學習遇上代碼搜索

當深度學習遇上代碼搜索

問題 3:使用文檔字符串作為監督訓練的語料庫效率如何?

文檔字符串作為用戶查詢的替代品,由於其可以被大量的收集並作為監督訓練的對齊數據集,目前正被廣泛的用作訓練中使用的自然語言。但是,表 8 顯示出當在 GitHub-Android-Train 語料庫上進行監督訓練時,有監督技術相比於預期並不總是起到改善作用。而當換用理想化的訓練語料庫 StackOverflow-Android-Train 時,可以直觀的感受到有監督技術對於代碼搜索的改善,而這個語料庫是最符合實際用戶查詢的。表 7 顯示出在 StackOverflow-Android-Train 上訓練時所有的有監督技術都得到了可觀的改善。這表明當訓練語料庫中的自然語言部分與實際用戶查詢足夠符合時,有監督技術可以極大地提高代碼搜索的性能。

當深度學習遇上代碼搜索

表 8 是對實驗結果的彙總:

當深度學習遇上代碼搜索

本文貢獻

  1. 這篇論文是首次在同一平臺、使用相同的語料庫,對近期的神經代碼搜索技術進行比較和評估。
  2. 作者設計了一種新的神經代碼搜索系統:UNIF,此模型是一種對 NCS 最小限度的拓展,只引入了有監督技術而未做其他任何改動。
  3. 本實驗發現 UNIF 比一些更加複雜的網絡(CODEnn 和 SCS)表現的更為突出,同時也比作為無監督技術的 NCS 更加突出。除此之外,在監督訓練時對於對齊語料庫的選擇也十分重要:一個理想化的訓練語料庫可以證明有監督技術能夠實現傲人的性能,並能明顯地展現出有監督技術與無監督技術在性能上的差異,而通過在正規代碼語料庫以及對齊的文檔字符串語料庫上的訓練,卻無法將這個性能差異直接表現出來。

致謝

感謝國家重點研發計劃課題:基於協同編程現場的智能實時質量提升方法與技術(2018YFB1003901)和國家自然科學基金項目:基於可理解信息融合的人機協同移動應用測試研究(61802171)支持!

本文由南京大學軟件學院 2020 級碩士生孫昱翻譯轉述。


分享到:


相關文章: