如何又快又好地搜索代碼?Facebook 提出基于機器學習的新工具!
2019-08-01 來源:raincent

日前,F(xiàn)acebook 提出了新型代碼搜索工具——神經(jīng)代碼搜索(NCS),能夠基于機器學習直接使用自然語言處理(NLP)和信息檢索(IR)技術(shù)處理源代碼文本,可大大提高代碼檢索效率。Facebook 在官網(wǎng)博客上對這項新成果進行了介紹,編譯如下。
當工程師能夠很容易地找到代碼示例來指導(dǎo)他們完成特定的編碼任務(wù)時,他們的工作狀態(tài)最佳。對于一些問題——例如,「如何通過編程關(guān)閉或隱藏 Android 軟鍵盤?」——相關(guān)信息隨時可以從像 Stack Overflow 這樣的常用資源中獲得。但是,專有代碼或 APIs(或用不太常見的編程語言編寫的代碼)的特定問題需要不同的解決方案,而論壇往往也不會探討這些問題。
為了滿足這一需求,我們開發(fā)了一個代碼搜索工具,它能夠直接使用自然語言處理(NLP)和信息檢索(IR)技術(shù)處理源代碼文本。這個工具叫做神經(jīng)代碼搜索(NCS),它接收自然語言作為查詢,并返回直接從代碼庫中檢索到的相關(guān)代碼片段。而它的前提是有可使用的大型代碼庫,從而有可能搜索到與開發(fā)者的查詢相關(guān)的代碼片段。在本文中,我們將介紹兩種模型來完成這一任務(wù):
NCS 是一種結(jié)合 NLP 和 IR 技術(shù)的無監(jiān)督模型。查看鏈接:https://dl.acm.org/citation.cfm?id=3211353&fbclid=IwAR2kUqUhkBP6tRlMJwvCWA-6vWWKccnckXeybOYEZpT1OpUZlIJ6q1l7SCA
UNIF 是 NCS 的一個擴展,它使用有監(jiān)督的神經(jīng)網(wǎng)絡(luò)模型來提升使用良好監(jiān)督數(shù)據(jù)訓(xùn)練時的性能。查看鏈接:https://arxiv.org/pdf/1905.03813.pdf?fbclid=IwAR3B0S-IMkHnhzBvCrnTaRu827HzjPJVMIxKDFghNJ8XKXDsGHcElX96HX0
利用開源 Facebook AI 工具(包括 fastText、FAISS 和 PyTorch),NCS 和 UNIF 均將自然語言查詢和代碼片段表示為向量,然后訓(xùn)練一個網(wǎng)絡(luò),使語義相似的代碼片段和查詢內(nèi)容的向量表征在向量空間中緊密結(jié)合。通過這些模型,我們可以直接從代碼庫中找到代碼片段,從而有效地回答工程師的問題。為了評估 NCS 和 UNIF,我們使用了在 Stack Overflow 上新創(chuàng)建的公共查詢數(shù)據(jù)集。我們的模型可以準確的回答這個數(shù)據(jù)集中的問題,例如:
如何關(guān)閉/隱藏 Android 軟鍵盤?
如何在 Android 中把位圖轉(zhuǎn)換成可繪制的?
如何刪除整個文件夾和內(nèi)容?
如何處理活動中的后退按鈕?
NCS 的表現(xiàn)顯示,相對簡單的方法在源代碼領(lǐng)域可以表現(xiàn)良好。UNIF 的表現(xiàn)顯示,當有標記的數(shù)據(jù)可用時,一個簡單的有監(jiān)督學習方法可以帶來顯著的額外收益。本項目與其他 Facebook 構(gòu)建的系統(tǒng)(如 Aroma 和 Getafix)一起,能為我們的工程師提供了一個廣泛的、不斷增長的 基于機器學習 工具包,幫助他們更有效地編寫和管理代碼。
NCS 如何使用嵌入
NCS 模型通過使用嵌入來捕獲程序語義(在本例中是代碼段的意思),即當適當計算連續(xù)向量表征時,能夠獲得將語義相似的實體彼此靠近放置在向量空間中的期望屬性。在下面的示例中,有兩個不同的方法體,它們都與關(guān)閉或隱藏 Android 軟鍵盤(上面的第一個問題)有關(guān)。因為它們具有相似的語義意思,即使它們沒有完全相同的代碼行,它們也由向量空間中彼此接近的點表示。

此圖顯示了相似的代碼段在向量空間中是如何聚集的。
(此圖顯示的公共代碼來源于 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 通用公共許可證下可共享使用。
我們使用這個概念來構(gòu)建 NCS 模型。在高層次上,模型生成過程中的每個代碼片段都以方法級粒度嵌入到向量空間中。一旦模型建立完成,給定的查詢將映射到相同的向量空間,并使用向量距離來評估代碼片段與查詢的相關(guān)性。本節(jié)將更詳細地描述模型生成和搜索檢索管道,如下圖所示。

此圖顯示了 NCS 的整體模型生成和搜索檢索過程。
模型生成
要生成模型,NCS 必須提取單詞,構(gòu)建單詞嵌入,然后構(gòu)建文檔嵌入。(這里的「文檔」參考了一種方法體。)
提取單詞

NCS 從源代碼中提取單詞并標記它們以生成單詞的線性序列。
(這里顯示的示例數(shù)據(jù)來自 GitHub 上公開可用的代碼,這些代碼在 Apache 2.0 許可下共享使用,地址為 https://github.com/sockeqwe/SecureBitcoinWallet/blob/master/app/src/main/java/de/tum/in/securebitcoinwallet/util/DimensUtils.java#L33-L36)
為了生成表示方法體的向量,我們將源代碼視為文本,并從以下語法類別中提。悍椒、方法調(diào)用、枚舉、字符串文本和注釋。然后,我們根據(jù)標準的英語慣例(如空格、標點符號)和與代碼相關(guān)的標點符號(如蛇形命名法和駝峰命名法)對其進行標記。例如,對于上圖中的方法體「pxToDp」,源代碼可以被視為單詞的集合:「converts pixelin dp px to dp get resources get display metrics」。
對于語料庫中的每個方法體,我們可以用這種方式標記源代碼,并學習每個單詞的嵌入。在此步驟之后,我們?yōu)槊總方法體提取的單詞列表類似于自然語言文檔。
構(gòu)建單詞嵌入

在這個矩陣中,如果相應(yīng)的單詞經(jīng)常出現(xiàn)在相似的上下文中,那么兩個向量表征就會很接近。我們使用與此相反的語句來幫助定義語義關(guān)系:向量越近的單詞應(yīng)該具有相關(guān)的含義。這在 NLP 文獻(相關(guān)文獻鏈接:https://www.tandfonline.com/doi/abs/10.1080/00437956.1954.11659520?fbclid=IwAR1xVI93AjRCAUKVRIr0g4PqzHi1ehZwwqDVdjumfshNVEEy14RK2e_5cAY)中被稱為分布假設(shè),我們認為同樣的概念也適用于源文本。
構(gòu)建文檔嵌入
下一步是使用方法體中出現(xiàn)的單詞來表達方法體的總體意圖。為此,我們對方法體中單詞集的單詞嵌入向量取加權(quán)平均值。我們稱之為文檔嵌入。

上式中,d 是代表方法體的單詞組,是單詞 w 的 fastText 單詞嵌入,C 是包含所有文檔的語料庫,u 是一個歸一化函數(shù)。
我們使用詞頻-逆本文頻率函數(shù)(TF-IDF),它為給定文檔中的給定單詞分配權(quán)重。它的目標是突出文檔中最具代表性的單詞——如果一個單詞經(jīng)常出現(xiàn)在文檔中,它的權(quán)重就會更高,但是如果它出現(xiàn)在語料庫中過多的文檔里,它也會受到懲罰。
在這一步的末尾,我們有了語料庫中每個方法體到其文檔向量表征的索引,并且模型生成已經(jīng)完成。
搜索檢索
搜索查詢用自然語言語句進行表示,如「關(guān)閉/隱藏軟鍵盤」或「如何創(chuàng)建沒有標題的對話框」。我們采用與源代碼相同的方式對查詢進行標記,并使用相同的 fastText 嵌入矩陣 T,我們對單詞的向量表征進行簡單平均來為查詢語句創(chuàng)建文檔嵌入;不含查詢單詞的詞會被刪除。然后,我們使用標準的相似度搜索算法 FAISS 來找到距離查詢余弦距離最近的文檔向量,并返回 topn 結(jié)果(加上一些后處理的排序,該文有進一步解釋,論文鏈接:https://dl.acm.org/citation.cfm?id=3211353)。

這兩個方法體和查詢被映射到同一向量空間中相鄰的點。這意味著查詢和這兩個方法體在語義上是相似的,并且與查詢相關(guān)。
結(jié)果
我們使用 Stack Overflow 問題評估了 NCS 的性能,用標題進行查詢,回答中的代碼片段作為所需的代碼答案。給定一個查詢,測量我們的模型是否能夠從 GitHub 存儲庫的集合中檢索并在前 1、5 和 10 個結(jié)果中得出正確答案(分別在下面的表中標記為 Answered@1、5、10)。我們還給出了平均倒數(shù)秩(MRR),以衡量 NCS 能夠在第幾個結(jié)果中正確地回答問題。我們將在下文更詳細地解釋實驗設(shè)置。在我們創(chuàng)建的 Stack Overflow 評估數(shù)據(jù)集里的 287 個問題中,NCS 在前 10 個結(jié)果中正確地回答了 175 個問題;這相當于整個數(shù)據(jù)集的 60% 以上。我們還將 NCS 的表現(xiàn)與傳統(tǒng)的 IR 技術(shù) BM25 進行了比較。如表所示,NCS 優(yōu)于 BM25。

NCS 表現(xiàn)良好的一個問題例子是「從 APP 中啟動 Android 市場」,其中 NCS 返回的第一個結(jié)果如下:

(該代碼片段來自 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:探索監(jiān)督方法
NCS 的關(guān)鍵在于它使用了單詞嵌入。因為 NCS 是一個無監(jiān)督的模型,它有幾個顯著的優(yōu)點:它可以通過搜索語料庫直接學習,并且可以快速、方便地進行訓(xùn)練。NCS 假定查詢中的單詞與從源代碼中提取的單詞來自同一域,因為查詢和代碼片段都映射到同一向量空間。然而,情況并非總是如此。例如,查詢「Get free space on internal memory」中沒有任何單詞出現(xiàn)在下面的代碼段中。我們想要的是將查詢詞「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 帖子的數(shù)據(jù)集中,我們分析了查詢中的單詞與源代碼中的單詞的重疊情形。我們發(fā)現(xiàn),在查詢中的 13,972 個單獨單詞中,只有不到一半(6,072 個單詞)同時存在于源代碼域中。這表明,如果查詢包含源代碼中不存在的單詞,那么我們的模型將不能進行有效地正確檢索,因為我們刪除了與查詢詞無關(guān)的單詞。這種觀察促使我們探索監(jiān)督學習,將查詢中的單詞映射到源代碼中的單詞。

我們決定使用 UNIF(NCS 技術(shù)的監(jiān)督最小擴展)進行實驗,以彌補自然語言單詞和源代碼單詞之間的差距。在該模型中,我們使用監(jiān)督學習方法對嵌入矩陣 T 進行修改,生成兩個分別用于代碼和查詢標記的嵌入矩陣 和
。我們還用一種學習的注意力機制權(quán)重方案替換了代碼標記嵌入的 TF-IDF 權(quán)重方案。
UNIF 模型如何工作
我們對 UNIF 進行與 NCS 相同的(c,q)數(shù)據(jù)點集合的訓(xùn)練,其中 c 和 q 分別表示代碼和查詢符號(有關(guān)此數(shù)據(jù)集的詳細信息,請參見下面的部分)。模型體系結(jié)構(gòu)可描述如下:令





然后將文檔向量計算為注意力權(quán)重加權(quán)后的單詞嵌入向量之和:


UNIF網(wǎng)絡(luò)
檢索的工作方式與 NCS 的方式相同。對于給定的查詢,我們使用上述方法將其表示為文檔向量,并使用 FAISS 查找與查詢余弦距離最近的文檔向量。(原則上,UNIF 也會像 NCS 一樣從后處理排名中受益。)
與 NCS 進行結(jié)果比較
我們基于 Stack Overflow 評估數(shù)據(jù)集將 NCS 和 UNIF 進行比較,看看模型是否能在前 1、5 和 10 個結(jié)果中正確地回答查詢,以及相應(yīng)的 MRR 評分。下表顯示,相比 NCS,UNIF 顯著提高了回答的問題數(shù)量。

這突出表明,如果能夠訪問理想的訓(xùn)練語料庫,監(jiān)督技術(shù)可以提供令人印象深刻的搜索性能。例如,使用搜索查詢「如何退出應(yīng)用程序并顯示主屏幕?」,NCS 返回結(jié)果:

(第一個代碼片段來自于 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 返回結(jié)果:

(第一個代碼片段來自于 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)
本文還提供了關(guān)于 UNIF 表現(xiàn)的其他數(shù)據(jù),鏈接:https://arxiv.org/abs/1905.03813?fbclid=IwAR10r1Y_3kKQ1nJ6OBWILQSa3xPS4rDjOBPQ2FC_SnwyNgJ532jwy-QfDHg。
構(gòu)建基于機器學習的有效工具
創(chuàng)建一個成功的機器學習工具,關(guān)鍵之一在于獲得高質(zhì)量的訓(xùn)練數(shù)據(jù)集。對于我們的模型,我們使用了來自 GitHub 的大型開源代碼庫。此外,擁有高質(zhì)量的評估數(shù)據(jù)集對于評估模型的質(zhì)量同等重要。在探索一個相對較新的研究領(lǐng)域(如代碼搜索)時,缺乏可用的評估數(shù)據(jù)集會限制我們通過各種代碼搜索工具進行評估的能力。因此,為了幫助在這方面進行基準測試,我們從 Stack Overflow 整理了 287 個公共可用數(shù)據(jù)點的數(shù)據(jù)集,其中每個數(shù)據(jù)點由一個自然語言查詢和一個「黃金」代碼片段回答組成。
創(chuàng)建一個訓(xùn)練數(shù)據(jù)集
通過在 GitHub 上挑選 26,109 個最受歡迎的 Android 項目,我們直接在搜索語料庫上訓(xùn)練我們的無監(jiān)督模型 NCS。這也成為 NCS 返回代碼片段的搜索語料庫。
為了對我們的 UNIF 模型進行監(jiān)督,我們需要一對對齊的數(shù)據(jù)點來學習映射。我們對 UNIF 進行了(c,q)數(shù)據(jù)點集合的訓(xùn)練,其中 q 是自然語言描述或查詢,c 是相應(yīng)的代碼片段。我們通過從 Stack Exchange(CC-BY-SA 3.0 許可)公開發(fā)布的數(shù)據(jù)(鏈接:https://archive.org/details/stackexchange)中提取 Stack Overflow 問題標題和代碼片段來獲得這個數(shù)據(jù)集。在使用各種啟發(fā)式方法過濾問題之后——例如,代碼片段必須有一個 Android 標記,或者必須有一個方法調(diào)用,或者不能包含 XML 標記——我們最終得到了 451,000 個訓(xùn)練數(shù)據(jù)點。這個數(shù)據(jù)集與評估查詢不相交。(這反映了訓(xùn)練數(shù)據(jù)集的最佳可用性;正如我們在一篇論文(該論文鏈接:https://arxiv.org/abs/1905.03813?fbclid=IwAR16thFXpe8iOKKfTNpGni9tpYDbYAxqRF8GotMPP-Jwhtja4CvBSvHmG0s)中所注意到的,基于文檔字符串的訓(xùn)練沒有得到好的結(jié)果。)
評估數(shù)據(jù)集
我們使用 Stack Overflow 問題評估 NCS 的有效性。Stack Overflow 是一種有用的評估資源,因為它包含大量的自然語言查詢,以及可以作為可接受響應(yīng)處理的向上投票的答案。給定一個 Stack Overflow 問題作為查詢標題,NCS 從 GitHub 檢索方法列表。在我們創(chuàng)建和改進 NCS 的工作中,我們認為如果來自 NCS 的 topn 結(jié)果中至少有一個與 Stack Overflow 應(yīng)答代碼片段中描述的方法匹配,那么搜索就成功了。(對于我們的評估,我們使用 top1、top5 和 top10 進行計算。)
我們使用腳本選擇 Stack Overflow 問題,標準如下:1)問題包含「Android」和「Java」標簽;2)有一個向上投票的代碼答案;3)真值代碼片段在我們的 GitHub Android repos 語料庫中至少有一個匹配。通過人工處理確保問題是可接受的,我們得到了 287 個問題的數(shù)據(jù)集。
使用 Aroma 進行自動評價
我們發(fā)現(xiàn),手工評估搜索結(jié)果正確性的操作很難重復(fù)進行,因為不同的作者和不同的人可能會有不同的觀點。我們決定使用 Aroma 實現(xiàn)一個自動化的評估管道。Aroma 給出搜索結(jié)果與真值代碼片段之間的相似性評分,以評估在得分超過閾值的情形下查詢是否被正確回答。有了這個管道,我們可以用一種可重現(xiàn)的方式對模型進行評估。我們使用 Stack Overflow 上找到的代碼答案作為評估的真值。
我們使用的上述評估過程不僅比較了 UNIF 和 NCS,還將 UNIF 與文獻中其他一些代碼搜索解決方案進行了比較。(相關(guān)比較的詳細鏈接如下:https://arxiv.org/pdf/1812.01158.pdf?fbclid=IwAR0x2bvo-ItQHCeqdSb4f139HBpJdyzuQU0Famiwx52jCsWQKQu3MWuNdN4)
一個用于編寫和編輯代碼的基于機器學習的擴展工具包
隨著大型代碼存儲庫在當今生產(chǎn)環(huán)境中廣泛可用,機器學習可以提取模式和觀點,從而提高工程師的工作效率。在 Facebook,這些機器學習工具包括帶有 Aroma 的代碼到代碼推薦和帶有 Getafix 的自動 bug 修復(fù)。NCS 和 UNIF 是代碼搜索模型的例子,它們可以在自然語言查詢和查找相關(guān)代碼片段之間架起橋梁。使用諸如此類的工具,工程師將能夠輕松地找到并使用相關(guān)代碼片段,即使是在使用專有源代碼或使用不太常用的編程語言編寫代碼時也是如此。未來,我們希望在綜合領(lǐng)域探索其他的深度學習模式,進一步提高工程師的工作效率。
相關(guān)文章
(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/
版權(quán)申明:本站文章部分自網(wǎng)絡(luò),如有侵權(quán),請聯(lián)系:west999com@outlook.com
特別注意:本站所有轉(zhuǎn)載文章言論不代表本站觀點!
本站所提供的圖片等素材,版權(quán)歸原作者所有,如需使用,請與原作者聯(lián)系。