Facebook 發佈 TransCoder:實現C ++到Java、Python的代碼轉化 | 論文解讀

近日,Facebook 的研究人員表示,已經開發出一種神經網絡編譯器,可以將代碼從一種高級編程語言(如 C ++,Java 和 Python)轉換爲另一種。

Facebook 正式發佈TransCoder

在過往的IT技術變遷史中,不乏有將代碼庫遷移到主流或更高效語言,如 Java 或 C++的案例,這需要開發人員具備源語言和目標語言方面的專業知識,而且通常成本很高。例如,澳大利亞聯邦銀行在 5 年內花費了約 7.5 億美元將其平臺從 COBOL 轉換爲 Java。超編譯器在理論上可以提供幫助,它們消除了從頭開始重寫代碼的過程,但在實踐中卻很難應用,因爲不同的語言可能有不同的語法,並依賴於不同的平臺 API、標準庫函數和變量類型。

爲簡化這一問題,Facebook 推出了 TransCoder ,該工具採用無監督學習,可以讓代碼在 C ++,Java 和 Python 之間進行轉換。

論文地址: https://arxiv.org/pdf/2006.03511.pdf

根據研究人員的說法,TransCoder 在實驗過程中展示了對每種語言特有的語法、數據結構及其方法的理解,並且在跨編程語言的情況下正確對齊了庫,同時適應了較小的修改(例如當輸入已重命名)。儘管它並不完美,例如 TransCoder 在生成過程中未能考慮某些變量類型,但它的性能仍然比一些框架要優秀。

該工具的一位共同作者寫道:TransCoder 可以輕鬆推廣到任何編程語言,不需要任何專業知識,並且在很大程度上優於商業解決方案。我們的研究結果表明,通過向解碼器添加簡單的約束以確保生成的函數在語法上是正確的,或者通過使用專用架構,可以輕鬆解決該模型所犯的許多錯誤。

模型

對於TransCoder,Facebook考慮了一個帶注意力的seq2seq模型,這個模型由一個編碼器和一個帶有transformer架構的解碼器組成。所有的編程語言都共享同一個模型,使用Lample et al. 中定義的無監督機器翻譯的三個原理來訓練它,即初始化、語言建模和回譯。本節總結了這些原理,並詳細介紹瞭如何在實例中編譯編程語言(下圖1給出了方法說明)。

跨編程語言模型預訓練

預訓練是無監督機器翻譯Lample中的重要一環。它能確保具有相似意義的序列被映射到相同的latent representation上,而不用考慮它們是哪種編程語言。最初,預訓練是通過用跨語言詞彙表徵初始化模型來完成的。在無監督英法翻譯語境中,“cat”這個詞的嵌入與其法語翻譯 “chat”的嵌入接近。通過訓練單語言詞彙嵌入並讓這些嵌入以無監督的方式訓練,可以得到跨語言詞彙嵌入。

隨後的工作表明,以跨語言的方式預訓練整個模型(而不僅僅是詞彙表徵)可以使無監督機器翻譯得到顯著改善。特別是,遵循Lample和Conneau的預訓練原則進行訓練時效果尤爲明顯——即在單語言源代碼數據庫上,用掩碼語言建模objective預訓練跨語言模型(XLM)。

所得模型的跨語言性質來自於不同語言間存在的海量通用標記(錨點)。在英法翻譯的語境中,錨點基本上由數字、城市和人名組成。在編程語言中,這些錨點通常由常見的關鍵詞組成(如for、while、if、try),也包括數字、數學運算符和源代碼中出現的英文字符串。

對於掩碼語言建模(MLM)objective來說,在每次迭代時,Facebook都會考慮源碼序列的輸入流,隨機屏蔽掉一些標記,並訓練TransCoder來根據上下文預測被屏蔽掉的標記。在不同語言的批次流之間來會切換,這使得該模型能夠創建高質量、跨語言的序列表徵。圖1展示了一個XLM預訓練的例子。

圖1

此方法中使用的無監督機器翻譯三個原理的說明。第一個原理是用跨語言掩碼語言模型預訓練來初始化模型。因此,無論使用哪種編程語言,表達相同指令的代碼塊都會被映射到相同的表徵上。第二個原理是去噪自動編碼,訓練解碼器始終生成有效序列,即使輸入的是噪聲數據,也能提高編碼器對輸入噪聲的魯棒性。最後一個原理是回譯,允許模型生成可以用於訓練的並行數據。當Python語言模型轉換成C++語言模型性能更優時,它會爲C++ → Python模型生成更準確的數據,反之亦然。

去噪自動編碼

Facebook用上述提到的預訓練XLM模型來初始化seq2seq模型的編碼器和解碼器。編碼器的初始化很簡單,因爲它的架構與XLM模型相同。然而,transformer 解碼器有一些與源注意力機制相關的額外參數。根據Lample和Conneau,隨機初始化這些參數。

XLM預訓練能使seq2seq模型生成高質量的輸入序列表徵。然而,由於解碼器從未被訓練去解碼一個基於源表徵的序列,因此它缺乏翻譯能力。爲了解決這個問題,Facebook以去噪自動編碼(DAE)爲目標來訓練模型編碼和解碼序列。DAE objective的操作就像一個監督的機器翻譯算法,使用這種算法可以訓練模型來預測一個給定損壞的標記序列。爲了損壞一個序列,可以使用與Lample et al. 中描述相同的噪聲模型。也就是說,隨機遮擋、刪除和打亂這些輸入標記。

輸入到解碼器中的第一個符號是一個特殊標記,表示輸出的編程語言。在測試時,Python序列可以被模型編碼,並使用C++起始符號進行解碼,生成C++翻譯。C++翻譯的質量將取決於模型的 “跨語言能力”:如果Python函數和有效的C++翻譯被編碼器映射到相同的latent representation,解碼器將成功生成C++翻譯。DAE objective還訓練了模型的 “語言建模 ”能力,也就是說,儘管有時編碼器的輸出是嘈雜的,但Facebook一直訓練解碼器去生成一個有效函數。此外,這種方法還訓練了編碼器對輸入噪聲的魯棒性,這在回譯的語境中非常有用,因爲在回譯過程中,模型是在有噪聲的輸入序列中訓練的。圖1對DAE進行了說明。

回譯

在實際操作中,僅XLM預訓練和去噪自動編碼就足以產生翻譯。然而,這些翻譯的質量往往很低,因爲模型在測試時的效果未達到預期水準,即將函數從一種語言翻譯到另一種語言。爲了解決這個問題,Facebook引入了回譯,這是在弱監督場景下利用單語言數據的最有效方法之一。最初引入回譯是爲了提高監督環境下機器翻譯的性能,後來發現回譯變成了無監督機器翻譯中的重要一環。在無監督環境下,source-to-target 模型與並行訓練的後向target-to-source模型耦合。Target-to-source模型用於將目標序列翻譯成源語言,產生與實際目標序列相對應的噪聲源序列。然而以弱監督的方式訓練 source-to-target模型,從target-to-source模型產生的噪聲源序列重建目標序列,反之亦然。兩個模型並行訓練,直至實現趨同。圖1中展示了一個回譯的例子。

實驗

訓練細節

Facebook使用具有6個layer,8個attention head,並將模型的維度設置爲1024。對於所有編程語言,我們都使用單個編碼器和解碼器。XLM預訓練期間,在C ++,Java和Python之間進行了轉換,它們由512個令牌的32個源代碼序列組成。訓練時,在去噪自編碼器和回譯objectives之間交替,並使用幾批總數約6000個的標記。Facebook使用Adam優化TransCoder,學習速率爲10^(−4),並使用與Vaswani等相同的學習速率調度器。 Facebook在PyTorch 中實現了模型,並在32個V100 GPU上對其進行訓練,使用float16操作來加快訓練速度並減少模型的內存使用量。

訓練數據

Facebook通過Google BigQuery4獲得GitHub公共數據集,其包含超過280萬個開源GitHub存儲庫,過濾其中許可證明確允許重新分發的項目,並選擇其中的C ++,Java和Python文件。理想情況下,轉編譯器應該能夠翻譯整個項目。在這項工作中,Facebook決定在函數級別進行轉換。與文件或類不同,函數足夠短以適合單個批處理,並且在函數級別上可以通過單元測試對模型進行更簡單的評估。Facebook會在所有可用的源代碼上對TransCoder進行預訓練,並僅對函數進行去噪自動編碼和回譯objectives,以獲取有關提取功能的更多詳細信息以及有關訓練集的統計信息。Facebook進行了一項消融研究,以確定保留還是刪除源代碼中的註釋更好。在源代碼中保留註釋會增加跨語言的定位點數量,從而提高整體性能。因此,Facebook將它們保留在最終數據集和實驗中。

預處理

多語言自然語言處理的最新方法趨向於使用通用分詞器和所有語言的共享詞彙表,這減少了整體詞彙量,並使語言之間的令牌重疊最大化,從而改善了模型的跨語言性。在本次實驗中,通用令牌生成器不是最佳的,因爲不同的語言使用不同的模式和關鍵字。邏輯運算符&&和||在C ++中存在,它們應該被單個標記,但在Python中不存在。縮進在Python中很重要,因爲它們定義了代碼結構,但在C ++或Java之類的語言中沒有任何意義。Facebook在Java中使用javalang tokenizer,Python標準庫的tokenizer,C ++中使用clang tokenizer。這些tokenizer可確保代碼中無意義的修改(例如,添加額外的新行或空格)不會對tokenized序列產生任何影響。Facebook在提取的令牌上學習BPE代碼,並將其拆分爲子單元。

評估

GeeksforGeeks是一個包含計算機科學和編程相關文章的在線平臺,收集了許多編碼問題,並提供了幾種編程語言的解決方案。從這些解決方案中,Facebook提取了一組C ++、Java和Python並行函數,以創建驗證和測試集。這些函數不僅返回相同的輸出,而且使用相似的算法計算結果。下圖顯示了一個C ++、Java和Python並行函數的示例,該函數確定由字符串表示的整數是否可以被13整除。

圖2: 顯示了無監督Python到C++轉換

大多數源代碼轉換研究都使用BLEU來評估生成的函數[1、10、22、36]或其他度量(基於翻譯和參考中token之間的重疊度)。一個簡單的度量是計算參考匹配,即與真實結果之間的匹配度,這些度量標準的侷限性在於未考慮語法正確性,語法差異小則得分高,而它們可能導致完全不同的編譯和計算輸出。相反,具有不同實現方式的語義等效程序將具有較低的BLEU分數。取而代之的是,Facebook引入了一種新的度量標準,即計算精度,該度量標準可以評估轉換後函數在給定相同輸入時是否生成與參考函數相同的輸出。如果每個輸入給出的輸出與參考相同,則認爲則轉換是正確的。

結果

在表1中報告了測試集上的結果。在表2中,報告了使用集束搜索解碼的結果,並將TransCoder與現有的baseline進行了比較。圖2給出了一個從Python到C++的無監督翻譯的例子。

評估度量標準之間的差異。在表1中,Facebook發現大部分翻譯與參考不同,雖然它們成功通過了單元測試,但是通過與參考匹配度量標準進行對比,這些翻譯被認爲是無效的。例如,當從C++翻譯到Java時,雖然60.9%的翻譯達到了預期水準,但僅有3.1%的生成結果與實際參考完全相同。此外,其性能在BLEU上也表現平平,與計算精度相關性不高。測試結果顯示了這種方法在該領域中常用的傳統參考匹配指標和BLEU指標上存在一些問題。

集束搜索解碼。在表2中,Facebook研究了集束搜索的影響,要麼考慮集束中所有通過單元測試的假設(Beam N),要麼只考慮對數概率最高的假設(Beam N - Top 1)。與greedy解碼(Beam 1)相比,集束搜索顯著提高了計算精度,使Beam 25 Java → Python的計算精度提高了33.7%。當模型只返回對數概率最高的假設時,性能就會下降,這說明TransCoder經常能找到有效的翻譯,儘管它有時會給錯誤的假設一個較高的對數概率。

表1:TransCoder在測試集上greedy解碼的結果。

表2:集束搜索解碼計算準確率和以及和Baseline的對比

在實際用例中,檢查生成的函數是否在語法上正確並被編譯過,或者從輸入函數中創建單元測試,這些方法都比對比對數概率更好。附錄中的表5顯示,當目標語言是Java或C++時,編譯錯誤是測試失敗的最主要原因之一。這表明 “Beam N - Top 1”指標可以很容易地進行改進。

與現有baseline相比。Facebook將TransCoder與現有的兩種方法進行比較:第一種是j2py10 ,一個從Java翻譯到Python的框架;第二種是Tangible Software Solutions11的商業解決方案,從C++翻譯到Java。這兩個系統都依賴於用專業知識手動建立的重寫規則。後者處理多種元素的轉換,包括核心類型、數組、一些集合(Vectors和Maps)和lambdas。

在表2中,Facebook觀察到TransCoder在計算精度上明顯優於兩個baseline,從C++到Java的計算準確率能達到74.8%,從Java到Python的計算準確率能達到68.7%,而baseline在這兩種轉換上的計算準確率分別爲61%和38.3%。在翻譯標準庫中的函數時,TransCoder的表現尤爲突出。在基於規則的編譯轉換器中,需要爲每個標準庫函數手動編碼重寫規則,而TransCoder則以無監督的方式學習這些規則。下圖介紹了TransCoder的幾個成功例子,而baseline則無法生成正確的翻譯。

圖3:錯誤的baseline翻譯與正確的TransCoder翻譯示例

結束語

事實上,Facebook 並不是唯一開發代碼生成系統的組織。在今年早些時候的 Microsoft Build 大會上,OpenAI 演示了一個在GitHub 存儲庫上訓練的模型,該模型使用英語註釋生成整個功能。兩年前,萊斯大學的研究人員創建了一個名爲 Bayou 的系統,該系統通過將公開代碼背後的“意圖”相關聯,實現自主編寫軟件程序。

論文地址: https://arxiv.org/pdf/2006.03511.pdf

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章