春節期間,DeepMind 的編程版 AlphaGo——AlphaCode 一度火到刷屏。它可以編寫與普通程序員水平相媲美的計算機程序,在 Codeforces 網站的 10 項挑戰中總體排名前 54.3%,擊敗了 46% 的參賽者。
這一成績給程序員群體帶來了不小的壓力,仿佛紡織工被紡織機淘汰的歷史正在重演。那麼,AlphaCode 是如何做到如此強大的?在最近的一個 YouTube 視頻中,清華大學朱軍門下博士後 Tim Pearce 詳細解析了 AlphaCode 的系統架構、「解題」原理、訓練流程等內容。原視頻地址:https://www.youtube.com/watch?v=YjsoN5aJChA前面提到,DeepMind 的研究者將 AlphaCode 放在 Codeforces 挑戰中進行了測試。Codeforces 是一個在線編程的平台,裡面有各種各樣的編程題目,各種各樣的比賽。它類似於國際象棋中使用的 Elo 評級系統,每周分享編程挑戰和問題排名。不同於編程人員在打造商業應用程序時可能面臨的任務,Codeforces 的挑戰更加獨立,需要對計算機科學中的算法和理論概念有更廣泛的了解,一般是結合邏輯、數學和編碼專業知識的非常專業的難題。
下圖展示了其中一個賽題的例子,包含賽題描述、輸入輸出示例等內容,挑戰者的任務就是根據這些內容寫出一段代碼,使得其輸出符合要求。

對於 AlphaCode 來說,這還只是中等難度的挑戰。在類似的十項挑戰中,研究者將賽題輸入 AlphaCode。然後,AlphaCode 生成大量可能的答案,並通過運行代碼和檢查輸出來篩選這些答案,就像人類競爭對手一樣。AlphaCode 論文的聯合負責人 Yujia Li 和 David Choi 表示:「整個過程是自動的,無需人工選擇最佳樣本。」下圖是 AlphaCode 的概念圖。這是一個精心設計的系統,主要構建塊是基於 Transformer 的語言模型。但從本質上來說,沒有一個單獨的組件是全新的。
在解決編碼問題時,AlphaCode 使用了一個非常具體的協議(protocol),這個協議決定了整個系統的 pipeline。協議規定,他們可以無限制地使用示例測試用例,因為這些是作為問題的一部分給出的。但在提交給隱藏測試用例時,他們將提交版本數限制在了 10 次以內(至多 10 次)。
在第一個階段,他們使用一個大型 Transformer 模型,該模型將問題描述示例測試和一些關於問題的元數據都放在一個字符串中作為輸入。然後,他們從這個模型中採樣,生成大量的潛在解決方案。所以第一個階段得到的是 100 萬套可能的代碼腳本。在第二個階段,他們用示例測試用例測試了得到的 100 萬套代碼,其中 99% 的代碼都沒有通過測試,可以直接排除。這就將可行的代碼套數降到了 1000 個左右(具體數量取決於題目的難度)。在第三個階段,他們使用了第二個 Transformer 模型。該模型將問題描述作為輸入,但它並沒有試圖生成代碼來解決問題,而是生成測試用例輸入(每個問題對應 50 個輸入)。也就是說,他們並沒有選擇生成輸入和輸出對,而是生成了一些與問題相關的實際輸入。所以模型可能要生成字符串、二進制數或數列(具體生成形式取決於問題類型)。這種做法好在哪兒呢?他們認為,如果兩個腳本為所有 50 個測試返回相同的答案,那麼它們可能使用的是相同的算法。這就可以避免浪費兩次提交機會把這兩個腳本都測試一下。所以在第二步得到 1000 套腳本後,他們就根據這 50 個生成的測試輸入的輸出對腳本進行聚類,然後從每個聚類中選出一個示例腳本,總共選出 10 個。如果這 10 個腳本中有一個通過了所有的隱藏測試,那麼他們就成功地解決了這個編程問題,否則就宣告失敗。以上就是 AlphaCode 在測試時的工作原理,其中用到了兩個 Transformer 模型。那麼這兩個模型是怎麼訓練的呢AlphaCode 的訓練分為兩個階段:預訓練和微調。這一過程涉及兩個數據集:第一個是由各種編程語言組成的公共 GitHub 庫,用於預訓練,數據量高達 715GB;第二個是從各個編程挑戰網站(包括 codeforces)搜集的賽題,用於微調,包括問題描述、測試用例和人類程序員編寫的答案。

在預訓練階段,他們會抓取 GitHub 上的一些代碼,然後隨機選擇他們所謂的「pivot point」。
pivot point 之前的所有東西都將被輸入到編碼器中,解碼器的目標則是重建 pivot point 以下的代碼。編碼器輸出代碼的向量表示,後續可用於整個解碼過程。解碼器以自回歸的方式工作。它從預測代碼的第一個 token 開始。損失函數就是預測的 softmax 輸出和真實 token 之間的交叉熵。然後,第一個真實的 token 成為解碼器的輸入,第二個 token 隨之被預測出來。在解碼器被要求預測出一個特殊的代碼結束標記前,這種情況會一直重複下去。現在,這些損失通過解碼器和編碼器反向傳播,但對於編碼器來說,增加第二個損失是非常重要的。這被稱為掩蔽語言建模損失:你將輸入到編碼器中的一些 token 留空,作為一種輔助任務,編碼器會試圖預測哪個 token 被掩蔽了。
預訓練結束之後就到了微調環節。在這個環節,他們將問題描述元數據和示例的輸入輸入到編碼器中,試着用解碼器生成人類編寫的代碼。此時可以看到,這與編碼器 - 解碼器架構所規定的結構非常自然地吻合在一起。這一階段的損失與預訓練時完全相同。而且,這裡也有第二個 Transformer 用來生成測試輸入。這也是由相同的 GitHub 預訓練任務初始化的,但它被微調以生成測試輸入而不是代碼。

除了上面提到的常規訓練步驟和架構,AlphaCode 還從最近的其他論文中借鑑了一些經驗。Tim Pearce 指出了其中比較不錯的一個:
除了問題描述,研究者還總是將元數據作為 Transformer 的輸入,包括編程語言、問題的難度等級、關於問題的一些標籤,以及解決方案是否正確等。在訓練時,模型顯然知道這些字段的值是什麼,但在測試時,它們並不知道。非常有趣的是,他們可以在測試時向這些字段中輸入不同的東西來影響生成的代碼。例如,你可以控制系統將要生成的編程語言,甚至影響它試圖生成的解決方案類型,比如是嘗試動態編程方法還是進行窮舉搜索。他們在測試時發現,當他們對最初的 100 萬個代碼腳本進行採樣時,將很多字段隨機化是非常有幫助的。因為,通過增加原始採樣池的多樣性,正確答案出現的可能性就會增加。以上就是 Tim Pearce 對 AlphaCode 的全部解析。他認為,DeepMind 的團隊在這項工作中的確取得了一些進展。但他比較不解的是:為什麼他們在這些編程問題中取得的成就遠遠不及他們在圍棋、《星際爭霸》等遊戲中取得的超越人類的成果?Tim Pearce 初步猜測是因為編程問題比較難,而且數據比較難以獲取,因為在遊戲中你可以無限制地產生很多模擬數據,但在編程問題上卻不能這麼做。https://www.youtube.com/watch?v=YjsoN5aJChAhttps://storage.googleapis.com/deepmind-media/AlphaCode/competition_level_code_generation_with_alphacode.pdf
©THE END
轉載請聯繫本公眾號獲得授權
投稿或尋求報道:content@jiqizhixin.com