當前位置︰首頁 > 新聞資訊 > 正文

如何又快又好地搜索代碼?Facebook 提出基于機器學習的新工具!2019-07-29 15:33:39 | 編輯︰hely | 查看︰ | 評論︰0

日前,Facebook 提出了新型代碼搜索工具——神經代碼搜索(NCS),能夠基于機器學習直接使用自然語言處理(NLP)和信息檢索(IR)技術處理源代碼文本,可大大提高代碼檢索效率。

日前,Facebook 提出了新型代碼搜索工具——神經代碼搜索(NCS),能夠基于機器學習直接使用自然語言處理(NLP)和信息檢索(IR)技術處理源代碼文本,可大大提高代碼檢索效率。Facebook 在官網博客上對這項新成果進行了介紹,編譯如下。

當工程師能夠很容易地找到代碼示例來指導他們完成特定的編碼任務時,他們的工作狀態最佳。對于一些問題——例如,「如何通過編程關閉或隱藏 Android 軟鍵盤?」——相關信息隨時可以從像 Stack Overflow 這樣的常用資源中獲得。但是,專有代碼或 APIs(或用不太常見的編程語言編寫的代碼)的特定問題需要不同的解決方案,而論壇往往也不會探討這些問題。

為了滿足這一需求,我們開發了一個代碼搜索工具,它能夠直接使用自然語言處理(NLP)和信息檢索(IR)技術處理源代碼文本。這個工具叫做神經代碼搜索(NCS),它接收自然語言作為查詢,並返回直接從代碼庫中檢索到的相關代碼片段。而它的前提是有可使用的大型代碼庫,從而有可能搜索到與開發者的查詢相關的代碼片段。在本文中,我們將介紹兩種模型來完成這一任務︰

NCS 是一種結合 NLP 和 IR 技術的無監督模型。查看鏈接︰https://dl.acm.org/citation.cfm?id=3211353&fbclid=IwAR2kUqUhkBP6tRlMJwvCWA-6vWWKccnckXeybOYEZpT1OpUZlIJ6q1l7SCA

UNIF 是 NCS 的一個擴展,它使用有監督的神經網絡模型來提升使用良好監督數據訓練時的性能。查看鏈接︰https://arxiv.org/pdf/1905.03813.pdf?fbclid=IwAR3B0S-IMkHnhzBvCrnTaRu827HzjPJVMIxKDFghNJ8XKXDsGHcElX96HX0

利用開源 Facebook AI 工具(包括 fastText、FAISS 和 PyTorch),NCS 和 UNIF 均將自然語言查詢和代碼片段表示為向量,然後訓練一個網絡,使語義相似的代碼片段和查詢內容的向量表征在向量空間中緊密結合。通過這些模型,我們可以直接從代碼庫中找到代碼片段,從而有效地回答工程師的問題。為了評估 NCS 和 UNIF,我們使用了在 Stack Overflow 上新創建的公共查詢數據集。我們的模型可以準確的回答這個數據集中的問題,例如︰

如何關閉/隱藏 Android 軟鍵盤?
如何在 Android 中把位圖轉換成可繪制的?
如何刪除整個文件夾和內容?
如何處理活動中的後退按鈕?

NCS 的表現顯示,相對簡單的方法在源代碼領域可以表現良好。UNIF 的表現顯示,當有標記的數據可用時,一個簡單的有監督學習方法可以帶來顯著的額外收益。本項目與其他 Facebook 構建的系統(如 Aroma 和 Getafix)一起,能為我們的工程師提供了一個廣泛的、不斷增長的 基于機器學習 工具包,幫助他們更有效地編寫和管理代碼。

NCS 如何使用嵌入

NCS 模型通過使用嵌入來捕獲程序語義(在本例中是代碼段的意思),即當適當計算連續向量表征時,能夠獲得將語義相似的實體彼此靠近放置在向量空間中的期望屬性。在下面的示例中,有兩個不同的方法體,它們都與關閉或隱藏 Android 軟鍵盤(上面的第一個問題)有關。因為它們具有相似的語義意思,即使它們沒有完全相同的代碼行,它們也由向量空間中彼此接近的點表示。

 

 

此圖顯示了相似的代碼段在向量空間中是如何聚集的。

(此圖顯示的公共代碼來源于 Github(https://github.com/kabouzeid/Phonograph/blob/master/app/src/main/java/com/kabouzeid/gramophone/ui/activities/SearchActivity.java#L162-L167,https://github.com/RooyeKhat-Media/iGap-Android/blob/master/app/src/main/java/net/iGap/module/SoftKeyboard.java#L78-L83),在 GNU 通用公共許可證下可共享使用。

我們使用這個概念來構建 NCS 模型。在高層次上,模型生成過程中的每個代碼片段都以方法級粒度嵌入到向量空間中。一旦模型建立完成,給定的查詢將映射到相同的向量空間,並使用向量距離來評估代碼片段與查詢的相關性。本節將更詳細地描述模型生成和搜索檢索管道,如下圖所示。

 

 

此圖顯示了 NCS 的整體模型生成和搜索檢索過程。

模型生成

要生成模型,NCS 必須提取單詞,構建單詞嵌入,然後構建文檔嵌入。(這里的「文檔」參考了一種方法體。)

提取單詞

 

 

NCS 從源代碼中提取單詞並標記它們以生成單詞的線性序列。

(這里顯示的示例數據來自 GitHub 上公開可用的代碼,這些代碼在 Apache 2.0 許可下共享使用,地址為 https://github.com/sockeqwe/SecureBitcoinWallet/blob/master/app/src/main/java/de/tum/in/securebitcoinwallet/util/DimensUtils.java#L33-L36)

為了生成表示方法體的向量,我們將源代碼視為文本,並從以下語法類別中提取︰方法名、方法調用、枚舉、字符串文本和注釋。然後,我們根據標準的英語慣例(如空格、標點符號)和與代碼相關的標點符號(如蛇形命名法和駝峰命名法)對其進行標記。例如,對于上圖中的方法體「pxToDp」,源代碼可以被視為單詞的集合︰「converts pixelin dp px to dp get resources get display metrics」。

對于語料庫中的每個方法體,我們可以用這種方式標記源代碼,並學習每個單詞的嵌入。在此步驟之後,我們為每個方法體提取的單詞列表類似于自然語言文檔。

構建單詞嵌入

 

 

在這個矩陣中,如果相應的單詞經常出現在相似的上下文中,那麼兩個向量表征就會很接近。我們使用與此相反的語句來幫助定義語義關系︰向量越近的單詞應該具有相關的含義。這在 NLP 文獻(相關文獻鏈接︰https://www.tandfonline.com/doi/abs/10.1080/00437956.1954.11659520?fbclid=IwAR1xVI93AjRCAUKVRIr0g4PqzHi1ehZwwqDVdjumfshNVEEy14RK2e_5cAY)中被稱為分布假設,我們認為同樣的概念也適用于源文本。

構建文檔嵌入

下一步是使用方法體中出現的單詞來表達方法體的總體意圖。為此,我們對方法體中單詞集的單詞嵌入向量取加權平均值。我們稱之為文檔嵌入。

 

 

上式中,d 是代表方法體的單詞組,是單詞 w 的 fastText 單詞嵌入,C 是包含所有文檔的語料庫,u 是一個歸一化函數。

 

我們使用詞頻-逆本文頻率函數(TF-IDF),它為給定文檔中的給定單詞分配權重。它的目標是突出文檔中最具代表性的單詞——如果一個單詞經常出現在文檔中,它的權重就會更高,但是如果它出現在語料庫中過多的文檔里,它也會受到懲罰。

在這一步的末尾,我們有了語料庫中每個方法體到其文檔向量表征的索引,並且模型生成已經完成。

搜索檢索

搜索查詢用自然語言語句進行表示,如「關閉/隱藏軟鍵盤」或「如何創建沒有標題的對話框」。我們采用與源代碼相同的方式對查詢進行標記,並使用相同的 fastText 嵌入矩陣 T,我們對單詞的向量表征進行簡單平均來為查詢語句創建文檔嵌入;不含查詢單詞的詞會被刪除。然後,我們使用標準的相似度搜索算法 FAISS 來找到距離查詢余弦距離最近的文檔向量,並返回 topn 結果(加上一些後處理的排序,該文有進一步解釋,論文鏈接︰https://dl.acm.org/citation.cfm?id=3211353)。

 

 

這兩個方法體和查詢被映射到同一向量空間中相鄰的點。這意味著查詢和這兩個方法體在語義上是相似的,並且與查詢相關。

結果

我們使用 Stack Overflow 問題評估了 NCS 的性能,用標題進行查詢,回答中的代碼片段作為所需的代碼答案。給定一個查詢,測量我們的模型是否能夠從 GitHub 存儲庫的集合中檢索並在前 1、5 和 10 個結果中得出正確答案(分別在下面的表中標記為 Answered@1、5、10)。我們還給出了平均倒數秩(MRR),以衡量 NCS 能夠在第幾個結果中正確地回答問題。我們將在下文更詳細地解釋實驗設置。在我們創建的 Stack Overflow 評估數據集里的 287 個問題中,NCS 在前 10 個結果中正確地回答了 175 個問題;這相當于整個數據集的 60% 以上。我們還將 NCS 的表現與傳統的 IR 技術 BM25 進行了比較。如表所示,NCS 優于 BM25。

 

 

NCS 表現良好的一個問題例子是「從 APP 中啟動 Android 市場」,其中 NCS 返回的第一個結果如下︰

 

 

(該代碼片段來自 Github 上公開可用的代碼,在 MIT 許可下共享使用,鏈接︰https://github.com/mobulum/android-receipts/blob/master/app/src/main/java/tech/receipts/ui/activity/MainActivity.java?fbclid=IwAR3so6yP5Tr0NkwBakiS_kioKckldh_Z97IpxmDy8H8O2scBfKKAK31MHhs#L388-L395)

UNIF︰探索監督方法

NCS 的關鍵在于它使用了單詞嵌入。因為 NCS 是一個無監督的模型,它有幾個顯著的優點︰它可以通過搜索語料庫直接學習,並且可以快速、方便地進行訓練。NCS 假定查詢中的單詞與從源代碼中提取的單詞來自同一域,因為查詢和代碼片段都映射到同一向量空間。然而,情況並非總是如此。例如,查詢「Get free space on internal memory」中沒有任何單詞出現在下面的代碼段中。我們想要的是將查詢詞「free space」映射到代碼中的「available」一詞。

 

 

(該代碼片段取自 Stack Overflow 上的公開可用代碼,在 CC-By-SA 3.0 許可下共享使用,鏈接︰https://stackoverflow.com/questions/4595334/get-free-space-on-internal-memory?fbclid=IwAR1wMoa6js7pSDmzuXZERspW4FUqdwY6tEtmbvOlN8hVFbu8OAAWCa2yDdE)

從 14,005 個 Stack Overflow 帖子的數據集中,我們分析了查詢中的單詞與源代碼中的單詞的重疊情形。我們發現,在查詢中的 13,972 個單獨單詞中,只有不到一半(6,072 個單詞)同時存在于源代碼域中。這表明,如果查詢包含源代碼中不存在的單詞,那麼我們的模型將不能進行有效地正確檢索,因為我們刪除了與查詢詞無關的單詞。這種觀察促使我們探索監督學習,將查詢中的單詞映射到源代碼中的單詞。

 

 

我們決定使用 UNIF(NCS 技術的監督最小擴展)進行實驗,以彌補自然語言單詞和源代碼單詞之間的差距。在該模型中,我們使用監督學習方法對嵌入矩陣 T 進行修改,生成兩個分別用于代碼和查詢標記的嵌入矩陣 。我們還用一種學習的注意力機制權重方案替換了代碼標記嵌入的 TF-IDF 權重方案。

 

UNIF 模型如何工作

我們對 UNIF 進行與 NCS 相同的(c,q)數據點集合的訓練,其中 c 和 q 分別表示代碼和查詢符號(有關此數據集的詳細信息,請參見下面的部分)。模型體系結構可描述如下︰令

為兩個嵌入矩陣,分別將每個單詞從自然語言描述和代碼符號映射到一個長度為 d 的向量(為查詢詞匯語料庫,為代碼詞匯語料庫)。使用相同的初始權重 T 初始化這兩個矩陣,並在訓練期間分別進行修正(與 fastText 對應)。為了將每組代碼符號向量合成一個文檔向量,我們使用注意力機制來進行加權平均計算。注意力權重是訓練中學習到的一個 d 維向量,與 TF-IDF 對應。給定一組代碼字嵌入向量 {e1,…,en},每一個 ei 的注意力權重 ai 計算如下︰

 

 

 

然後將文檔向量計算為注意力權重加權後的單詞嵌入向量之和︰

 

 

 

 

 

 

UNIF網絡

檢索的工作方式與 NCS 的方式相同。對于給定的查詢,我們使用上述方法將其表示為文檔向量,並使用 FAISS 查找與查詢余弦距離最近的文檔向量。(原則上,UNIF 也會像 NCS 一樣從後處理排名中受益。)

與 NCS 進行結果比較

我們基于 Stack Overflow 評估數據集將 NCS 和 UNIF 進行比較,看看模型是否能在前 1、5 和 10 個結果中正確地回答查詢,以及相應的 MRR 評分。下表顯示,相比 NCS,UNIF 顯著提高了回答的問題數量。

 

 

這突出表明,如果能夠訪問理想的訓練語料庫,監督技術可以提供令人印象深刻的搜索性能。例如,使用搜索查詢「如何退出應用程序並顯示主屏幕?」,NCS 返回結果︰

 

 

(第一個代碼片段來自于 GitHub 上的公共可用代碼,在 Apache 2.0 許可下共享使用,鏈接︰https://github.com/selendroid/selendroid/blob/master/selendroid-test-app/src/main/java/io/selendroid/testapp/WebViewActivity.java?fbclid=IwAR222brn93ZC3KK8kcTJhDhNMv8hc6JYSxv6KfQSSaklcm5WtLvmsc0uBQ0#L111-L114。第二個來自于 GitHub,在 MIT 許可下共享使用,鏈接︰https://github.com/JosielSantos/android-metronome/blob/master/app/src/main/java/com/josantos/metronome/ui/activity/Base.java?fbclid=IwAR2xhso5v0vCAQBcNJ0DDg1DZLVdtC1hf5doVqwC1ib_rTB5bm38VSzLomo#L28-L36)

另一個例子是查詢「如何獲得 ActionBar 的高度?」NCS 返回結果︰

 

 

(第一個代碼片段來自于 GitHub 上的公共可用代碼,在 Apache 2.0 許可下共享使用,鏈接︰https://github.com/RealMoMo/Android_Utils/blob/master/SystemBarTintManager.java?fbclid=IwAR0SaLCK1xR18fxlfSvG72wcD4RBLnh7aZLNvCIls-Pe926LOpQ-2rmKPd0#L495-L497。第二個來自于 GitHub,同樣在 Apache 2.0 許可下共享使用,鏈接︰https://github.com/hearsilent/Universal-CollapsingTabLayout/blob/master/app/src/main/java/hearsilent/universalcollapsingtoolbarlayouttablayoutexample/libs/Utils.java?fbclid=IwAR38dLHvVRwZWGZoFTW6aniRbWQ0OAXAptH1lF-t1zyFuhopAJJVbGzkMpU#L36-L47)

本文還提供了關于 UNIF 表現的其他數據,鏈接︰https://arxiv.org/abs/1905.03813?fbclid=IwAR10r1Y_3kKQ1nJ6OBWILQSa3xPS4rDjOBPQ2FC_SnwyNgJ532jwy-QfDHg。

構建基于機器學習的有效工具

創建一個成功的機器學習工具,關鍵之一在于獲得高質量的訓練數據集。對于我們的模型,我們使用了來自 GitHub 的大型開源代碼庫。此外,擁有高質量的評估數據集對于評估模型的質量同等重要。在探索一個相對較新的研究領域(如代碼搜索)時,缺乏可用的評估數據集會限制我們通過各種代碼搜索工具進行評估的能力。因此,為了幫助在這方面進行基準測試,我們從 Stack Overflow 整理了 287 個公共可用數據點的數據集,其中每個數據點由一個自然語言查詢和一個「黃金」代碼片段回答組成。

創建一個訓練數據集

通過在 GitHub 上挑選 26,109 個最受歡迎的 Android 項目,我們直接在搜索語料庫上訓練我們的無監督模型 NCS。這也成為 NCS 返回代碼片段的搜索語料庫。

為了對我們的 UNIF 模型進行監督,我們需要一對對齊的數據點來學習映射。我們對 UNIF 進行了(c,q)數據點集合的訓練,其中 q 是自然語言描述或查詢,c 是相應的代碼片段。我們通過從 Stack Exchange(CC-BY-SA 3.0 許可)公開發布的數據(鏈接︰https://archive.org/details/stackexchange)中提取 Stack Overflow 問題標題和代碼片段來獲得這個數據集。在使用各種啟發式方法過濾問題之後——例如,代碼片段必須有一個 Android 標記,或者必須有一個方法調用,或者不能包含 XML 標記——我們最終得到了 451,000 個訓練數據點。這個數據集與評估查詢不相交。(這反映了訓練數據集的最佳可用性;正如我們在一篇論文(該論文鏈接︰https://arxiv.org/abs/1905.03813?fbclid=IwAR16thFXpe8iOKKfTNpGni9tpYDbYAxqRF8GotMPP-Jwhtja4CvBSvHmG0s)中所注意到的,基于文檔字符串的訓練沒有得到好的結果。)

評估數據集

我們使用 Stack Overflow 問題評估 NCS 的有效性。Stack Overflow 是一種有用的評估資源,因為它包含大量的自然語言查詢,以及可以作為可接受響應處理的向上投票的答案。給定一個 Stack Overflow 問題作為查詢標題,NCS 從 GitHub 檢索方法列表。在我們創建和改進 NCS 的工作中,我們認為如果來自 NCS 的 topn 結果中至少有一個與 Stack Overflow 應答代碼片段中描述的方法匹配,那麼搜索就成功了。(對于我們的評估,我們使用 top1、top5 和 top10 進行計算。)

我們使用腳本選擇 Stack Overflow 問題,標準如下︰1)問題包含「Android」和「Java」標簽;2)有一個向上投票的代碼答案;3)真值代碼片段在我們的 GitHub Android repos 語料庫中至少有一個匹配。通過人工處理確保問題是可接受的,我們得到了 287 個問題的數據集。

使用 Aroma 進行自動評價

我們發現,手工評估搜索結果正確性的操作很難重復進行,因為不同的作者和不同的人可能會有不同的觀點。我們決定使用 Aroma 實現一個自動化的評估管道。Aroma 給出搜索結果與真值代碼片段之間的相似性評分,以評估在得分超過閾值的情形下查詢是否被正確回答。有了這個管道,我們可以用一種可重現的方式對模型進行評估。我們使用 Stack Overflow 上找到的代碼答案作為評估的真值。

我們使用的上述評估過程不僅比較了 UNIF 和 NCS,還將 UNIF 與文獻中其他一些代碼搜索解決方案進行了比較。(相關比較的詳細鏈接如下︰https://arxiv.org/pdf/1812.01158.pdf?fbclid=IwAR0x2bvo-ItQHCeqdSb4f139HBpJdyzuQU0Famiwx52jCsWQKQu3MWuNdN4)

一個用于編寫和編輯代碼的基于機器學習的擴展工具包

隨著大型代碼存儲庫在當今生產環境中廣泛可用,機器學習可以提取模式和觀點,從而提高工程師的工作效率。在 Facebook,這些機器學習工具包括帶有 Aroma 的代碼到代碼推薦和帶有 Getafix 的自動 bug 修復。NCS 和 UNIF 是代碼搜索模型的例子,它們可以在自然語言查詢和查找相關代碼片段之間架起橋梁。使用諸如此類的工具,工程師將能夠輕松地找到並使用相關代碼片段,即使是在使用專有源代碼或使用不太常用的編程語言編寫代碼時也是如此。未來,我們希望在綜合領域探索其他的深度學習模式,進一步提高工程師的工作效率。

相關文章

(1)Aroma: Using machine learning for code recommendation

鏈接︰https://ai.facebook.com/blog/aroma-ml-for-code-recommendation/

(2)Recap of first-ever Glow Summit

鏈接︰https://ai.facebook.com/blog/glow-summit-recap/

(3)Getafix: How Facebook tools learn to fix bugs automatically

鏈接︰https://ai.facebook.com/blog/getafix-how-facebook-tools-learn-to-fix-bugs-automatically/

Via︰https://ai.facebook.com/blog/neural-code-search-ml-based-code-search-using-natural-language-queries/

上一篇︰機器學習在高德起點抓路中的應用實踐 數據中台不是技術平台,沒有標準架構下一篇︰

公眾平台

搜索"raincent"或掃描下面的二維碼

?