像人一樣編輯源代碼,谷歌大腦提出神經(jīng)網(wǎng)絡也可以學「編程」

利用機器學習學會如何自動寫代碼或修改代碼一直非常誘人,它不僅能減少大量工程努力,同時也能構建更高級的智能體。在這篇論文中,谷歌大腦的研究者提出利用神經(jīng)網(wǎng)絡建模我們對源代碼的編輯,也就是說將我們對代碼的編輯視為一個序列,然后像語言模型那樣學會如何「寫代碼」。

 
總體而言,這份研究在于理解人類編寫代碼的過程(例如 GitHub 的 commit),并使用深度神經(jīng)網(wǎng)絡模擬這個動態(tài)的編輯過程。只需要給定上一次的編輯信息,模型就能預測下一次代碼編輯該改什么,從而繼續(xù)修改與生成代碼。前一段時間,OpenAI 的 GPT-2 能生成逼真的自然語言對話,也許采用相同的模式,這種動態(tài)代碼編輯也能生成「邏輯合理」的源代碼。
 
這篇論文的四位作者都來自于谷歌大腦,其中二作 David Bieber 還發(fā)布過一個可以自動生成命令行接口的庫:Python Fire。
 
什么是代碼建模
 
代碼是一種機器語言,它和自然語言一樣以一種序列的方式展現(xiàn)出來。以前機器之心曾介紹過多種代碼生成的方式,其中研究最多的是如何根據(jù) GUI 生成對應代碼,例如 17 年提出的 Pix2Code,我們只需要輸入界面圖像就能生成對應的前端代碼。
 
其次,2018 年 11 月,北大研究者首次成功用 CNN 自動生成代碼,他們這篇 AAAI 2019 論文采用了 CNN 解碼器,并在《爐石傳說》數(shù)據(jù)集上進行了測試,效果超過了此前各類業(yè)內最佳模型。這類研究一般都會采用結構化的神經(jīng)網(wǎng)絡來建模代碼結構,例如北大研究者的這篇論文就根據(jù)抽象語法樹(AST)中的語法結構規(guī)則生成代碼。
 
但是,這些方法都將代碼生成看成是一種「一次到位」的靜態(tài)過程。不過我們知道,代碼的編寫是動態(tài)的,隨著新特性的實現(xiàn)、bug 的修復以及重構的進行,源代碼庫一直處在變化之中。其實在人類開發(fā)的過程中,開發(fā)者都需要訪問已有的代碼庫或片段,考慮用一個或多個意圖對其進行更改。
 
在本文中,谷歌大腦團隊探討的主要問題是如何觀察一個過去的編輯序列并預測即將發(fā)生的編輯。這是一個重要的問題,因為構建更好的開發(fā)者工具的核心挑戰(zhàn)是理解開發(fā)者行為背后的意圖。
 
這也是一個有趣的研究挑戰(zhàn),因為僅根據(jù)編輯的內容(輸入或刪除的內容)無法理解編輯模式。我們需要根據(jù)變更與變更之前的狀態(tài)之間的關系來理解編輯,而且,準確地對編輯序列建模需要學習過去編輯的表征,這一表征允許模型泛化模式并預測未來編輯。
 
如圖 1 所示,圖中有兩個可能的編輯序列(History A 和 History B)。經(jīng)過兩次編輯后,兩個序列都有了相同的編碼狀態(tài)(State 2),但 History A 正在給 foo 函數(shù)添加一個額外的參數(shù),History B 正在從 foo 函數(shù)中移除第二個參數(shù)。
 
研究者希望通過觀察初始狀態(tài)(State 0)和編輯序列(Edits 1 & 2)讓模型具備預測 Edit 3 的能力。在 History A 的情況下,要插入的特定值是不明確的,但是在該位置插入某個值這一事實應該具有相當高的置信度

圖 1:兩個編輯序列圖示。History A 和 History B 共享相同的 State 2,但根據(jù)以往經(jīng)驗,History A 更有可能通過修改對 foo 函數(shù)的調用來獲取一個額外的參數(shù),History B 更有可能通過修改 foo 的定義來獲取一個參數(shù)。
 
因此在谷歌大腦的這篇研究中,神經(jīng)網(wǎng)絡需要學習不同的編輯序列及編輯內容,從而在給定編輯序列的情況下,模型能知道后面該怎樣繼續(xù)「寫代碼」。這就和語言模型一樣,給定一小段話,模型就能接著用自然語言「編下去」。
 
谷歌大腦的解決方案
 
編輯建模序列的主要挑戰(zhàn)是如何開發(fā)良好的表征,既能捕捉所需的意圖信息,又能優(yōu)雅地縮放序列長度。研究者考慮了兩種編輯表征:顯式表征和隱式表征。
 
顯式表征明確實例化序列中每一次編輯的狀態(tài)結果,而隱式表征實例化完整的初始狀態(tài)以及更緊湊的類 diff 表征中的后續(xù)編輯。在顯式表征中,研究者將層級遞歸指針網(wǎng)絡模型視為一個強大但計算昂貴的基線。
 
在隱式表征中,研究者考慮一個簡單的序列到序列模型以及一個基于注意力的雙向模型,后者擁有一個生成編輯位置的指針網(wǎng)絡 head 和一個生成編輯內容的內容 head。這些模型顯示了源自不同問題公式化之間的權衡,并為將來的編輯序列模型提供設計方案。
 
在精心設計的合成數(shù)據(jù)以及對 Python 源代碼進行細粒度編輯的大規(guī)模數(shù)據(jù)集中,研究者根據(jù)模型觀察一系列過去編輯的能力來評估模型的可擴展性和準確性,然后預測未來的編輯。
 
在制作合成數(shù)據(jù)集以評估模型的特定功能之后,研究者將注意力轉移到真實數(shù)據(jù)。研究者根據(jù)開發(fā)實際代碼的專業(yè)開發(fā)人員創(chuàng)建的谷歌代碼庫構建了一個大型編輯序列數(shù)據(jù)集。
 
開發(fā)人員每保存一份文件,就會創(chuàng)建一份靜態(tài)代碼狀態(tài),由此生成比典型 Git commit 等更細的粒度。研究者對不同模型觀察以往編輯和預測未來編輯的能力進行可擴展性和準確性評估。
 
結果顯示,雙向注意力模型特別能夠在真實數(shù)據(jù)中實現(xiàn)高準確率、精準置信度和較好的可擴展性,這使得研究者對開發(fā)者工具的前景保持樂觀,而這些工具在開發(fā)人員對大型和真實代碼庫進行編輯時學習提取他們的意圖。
 
總之,本文將研究從編輯序列中學習和預測編輯的問題,是對模型空間的初步探索,此外還展示了從開發(fā)者編輯源代碼過程中學習的適用性。
 
論文:NEURAL NETWORKS FOR MODELING SOURCE CODE EDITS

摘要:編程語言正成為機器學習中一個充滿挑戰(zhàn)與趣味的領域。其核心任務是構建源代碼的生成模型,這一任務近年來已受到大量關注。
 
但是,就目前所知,以前的生成模型總是生成靜態(tài)代碼片段。在本文中,我們將源代碼視作動態(tài)目標,要解決的問題是建模軟件工程師對源代碼文件進行的編輯。
 
解決上述問題需要從先前的編輯中提取意圖,然后利用它來生成后續(xù)編輯。我們開發(fā)了幾個神經(jīng)網(wǎng)絡,并利用合成數(shù)據(jù)來測試它們學習編輯模式的能力,而這需要很強的泛化能力。然后我們收集并在谷歌源代碼的大型數(shù)據(jù)集上訓練了我們的模型,該源代碼包含來自數(shù)千 Python 開發(fā)者的數(shù)百萬次細粒度編輯。
 
從建模的角度來看,我們的主要結論是注意力和指針網(wǎng)絡組件的新組合提供了最好的整體性能和可擴展性。而從應用角度來看,我們的結果表明,開發(fā)工具以學習預測未來的編輯是可行的。
 
模型方法
 
第一個要思考的問題是我們該如何表征編輯代碼的序列數(shù)據(jù)。我們定義了兩種數(shù)據(jù)格式,它們各有各的權衡。下圖 2(a) 所示為顯式格式,它將編輯序列以二維網(wǎng)格的形式表示為序列的序列,橫縱坐標分別為兩種序列。這種格式的預測任務會根據(jù)前面 t-1 行的編輯序列預測第 t 個時間步的編輯位置與內容

圖 2:編輯序列的顯式和隱式表征,它們都將「BACA」轉換為「BABBCACC」,其中<S>和<E>分別為起始和終止符。

 
如上圖 2(b) 所示,隱式格式將初始狀態(tài)表示為一個 Token 序列,并將其作為(position, content)對進行編輯。
 
根據(jù)兩種數(shù)據(jù)表征格式,現(xiàn)在我們有基線顯式模型和基線隱式模型。其中基線顯式模型是一個兩階段的 LSTM 網(wǎng)絡,有點類似于層級 RNN 模型。
 
在最簡單的基線顯式模型中,第一階段的 LSTM 會并行地編碼每一個狀態(tài)序列,并產(chǎn)生隱藏狀態(tài);而第二階段的 LSTM 會將前面的隱藏狀態(tài)和已觀察到的編輯序列作為輸入,并產(chǎn)生解碼的隱藏狀態(tài)和輸出狀態(tài)。下圖 3(a) 有一個更形象的展示。
 
而基線隱式模型最自然的方式就是使用 Seq2Seq 框架,將初始狀態(tài)序列輸入到編碼器中,并期待解碼器輸出(position, content)對。

圖 3:(a):基線顯式模型;(b, c)隱式注意力模型。
 
除了基線模型,更強大的是隱式注意力模型,該模型能對隱式表征進行操作,并能更好地捕捉到編輯內容和編輯上下文之間的關系序列。隱式注意力模型的編碼器和解碼器在上圖 3(b, c) 中展示,其中編碼器會將初始狀態(tài)和所有已知編輯編碼為隱藏向量,解碼器會將其解碼為每一個編輯的位置、以及給定位置的編輯內容。該模型的細節(jié)見原論文的附錄,它參考了 Transformer 的位置編碼與 Multi-head Attention(MHA)。
 
實驗
 
實驗的目標是了解模型的能力和限制。兩個主要的因素是,模型能夠多準確地識別編輯序列中的模式?它對大型數(shù)據(jù)的適應效果如何?
 
表 1 中報告了能夠產(chǎn)生最佳開發(fā)性能的步驟和超參數(shù)設置的測試性能。顯式模型和改進的隱式模型幾乎可以解決所有任務,甚至是那些涉及元字符和具有較長替換序列的任務。

 
表 1:具有最佳開發(fā)性能的步驟和超參數(shù)設置在合成數(shù)據(jù)集上的測試準確率。準確率在.5% 以內的結果用粗體顯示。POMP:Position-Oracle Match-Pattern;E:顯式基線模型;IR:隱式基線模型;IA:改進的隱式模型。
 
如圖 4 所示,顯式模型始終比隱式模型要昂貴,而且隨著數(shù)據(jù)的增加,這個差距也在拉大。長度為 100 的插入序列比真實數(shù)據(jù)集中的序列小十倍,但在運行時方面已經(jīng)存在一個數(shù)量級的差異。
圖 4:(a)-(c):具有不同插入數(shù)量(10,50,100)的 n 元問題的訓練過程中處理序列所需的時間。注意,每個圖的 y 軸刻度不同。(d):把預測限制到模型置信度最高時,模型在真實數(shù)據(jù)集上的 Token 級別準確率。
 

來源  | 機器之心 

Share this article:

Facebook
Twitter
LinkedIn
WhatsApp