引用
Islam M J, Pan R, Nguyen G, et al. Repairing Deep Neural Networks: Fix Patterns and Challenges[J]. arXiv preprint arXiv:2005.00972, 2020.
Abstract軟體工程中對於應用深度神經網路(DNN)的需求越來越大。修復使用 DNN 的軟體是一個明確的軟體工程需求,使用自動化工具可能是有益的;但是,我們不完全瞭解修復的挑戰以及手動修復 DNN 時使用的模式。自動化維修工具應解決哪些挑戰?自動化可以幫助開發人員的修復模式是什麼?在構建自動缺陷修復工具時,哪些修復模式應該被賦予更高的優先順序?這項工作提出了一個全面的研究缺陷修復模式來解決這些問題。我們針對五個流行的深度學習庫 Caffe、Keras、Tensorflow、Theano 和 Torch 研究了來自 Stack Overflow 的 415 個修復和來自 GitHub 的 555 個修復,以瞭解修復和 bug 修復模式中的挑戰。我們的主要發現表明,與傳統的 bug 修復模式相比,DNN bug 修復模式是獨特的;最常見的 bug 修復模式是修復資料維度和神經網路連線;DNN bug 修復有可能引入對抗性漏洞;DNN bug 修復經常引入新的 bug;以及 DNN bug 定位,開發人員在修復 bug 時面臨的主要挑戰是重用經過訓練的模型,並應對頻繁的釋出。我們還提供了 667 個 DNN(bug,repair)例項的基準測試。
1.Introduction大資料的可用性推動了深度神經網路(DNN)的出現。DNN 由一系列層組成。每層包含一組節點,從上一層收集輸入,並透過一組加權邊將輸出饋送給下一層的節點。這些權重使用稱為訓練資料的示例進行調整,並設定為使 DNN 的實際輸出與使用稱為損失函式的目標函式測量的預期輸出之間的差異最小化的值。大資料的可用性使得能夠精確地調整包含許多層的 DNN 的權重。因此,許多軟體系統經常使用 DNN。因此,使用 DNN 的軟體工程變得越來越重要。
在使用 DNN 的軟體中,一個重要的軟體工程問題是 bug 的存在。這類軟體中常見的錯誤是什麼?它們有何不同?回答這些問題有可能推動 DNN 缺陷檢測和修復的軟體工程研究。最近的研究對這個問題有了一些啟示。Zhang 等人[41]已經在 DNN 的 Tensorflow 庫中確定了缺陷型別、根本原因及其影響。Islam 等人[11]研究了一組更大的庫,包括 Caffe、Keras、Tensorflow、Theano 和 Torch 來識別 bug 特徵。雖然先前的工作對張量流的修復模式進行了初步的研究,但是這些工作並沒有關注修復的特性。由於修復使用 DNNs 的軟體是一個無可辯駁的軟體工程需求,自動化工具可能非常有用,因此充分理解修復的挑戰以及在手動修復 DNN 中的 bug 時使用的模式是至關重要的。自動化維修工具應解決哪些挑戰?自動化可以幫助開發人員的修復模式是什麼?應優先考慮哪些維修模式?
基於這些問題,我們對五個 DNN 庫 Caffe、Keras、Tensorflow、Theano 和 Torch 進行了全面研究。我們利用 Islamet al.[11]釋出的 DNN bug 資料集,其中包括 415 個來自 Stack Overflow 的 bug 和 555 個來自 GitHub 的 bug。然後,我們從 Stack Overflow 和 GitHub 收集用於修復這些錯誤的程式碼片段。然後我們手動研究這些修復,並根據使用開放編碼方法開發的分類方案對其進行標記。為了 Stack Overflow 的修復,我們研究 accepted answer 和 score>=5 的來自 Stack Overflow 帖子的答案,該帖子修復了原始帖子中的錯誤。為了研究 GitHub 中的 bug 修復模式,我們在資料集中獲取 bug-fix commits,並研究為修復 bug 而更改的程式碼。如果在 Stack Overflow 和 GitHub 中找不到與我們的選擇標準相匹配的任何修復,我們將丟棄這些 bug。我們總共研究了 Stack Overflow 中的 320 個錯誤修復程式碼和 GitHub 中的 347 個錯誤修復程式碼。我們還分析了這些錯誤修復,以回答以下研究問題:
RQ1:(常見錯誤修復模式):最常見的錯誤修復模式是什麼?
RQ2(跨錯誤型別的修復模式):對於不同的 bug 型別,錯誤修復模式是否不同?
RQ3(跨庫修復模式):不同庫的 bug 修復模式是否不同?
RQ4(修復中的風險):修復 DNN 錯誤會引入新的錯誤嗎?
RQ5(挑戰):修復 DNN 錯誤的挑戰是什麼?
我們的主要發現如下:與傳統的 bug 修復模式相比,DNN bug 修復模式具有獨特性;最常見的 bug 修復模式是修復資料維度和網路連線;DNN bug 修復有可能引入對抗性漏洞;DNN bug 修復經常引入新的 bug;以及 DNN bug 定位,開發人員在修復 bug 時面臨的主要挑戰是重用經過訓練的模型,並應對頻繁的釋出。我們還提供了 667 個 DNN(bug,repair)例項的基準測試。該基準也可公開獲取。
2.Methodology2.1 錯誤修復模式分類我們建立了一個分類方案來手動標記 bug 修復資料集。我們從 Pan、Kim 和 Whitehead[23]使用的分類方案開始,發現他們的分類方案有 28 個 non-ML 錯誤修復類別,其中只有 4 個修復類別適用於 DNN 相關修復。然後,我們使用開放式編碼方法對其進行改進,得到了一個由 15 種不同型別的 DNN 特定錯誤修復模式組成的模式。我們進行了一項試點研究,兩名博士生分別研究了這些修復方法,以得出一個可能的分類。每個學生都提出了一套課程,然後在一次所有作者都在場的當面會議上進行了協調。在當面會議上,作者驗證了來自兩個獨立評分員的分類方案,並在主持人的監督下根據和解工作的結果更新了分類方案。我們的初步研究顯示,在我們的 DNN 設定中有許多獨特的 bug 修復模式。因此,必須對先前工作中的分類進行重大修改。最終分類如表 2 所示,討論如下。
Loss function(損失函式)這組修復基於在訓練期間新增、刪除或更新丟失功能。損失函式是一個關鍵引數,它有助於訓練過程識別與所學和實際例子的偏差。不同型別的問題需要不同的損失函式,例如,交叉熵損失廣泛應用於分類問題,而均方誤差損失(MSE)則主要用於基於迴歸的問題。有些問題需要一個自定義的損失函式來獲得更好的訓練效果,我們將這種修復方法分組到這個類中。
Network Connection(網路連線)這組修復更改了 DNN 中節點之間的連線。DNN 是一個圖,其中邊是權重和偏差,節點是每個層的元素。例如,在密集層中,權重邊與下一層完全連線,層的尺寸決定了該層中可用的節點數。那些重新配置這些連線以獲得更好的結果的 bug 修復被歸為這一類。這些變化包括權值的改變,透過修剪網路去除邊緣,新增反向傳播等。
Add layer(新增層)在任何基於分類的問題中,模型中至少有兩層,輸入層和輸出層。為了瞭解輸入的特性,DNN 通常需要更多的中間層(稱為隱藏層)。這組修復程式向 DNN 添加了更多層以提高效能。新增層可以是密集的,其中兩個連續層完全連線,卷積層,其中卷積函式已應用於輸入,dropout 層,以減少過度擬合等。
Layer Dimension(層維度)這些修復會更改層的維度,使其與相鄰層和輸入相容。
Data Dimension(資料維度)與資料維相關的 fix 類似於層維度,但它與輸入資料相關,而不是與 DNN 層相關。資料的維度需要與 DNN 對齊。當 DNN 的輸入維度和資料維度不匹配時,通常需要這種型別的修復。
Accuracy Metric(精度指標)為了測量 DNN 的正確性,精度度量是需要配置的關鍵引數之一。問題型別對要使用的精度度量的型別有很大的影響,例如,使用分類精度、F1 score 或混淆矩陣來判斷分類問題,但這些度量不適合評估更適用於對數損失的基於迴歸的模型。
Data Type(資料型別)這組修復更改了輸入的資料型別,以符合 DNN 的期望。
Activation(啟用)DNN 層中節點的啟用函式將輸入對映到輸出。這組修復更改了層中使用的啟用函式,以更好地匹配問題。
Iteration(迭代)這組修復程式將調整訓練過程的執行次數。這通常是為了提高精度或減少過度擬合。這些修復包括更改 batch size 或 epoch。在某些情況下,開發人員會在整個培訓過程中新增一個迴圈。
Versioning(版本控制)DNN 庫正在快速開發中,許多版本不向後相容,從而破壞了程式碼。這組修復程式調整程式碼以與 DNN 庫的新版本一起使用。
API Contract(API 相容)當一個 DNN API 的輸出被輸入到另一個 DNN API 操作的輸入時,這兩個操作必須是相容的。這組修復程式添加了介面卡來修復組合操作之間的不相容。
Data Wrangling(資料整理)資料整理是指在不改變資料意圖的情況下改變資料的形式。它通常是為了修復下游操作的資料。修正了資料組的移位,等等。
Monitor(監聽器)此類別中的修復程式在訓練過程中添加了診斷程式碼,通常用於列印訓練資料。這組修復程式不能修復程式碼中的缺陷,但它們有助於將缺陷本地化。
Optimizer(最佳化器)這組修復修改了 DNN 模型使用的最佳化演算法。最佳化演算法依賴於問題,確定了提高 DNN 模型精度的迭代過程。
Change Neural Architecture(改變神經網路結構)這組修復程式實質上重新構建了 DNN 模型,因為初始模型不合適。
2.2 標籤對於標籤,我們使用表 2 所示的分類方案。兩名專業博士生被要求根據分類方案對修復打標籤。我們舉辦了多個培訓班,對評分員進行分類培訓。我們使用 Kappa 係數[36]來衡量每 100 個錯誤修復模式的標籤後,評分者之間的一致性。我們發現前 100 個標籤的 Kappa 係數為 82%,第二個 100 個標籤的 Kappa 係數為 85%。Cohen’s Kappa 係數的高值表明評分者之間完全一致。評級員之間的衝突是一個調和的標籤。我們從[11]中改編了這種方法。按照這一策略,我們對所有的修復打了標籤,並透過討論協調了標籤衝突。整個過程中的 Kappa 評分>85%,表明理解清晰,完全一致。
3.Bug Fix Patterns在本節中,我們將探討 RQ1 的答案,以瞭解 DNN 中最常見的錯誤修復模式是什麼。為了回答 RQ1 的問題,我們使用標記的資料集和不同類別的 bug 修復模式的統計分佈。我們還分析了這些修復的原始碼和差異,以瞭解這些模式背後的挑戰。圖 1 顯示了 Stack Overflow 和 GitHub 中不同錯誤修復模式的分佈。
3.1 資料維度Stack Overflow 中的大量錯誤(415 箇中有 59 個)透過更改資料維度得到修復。這表明,如果資料處理流水線發生變化,或者向 DNN 提供不同格式的資料,則大多數 DNN 模型很容易被破壞。例如,在下面的程式碼片段中,我們將看到如何透過向輸入影象新增維度來修復 Stack Overflow post1 中討論的 bug。
在清單中,開發人員希望讀取一個 CIFAR-10 影象,其尺寸為(32,32,3),但預期的影象大小為(1,3,32,32)。資料維的變化可以分為以下幾種。
Resize。調整輸入資料的大小是常見的,例如,將形狀(190,150)的輸入影象調整為(150,150)。這種修復的一個風險是由於調整大小而丟失輸入的資訊。不過在我們研究過的 bug 修復中,這個風險從來沒有出現過。59 個數據維度修復中有 11 個涉及調整資料大小。調整大小有兩種方式:縮小或增大。從我們的觀察來看,資料丟失帶來的風險是至關重要的。上取樣不存在資料丟失的風險,最近的結果表明,給資料新增噪聲可以潛在地提高模型的魯棒性。
Stack Overflow 的 11 個數據大小調整中有 7 個涉及縮小尺寸。縮小尺寸降低了魯棒性,並且[37]已經證明了一個簡單的調整大小的縮小操作可以對魯棒性產生負面影響。在縮小尺寸過程中,會發生顯著的資訊丟失,這最終會降低 DNN 所學習的特徵。與使用原始影象訓練的 DNN 相比,用縮小的影象訓練的 DNN 更容易受到攻擊。我們的研究結果表明,驗證調整大小對 DNN 脆弱性的影響是有用的。
Reshape。當輸入向量的形狀發生變化時,會對輸入進行變形。例如,大小為(32,32)的向量更改為(1,32,32)。在這種情況下,不會發生資料丟失,張量順序從 2D 更改為 3D。Stack Overflow post#415637202 中給出了一個修復的示例。變形不會導致資料丟失。59 個數據維度修復中有 38 個涉及到對輸入維度的變形。變形還可能涉及透過一個熱編碼(如以下程式碼片段)更改維度,以修復 Stack Overflow post #49392972
Reorder。這類資料的輸入大多是為了改變通道的位置。在影象分類問題中,通道是指三種原色的顏色通道。(高度、寬度、通道)表示三維影象的典型結構。例如,將 shape(32,32,3)的輸入更改為(3,32,32),以修復某些錯誤。這裡,通道號從第三個引數移到第一個引數。它還可能涉及更改影象維度順序格式,如從 RGB 更改為 BGR,如下程式碼片段用於修復 Stack Overflow post#33828582
59 個數據維度修復中有 9 個涉及對輸入的維度進行重新排序。之所以這樣做,是因為有些庫需要按特定順序排列維度。這些修復可以在開發人員使用多個庫的錯誤中看到,這些庫在影象資料中具有不同的通道位置要求,例如 Stack Overflow post#45645276。DNN 訓練可以假設為一個基於梯度下降的最佳化問題,當模型建立過程中使用的所有函式都是可微的時候,可以計算該最佳化問題。應以不影響計算的方式更改梯度資料。在“reshape 和 reorder”中,唯一發生的更改是新增維度和重新排序值,這些值不會影響梯度下降計算。所以這些變化理論上對 DNN 模型的行為沒有副作用。
3.2 層維度在 GitHub 中,與資料維度相關的修復佔所有修復的 7.5%。另一方面,在 GitHub 中,固定層維度以使 DNN 與輸入資料相容是一種更常見的做法。透過將神經網路轉換為資料流圖,可以透過分析層的輸入和輸出來完成與維度相關的修復。這種修復包括基於相鄰層結構的降維或增維。但是,這些修復可以透過更改資料維度來完成,以使資料與層維度相匹配,反之亦然。修復程式的選擇會影響模型的效能。這種現象被稱為維度災難、[9]。維度災難指出,增加或減少維度會導致過度擬合/欠擬合問題。PCA[17],T-SNE[21]是降維技術的一些例子,這些技術都受到維度災難的影響。為了構建一個自動化的方法來避免這種副作用,工具需要透過改變資料維度或層維度來最佳化模型的效能。AutoML[16]已經在這個領域做了一些初步的工作,透過改變層維度和新增層來重新構造模型以提高效能。據我們所知,目前還沒有工具可以分析資料維度和層維度的變化,從而為 DNN 模型選擇最佳操作。
3.3 版本相關的修復我們發現,由於 DNN 庫的頻繁版本迭代,長時間執行的專案必須修復許多錯誤。其中許多修復需要更改 API 簽名以匹配庫中的更改。我們還觀察到使用 Tensorflow 庫的專案的修復模式更為複雜,如§7.3 所述。Tensorflow 通常會進行侵入性的、不相容的更改,從而增加了修復引入的錯誤的難度。這說明 DNN 軟體的維護成本很高。
3.4 網路連線在正向和反向傳播或預測過程中,透過網路的張量和資料流。為了資料的順暢流動,網路中的端到端連線是必不可少的。415 個修復中有 57 個需要修復或調整網路中的連線。我們發現了三種網路連線修復。
合併層。許多修復案例透過將兩個並行層合併為一個層修復了錯誤。例如,下面的程式碼片段顯示了一個修復,其中兩個不同的分支透過點積連線起來。在導致崩潰的錯誤中,網路已斷開連線。
新增反饋迴圈和輸入層。在一些錯誤修復中,DNN 模型中添加了一個反饋迴圈。在某些修復中,模型透過如下輸入層連線到輸入:
遷移學習。遷移學習是一種流行的技術,它利用一個已經訓練好的網路,使用不同的資料集。然後,新模型修改最後一層以支援新問題的目標,然後在不修改前一層網路的權重和偏差的情況下進行再訓練。我們觀察到開發人員在嘗試遷移學習時需要進行幾個網路連線修復。通常,這些修復會更改 DNN 的最後幾層。下面是 Stack Overflow post#572481216 中的一種修復方法。
在本例中,開發人員希望使用一個預訓練的網路 VGG19 訓練 imagenet,該網路已用於面部識別。在這個 bug 中,開發人員沒有提供導致錯誤的正確的資料輸入大小,修復方法是給定一個數據生成器,該生成器按照 VGG19 模型的預期載入訓練資料。
3.5 新增層在 DNN 模型中,新增層有助於提高效能並更準確地瞭解特性。我們發現這些 bug 修復模式中的絕大多數(30%)都包含了 Dropout 層的新增。Dropout 層有助於消除過度擬合的影響[31],這也可以透過使用反向傳播來實現。根據[31],反向傳播對於訓練資料集更有效,但對新資料無效。Dropout 層有助於神經網路在每次迭代中學習更多的特徵。Dropout 層移除了層之間的連線,隨機停止了透過這些節點和邊的資料流。隨機減少連線會對訓練時間產生負面影響。有 Dropout 層的訓練的收斂需要 2-3 倍的時間[31]。
3.6 損失函式損失函式在訓練過程的收斂性和提高預測精度方面起著至關重要的作用。具有錯誤損失函式的模型不能很好地學習特徵的決策邊界,在高維特徵空間中,決策邊界之間可能存在重疊[14,24],使得模型容易受到攻擊[29]。透過對這些與損失函式相關的修復進行仔細和深入的分析,我們發現它們可以分為以下幾類:
新增新的損失函式。這類修復包括新增自定義或內建的損失函式。23 個修復中有 10 個屬於這一類。在某些修復中,需要修改網路連線以使新的損失函式起作用。例如,在下面的 bug 修復 Stack Overflow post#512570377 中,最後一層在訓練期間透過新增 trainable=False 保持在梯度下降計算之外。
自定義損失函式由開發人員設計,使得除了輸出層以外的所有層都參與進來,從而導致模型的收斂。但是,由於輸出層積極參與了前向和後向傳播,導致了損失函式值的突變,因此收斂並不成功。修復這些錯誤需要實時可訓練的引數分析。這種方法將有助於在訓練期間監聽活躍的可訓練引數,以定位和修復這些錯誤。目前,由於缺乏此類分析框架,開發人員需要依靠理論知識來修復這些缺陷。
更變損失函式。9 個錯誤修復例項屬於更改損失函式的類別。我們對這些修復的分析表明,這些損失函式的選擇有時會令人困惑。開發人員需要了解資料屬性和 DNN 任務的目標,才能得出正確的損失函式。例如,在構建分類問題的 DNN 模型時,開發人員混淆了二進位制交叉熵和分類交叉熵的選擇,正如在修復 Stack Overflow post#457994748 和 Stack Overflow post#420812579 中所討論的那樣。對於二元分類問題,第一個損失函式效果更好;但是,當分類問題有兩個以上類別時,應使用分類熵作為損失函式,以避免效能不佳。有時,修復包括在損失函式中使用的數學運算中新增一些過濾器。例如,我們看到以下修復 Stack Overflow post#342233151 的錯誤
由下行程式碼引起:
在上面的程式碼片段中,問題是,如果 y_conv 變為負數,因為負數的 log 值是無定義的,那麼使用者將獲得 NaN 值。修復程式添加了一個 clipper 函式來過濾掉 log 運算元中的負值。在另一個修復 Stack Overflow post#42521400 的同類錯誤中,softmax 用作過濾運算元,停止將<=0 的值傳播到 log 運算元。
3.7 Stack Overflow 和 GitHub 中修復模式的共性
我們在 95%顯著性水平上進行了 t 檢驗,以瞭解 Stack Overflow 和 GitHub 中錯誤修復模式的分佈情況。零假設是 H0:分佈是相同的。如果 p 值小於 5%或 0.05,則零假設將被拒絕。我們的計算表明 p 值非常高(0.83)。因此,不能因為 H0 的分佈相似而拒絕。我們還注意到,儘管在某些 bug 修復類別中,例如資料維度、層維度和版本控制,Stack Overflow 和 GitHub 分佈之間存在顯著差異,但其他類別在 Stack Overflow 和 GitHub 中的發生率相似。這表明 bug 修復模式在 Stack Overflow 和 GitHub 之間具有通用性。
4.Fix Patterns Across Bug Types為了回答 RQ2,我們利用[11]給出的 bug 資料集中的 bug 型別和本文研究的 bug 修復模式之間的相關性,利用 bug 的分佈和它們對應的補丁進行分析。圖 2 和圖 3 分別顯示了 Stack Overflow 和 GitHub 中不同 bug 型別的 bug 修復模式的分佈。水平軸和垂直軸分別描述了[11]中的不同缺陷型別,以及修復這些缺陷所需的不同修復模式的百分比。
修復 API 規範涉及到由於 API 版本控制和支援模型內庫間操作而更改 API 規範。由於以下原因,需要修改 API 規範:
由於版本升級而更改規範。Stack Overflow 中的 20 個修復涉及到由於庫版本的更改而需要更改的規範。庫版本升級期間的更改包括以下更改:更改完全限定的方法名稱、更改 API 簽名和更改 API 的機率行為。雖然由於全限定方法名的更改和 API 簽名的更改引起的修復是一個很好的問題[3,7,15],但是由於 API 的機率行為的改變而導致的修復是困難的,並且與傳統的 API 更改不同。由於缺乏成熟的 DNN 機率分析工具,這些缺陷的定位非常困難。例如,Stack Overflow#4974206112 中討論的 bug 表明,在兩個版本的 Tensorflow 中,結果是不同的。這個錯誤的修復包括新增一個程式碼行,透過重寫修改後的隨機種子來調整 API 的潛在機率行為。Stack Overflow#49742061 的修復如圖 4 所示。修復程式在 R=tf.random_uniform(shape=())前添加了一行 xf=tf.contrib.layer.flatten(x)。此新增將用以前版本中的隨機種子覆蓋新版本中的隨機種子。
我們的觀察結果表明,由於不同版本的機率分佈的變化而導致的版本控制錯誤的修復需要新的 DNN 特有的機率分析技術。
更改規範以支援庫間互動。在這些修復中,DNN 程式使用多個庫。這些錯誤是由於對不同庫中不同 API 的行為和規範的相似假設而產生的。修復這些錯誤需要兩個庫中的專業知識,例如,圖 5 所示的堆疊溢位中討論的 bug。討論指向了 Tensorflow 官方庫中的一個問題。該解決方案建議避免使用其他庫中的 API 來預處理影象。但是,在類似的場景中,建議使用專門的影象處理庫來獲得更好的效能。
從圖 2 和圖 3 中,我們發現在 Stack Overflow 中,修復資料維度是最顯著的模式(41.77%)。對於解決 GitHub 中的資料錯誤,最突出的修復模式是資料型別(38.64%)和資料維度(29.55%)的更改。這表明,對於修復資料錯誤,主要的變化與資料維度有關。這是因為資料的維度對於 DNN 模型的正確功能非常重要。
為了修復邏輯錯誤,最常見的做法是修改網路連線(Stack Overflow 為 27.03%,GitHub 為 33.33%)。有關網路連線的詳細討論見§3.4。然而,大量的資料流錯誤可以透過改變層維度來修復(~36.36% in Stack Overflow and ~38.98% in GitHub)
5. Fix Patterns Across Libraries為了回答 RQ3,我們研究了修復模式在 5 個庫中的分佈情況。然後,我們在 95%顯著性水平上對兩個庫進行了 t 檢驗。表 4 顯示了從這個測試中跨庫找到的 p 值。
我們假設零假設是 H0:修復模式在兩個庫中的分佈是相同的。如果 p 值小於 5%或 0.05,則拒絕 H0。庫對 Caffe-Theano(.19)、Caffe-Torch(.30)、Keras-Tensorflow(0.84)、Theano-Torch(0.8)的 p 值遠大於 5%。因此,在這些情況下,我們不能拒絕零假設。因此,Caffe、Theano 和 Torch 庫顯示了類似的 bug 修復模式。Keras 張量流對形成了一個非常強的相關群,p 值接近 100%。這表明,在轉換成一個通用的中間表示之後,類似種類的自動 bug 修復工具可以被重用到 Caffe、Theano 和 Torch 中。類似地,Keras 和 Tensorflow 錯誤也可以使用類似的技術方法進行修復。
6. Introduction of Bugs Through Fixes為了回答 RQ4,我們分析了從 Stack Overflow 中隨機選擇的 100 個修復,以瞭解修復一個 bug 是否會引入新的 bug。我們已經閱讀了根據第 2 節討論的篩選標準選擇的答案的答覆。然後,我們透過分析修復原始錯誤的答案的所有回覆來確定修復是否引入了新的 bug,並使用前面的工作提出的分類方案將它們分類為 bug 型別、根本原因和影響[11]。我們發現在隨機抽樣的資料集中有 29%的修復在程式碼中引入了至少一個新的 bug。在這裡,一個新的 bug 表明原來的 bug 已經被髮布的解決方案修復了;但是,這個解決方案引入了一個不同於原始 bug 型別的新 bug。此外,我們還比較了 Stack Overflow posts 的 bug 型別、根本原因和 bug 的影響,發現只有 6.8%、13.8%和 24.1%的 bug 與父 bug 型別、根本原因和影響的分類相匹配。這一結果表明,大多數引入的 bug 是新型別的,它們的行為與父 bug 的行為完全不同。在表 5 中,我們展示了新 bug 在不同庫中的分佈,以及如何將這些新 bug 劃分為不同的 bug 型別、根本原因和影響。我們還發現,崩潰(55.8%)是這些新錯誤最常見的影響,其中大部分是 API 錯誤(37.9%),這些錯誤最常見的根本原因是 API 更改(34.5%),其中包括 API 簽名或 API 完全限定名稱的更改。44.8%和 34.5%的新引入 bug 來自 Keras 和 Tensorflow。Caffe、Theano 和 Torch 相關的 bug 修復分別引入了 10.34%、3.45%和 6.90%的新 bug。
在圖 6 中,父 bug 的根本原因、型別和影響與新引入的錯誤分佈之間的關係已經視覺化。在這個視覺化中,old 表示父 bug,關係是由兩個 bug 分佈之間的連線繪製的。連線的寬度決定了關係的強度。每種缺陷型別/根本原因/影響所覆蓋的範圍描述了其整體強度。我們發現,大部分錯誤修復都引入了 API 錯誤,其主要原因是 API 的更改,這主要是由於 API 的版本控制而導致的,這些修復主要導致崩潰和效能差。
7. Challenges in Fixing Bugs在本節中,我們將探討 RQ5 的答案,以確定開發人員在修復 DNN 錯誤時面臨的常見挑戰。為了理解這些挑戰,我們使用了一個與 bug 修復模式分離的分類方案。與錯誤修復模式的標記類似,兩個評分者對本研究中使用的每個帖子都進行了獨立分類。這些新挑戰類別如下:
7.1 DNN Reuse
訓練 DNN 模型的代價可能是昂貴的,因為它需要複雜的計算資源和大量標記的資料,而這些資料可能並不容易獲得。這導致了 DNN 模型的重用,這些模型產生了諸如後門攻擊[5]、偏差注入[2]以及預先訓練的 DNN 模型的意圖與開發者意圖之間的不匹配。
在上面的 Stack Overflow post#4922644714 的示例中,開發人員希望使用 cancer 資料集訓練預定義的 DNN 模型結構 ResNet50。訓練過的網路會導致過度擬合,因為開發人員不知道重用模型的結構,需要透過新增丟失和密集層來修改網路,以減少過度擬合的影響。
7.2 不可追蹤或半可追蹤錯誤
在發生崩潰錯誤的情況下,將 bug 本地化的常用策略是分析錯誤訊息。然而,我們發現在 DNN 軟體中錯誤定位是非常有挑戰性的,因為錯誤和錯誤是非平凡相關的。為了說明這一點,請考慮下面來自 Stack Overflowpost#3347442415 的程式碼片段:
此程式碼生成以下的錯誤跟蹤
從這個錯誤訊息中,開發人員可能會開始深入研究 predict 函式和 Sequential 物件的程式碼;但是,問題是缺少編譯步驟。因此,模型連線沒有初始化,錯誤會傳播到預測操作並停止訓練過程。我們隨機研究了 50 個 Stack Overflow 中導致崩潰的 bug。我們發現,50 個 posts 中有 11 個沒有顯示任何錯誤訊息,在其餘 39 個 posts 中,有 20 個 posts 的修復與錯誤訊息不匹配。
7.3 快讀的發行
我們之前已經討論過,大量修復是由於 DNN 庫中的快速版本控制和侵入性更改造成的。為了研究這一挑戰,我們將 Tensorflow 的所有移除、重新配置或重新命名的操作從 1.10 版標記為 2.0 版(最新版本為 2019 年 6 月)。
在表 6 中,我們顯示了每個 Tensorflow 版本可用的運算元符號數,以及與以前版本相比已刪除、重新命名或重新配置的運算元。我們發現,從 v1.14 到 v2.0,有 26%的運算元發生了變化。我們還研究了 Keras v2.0、v2.1、v2.2 和 v2.3,以瞭解這個問題是否只在 Tensorflow 中普遍存在。我們的研究發現,在從 v2.0-v2.1、v2.1-v.2.2 和 v2.2v2.3 的轉換過程中,運算元變化的百分比分別為 6%、8%和 4%。
修復 DNN 軟體的一個重要挑戰是 API 的機率行為。其中一些版本升級也會改變 API 的機率行為,從而導致一些難以解決的錯誤。下面給出了一個例子,其中機率分佈的變化改變了同一操作不同版本的輸出。
8. Conclusion and Future Work深度神經網路在軟體系統中的廣泛採用,推動了對特定於 DNN 的軟體工程實踐的需求。以前的工作已經表明,與傳統軟體一樣,DNN 軟體雖然具有非常不同的特性,但也容易出現 bug。重要的是要進一步瞭解錯誤修復的特性,以便為修復具有這些 bug 的 DNN 軟體提供策略。開發人員如何著手修復這些錯誤?自動化維修工具應解決哪些挑戰?為此,我們進行了全面的研究,以瞭解如何修復 DNN 軟體中的錯誤。我們的研究得出了一些發現。首先,我們發現 DNN 中的錯誤修復模式與傳統的錯誤修復模式有很大的不同。第二,我們的研究結果表明,解決資料與 DNN 之間的不相容性對 DNN 軟體的開發人員有很大的幫助,尤其是如果可以警告開發人員他們的 bug 修復對 DNN 模型的魯棒性的影響。第三,我們的研究表明,一個流行的缺陷修復模式是版本升級。雖然版本升級在軟體工程研究中得到了很好的研究,但我們的 bug 修復模式表明,自動修復工具至少需要解決兩個獨特的挑戰:入侵的、向後不相容的更改和機率行為的更改。第四,我們的研究表明,DNN 本身的結構需要在修復工具中表示出來,因為有幾種修復模式依賴於識別該結構中的不相容性。例如,識別和連線斷開連線層的網路連線修復,或新增缺失層等。第五,我們發現大量的錯誤修復在程式碼中引入了新的錯誤。最後,我們確定了修復 bug 的三個挑戰:bug 定位非常困難;DNN 模型的重用由於對其行為的洞察有限而變得困難;跟上快速釋出是困難的。
這項研究為今後的工作開闢了幾個途徑。首先,透過這項工作識別出的許多 bug 修復模式可以在修復工具中實現自動化。這樣的缺陷修復工具可以幫助開發人員將 DNN 整合到他們的軟體中。其次,可以開發 DNN 的抽象表示以及使用它的程式碼。我們看到了一些依賴於分析這種表示的 bug 修復模式。第三,可以透過解決出現的獨特挑戰和建立 DNN 感知的 bug 定位工具來改進 DNN 的 bug 定位。第四,可以檢測由維度不匹配引起的缺陷,特別是可能在 DNN 中引入漏洞的變更。第五,可以開發升級工具來編碼版本更改的語義,並跟上 DNN 庫的簽名和語義的變化。這對於適應這一領域的快速發展是至關重要的。