自動生成和驗證程式修復技術通常依賴於硬編碼規則,因此只按照特定的修復模式修復 bug。這些規則需要大量的手工工作來發現,並且很難使這些規則適應不同的程式語言。
為了應對這些挑戰,我們提出了一種新的技術——CoCoNuT,它在卷積神經網路和新的上下文感知神經機器翻譯架構的組合上使用整合學習,自動修復多種程式語言中的 bug。為了更好地表示 bug 的上下文,我們引入了一個新的上下文感知的 NMT 體系結構,它分別表示有 bug 的原始碼及其周圍的上下文。CoCoNuT 使用 CNN 而不是迴圈神經網路,因為 CNN 的層可以堆疊來提取層次特徵,並在不同粒度級別更好地建模原始碼。此外,椰殼利用超引數調優的隨機性來建立多個模型來修復不同的 bug,並使用整合學習來結合這些模型來修復更多的 bug。
我們對四種程式語言的六種流行基準進行了評估,結果顯示 CoCoNuT 正確地解決了以下問題:509 個 bug,其中 309 個 bug 沒有被我們比較的 27 種技術所修復。
關鍵字:自動化程式修復,深度學習,神經機器翻譯,人工智慧和軟體工程
1 介紹為了提高軟體的可靠性和工程效率,研究人員開發了許多自動修復軟體缺陷的方法。G&V 方法是程式自動修復的主要方法之一。首先,候選補丁是使用一組轉換或突變生成的。其次,透過編譯和執行給定的測試套件,對這些候選項進行排序和驗證。G&V 工具返回最高階的修復程式,該修復程式編譯並通過了揭示錯誤的測試用例。
雖然 G&V 技術成功地修復了不同資料集中的 bug,但最近的一項研究表明,在最先進的技術的搜尋空間中,只有很少的補丁是正確的,這就給 G&V 技術可以生成的正確補丁數量設定了上限。此外,現有的技術需要廣泛的定製才能跨程式語言工作,因為大多數修復模式都需要手工重新實現才能適用於不同的語言。
因此,需要一種新的 APR 技術來修復更多的 bug,並且很容易轉移到不同的程式語言。神經機器翻譯是一種流行的深度學習方法,它使用神經網路體系結構來生成給定輸入序列的可能標記序列。NMT 使用一個編碼器塊,以建立從訓練資料中學習到的輸入的中間表示,以及一個解碼塊,將這個表示解碼為目標序列。NMT 主要應用於自然語言的翻譯任務。
APR 可以被看作是從錯誤的原始碼到正確的原始碼的翻譯。因此,有一個獨特的機會來應用 NMT 技術,從開源儲存庫中現成的 bug 修復中學習,併為看不見的 bug 生成修復。
這種基於 nmt 的 APR 技術有兩個關鍵優勢。首先,NMT 模型自動學習輸入和輸出序列之間的複雜關係,這是很難手動捕獲的。類似地,NMT 模型也可以捕獲 bug 和乾淨程式碼之間的複雜關係,這對於手工設計的修復模式來說是很難捕獲的。第二,雖然 G&V 方法經常使用硬編碼的修復模式,這些模式依賴於程式語言,並且需要領域知識,但是 NMT 技術可以自動為不同的程式語言重新培訓,而無需重新實現修復模式,因此只需要很少的手工工作。
儘管有巨大的潛力,但在 APR 應用 NMT 仍面臨兩大挑戰:
表示上下文:如何修復一個 bug 通常取決於上下文,例如,在 bug 行之前和之後的語句。然而,無論在自然語言任務還是 bug 修復任務中,如何有效地表示上下文都是 NMT 模型面臨的挑戰;因此,要翻譯的句子的直接上下文通常被忽略。兩種使用 NMT 修復 bug 的技術將上下文和 bug 程式碼連線為一個輸入例項。這種設計選擇是有問題的。首先,連線上下文和有 bug 的程式碼使輸入序列非常長,已知現有的 NMT 體系結構很難處理長輸入。因此,這類方法只能修復較短的方法。例如,Tufano 等人必須關注包含少於 50 個令牌的短方法。其次,連線 bug 行和上下文行使得 NMT 更難提取標記之間有意義的關係。例如,如果輸入由 1 車線和 9 行背景下,9 上下文行新增噪聲的車線,防止網路學習有用的車線和修復之間的關係,這使得模型效率低下和不那麼有效修復 bug 的程式碼。
我們提出了一種新的上下文感知的 NMT 體系結構,它有兩個獨立的編碼器:一個用於 bug 行,另一個用於上下文。使用獨立編碼器有三個優點。首先,錯誤的行編碼器將只有更短的輸入序列。因此,它將能夠提取錯誤行中令牌之間的強關係和正確的修復,而不會在上下文中令牌之間的關係上浪費資源。其次,一個單獨的上下文編碼器可以幫助模型從上下文中學習有用的關係,而不會給從 bug 行中學習到的關係新增噪音。第三,由於兩個編碼器是獨立的,上下文和 bug 行編碼器可以有不同的複雜性,這可以提高模型的效能。例如,由於上下文通常比有 bug 的行要長得多,上下文編碼器可能需要更大的卷積核心來捕獲長距離關係,而有 bug 的行編碼器可能受益於更多的層,以捕獲 bug 和乾淨線條之間更復雜的關係。這種上下文感知的 NMT 體系結構是新穎的,也可以用於改善其他任務,如修正語法錯誤和自然語言翻譯。
捕獲 bug 修復的多樣性。由於 bug 和修復的多樣性很難一般化,因此,我們利用整合學習來組合不同複雜級別的模型,以捕獲 bug 和乾淨程式碼之間的不同關係。這使得我們的技術可以學習不同的修復策略來修復不同型別的 bug。
在本文中,我們提出了一種新的 G&V 技術,稱為 CoCoNuT,它由全卷積模型和不同複雜度的新的上下文感知 NMT 模型組成。每個上下文感知模型使用兩個獨立的編碼器捕捉關於修復操作及其上下文的不同資訊。透過結合這些模型,CoCoNuT 可以學習不同的修復策略,這些策略用於修復不同型別的 bug,同時克服現有 NMT 方法的侷限性。
透過對 4 種程式語言的 6 個 bug 基準的 27 個 APR 技術進行評估,CoCoNuT 修復了 509 個 bug,其中 309 個沒有被任何現有的 APR 工具修復。圖 1 顯示了兩個針對缺陷中的 bug 的補丁,演示了 CoCoNuT 從 Java 訓練集中的 3,241,966 個例項中學習 bug 和乾淨程式碼之間新的複雜關係的能力。之前的工作沒有發現的錯誤型別。圖中“-”表示要刪除的一行,CoCoNuT 作為輸入,“+”表示 CoCoNuT 生成的一行。這些以前的技術代表了 APR 十年來使用手工設計的 Java 修復模式的研究。這表明,CoCoNuT 透過自動學習現有技術沒有的新修復模式,並自動修復現有技術沒有修復的 bug 來補充現有的 APR 方法。為了修復圖 1b 中的錯誤,CoCoNuT 從上下文行中瞭解要插入條件語句的正確變數。
2 背景和術語DL 網路是一種結構。它包含了為執行特定任務而堆疊的節點或層。每一種型別的層代表一個特定的低層次轉換的輸入資料與特定的引數。我們將 DL 體系結構稱為一組 DL 網路的抽象,這些網路具有相同的層型別和順序,但沒有指定層的數量和維度。一組超引數指定了如何將一個體繫結構合併到一個網路中。超引數還決定了在訓練中使用哪個最佳化器,以及最佳化引數,如學習速率和動量。我們稱一個模型,一個經過訓練的網路,它有固定的權值。
注意機制是最近 DL 的改進。它幫助神經網路關注最重要的特徵。傳統上,只有編碼器的最新隱藏狀態被饋給解碼器。如果輸入序列太長,有關早期令牌的一些資訊將丟失,即使在使用 LSTM 節點時也是如此。注意力機制透過將這些長距離依賴關係儲存在單獨的注意力圖中,並在每個時間步驟將它們提供給解碼器來克服這個問題。
候選補丁、可信補丁和正確補丁。我們將工具生成的補丁稱為候選補丁。透過故障觸發測試用例的候選補丁是可信的補丁。在語義上與開發者的補丁等價的看似合理的補丁就是正確的補丁。
3 方法我們的技術包含三個階段:訓練、推斷和驗證。圖 2 顯示了 CoCoNuT 的概述。在訓練階段,我們從開源專案中提取了 bug、上下文和固定線路的元組。然後,我們對這些行進行預處理以獲得令牌序列,將這些序列提供給一個 NMT 網路,並使用不同的超引數集對網路進行最佳化。我們進一步訓練最上面的 k 個模型直到收斂,得到 k 個模型的集合。由於每個模型有不同的超引數,每個模型學習不同的資訊來幫助修復不同的 bug。
在推理階段,使用者向 CoCoNuT 輸入一個 bug 線及其上下文。然後,它對輸入進行標記,並將其提供給前 k 個最佳模型,每個模型都輸出一個補丁列表。然後對這些補丁進行排名並透過編譯補丁專案進行驗證。然後 CoCoNuT 在可編譯的補丁上執行測試套件來過濾不正確的補丁。最後的輸出是透過驗證階段的候選補丁的列表。
3.1 挑戰除了引言中討論的兩個主要挑戰,即表示上下文,捕捉固定模式的多樣性,使用 NMT 對 APR 有額外的挑戰:神經元層的選擇,自然語言文字是按照從左到右的順序讀取的,而原始碼通常不是按照相同的順序執行的。因此,相關資訊可以放置在遠離 bug 的位置。因此,使用 LSTM 層的傳統遞迴神經網路在 APR 中可能表現不佳。
為了解決這些挑戰,我們構建了新的上下文感知的 NMT 體系結構,使用卷積層作為兩個編碼器和解碼器的主要元件,因為它們比 RNN 層更好地捕捉這些不同的依賴關係。我們將不同核大小的卷積層堆疊起來,表示不同粒度級別的關係。大的核層模型長期關係,而小的核層模型短期關係。為了進一步追蹤輸入編碼器和上下文編碼器的長期依賴關係,我們使用了一個多步驟注意機制。詞彙量大,與傳統的自然語言處理任務相比,原始碼的詞彙量大,而且許多標記很少出現,因為開發人員實際上可以建立任意的標記。此外,字母大小寫表示原始碼中的重要含義,這進一步增加了詞彙表的大小。例如,以前的工作必須處理大於 560000 個令牌的程式碼詞彙表。實踐者需要顯著減少詞彙表的大小,使其可用於 NMT,這就留下了大量不常見的詞彙表外標記。我們透過使用一種新的標記化方法來解決這一挑戰,該方法在不增加詞彙表外單詞數量的情況下顯著減少詞彙量。對於 Java,我們的標記化將詞彙表大小從 1,136,767 減少到 139,423 個標記,同時將測試集中詞彙表外的標記百分比保持在 2%以下。
3.2 資料提取我們訓練 CoCoNuT 從開源專案的提交歷史中提取的 bug、上下文和固定行程式碼元組。為了刪除與 bug 修復無關的提交,我們遵循前面的工作,只保留在提交訊息中具有關鍵字“fix”、“bug”或“patch”的提交。我們還使用六個提交訊息反模式來過濾提交,“重新命名”、“清理”、“重構”、“合併”、“拼寫錯誤”和“編譯器警告”。“我們用這種方法篩選了 100 個隨機提交樣本,手工調查其中 93 個是與 bug 相關的提交。對於大規模訓練資料的 ML 訓練來說,這是一個合理的噪聲量。我們將提交拆分為塊,並將每個塊視為唯一的例項。
我們使用圍繞 bug 行的函式來表示 bug 的上下文,因為它提供了關於 bug 功能的語義資訊,相對較小,包含大多數相關變數,並且可以為數百萬個例項提取。圖 2 中的塊“資料提取”顯示了一個示例,其中有一條錯誤的線,一條正確的線,以及一些上下文線。
所提議的上下文感知的 NMT 體系結構獨立於上下文的選擇,並且仍然適用於不同的上下文定義。我們的貢獻是將 bug 行和上下文分別表示為第二個編碼器,獨立於選擇的上下文。探索其他上下文定義是未來有趣的工作。
3.3 輸入表示和標記化我們使用一種類似於詞級標記化的標記化方法。為了解決這個問題,我們還考慮將下劃線、駝峰字母和數字作為分隔符,從而增強單詞級別的標記化。因為我們需要從 NMT 模型生成的令牌列表中正確地重新生成原始碼,所以我們還需要引入一個新令牌來標記 CAMEL case 拆分發生的位置。此外,除了訓練集中最常見的數字外,我們還對字串和數字文字進行抽象。
3.4 上下文感知的 NMT 架構CoCoNuT 的建築有兩個主要的新奇之處。第一個是使用兩個獨立的編碼器來表示上下文和錯誤的行。第二個是一個新的應用,全卷積層用於 APR,而不是傳統的 RNN,如在以前的工作中使用的 LSTM 層。我們選擇 FConv 層是因為 FConv 的 CNN 層可以堆疊,以提取層次特徵用於更大的上下文,這允許在不同粒度級別建模原始碼。這更接近於開發人員閱讀程式碼的方式。RNN 層將程式碼模型為序列,這更類似於從左到右讀取程式碼。
在訓練模式下,上下文感知模型可以訪問故障行、上下文和固定行。該模型經過訓練,以生成從有上下文的線路到固定線路的轉換的最佳表示。在實踐中,這是透過尋找將輸入例項從訓練集轉換為固定行的權值的最佳組合來進行的。為了獲得最佳的權值集,需要對訓練資料進行多次傳遞。
在圖 3 中的示例輸入之後,使用者向 CoCoNuT 輸入錯誤的語句“int sum=0;”及其上下文。在標記化之後,將有 bug 的語句提供給輸入編碼器,同時將上下文提供給上下文編碼器。兩個編碼器的輸出然後在合併層中連線。
由於 CoCoNuT 沒有生成任何令牌,令牌一代首先喂牌<開始>解碼器迭代譯碼器的輸出,然後結合使用點積的合併輸出,形成注意力地圖的第一列。注意圖的顏色表示每個輸入標記對產生輸出的重要性。例如,要生成第一個令牌,令牌 int 是最重要的輸入令牌,用紅色表示。令牌生成將關注的輸出以及合併和解碼器輸出的總和組合在一生成令牌 double。這個新的令牌被新增到生成的令牌列表中,該列表作為新輸入返回給解碼器。解碼器使用這個新輸入計算下一個它用於構建注意力對映的第二列,並生成下一個標記。令牌的生成將繼續,直到生成為止。
嵌入層將輸入和目標標記表示為向量,出現在類似上下文中的標記具有類似的向量表示。在某種意義上,這些層代表了模型對程式語言的知識。
將嵌入層的輸出反饋給幾個卷積層。卷積核的大小表示要考慮的周圍令牌的數量。將這些卷積層與不同的核心大小堆疊起來,為我們的網路提供了多個抽象級別。例如,核心大小較小的層只關注語句中幾個周圍的標記,而較大的層則會關注一個程式碼塊,甚至是一個完整的函式。這些層在編碼器和解碼器上是不同的。編碼器使用來自輸入序列中前一個和下一個標記的資訊,而解碼器只使用關於之前生成的標記的資訊。圖 3 顯示了這些差異。
在卷積層之後,一個 GLU 層決定哪些資訊應該由網路儲存。然後合併連線輸入編碼器的輸出和上下文編碼器。
注意對映表示輸入標記對生成特定輸出標記的影響,並可以幫助解釋為什麼生成特定輸出。我們分析了 RQ4 中的注意圖。令牌生成:令牌生成將關注層的輸出組合,並和解碼器生成下一個令牌。詞彙表中的每個令牌都由令牌生成元件根據它們成為輸出序列中下一個令牌的可能性進行排序。然後,搜尋演算法選擇的令牌追加到生成的令牌列表中,該列表作為解碼器的新輸入發回。當生成令牌時,令牌生成停止。
束搜尋:我們使用一種常用的搜尋策略束搜尋來生成大量的候選補丁並對其進行排序。對於每一次迭代,束搜尋演算法檢查 最有可能令牌總似然得分和排名的下一個 預測步驟。最後,束搜尋演算法輸出頂端 最有可能的序列命令基於每個序列的可能性。
3.5 整體學習修復 bug 是一項複雜的任務,因為有各種各樣的 bug,修復模式也各不相同,而且複雜性也各不相同。有些固定模式非常簡單 而其他的則需要更復雜的修改。訓練一個模型來修復所有型別的 bug 是很困難的。相反,將多個專門的模型組合到一個整合模型中會比單個模型修復更多的錯誤更有效。
因此,我們提出了一種整合方法,它將:有或沒有上下文的模型,以及具有不同超引數的模型在我們的驗證集上表現最好。
如第 2 節所述,超引數將一個體繫結構合併為一個網路。不同的超引數對網路的複雜性、訓練過程的速度以及訓練模型的最終效能有很大的影響。對於這個調優過程,我們應用了隨機搜尋,因為之前的工作表明,它是一種廉價的方法,比其他常見的超引數調優策略效能更好。對於每個超引數,基於硬體限制,我們定義了一個範圍,可以從中選擇一個隨機值。由於訓練一個模型直到收斂是非常昂貴的,我們只調整一個紀元。我們訓練 不同隨機引數集的模型獲得不同行為的模型並保持頂部 最佳模型基於每個模型在單獨驗證集上的效能。這個最佳化過程允許我們丟棄不適合或過適合的模型,同時保留 最佳模型收斂到不同的區域性最優,並修復不同的現實世界的 bug。
最後,我們根據不同模型生成的 patch 的秩對其進行排序。我們使用每個序列由每個模型生成,以對同等等級的補丁進行排序。
3.6 補丁驗證語句重構,一個模型輸出一系列令牌,這些令牌形成了對輸入錯誤行的修復。語句重構模組從令牌列表中生成一個完整的補丁。對於抽象的標記,我們從發生錯誤的原始檔案中提取捐贈者程式碼。一旦生成了修復,它就會被插入到有 bug 的位置,然後我們就可以進入驗證步驟了。
編譯和測試套件驗證,模型不能訪問整個專案;因此,它不知道生成的補丁是否 可編譯或透過測試套件。驗證步驟過濾掉未編譯或未透過觸發測試用例的補丁。在驗證過程中,我們使用與之前工作相同的兩個標準。首先,讓 bug 版本透過的測試用例仍然應該透過修補過的版本。第二,至少有一個測試用例在有 bug 的版本上失敗了,應該透過修補過的版本。
3.7 對其他語言的概括由於 CoCoNuT 可以自動學習模式,而不是依賴於手工製作的模式,因此它可以用最少的努力推廣到其他程式語言。主要需要的更改是獲取新的輸入資料。幸運的是,這很容易做到,因為我們的訓練集是從開源專案中提取的。
4 實驗裝置選擇訓練資料:由於我們的 Java 基準測試中最早的錯誤來自 2006 年,最新的錯誤來自 2016 年,我們將從訓練專案中提取的例項分為兩個訓練集。第一個例項包含 2006 年之前提交的所有例項,第二個包含 2010 年之前提交的例項。在 2010 年之後提交的例項將被丟棄。使用第一個訓練集訓練的模型可以用來訓練模型以修復測試基準中的所有 bug,而使用第二個訓練集訓練的模型應該只用於 2010 年之後修復的 bug。這個設定是為了確保實驗的有效性,這樣就不會使用未來的資料。
對於 Java,我們使用 GHTorrent 從 59237 個包含 2010 年前提交的專案中收集例項。我們也從最古老的 20000 個 Gitlab 專案中提取資料的侷限性造成的,因為我們希望老專案含有更多的 bug 修復之前第一個錯誤在我們的基準,和 10111 年 Bitbucket 都儲存庫。
對於其他語言,我們使用 GHTorrent 從所有 GitHub 專案中提取資料,在它們的相關基準測試出現第一個錯誤之前。表 1 顯示了所有訓練集中的專案數量和例項數量。
選擇最先進的工具進行比較:我們將 CoCoNuT 與 27 種 APR 技術進行比較,包括之前比較中使用的所有 Java 工具,另外兩種最近的技術,五種最先進的 C 工具,以及兩種基於奈米技術的技術。我們選擇 DLFix 和排序器而不是其他 NMT 技術進行比較,因為只生成模板,關注的是編譯錯誤,這是另一個問題。
5 評價與結果在處理時序資料時,錯誤地建立評估並不罕見。如果用於構建 APR 技術的歷史資料比基準測試中的 bug 更近期,那麼它可能包含有幫助的資訊,這些資訊在修復時實際上是不可用的。使用比基準測試中的 bug 更新的訓練/驗證例項來訓練或驗證我們的模型是不正確的設定,並且可能會人為地提高模型的效能。
這個錯誤的設定可能會影響所有以前使用歷史資料的 APR 技術。儘管影響可能會小一些,但甚至基於模式的技術也可能會受到這個問題的困擾,因為模式可能是從基準測試中修復的 bug 中手動學習的。據我們所知,我們是第一個在 4 月份承認並解決這個錯誤設定問題的。使用未來資料的威脅也是我們沒有使用 k-fold 交叉驗證進行評估的原因之一。
為了解決設定問題,我們提取基準測試中最老 bug 的時間戳,並且只使用時間戳之前的訓練和驗證例項。然而,向訓練集新增更新的資料將有助於修復最近的 bug。與之前的工作類似,我們在第一個生成的 patch 成功透過測試集驗證後停止 CoCoNuT。如果超過 6 個小時沒有補丁透過測試套件,我們就會停下來,認為這個 bug 沒有被 CoCoNuT 修復。僅為評估目的,三位共同作者手動比較了可信的斑塊傳遞給開發人員的補丁,如果他們都同意使用前面的工作中描述的等價規則,一個補丁與開發人員的補丁是相同的或語義等價的,那麼這個補丁就是正確的。
5.1 RQ1:CoCoNuT 如何與最先進的 APR 技術相抗衡?表 2 顯示了我們在 4 種不同程式語言的 6 個基準上比較了 CoCoNuT 與 27 種最先進的 G&V 方法。我們對 Java 使用了 defts4j 和 QuixBugs,對 C 使用了 code 瑕疵和 ManyBugs,對 Python 使用了 QuixBugs。JavaScript;我們使用了在之前的工作中描述的 12 個與 JavaScript 常見 bug 模式相關的示例。每個資料集中的錯誤總數都在基準測試的名稱之下。
我們將我們的結果與流行的和最近的用於 C 和 Java 的 G&V 技術進行比較。我們不比較 JavaScript APR 技術 Vejovis,因為它只修復了文件物件模型中的 bug。我們從最近的評估中提取每種技術的結果,並在可用時對原始結果進行交叉檢查。完美的 bug 定位結果是從 GitHub 儲存庫中提取的以前的工作,並手動驗證以刪除重複的 bug。
我們在整個程式碼缺陷資料集上執行 Angelix、Prophet、SPR 和 GenProg,因為這些技術還沒有在整個資料集上進行評估。我們使用 code 瑕疵資料集作者提供的預設超時值。由於 codedefects 由小的單檔案程式組成,所以這些技術在超時較大時的效能不太可能不同。
在 Java 基準測試中,CoCoNuT 在 QuixBugs 基準測試中超越了現有的工具,修復了 13 個 bug,其中包括 10 個以前沒有修復的 bug。在 Defects4J 上,CoCoNuT 的效能比除 TBar 和 Hercules 之外的所有技術都要好。此外,CoCoNuT 修復的 6 個 bug 沒有被任何其他技術修復。6 個 bug 中有兩個需要新的修復模式,而這在 APR 十年的研究中從未被發現過。我們將在 RQ2 中詳細研究這六個 bug。此外,Hercules 修復的 15 個 bug 是多大塊的 bug,目前超出了 CoCoNuT 的範圍,它主要生成單個大塊的 bug 修復。將來,赫拉克勒斯修復多塊臭蟲的方法可以應用到 CoCoNuT 上。
在 JavaScript 和 Python bug 基準測試中,CoCoNuT 分別修復了 3 個和 19 個 bug。由於不同的 bug 基準包含不同型別 bug 的不同發行版,不同的 APR 工具修復不同型別的 bug,因此在不同的基準上評估新的 APR 技術以進行公平和全面的比較是很重要的。CoCoNuT 是六個標準中的四個最好的技術。
5.2 RQ2:哪些 bug 只有 CoCoNuT 可以修復?對於只有 CoCoNuT 可以在 Defects4J 中修復的 bug,我們在我們的硬體上以完美的本地化重新執行 TBar,這是 Java 的最佳技術,並且沒有時間限制來確認 TBar 不能修復這些 bug,即使在可能的最佳條件下也是如此。對於 C 語言,如 RQ1 中所述,我們使用與椰書相同的硬體,在程式碼缺陷上執行 Angelix、SPR、Prophet 和 GenProg,以便進行公平的比較。CoCoNuT 是唯一修復 Python 和 JavaScript 基準測試中的 bug 的技術。
結果:儘管已經對 Java 修復模式進行了十年的研究,CoCoNuT 還是透過自動學習尚未發現的新模式來修復 bug。Mockito 5 是缺陷 4j only CoCoNuT 修復中的一個 bug,因為它需要的模式沒有被現有的基於模式的技術覆蓋。,異常型別更新)。Lang 29 是另一個不能由其他工具修復的錯誤,因為現有的基於模式的技術沒有用於更新函式返回型別的模式。TBar 不能為這兩個錯誤生成任何候選補丁。
多虧了上下文感知的架構,CoCoNuT 透過從上下文中正確提取捐贈者程式碼修復了其他技術無法修復的 bug,而 TBar 等技術則依賴於啟發式。圖 1b 中的錯誤示例在第 1 節中解釋。
CoCoNuT 是唯一修復 Closure 92 的技術,因為它從歷史資料中瞭解到,String 庫中的 lastIndexOf 方法很可能取代 indexOf 方法。其他技術如 TBar 無法生成正確的補丁,因為捐贈程式碼不在它們的搜尋空間中。
在 Defects4J 中,43%由 CoCoNuT 修復的 bug 沒有被 TBar 修復,因此 CoCoNuT 可以很好地補充 TBar。還有幾個由 TBar 修復的 bugCoCoNuT 沒有修復。其中 7 個是 if 語句插入,3 個是將語句移動到不同位置的修復。對於 CoCoNuT 來說,這些 bug 很難修復,因為我們的目標是透過修改語句來修復的 bug,因此這兩個轉換不會出現在我們的訓練集中。透過插入 if 語句來修復 bug 已經得到了廣泛的研究。相反,我們提出了一種新的技術來修復那些對於其他技術來說更具挑戰性的 bug。
當我們為每個模型的每個 bug 生成 1000 個補丁時,正確的補丁通常排名非常高。Defects4J 中的 44 個正確補丁中的 10 個被其中一個模型排在第一位。一個正確 patch 的平均 rank 是 63,中位數 rank 是 4。一個正確補丁的最差排名是 728。
對有效性的一個潛在威脅是一些工具使用不同的故障定位技術。雖然我們不能使用完美的本地化來重新實現所有現有的工具,但我們會盡我們最大的努力來減輕這種威脅。首先,我們考慮 13 個同樣使用完美本地化進行比較的工具,包括 TBar,它修復了缺陷 4j 中最多的 bug。其次,TBar 使用來自 10 個工具的修復模式進行完美的本地化。因此,雖然這 10 種工具中的一些不使用完美故障定位,我們間接比較這些工具使用完美故障定位。CoCoNuT 修復了包括 TBar 在內的現有工具沒有修復的 6 個 bug。
在 C 基準測試中,CoCoNuT 修復了 430 個 bug,其中 271 個以前沒有修復過。CoCoNuT 在 Codeflaws 資料集上優於現有技術,比 Angelix 多修復了 105 個 bug
5.3 CoCoNuT 不同成分的貢獻是什麼?它與其他以 nmt 為基礎的 APR 技術相比如何?為了瞭解 CoCoNuT 中每一種成分的影響,我們分別對它們進行了研究。更具體地說,我們關注三個關鍵貢獻:與最先進的 NMT 體系結構相比,我們的新 NMT 體系結構的效能,上下文的影響,以及整合學習的影響。我們比較了椰與 DLFix 和音序器,兩種最先進的基於 NMT 的 APR 技術和三種其他最先進的 NMT 架構。這些模型並沒有被用於程式修復,因此我們在與我們的工作。為了確保公平的比較,我們對 LSTM、Transformer 和 FConv 進行了類似於 CoCoNuT 的調優和訓練。音序器使用 LSTM 編碼器-解碼器的方法自動修復 bug。我們使用 SequenceR 和 DLFix 的作者在 Defects4J 資料集上報告的數字進行比較,因為在編寫本文時,SequenceR 和 DLFix 的工作版本是不可用的。使用了一種新的 treeRNN 架構,它將源程式碼表示為一棵樹。
與最先進的 NMT 相比:CoCoNuT 修復了最多的 bug,在 Defects4J 中修復了 44 個 bug。DLFix 是其次是 FConv,修復了 29 個 bug,其次是 FConv,修復了 21 個 bug。Transformer 和 SequenceR 效能相近,分別修復了 13 個和 12 個 bug。最後一個基線 LSTM 的效能很差,只修復了 5 個 bug。這些結果表明,CoCoNuT 比最先進的 DL 方法表現更好,直接對 APR 應用現成的深度學習技術是無效的。
整體學習的優勢:圖 7 顯示,隨著 增加從 1 到 10,CoCoNuT 修復的 bug 數量從 22 歲到 44 歲的增加提高了 50%。我們在 FConv 模型中觀察到類似的趨勢,表明整合學習獨立於所使用的架構是有益的。模型 9 和模型 7 分別是最好的 FConv 和上下文感知模型,都修復了 26 個 bug。
同時增加 也增加了執行時的技術,這個成本不是太高,因為 CoCoNuT 是離線技術和可以在一夜之間執行。在更糟糕的情況下,隨著 = 10,CoCoNuT 需要平均 16.7 分鐘為一個錯誤。
雖然 CoCoNuT 在 Defects4J 中修復了 44 個 bug,但單個模型修復的 bug 平均數量是 15.65 個。在 Defects4J 中,40%的 bug 是由五個或更少的模型修復的。其中 6 個正確修復的 bug 僅由一個模型修復,而所有模型只修復了 2 個 bug。這表明在我們的整合方法中,不同的模型專門用於修復不同的 bug。
5.4 RQ4:我們能解釋為什麼 CoCoNuT 可以產生特定的修復嗎?大多數修復都不是克隆:透過學習歷史資料,我們的神經網路的深度允許 CoCoNuT 修復複雜的 bug,包括那些需要生成新變數的 bug。正如第 5 節開始時所討論的,我們只在測試中出現第一個 bug 之前對其進行培訓和驗證,以便進行公平的評估。因此,完全相同的錯誤不能出現在我們的訓練/驗證集和評估基準中。然而,同一個補丁仍然可以用來修復不同時間、不同地點引入的不同 bug。在訓練和測試集中都有這樣的補丁克隆是有效的,因為反覆修復是很常見的。CoCoNuT 修復的大多數 bug 都沒有出現在訓練集中:訓練或驗證集中只出現了兩個 C 基準和一個 JavaScript 基準的補丁。這表明 CoCoNuT 在學習和產生完全不同的固定物方面是有效的。
圖 8 所示的 Defects4J 資料集需要注入一個新的變數 mLocale。這個新變數在我們的訓練集中只出現了四次,而且從來沒有在類似的上下文中出現過。但是,mLocale 包含令牌區域設定,它與有 bug 的語句令牌 Gregorian、Time 和 Zone 同時出現在我們的訓練集中。
圖 9 中的注意對映確認了令牌時間對於生成區域設定變數很重要。具體來說,令牌化的輸入顯示在 y 軸上,而令牌化的生成輸出顯示在 x 軸上。m 和 Locale 之間的標記表示這兩個標記構成一個唯一的變數。注意力地圖顯示了輸入標記和生成標記之間的關係。單元格中的顏色表示相應的輸入和輸出標記之間的關係。圖中右側所示的色標從 0 到 0.6 變化,表示每個輸入令牌對生成輸出令牌的貢獻。
這個注意對映幫助我們理解為什麼模型會生成特定的標記。例如,第二個 m 輸出中生成的令牌 m 輸入,表明網路可以保持命名約定在生成新變數。令牌地區主要是由於生成令牌時間,表明網路相信這些標記應該在一起。最後,令牌形成變數 mLocale 都受到輸入令牌);和 EOS,表明該令牌經常在語句結束之前使用,或者在正確修復之前超時。使用先前工作中提出的增強測試套件可以緩解這個問題。
5.5 執行時間資料提取:從開源儲存庫提取資料和培訓 CoCoNuT 是一次性成本,可以攤銷在許多 bug 上,不應該計算在端到端修復一個 bug 的時間內。對於 Java,使用三臺伺服器從 59237 個專案中提取資料需要 5 天時間。
訓練時間:在調整過程中,訓練我們的上下文感知 NMT 模型 1 epoch 的中位數時間是 8.7 小時。平均來說,在一個 GPU 上訓練一個模型 20 個時代需要 175 個小時。變壓器和 FConv 網路的訓練速度更快,平均每個 epoch 需要 2.5 和 2.7 小時。然而,訓練 LSTM 網路要慢得多。
這一次的成本可以與花在設計和實現新的固定模式上的十年研究進行比較。
修復一個錯誤的成本:一旦模型得到訓練,主要的成本是推理和驗證。在推理過程中,為一個 bug 生成 20,000 個補丁平均需要 16.7 分鐘使用一個 GPU。在我們的硬體上,CoCoNuT 驗證 bug 的平均執行時間在 code 瑕疵上是 6 秒,在缺陷 4j 上是 6 分鐘。
修復 bug 的端到端平均時間從 code 瑕疵的 16.7 分鐘到缺陷的 22.7 分鐘不等。相比之下,在相同的硬體上,我們在 code 瑕疵上執行的其他工具的平均時間從 30 秒到 4 分鐘不等。在相同的硬體上,TBar 在 Defects4J 上的平均執行時間為 8 分鐘。
CoCoNuT 的端到端方式雖然比現有的方式慢,但仍然是合理的。此外,我們還可以透過減少推理中生成的補丁數量來縮短執行時間。只生成 1000 個補丁。多個 gpu 和 cpu 上的並行性也可以加速推理。
6 的侷限性用於訓練我們方法的資料集與其他工作使用的資料集不同,這可能會影響我們的比較結果。然而,資料集的選擇以及如何提取和表示資料是一項技術的關鍵組成部分。此外,我們在使用相同的訓練資料和硬體的情況下,將我們的方法與 LSTM、FConv 和 Transformer 架構進行了比較,結果表明 CoCoNuT 的效能優於其他三種。最後,DLFix 和 SequenceR 都使用了 bug 修復時不可用的資料。,他們的模型是使用在修復了缺陷 4j 中的 bug 之後提交的例項來訓練的),這可能會產生先前工作所顯示的錯誤的良好結果。
深度學習的一個挑戰是解釋神經網路的輸出。幸運的是,對於開發人員來說,編譯並透過測試用例的修復程式應該是不言而喻的。對於那些構建和改進 CoCoNuT 模型的使用者,我們利用了最近的多步驟關注機制來解釋為什麼會生成補丁或不會生成補丁。
7 相關工作APR 的 Deep Learning: SequenceR、DLFix 和 Tufano 等是與 CoCoNuT 研究關係最近的研究。與 CoCoNuT 的主要區別是,這些方法使用 RNN ,並將 bug 行及其上下文作為一個輸入表示。這些方法難以提取標記之間的長期關係,也無法捕獲 bug 修復的多樣性。我們在 5.3 節中展示了 CoCoNuT 優於 DLFix 和 SequenceR。Tufano 等人生成模板而不是完整的補丁,因此不能直接比較。深度學習也被用於檢測和修復小語法和編譯問題。這些模型顯示了修復編譯問題的良好結果,但只學習程式語言的語法。
G&V 程式修復:許多 APR 技術已經被提出。與這些技術相比,我們使用了不同的方法,如第 5 節所示,我們的方法修復了現有技術沒有修復的 bug。此外,這些技術需要重要的領域知識和依賴於語言的手工規則,而多虧了我們的上下文感知整合 NMT 方法,CoCoNuT 自動學習了這些模式,並且可以用最少的努力推廣到幾種程式語言。
語法錯誤修正:最近的研究使用機器翻譯來修正語法錯誤。其中,採用基於注意的卷積編碼解碼器模型來糾正句子級語法錯誤。CoCoNuT 是一個新的 NMT 模型在原始碼和程式語言上的應用,解決了獨特的挑戰。研究我們新的上下文感知的 NMT 體系結構是否能改善 GEC 仍然是未來的工作。
深度學習在軟體工程:軟體工程社群申請深度學習來執行各種任務,如缺陷預測,源程式碼表示,原始碼總結原始碼建模 5 日,11 日,26 日,程式碼克隆檢測,和程式合成。我們的工作為 APR 使用了一種新的深度學習方法。
8 結論我們提出了 CoCoNuT,一種新的端到端方法,使用 NMT 和整合學習來自動修復多種語言中的 bug。我們在四種不同程式語言的六個基準測試中評估了 CoCoNuT,發現它可以修復 509 個 bug,其中 309 個以前沒有被修復過技術。在未來,我們計劃改進我們處理多塊 bug 的方法。