滅霸來了!微軟發(fā)布BugLab:無需標注,GAN掉Bug
程序員的死對頭就是各種 bug!最近微軟在 NeurIPS 2021 上帶來了一個好消息,研究人員設(shè)計了一個類似 GAN 的網(wǎng)絡(luò),通過選擇器和檢測器來互相寫和改 bug,而且還不需要標注數(shù)據(jù)!
常言道,「一杯茶,一包煙,一個 bug 改一天」。
寫代碼是軟件工程師們每天的工作,但當你辛辛苦苦寫了一大堆代碼,卻發(fā)現(xiàn)無法運行的時候,內(nèi)心一定是崩潰的。
找 bug 不僅費時費力,最關(guān)鍵的是還經(jīng)常找不著,并且有時候改了一個 bug 又會引入更多 bug,子子孫孫無窮盡也。
簡直就是找 bug 找到吐血。
隨著 AI 技術(shù)的發(fā)展,各大公司開發(fā)的代碼助手如 GitHub Copilot 等也能幫你少寫一些有 bug 的代碼。
但這還遠遠不夠!
深度學習要是能幫我把代碼里的 bug 也給修了,我上班只負責摸魚,豈不是美滋滋!
微軟在 NeurIPS 2021 上還真發(fā)了一篇這樣的論文,其中提出了一個新的深度學習模型 BugLab,并通過自監(jiān)督的學習方法,可以在不借助任何標注數(shù)據(jù)的情況下檢測和修復(fù)代碼中的 bug,堪稱程序員的救世主!
修 bug 難在哪?
所謂的 bug,就是代碼的實際運行和自己的預(yù)期不符。
該運行的沒運行,該輸出a,結(jié)果卻輸出個b,這種代碼故意找茬的行為都屬于 bug。
所以想要找到并修復(fù)代碼中的 bug,不僅需要對代碼的結(jié)構(gòu)進行推理,還需要理解軟件開發(fā)者在代碼注釋、變量名稱等方面留下的模糊的自然語言提示。
例如一段程序的意圖是,如果名字的長度超過了 22 個字符,那就只截取前 22 個。但原始代碼中錯誤地把大于號寫成了小于號,導致條件判斷錯誤,程序運行結(jié)果和預(yù)期不符。
這種小錯誤在寫代碼的過程也是太常見了,稍不注意就會把條件弄反。
還有一種 bug 就是使用了錯誤的變量,例如下面的例子里面 write 和 read 弄錯了,就會導致條件判斷失敗,這種 bug 的修復(fù)只有在理解了變量名的意義后才能修復(fù),傳統(tǒng)的修復(fù)手段對此是無能為力。
這種錯誤看起來很簡單,但往往盯著看代碼的時候卻很難發(fā)現(xiàn),屬于一改改一天的那種。
并且每個程序員有自己的編程風格,比如不同的命名、縮進、判斷以及重構(gòu)的方式,想讓代碼來給自己找 bug,一個字,難!
對于微軟來說,好在有 GitHub 代碼庫可以用來訓練模型。但問題來了,GitHub 上帶 bug 的代碼有那么多嗎?有 bug 誰還 commit 啊?就算能找到代碼,也沒人來標注數(shù)據(jù)啊!
微軟提出的 BugLab 使用了兩個相互競爭的模型,通過玩躲貓貓(hide and seek)游戲來學習,主要的靈感來源就是生成對抗網(wǎng)絡(luò)(GAN)。
由于有大量的代碼實際上都是沒有 bug 的,所以需要設(shè)計一個 bug selector 來決定是否修改正確的代碼來引入一個 bug,以及以何種方式引入 bug(例如把減號改為加號等)。當選擇器確定了 bug 的類別后,就通過編輯源代碼的方式引入 bug。
另一個用來對抗的是 bug detector,用來判斷一段代碼是否存在 bug,如果存在的話,它需要定位并修復(fù)這個 bug。
選擇器和檢測器都能夠在沒有標記數(shù)據(jù)的情況下共同訓練,也就是說整個訓練過程都是以自監(jiān)督的方式進行,并成功在數(shù)百萬個代碼片段上訓練。
selector 負責寫 bug,并把它藏(hide)起來,而 detector 負責找 bug,并修復(fù),整個過程就像躲貓貓一樣。
隨著訓練的進行,selector 寫 bug 越來越熟練,而 detector 也能夠應(yīng)對更復(fù)雜的 bug。
整個過程與 GAN 的訓練大體相似,但目的卻大不相同。GAN 的目的是獲得一個更好的生成器來修改圖片,但 BugLab 的目的是找到一個更好的檢測器(GAN 中的判別器)。
并且整個訓練也可以看作是一個 teacher-student 模型,選擇器教會檢測器如何定位并修復(fù) bug。
為開源社區(qū)修 bug!
雖然從理論上來說,使用這種 hide and seek 的方式可以訓練更復(fù)雜的 selector 來生成更多樣的 bug,從而 detector 的修 bug 能力也會更強。
但以目前的 AI 發(fā)展水平來說,還無法教會 selector 寫更難的 bug。
所以研究人員表示,我們需要集中精力關(guān)注那些更經(jīng)常犯的錯誤,包括不正確的比較符,或者不正確的布爾運算符,錯誤的變量名引用等等其他一些簡單的 bug。并且為了簡單起見,實驗中只針對 python 代碼進行研究訓練。
雖然這些解釋聽起來都像是借口。
為了衡量模型的性能,研究人員從 Python 包索引中手動注釋了一個小型 bug 數(shù)據(jù)集,和其他替代方案(例如隨機插入 bug 的 selector)相比,使用 hide and seek 方法訓練的模型性能最多可以提高 30%
并且實驗表明大約 26% 的 bug 都可以被發(fā)現(xiàn)并自動修復(fù)。在檢測器發(fā)現(xiàn)的 bug 中,有 19 個在現(xiàn)實生活中的開源 GitHub 代碼中都屬于是未知的 bug。
但模型也會對正確的代碼報告存在 bug,所以這個模型在離實際部署上線還有一段距離。
如果更深入地研究 selector 和 detector 模型的話,就會引出那個老生常談的問題:深度學習模型到底有沒有,又怎么樣去「理解」一段代碼的作用?
過去的研究表明,將代碼表示為一個 token 序列就能夠產(chǎn)生次優(yōu)的(suboptimal)效果。
但如果想要利用代碼中的結(jié)構(gòu),例如語法、數(shù)據(jù)、控制流等等,就需要將代碼中的語法節(jié)點、表達式、標識符、符號等等都表示為一個圖上的節(jié)點,并用邊來表示節(jié)點間的關(guān)系。
有了圖以后就可以使用神經(jīng)網(wǎng)絡(luò)來訓練 detector 和 selector 了。研究人員使用圖神經(jīng)網(wǎng)絡(luò)(GNN)和 relational transformer 都進行了實驗,結(jié)果發(fā)現(xiàn) GNN 總體上優(yōu)于 relational transformer。
如何讓 AI 幫助人類來寫代碼和改 bug 一直都是人工智能研究中的一項基礎(chǔ)任務(wù),任務(wù)過程中 AI 模型需要理解人類對程序代碼、變量名稱和注釋提供的上下文線索來理解代碼的意圖。
雖然 BugLab 離真正解放程序員改 bug 還很遙遠,但距離我們消滅 bug 總算又向前走了一步!

































