TransCoder介紹

人工智能如果能寫代碼的話那可能就是程序員的噩夢了。不過也許人們可以把更多的精力放在真正創造性的工作上去,比如移民火星什麼的。Facebook的TransCoder雖然不能解放人類,但是也算朝這個方向邁出了堅實的一步。

無監督的代碼轉換

這項工作的重點在"無監督"上面。畢竟,如果我們有完美的平行語料,即源語言語料庫和對齊的目標語言語料庫,那麼代碼轉換(或者代碼互翻)可以簡單理解爲神經機器翻譯(NMT)問題,比如英譯德,中譯英等等。然而現實並不存在這樣的完美對齊的代碼語料庫。

作者用了github上大量的單語料庫作爲訓練集,包括C++, Java, Python,成功實現了它們之間的互譯功能。先看下圖從Python到C++的效果。翻譯模型顯然需要能夠推斷變量的類型,然後才能正確的實現從動態類型語言到靜態類型語言的轉換。另外模型也照顧到了兩種語言裏deque包含的不同的方法,python裏獨有的range等等。這些都是通過無監督的訓練實現的,這是怎麼做到的?
在這裏插入圖片描述

無監督機器翻譯

這個要從無監機器督翻譯說起。無監督代碼轉換(翻譯)可以看成是無監督機器翻譯的一個子問題,或者一個簡化問題。很長一段時間以來人們就在研究語言翻譯裏的few shots或者zero shots問題,因爲小語種的翻譯總是受限於稀少的平行語料。這方面出彩的工作包括 XLM,這是Facebook在BERT出現後不久就提出的用來編碼多種語言的模型。也包括前面介紹過的多語種句子嵌入,裏面有提到了NMT問題和Monolingual語料庫在不同任務上共同發力的例子。這裏有必要再跑題一下,由於Transcoder利用XLM來預訓練單語料模型,我們先簡要介紹一下XLM。

XLM

XLM代表Cross-lingual Language Modeling,是一種跨(多)語言模型。對應的,該模型需要一個所有語言共享的字典。

字典-- BPE

現在BPE簡直成爲NLP各種模型的字典標配了,在跨語言模型裏更是如此。 優點是它可以有效地幫助不同語言的同形詞根對齊,比如英語,德語,法語這些相近的語言。舉個例子,英語的Hello和德語的Hallo共享"llo", 以此爲錨點,進一步把詞根周圍的其他詞根對齊,這裏英語裏的He和德語裏的Ha也可以在嵌入空間找到相近的位置。 這個方法的缺點是對於距離比較遠的語言,比如英語和漢語,就沒有什麼作用。在代碼翻譯領域,很多語言有一些相似或者相同的語法保留詞,比如if, for, while,try, int, long 等等,這些非常適合使用BPE。

兩種預訓練

XLM提出了兩種不同的預訓練目標。如下圖:
在這裏插入圖片描述
這裏都是用Transformer來訓練,上半部分的MLM大家都熟悉,我就不多介紹了。這裏的亮點在於作爲輸入的語言類型編碼(Language embeddings)。因爲我們的目的是訓練一個多語言共享的編碼器,所以有必要在編碼端區分不同的語言。(作爲對比,我們在多語種句子嵌入看到爲了能夠製造出多語言的編碼器,語言類型在編碼器的輸入端被刻意隱瞞了,而在解碼器一端作爲輸入的一部分出現。具體方法的選擇都是靈活的,取決於希望達到的效果。)
下半部分的TLM是把對齊的兩種語言一起放在模型裏,本質上仍然是MLM,區別在於這裏不是僅對一種語言訓練。所以這其實是有監督訓練。我們這裏可以自動忽略TLM。

TransCoder裏用到的,就是上面的這個MLM。

去噪編碼和回譯

無監督機器翻譯有兩大技術: Denoising Auto-Encoding和Back-translation。 它們極大的促進了無監督翻譯領域的發展。在前面多語種句子嵌入一文我們提到過Back-translation,當時是以Dual Learning的形式介紹的。在MASS: 一統GPT和BERT的Seq to Seq框架一文中,我們曾經提到過Denoising Auto-Encoding。

最早把它們落實在翻譯中的研究來自Facebook的Unsupervised Translation of Programming Languages。TransCoder的很多idea都借鑑了它的想法。如果想搞清楚算法的來龍去脈,推薦讀這篇文章。簡要介紹一下它的做法:

  1. 假設我們有兩種語言A, B和對應的兩個質量還過得去的MT Model,一個是從A到B的翻譯模型,一個是從B到A的翻譯模型。
    這個質量還過得去的機器翻譯模型,可以來自字/詞典上逐字的翻譯,就是我們常說的字譯。
  2. Denoising Auto-Encoding: 首先給輸入加上干擾,比如隨機遮掩,去掉,或者打亂一些詞的位置,然後把它傳給MT Model,在解碼器 這一端重新把正確的代碼恢復。也就是說,自己"翻譯"自己。兩個好處,一是讓解碼器學會了解碼,二是讓編碼器在面對有噪音的輸入時更加robust,從而學到更優的表徵。具體參考下圖中的左邊部分。C(x)代表corrupted版本的x,即加過干擾的輸入。
  3. Back-translation: 我們進行兩次翻譯。利用前兩步產生的模型,從A語言翻譯到B語言,再從B語言到A語言。這樣我們就自動構建了一個"有監督"的數據集,它包括原A語言,和經過兩次翻譯而產生的A‘。這可以當做信號回傳給翻譯模型進行訓練。參考下圖的右半部分。C(y)是noisy translation,指的是用現有翻譯模型從A到B產生的句子。它經過再次翻譯之後從新回到A語言,產生句子x^\hat{x}

在這裏插入圖片描述有了以上這些準備,我們終於可以介紹TransCoder了。

TransCoder三部曲

TransCoder是一個seq2seq的架構,即encoder+decoder。它的訓練包括了三個步驟。具體見下圖,是不是很眼熟?和Unsupervised Translation of Programming Languages這篇文章相比,TransCoder簡直是照搬了它的做法,僅是在預訓練時用XLM(即圖中的Cross-lingual Masked Language Model pretaining)替代了基於字典的模型。

在這裏插入圖片描述

XLM: 預訓練編碼器和解碼器

作者採用XLM來分別預訓練編碼和解碼器。具體方法就是把不同的編程語言語料庫放在一起,每次batch選擇一種語言,然後使用MLM。這種方法能夠產生高質量的跨語言的句子表徵。但是這裏的解碼器還沒有學會翻譯,這需要以下兩步。

Denoising auto-encoding: 訓練同語種"翻譯"

如圖例所示,函數名quicksort被替代成了MASK,piv+1去掉了1, piv-1只保留了-,MT Model負責把噪音輸入還原。注意,這裏仍然是針對單一編程語言的編碼解碼。在解碼端,我們用一個標誌語言的token來作爲解碼序列的初始值。比如用[PYTHON]來代表第一個token。
這時我們的模型已經可以做翻譯了。具體方法是比如在輸入Python代碼之後,在解碼器一段用[C++]來作爲第一個初始token引導後續的翻譯。翻譯的質量取決於模型"跨語言"的能力,就是說,如果編碼器能夠把一個Python片段和它的對應的C++翻譯投影在相近的latent space,那麼解碼器應該可以給出較好的C++翻譯。
這個時候我們的MT Model從來沒有進行過真正的語言間的互譯,翻譯的質量仍然不夠。這需要第三步來完成。

Back-translation: 訓練跨語種翻譯

如圖,我們可以進行兩次翻譯,利用前兩步產生的模型,從Python翻譯到C++,再從C++到Python。這樣我們就自動構建了一個"有監督"的數據集,它包括原Python代碼,和經過兩次翻譯而產生的Python代碼。這些可以當做信號來回傳給原來的翻譯模型。

到此爲止算法部分介紹完畢,我們看一下測試數據是如何產生的。

測試集

測試數據來源於很多北美程序員都知道的GeekForGeeks。它收集了很多編程面試題,而且提供了不同語言版本(比如Python
C++, Java)的答案。
下圖是一個來自GeekForGeeks的例子。看的出來不同編程語言直接對齊的質量很高。
在這裏插入圖片描述

關於evaluation metrics也很有意思,這裏從略。接下來直接看一下效果吧。

效果

不同語言的tokens有效的投影在了一個空間。相似的key words位置非常接近。
在這裏插入圖片描述
互譯的例子
在這裏插入圖片描述
在這裏插入圖片描述

總結

澳大利亞聯邦銀行花了8億美金5年時間才把COBOL系統遷移完畢。希望未來的TransCoder能夠避免這種無聊又浪費的事情重演。我們看到TransCoder的實現過程簡直是毫無創新之處,全部來自於過去的研究成果。但是從另一個角度來看,很多令人驚豔的產品都不需要太多自主創新,比如iphone,在它產生之前所有的科技突破已經全部就位了。可是沒有人會低估iphone的偉大。同樣的,我們應該給TransCoder這樣接地氣的應用掌聲。

關注公衆號《沒啥深度》有關自然語言處理的深度學習應用
這裏寫圖片描述

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