代碼也能預訓練,微軟&哈工大最新提出 CodeBERT 模型,支持自然-編程雙語處理

代碼也能預訓練,微軟&哈工大最新提出 CodeBERT 模型,支持自然-編程雙語處理

近日,微軟、哈工大在arxiv上聯合發表了一篇論文,標題為《CodeBERT: A Pre-Trained Model for Programming and Natural Languages》,再次拓寬了BERT的應用,將BERT應用到了Python、PHP、Java、JavaScript、Go、Ruby等編程語言的代碼搜索和生成任務當中。

代码也能预训练,微软&哈工大最新提出 CodeBERT 模型,支持自然-编程双语处理

論文鏈接:https://arxiv.org/pdf/2002.08155.pdf

這篇論文提出了一個被稱為「CodeBERT」的雙模預訓練模型,據作者介紹,這也是目前已知的第一個大型 NL-PL(自然語言-編程語言)預訓練模型。

該預訓練模型能夠處理NL-PL 的普遍問題,例如用自然語言搜索代碼、自動生成代碼等。 所謂自然語言代碼搜索,所要解決的問題是,如何通過自然語言query查找到所需的代碼塊,這和我們常用的搜索引擎(通過自然語言query來查找所需網頁)類似。

事實上,微軟Bing在2018年便上線了類似的功能,在搜索框中輸入自然語言 “convert case using a function of R”,便會返回一段 R 代碼。

代码也能预训练,微软&哈工大最新提出 CodeBERT 模型,支持自然-编程双语处理

(雷鋒網)

針對自然語言代碼搜索,在這篇論文裡,作者在 CodeSearchNet語料庫上對CodeBERT進行了預訓練並做微調,這是一個包含了 6 種較為普遍的代碼語言(分別為Ruby、JavaScript、Go、Python、Java、PHP)的語料庫。如下圖所示,他們在自然語言代碼搜索任務中取得了SOTA的結果:

代码也能预训练,微软&哈工大最新提出 CodeBERT 模型,支持自然-编程双语处理

而另一方面,代碼文檔生成任務,是未來能夠極大節省程序員工作量的極具前景的一個研究方向。如下圖所示,

代码也能预训练,微软&哈工大最新提出 CodeBERT 模型,支持自然-编程双语处理

針對這個任務,CodeBERT也基本上都取得了SOTA結果,特別是相較於之前的ROBERTa模型,更是有顯著的提高。 值一提的是,CodeBERT有一大亮點,即儘管它只在Ruby、JavaScript、Go、Python、Java、PHP等代碼語言上進行了預訓練,但預訓練的模型卻可以泛化到其他代碼語言任務上,例如C#語言。

一、背景

BERT作為一種雙向Transformer的編碼器,其對預訓練方法的創新深受業界和學術界的喜愛,雖然其他大規模的預訓練模型例如ELMo、GPT等已經能夠在各種NLP任務中提升SOTA。

但是上述提到的模型基本上都是面向自然語言處理,例如掩蔽語言建模、從未標記文本學習上下文表示。 相比以往的Bert的應用場景,作者另闢蹊徑,推出雙模態預訓練模型,即兼顧NLP任務和Python、Java等編程語言。

具體來說,CodeBERT抓住了自然語言和編程語言之間的語義聯繫,能夠支持自然語言代碼搜索等NL-PL理解任務以及一系列像代碼生成這樣的生成任務。

代码也能预训练,微软&哈工大最新提出 CodeBERT 模型,支持自然-编程双语处理

(雷鋒網)

一個NL-PL對,其中紅線框中的是NL文本,黑色框是PL文本。 為了利用Nl-PL對的雙模實例(bimodal instances)以及大量可用的單模代碼(unimodal codes),作者使用了混合目標函數來訓練CodeBERT,包括標準掩碼語言建模和可替換Token檢測。

在具體的訓練過程,作者用了六種編程語言在多語言BERT的設置中訓練模型。 我們首先來看下CodeBERT的模型框架。

二、框架

在模型的整體架構上,CodeBERT並未脫離BERT和Roberta的思想。和大多數工作類似,作者使用了多層雙向Transformer。更為具體一點,作者使用的模型架構與Roberta-base完全相同,即都有12層,每層有12個自注意頭,每個頭的大小是64,隱藏尺寸為768,前饋層的內部隱藏尺寸為3072。

模型參數的總數為125M。 在預訓練階段,總共設計了兩部分輸入,一個是自然語言文本,另一個是編程語言的代碼。對於自然語言文本將其視為單詞序列,並拆分為WordPiece。對於編程代碼,將其看做Token序列。 CodeBERT的輸出也包括兩個部分:1、聚合序列表示;2、有標記的上下文向量(contextual vector)。

代码也能预训练,微软&哈工大最新提出 CodeBERT 模型,支持自然-编程双语处理

數據集統計 訓練CodeBERT所使用的數據集是Husain等人在2019年提供的最新數據集,裡面包括 2.1M雙模數據和6.4M 單碼數據,其中雙模碼數據是指自然語言-代碼對的並行數據,單碼是指“未成對”的數據。 另外一些數據來自開源Nonfork GitHub倉庫。對這些數據的處理是採用了一些約束和規則進行過濾。

代码也能预训练,微软&哈工大最新提出 CodeBERT 模型,支持自然-编程双语处理

(雷鋒網)

可替換Token檢測目標圖解 在模型訓練的設計上,其主要包括兩個目標,其一是掩碼語言建模,其二是可替換Token檢測。在第二個目標中,作者進一步使用了大量的單模碼數據。

目標一:掩碼語言建模。將NL-PL對作為輸入,隨機為NL和PL選擇位置進行掩碼,然後用特殊的掩碼Token進行替換。注意,掩碼語言建模的任務是預測出被掩碼的原始Token。

目標二:替換Token檢測。在這部分有兩個數據生成器,分別是NL生成器和PL生成器,這兩個生成器都用於隨機掩碼位置集(randomly masked positions)生成合理的備選方案。

另外,還有一個學習生成器用來檢測一個詞是否為原詞,其背後原理是一個二進制分類器,這裡與GAN不同的是,如果生成器碰巧產生正確的Token,則該Token的標籤是“real”而不是“fake”。

代码也能预训练,微软&哈工大最新提出 CodeBERT 模型,支持自然-编程双语处理

學習器的損失函數 經過調整後,損失函數優化如下:

模型訓練的最後一步是模型微調,具體操作是在NL-PL任務中使用不同的CodeBERT設置。例如在自然語言代碼搜索中,會使用與預訓練階段相同的輸入方式。而在代碼到文本的生成中,使用編碼器-解碼器框架,並使用CodeBERT初始化生成模型的編碼器。

三、實驗

作者做了四個實驗,分別是:1)將CodeBERT應用到自然語言代碼搜索任務上,並與傳統方法進行對比;2)進行NL-PL Probing實驗,考察CodeBERT在預訓練階段到底學習了什麼知識;3)將CodeBERT應用到生成任務當中;4)考察CodeBERT預訓練模型的泛化能力,發現效果非常之好。

1、自然語言代碼搜索

給定一段自然語言作為輸入,代碼搜索的目標是從一組代碼中找到語義上最相關的代碼。為了進行比較,作者選擇了Husain 等人在2019年發佈的 CodeSearchNet 語料庫進行訓練。這個語料庫框架如下圖所示,共包含6中常見的編程語言(Python、JavaScript、Java、Ruby、PHP、Go)。

代码也能预训练,微软&哈工大最新提出 CodeBERT 模型,支持自然-编程双语处理

在預訓練階段,作者首先對每種語言的數據集進行了訓練。數據集分割如下:

代码也能预训练,微软&哈工大最新提出 CodeBERT 模型,支持自然-编程双语处理

在微調階段,設置學習率為1e-5,批量大小為64,最大序列長度為200,最大微調週期為8,並使用Adam來更新參數,並從開發集中選擇出表現最好的模型,並用於測試集上進行評估。 結果如下表所示:

代码也能预训练,微软&哈工大最新提出 CodeBERT 模型,支持自然-编程双语处理

性能相比於之前的SOTA模型ROBERTa取得了顯著的提高。

2、NL-PL Probing

這部分實驗主要研究在不更改參數的的情況下,Code BERT能夠學習哪些類型的知識。目前學界還沒有針對NL-PLProbing的工作,所以在這部分實驗中,作者自行創建了數據集。 給定NL-PL對,NL-PL Probing的目標是測試模型的正確預測能力。模型比較結果如下圖所示:

代码也能预训练,微软&哈工大最新提出 CodeBERT 模型,支持自然-编程双语处理

上表顯示了正確預測實例的數量與全部實例數量的比例。可以看出,在各個變成語言的預測上,CodeBERT基本都取得了最高的分數。但由於不同編程語言的數據集非常不平衡,因此用累計的數據進行比較更為恰當,在PL和NL的probing中,CodeBERT的結果都要比RoBERTa高10~20個百分點。 也可以用一個具體的案例來對比下。下圖案例中分別掩蓋了NL和PL中的“min”:

代码也能预训练,微软&哈工大最新提出 CodeBERT 模型,支持自然-编程双语处理

上圖為RoBERTa和CodeBert的預測概率 從結果來看,CodeBERT在NL上的正確預測率為60.6%,而在PL上直接高達99.999%。

3、代碼文檔生成

這部分研究代碼到文檔的生成問題,並在六種編程語言中研究了生成任務在Code Search Net Corpus上的結果。 另外,為了證明CodeBERT在代碼到NL生成任務中的有效性,作者採用了各種預訓練的模型作為編碼器,並保持了超參數的一致性。 實驗結果如下:

代码也能预训练,微软&哈工大最新提出 CodeBERT 模型,支持自然-编程双语处理

在編程語言上進行預訓練的模型的性能優於ROBERTa

4、泛化能力

那麼,在Python、JavaScript、Java、Ruby、PHP、Go這些語言上做的預訓練模型能夠應用到別的編程語言上嗎? 作者拿著前面預訓練出的CodeBERT模型在C#語言上做了測試。 作者選擇了Codenn數據集,這是一個包含Stack Overflow自動收集的66015對問題和答案的數據集,其規模相比 CodeSearchNet語料庫要小几個數量級。為了可靠地評估模型,作者通過人工方式,為測試集中的代碼片段提供兩個附加 titles 來擴展測試集。 模型評估標準採用平滑的BLEU-4分數,評估結果如下圖:

代码也能预训练,微软&哈工大最新提出 CodeBERT 模型,支持自然-编程双语处理

從這個結果可以看出,相較於RoBERTa,CodeBERT能夠更好地推廣到其他編程語言。不過值得注意的是,模型的效果略低於code2seq,作者認為原因可能是code2seq使用其抽象語法樹AST中的組合路徑,而CodeBERT僅將原始代碼作為輸入。

雖然作者也按照一定的順序通過遍歷AST的樹結構來訓練CodeBert,但並不會帶來生成任務的改進。這種結果意味著結合AST來改進codebert是潛在方向。

四、總結

如前面提到,微軟的 Bing 在2018年便已經上線了代碼搜索功能,可以預期,基於預訓練的代碼功能也將很快落實到 Bing 的產品當中,從而提供能加優質的服務。同時我們也可以期待,該項工作能夠在近期開源,以讓更多研究人員快速跟進這一工作。

我們用幾句話來總結這項工作的意義:

1、據作者表示,CodeBERT也是目前已知的首個大型的NL-PL(自然語言-編程語言)預訓練模型;

2、本文提出了一個混合學習目標,能夠支持使用雙模數據NL-PL,且能夠很容易地應用到單模數據中(例如沒有自然語言文本的編程代碼);

3、CodeBERT在自然語言代碼搜索和代碼文檔生成兩個任務中都達到了SOTA性能,此外作者在實驗中還建立了一個數據集來研究NL-PL預訓練模型的探測能力,方便了以後跟進的研究人員。


分享到:


相關文章: