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

  總體而言,這份研究在於理解人類編寫代碼的過程(例如 GitHub 的 commit),並使用深度神經網絡模擬這個動態的編輯過程。只需要給定上一次的編輯信息,模型就能預測下一次代碼編輯該改什麼,從而繼續修改與生成代碼。前一段時間,OpenAI 的 GPT-2 能生成逼真的自然語言對話,也許採用相同的模式,這種動態代碼編輯也能生成「邏輯合理」的源代碼。

  這篇論文的四位作者都來自於谷歌大腦,其中二作 David Bieber 還發布過一個可以自動生成命令行接口的庫:Python Fire。

  什麼是代碼建模

  代碼是一種機器語言,它和自然語言一樣以一種序列的方式展現出來。以前機器之心曾介紹過多種代碼生成的方式,其中研究最多的是如何根據 GUI 生成對應代碼,例如 17 年提出的

  Pix2Code

  ,我們只需要輸入界面圖像就能生成對應的前端代碼。

  其次,2018 年 11 月,北大研究者首次成功用 CNN 自動生成代碼,他們這篇 AAAI 2019 論文采用了 CNN 解碼器,並在《爐石傳說》數據集上進行了測試,效果超過了此前各類業內最佳模型。這類研究一般都會採用結構化的神經網絡來建模代碼結構,例如北大研究者的這篇論文就根據抽象語法樹(AST)中的語法結構規則生成代碼。

  但是,這些方法都將代碼生成看成是一種「一次到位」的靜態過程。不過我們知道,代碼的編寫是動態的,隨着新特性的實現、bug 的修復以及重構的進行,源代碼庫一直處在變化之中。其實在人類開發的過程中,開發者都需要訪問已有的代碼庫或片段,考慮用一個或多個意圖對其進行更改。

  在本文中,谷歌大腦團隊探討的主要問題是如何觀察一個過去的編輯序列並預測即將發生的編輯。這是一個重要的問題,因爲構建更好的開發者工具的核心挑戰是理解開發者行爲背後的意圖。

  這也是一個有趣的研究挑戰,因爲僅根據編輯的內容(輸入或刪除的內容)無法理解編輯模式。我們需要根據變更與變更之前的狀態之間的關係來理解編輯,而且,準確地對編輯序列建模需要學習過去編輯的表徵,這一表徵允許模型泛化模式並預測未來編輯。

  如圖 1 所示,圖中有兩個可能的編輯序列(History A 和 History B)。經過兩次編輯後,兩個序列都有了相同的編碼狀態(State 2),但 History A 正在給 foo 函數添加一個額外的參數,History B 正在從 foo 函數中移除第二個參數。

  研究者希望通過觀察初始狀態(State 0)和編輯序列(Edits 1 & 2)讓模型具備預測 Edit 3 的能力。在 History A 的情況下,要插入的特定值是不明確的,但是在該位置插入某個值這一事實應該具有相當高的置信度。

  圖 1:兩個編輯序列圖示。History A 和 History B 共享相同的 State 2,但根據以往經驗,History A 更有可能通過修改對 foo 函數的調用來獲取一個額外的參數,History B 更有可能通過修改 foo 的定義來獲取一個參數。

  因此在谷歌大腦的這篇研究中,神經網絡需要學習不同的編輯序列及編輯內容,從而在給定編輯序列的情況下,模型能知道後面該怎樣繼續「寫代碼」。這就和語言模型一樣,給定一小段話,模型就能接着用自然語言「編下去」。

  谷歌大腦的解決方案

  編輯建模序列的主要挑戰是如何開發良好的表徵,既能捕捉所需的意圖信息,又能優雅地縮放序列長度。研究者考慮了兩種編輯表徵:顯式表徵和隱式表徵。

  顯式表徵明確實例化序列中每一次編輯的狀態結果,而隱式表徵實例化完整的初始狀態以及更緊湊的類 diff 表徵中的後續編輯。在顯式表徵中,研究者將層級遞歸指針網絡模型視爲一個強大但計算昂貴的基線。

  在隱式表徵中,研究者考慮一個簡單的序列到序列模型以及一個基於注意力的雙向模型,後者擁有一個生成編輯位置的指針網絡 head 和一個生成編輯內容的內容 head。這些模型顯示了源自不同問題公式化之間的權衡,併爲將來的編輯序列模型提供設計方案。

  在精心設計的合成數據以及對 Python 源代碼進行細粒度編輯的大規模數據集中,研究者根據模型觀察一系列過去編輯的能力來評估模型的可擴展性和準確性,然後預測未來的編輯。

  在製作合成數據集以評估模型的特定功能之後,研究者將注意力轉移到真實數據。研究者根據開發實際代碼的專業開發人員創建的谷歌代碼庫構建了一個大型編輯序列數據集。

  開發人員每保存一份文件,就會創建一份靜態代碼狀態,由此生成比典型 Git commit 等更細的粒度。研究者對不同模型觀察以往編輯和預測未來編輯的能力進行可擴展性和準確性評估。

  結果顯示,雙向注意力模型特別能夠在真實數據中實現高準確率、精準置信度和較好的可擴展性,這使得研究者對開發者工具的前景保持樂觀,而這些工具在開發人員對大型和真實代碼庫進行編輯時學習提取他們的意圖。

  總之,本文將研究從編輯序列中學習和預測編輯的問題,是對模型空間的初步探索,此外還展示了從開發者編輯源代碼過程中學習的適用性。

  論文:NEURAL NETWORKS FOR MODELING SOURCE CODE EDITS

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

  摘要:編程語言正成爲機器學習中一個充滿挑戰與趣味的領域。其核心任務是構建源代碼的生成模型,這一任務近年來已受到大量關注。

  但是,就目前所知,以前的生成模型總是生成靜態代碼片段。在本文中,我們將源代碼視作動態目標,要解決的問題是建模軟件工程師對源代碼文件進行的編輯。

  解決上述問題需要從先前的編輯中提取意圖,然後利用它來生成後續編輯。我們開發了幾個神經網絡,並利用合成數據來測試它們學習編輯模式的能力,而這需要很強的泛化能力。然後我們收集並在谷歌源代碼的大型數據集上訓練了我們的模型,該源代碼包含來自數千 Python 開發者的數百萬次細粒度編輯。

  從建模的角度來看,我們的主要結論是注意力和指針網絡組件的新組合提供了最好的整體性能和可擴展性。而從應用角度來看,我們的結果表明,開發工具以學習預測未來的編輯是可行的。

  模型方法

  第一個要思考的問題是我們該如何表徵編輯代碼的序列數據。我們定義了兩種數據格式,它們各有各的權衡。下圖 2(a) 所示爲顯式格式,它將編輯序列以二維網格的形式表示爲序列的序列,橫縱座標分別爲兩種序列。這種格式的預測任務會根據前面 t-1 行的編輯序列預測第 t 個時間步的編輯位置與內容。

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

  如上圖 2(b) 所示,隱式格式將初始狀態表示爲一個 Token 序列,並將其作爲(position, content)對進行編輯。

  根據兩種數據表徵格式,現在我們有基線顯式模型和基線隱式模型。其中基線顯式模型是一個兩階段的 LSTM 網絡,有點類似於層級 RNN 模型。

  在最簡單的基線顯式模型中,第一階段的 LSTM 會並行地編碼每一個狀態序列,併產生隱藏狀態;而第二階段的 LSTM 會將前面的隱藏狀態和已觀察到的編輯序列作爲輸入,併產生解碼的隱藏狀態和輸出狀態。下圖 3(a) 有一個更形象的展示。

  而基線隱式模型最自然的方式就是使用 Seq2Seq 框架,將初始狀態序列輸入到編碼器中,並期待解碼器輸出(position, content)對。

  圖 3:(a):基線顯式模型;(b, c)隱式注意力模型。

  除了基線模型,更強大的是隱式注意力模型,該模型能對隱式表徵進行操作,並能更好地捕捉到編輯內容和編輯上下文之間的關係序列。隱式注意力模型的編碼器和解碼器在上圖 3(b, c) 中展示,其中編碼器會將初始狀態和所有已知編輯編碼爲隱藏向量,解碼器會將其解碼爲每一個編輯的位置、以及給定位置的編輯內容。該模型的細節見原論文的附錄,它參考了 Transformer 的位置編碼與 Multi-head Attention(MHA)。

  實驗

  實驗的目標是瞭解模型的能力和限制。兩個主要的因素是,模型能夠多準確地識別編輯序列中的模式?它對大型數據的適應效果如何?

  表 1 中報告了能夠產生最佳開發性能的步驟和超參數設置的測試性能。顯式模型和改進的隱式模型幾乎可以解決所有任務,甚至是那些涉及元字符和具有較長替換序列的任務。

  表 1:具有最佳開發性能的步驟和超參數設置在合成數據集上的測試準確率。準確率在.5% 以內的結果用粗體顯示。POMP:Position-Oracle Match-Pattern;E:顯式基線模型;IR:隱式基線模型;IA:改進的隱式模型。

  如圖 4 所示,顯式模型始終比隱式模型要昂貴,而且隨着數據的增加,這個差距也在拉大。長度爲 100 的插入序列比真實數據集中的序列小十倍,但在運行時方面已經存在一個數量級的差異。

  圖 4:(a)-(c):具有不同插入數量(10,50,100)的 n 元問題的訓練過程中處理序列所需的時間。注意,每個圖的 y 軸刻度不同。(d):把預測限制到模型置信度最高時,模型在真實數據集上的 Token 級別準確率。

  《萬物》2019年3月刊現已上市

相關文章