首頁>技術>
引用

Zhang R, Xiao W, Zhang H, et al. An empirical study on program failures of deep learning jobs[C]//Proceedings of the ACM/IEEE 42nd International Conference on Software Engineering. 2020: 1159-1170.

摘要

深度學習在許多應用領域都取得了顯著成就。為了更有效地訓練和測試模型,企業開發人員在共享的多支撐平臺上提交和執行他們的深度學習程式。然而,由於程式碼/指令碼缺陷,一些程式在長時間的執行後失敗,這降低了開發效率,浪費了 GPU、儲存、網路 I/O 等昂貴的資源。

本文首次對深度學習工作的程式故障案例進行了全面的實證研究。從微軟的一個深度學習平臺收集了 4960 個真正的故障案例。我們手動檢查他們的錯誤資訊並將它們分類為 20 類。此外,我們在 400 個故障樣本上確定了常見的根本原因和錯誤修復解決方案。為了更好地理解當前深度學習測試的 debug 實踐,我們還進行了開發人員訪談。我們的主要發現有:(1)48.0%的故障發生在與平臺的互動中,而不是程式碼邏輯的執行,這主要是由於本地和平臺執行環境之間的差異;(2)深度學習特有故障(13.5%)主要是由不恰當的模型引數/架構和框架 API 的錯誤解析引起的(3)目前的除錯實踐在許多情況下對於故障定位是無效的,開發人員需要更多深度學習特定工具。基於我們的這些發現,我們進一步給出了研究主題和工具支援的相關建議,以促進未來的深度學習發展。

一、引言

近年來,深度學習(DL)迅速成為最成功的機器學習技術之一。隨著計算能力和資料量的巨大增長,深度學習已經廣泛應用於各個領域(如語音和影象識別、自然語言處理、強化學習遊戲等 ),可能會產生許多重要但以前似乎遙不可及的結果。

為了幫助資料科學家訓練和測試他們的深度學習模型,企業構建了專用平臺,如微軟 AzureMachineLearning[3]、AmazonSageMaker[1]和 GoogleCloudAI[2] 允許多個開發人員提交和執行他們的深度學習程式。這些平臺是共享的,多租戶的,並配備了大量的 CPU,GPU 或新的 AI 加速器為多種深度學習框架提供支援,框架有 TensorFlow(TF)[7]、PyTorch[30]、MXNet[10]和 CNTK[37]。

Philly 是微軟的一個類似的深度學習平臺,它使用的開源技術和典型的計算硬體構建。每天都有幾十個研究團隊和產品團隊將成千上萬的深度學習工作提交給 Philly。然而,我們發現,由於程式碼或指令碼缺陷,這些作業中有相當一部分丟擲了執行時異常,並且未能完成。這樣的故障,特別是那些發生在長時間的執行後,導致了 GPU、儲存和網路 I/O 等共享資源的高度浪費。例如,一個工作在 4 個 NVIDIA Telsa P100 GPU 上運行了 40 個小時,由於測試影象的路徑配置錯誤,然後觸發異常。此外,深度學習訓練過程的隨機性也可能導致意外的故障。因此,瞭解工作故障的類別和根源對於提高程式質量和節省寶貴資源至關重要。而且,它還可以為預防、檢測、除錯和修復與深度學習工作相關的程式缺陷提供指導。

雖然對機器學習/深度學習程式[22,38,40,49]的缺陷進行了一些實證研究,但對於執行在遠端控制平臺上的深度學習工作的程式故障幾乎沒有相關的工作。與深度學習程式故障最相關的工作是 Zhang 等人[49]和 Islam 等人[22]的工作。然而,他們的主題是從 GitHub 問題和堆疊溢位問題收集的,這些問題在許多方面與 Philly 的工作不同。Jeon 等人的另一項相關工作[23] 研究微軟內部深度學習工作的行為。然而,它們的目的是瞭解叢集 GPU 的利用率,而不是減少工作故障。

在本文中,我們對深度學習工作的程式故障和修復進行了第一次全面的實證研究。我們研究了微軟數百名開發人員提交的 4960 個故障的工作。這些故障是由開發人員的程式碼/指令碼缺陷引起的,我們排除了底層硬體或系統故障。在提交作業之前,程式可能已經在本地進行了測試,因此有些透過區域性測試可以解決的故障可能不在我們的研究中。本研究的目的是對深度學習的故障提供一個系統和概括的理解,這可能在共享平臺中實現故障減少和資源節約。具體來說,我們的研究旨在解決以下研究問題:

RQ1:哪些型別的深度學習工作故障更多? 為了回答這個問題,我們手動檢查了 4960 個失敗作業的故障訊息,並將它們分類為 20 個類別。我們得到了許多發現。例如,48.0%的故障發生在與平臺的互動中,而不是在程式碼邏輯的執行中,主要是由於本地和平臺執行環境之間的差異。詳細的結果將在第四節中報告。

RQ2:失敗的深度學習工作的共同根源是什麼? 為了回答這個問題,我們選擇了 400 個失敗作業的樣本,並手動區分它們的根本原因:原始碼或是相關指令碼。對於一些複雜的問題,我們聯絡開發人員進行解釋。我們還研究了開發人員如何修復錯誤。我們得到了許多發現。例如:深度學習特定故障(13.5%)主要是由於模型引數/結構不當和 API 誤解所致。詳細結果將在第 5 節中報告。

RQ3:什麼是目前深度學習程式設計中測試和除錯實踐? 為了回答這個問題,我們對來自微軟的 6 名有代表性的開發人員進行了深入的面對面訪談。我們發現當前的測試和除錯實踐在許多情況下都是低效的。詳細結果將在第 6 節中報告。

在我們的實證研究的基礎上,我們還總結了經驗教訓,並建議未來的工具支援深度學習測試和除錯。例如,我們建議對 Philly 和深度學習框架擴充套件一些工具。

總之,本文做出了以下貢獻:

(1)我們對深度學習工作的程式故障進行了第一次全面的研究。我們將 4960 個故障案例手動分類,並分析其中 400 個案例的根本原因。

(2)我們指出了我們的調查結果的影響,並提出了發展深度學習平臺和框架的相關建議。

論文的其餘部分組織如下。在第二節中,我們概述了新的深度學習程式設計正規化還有 Philly 平臺。第三節介紹了研究方法。第四節和第五節介紹了故障分類、根本原因和修復方法。第六節介紹了我們對當前測試和 debug 的使用者研究以及在生產環境中的實踐。第七節討論了我們的研究的普適性和未來的故障減少相關的研究工作。我們在第八節中調查了相關工作,並在第 9 節中總結了全文。

二、背景2.1 深度學習程式

深度學習(DL)是機器學習的一個子領域,它學習分層的資料表示,稱為神經網路或模型。開發人員使用 TensorFlow、PyTorch、MXNet、CNTK 等框架編寫深度學習程式,加上工具包庫,如 NumPy[28],DLTK[31],Detectron[16]和 Fairseq[15]。Python 是最流行的程式語言,而在某些情況下也使用 C++或 Java。

典型的 DL 程式碼由三個邏輯連續的階段組成:資料預處理、模型訓練和驗證以及模型評估。第一階段通常有輸入資料清洗和資料擴增(例如,隨機裁剪輸入影象以獲得更多的訓練資料)。接下來,開發人員使用計算原語(如神經網路層(例如 CNN)、啟用函式(例如 ReLU)、損失函式最佳化器(例如 Adam[25])和變數初始化器。該模型由層的權重引數組成,並允許張量(多維陣列值)的流動。訓練實際上是透過迭代更新模型來找到最佳的權重引數,直到其學習效能(例如損失和精度)滿足要求為止。驗證集每隔幾次訓練迭代一次,為超引數的決策(例如學習速率、隱藏單元數)調整或早期停止提供及時的反饋。最後評估(即測試)階段,開發人員量化評估最終模型效能。

2.2 Philly 中深度學習工作

Philly 是微軟的一個 DL 平臺,部署在多個物理叢集上,配備了不同代的 GPU。每天都有來自諸多研究團隊和產品團隊的數千個工作執行在 Philly 中,包括機器翻譯(例如 Transformer[43])、閱讀理解(例如 BERT[13])、目標檢測(例如 Mask RCNN[21])、遊戲(例如 DQN[27])、廣告(例如 Wide&Deep[11])等。

Philly 的作業提交和執行工作流程類似於 MicrosoftAzureMachineLearning、AmazonSageMaker 和 GoogleCloudAI。圖 1 概述了 Philly 中工作的生命週期。開發人員首先將他們的程式碼/指令碼和輸入資料上傳到分散式儲存中。然後,它們指定作業配置,如所需程序/GPU、Docker[26]影象的數量,輸入/輸出資料夾和 Python 程式碼檔案。Philly 提供標準深度學習工具鏈的 Docker 影象,以建立一個密封的工作執行環境。儘管如此,定製 Docker 影象還允許適配額外的軟體需求(例如安裝依賴的 Python 庫)。可以以手動或自動的方式[17,35]提交具有相同程式但不同超引數的多個作業尋找最好的模型。作業最初在佇列中等待排程。一旦選擇了作業,Philly 就例項化 Docker 容器來執行啟動 Shell 指令碼,然後執行 Python 程式碼檔案。如果丟擲 Python 異常或 Shell 錯誤程式碼,則作業可能失敗。為了增加容錯,Philly 可以自動重新執行它[23]。每個執行例項稱為 retry。最後,作業將進入三個終端狀態之一:SUCCEEDED、KILLED(由開發人員主動終止)和 FAILED。

請注意,雖然 Philly 是由微軟開發的,但它實際上在原則上類似於其他常用的工業 DL 平臺。Philly 的硬體、系統體系結構和作業提交/執行機制[9,23,47]被廣泛採用。此外,在 Philly 執行的大多數 DL 程式也使用程式設計正規化(如 Python 和 TensorFlow)。

三、方法3.1 主題

我們把 Philly 故障的深度學習工作作為我們的研究主題。這些工作是由微軟的研究和產品團隊提交的,並具有“FAILED”的最終狀態。對於每一項失敗的工作,我們都對相關資訊做了整理。這些資訊包括輸入資料、原始碼、作業指令碼、執行日誌和執行時統計資訊。

我們研究中的故障表現為意料之外的執行時錯誤。我們在一項工作完成但結果與預期不同時沒有研究其語義錯誤,因為我們沒有測試 oracle。我們還排除了故障的工作機會 由於硬體故障或系統問題,因為它們超出了本研究的範圍。由於開發人員在提交作業之前可能已經在本地測試了他們的程式,因此可能會出現一些透過區域性測試解決所以不存在與我們研究中的故障。

為了研究故障分類,我們選擇了 4960 個由開發人員程式碼/指令碼缺陷引起的故障工作,時間範圍為 2018 年 10 月的 3 周內。我們稱之為完整樣本集。由於 Philly 的重試機制,故障的工作可能有幾個例項,我們只考慮了最後一個例項。為了進一步瞭解根本原因和修復,我們隨機選擇了 400 個故障的工作,並對它們進行了詳細的分析。我們稱之為小樣本集。

3.2 故障分類

全樣本集中的作業故障是根據其執行時錯誤型別手動分類的。對於每個故障的作業,我們首先透過搜尋帶有關鍵字的執行日誌來定位故障訊息,如 assert, wrong, error, exception, fault, fail, crash, unsuccessful 等。然後,我們手動檢查了故障周圍的所有相關日誌訊息,理解了上下文,過濾掉了錯誤定位導致工作終止的失敗,並對其進行分類。例如,訊息“cuda running time error(2):記憶體不足”的故障被歸類為 GPU 輸出記憶體不足,而不是 CPU 記憶體不足。我們還從執行的角度將所有故障類別分為 4 個主要維度:深度學習特性、執行環境、通用程式碼錯誤和資料。我們在小組會議上討論了每一次故障的類別,直到達成共識。如果有差異,我們聯絡了工作提交人尋求幫助。

3.3 索引與修復

我們手動研究了小樣本集中每個故障作業的原始碼和指令碼。對於資料相關故障,對相應的輸入資料進行了額外的檢查。然後分析了每次故障其發生階段和根本原因。我們還透過匹配作業和提交者名稱來確定作業的後一個“固定”版本,並透過比較來檢查錯誤修復更改故障的和固定的版本。如果一個複雜的修復超出了我們的理解,我們聯絡了工作提交人進行澄清。要計算故障的執行時成本,我們只需計算它的所有 GPU 服務時間(即 GPU 數量 × 作業執行時間)。

3.4 有效性威脅

對內部有效性的威脅:由於工作的複雜性和大量的人工操作,在故障分類和根本原因分析中可能存在主觀性。為了減少這種主觀性,在做出決定之前,我們努力實現群體共識。對於工作不明確或困難的故障,我們也直接與開發人員溝通,尋求澄清。

對外部有效性的威脅:我們的研究物件都是從 Philly 收集的。雖然在 Philly 和其他的深度學習平臺在軟體棧、平臺架構和作業管理方面有明顯的相似之處,但是有可能有些發現可能不存在於其他平臺或其他公司。為了減輕這種威脅,在這項研究中,我們儘量只涉及 Philly 和 Microsoft。在第 7 節中,我們討論了可以推廣到類似於 Philly 的其他平臺的發現。

四、故障分類

在本節中,我們介紹了完整樣本集中 4960 個故障的分類。表 1 總結了 20 個故障類別,圖 2 顯示了 4 個類別的故障分佈。

4.1 深度學習相關

13.5%的故障是深度學習相關的,分為 5 類。TensorMismatch 是指張量的形狀或名稱與它的期望不匹配。通常有 3 中情況:

(1)相互連線的模型層具有不相容的張量需求

(2)將形狀不匹配的輸入資料輸入到模型中

(3)將不匹配的模型檔案恢復到構建的模型中

當工作集超過 GPU 可用時,GPU 退出記憶體,故障發生。它是這個維度中的頂級錯誤型別。由於 GPU 記憶體相對有限,開發人員需要非常仔細地對模型進行大小調整。當作業執行時,若作業在主存中執行(處理大量資料時),CPU 記憶體耗盡,故障發生。Loss NaN 表示計算的損失值變得未定義或不可表示(例如,0×log0)。

最後一類是框架 API 誤用,這意味著框架 API 呼叫違反了固有的假設。例如,TensorFlowAPI“session.run()”假設所有變數都應該初始化正確。否則,它會丟擲一個異常訊息“FailedPreconditionError: Attempting to use uninitialized value”。

結論 1:13.5%的故障是深度學習相關的。在這 5 個類別中,GPU 記憶體不足是佔比最大的,佔該維度故障的 65.0%。

4.2 執行環境

執行環境相關故障發生在與平臺的互動中,而不是在程式碼邏輯的執行中,佔總故障的近一半(48.0%)。很明顯,平臺提供的執行環境與本地執行環境是不同的。例如,所需的 Python 模組(例如 Fairseq[15])或依賴的 DLL(例如 libcudnn.so)可能沒有預先安裝在 Docker 容器中,然後發生庫未找到的故障。允許開發人員對執行環境進行修改。但是,如果他們沒有足夠的許可權,則此操作故障並觸發許可權拒絕故障。例如,開發人員在所需的 Fairseq 庫的啟動指令碼中執行“pip install Fairseq”。此命令不能成功,因為需要 root 許可權。它需要識別您的“--user”選項,以便將庫安裝到它的主目錄中。這個維度中的主要錯誤類別是路徑未找到(39.4%),這意味著編譯器通過了不存在的檔案或目錄。例如,開發人員在提交作業之前忘記更改程式碼中的本地檔案路徑。

結論 2:近一半(48.0%)的總故障發生在與平臺的互動中,而不是在程式碼邏輯的執行中。在這三個類別中,路徑未發現是主導的,它在這個維度中佔比 82.1%。

4.3 程式碼錯誤

我們發現,36.5%的故障是常見的,類似於其他計算機程式。14.6%為 Illegal Argument(不符合要求的 Argument),其中近一半為、在啟動指令碼中將引數輸入 Python 程式碼時導致的非法 Argument。還有其他類別,如 Key Not Found(使用不存在的金鑰訪問集合項)、Attribute Not Found(涉及不存在的 Python 類欄位或函式)、空引用和語法錯誤(例如,不正確的 Python 縮排)。由於 Python 是一種動態程式語言,所以型別 Mismatch 故障都相當普遍(11.4%)。例如“TypeError: join() argument must be str or bytes, not ‘PosixPath’”

結論 3:一般程式碼錯誤維度中的故障佔總故障的很大一部分(36.5%),非法 argument 和型別錯配是其中佔比最多的兩類。

4.4 資料

此維度中的故障與無法處理的意外資料有關,可能是由於上傳失敗或對資料屬性的錯誤解析。這兩個類別之一是 Corrupt Data,這表明資料完整性受到損害。例如,可能被意外截斷的 JSON 檔案會丟失屬性值對中的值部分。另一個是 Unexpected Encoding,這意味著一些資料欄位無法正確編碼或解碼。我們注意到一個程式,它使用預設的 ASCII 編碼來解碼帶有一些非 ASCII 字元的字串。

結論 4:一些深度學習作業(2.0%)無法處理資料錯誤,如損壞資料和錯誤資料編碼。

五、索因和修復

我們對小樣本集(400 個故障)進行了根本原因和修復分析,因為它需要大量的人工來研究原始碼/指令碼。我們還聯絡了開發人員,必要時進行澄清。我們定義了 5 種常見的故障原因。。圖 3 顯示了 400 個故障的故障類別和根本原因的分佈。在下面的小節中,我們將詳細描述根本原因,並演示一些故障程式和相應修復過程的示例。

5.1 環境區別(DE)

雖然 Philly 透過標準 DL 工具鏈的 Docker 影象建立了一個密封的作業執行環境,但小樣本集中的 140(35%)故障是由本地和平臺之間的執行環境差異引起的,佔 GPU 服務時間的 14.8。主要差異包括環境變數、輸入/輸出路徑、依賴軟體、Python 版本、框架和工具 工具包庫等。另一個顯著的區別是,在新憑證下的 Docker 容器中執行用於本地機器的 DL 作業,授予的許可權很可能與這些許可權不同。

這些故障大多在執行環境維度。路徑未找到類別的修復是引數化檔案/資料夾路徑並從中獲取它們外部引數或配置檔案。此外,開發人員應儘早驗證這些路徑,因為以後的故障發生(例如模型評估階段的故障)將會浪費很多資源。庫未找到和部分許可權被拒絕(將 Python 包安裝到系統資料夾中)故障可以透過自定義 Docker 映像來解決,所有所需的軟體都是預先輸入的停滯了。取樣語法錯誤失敗是由於誤用了早期版本的 Python,也可以這樣解決。如果在作業 init 期間手動安裝了相關軟體初始化,開發人員應該向 pip 命令指定“--user”選項,並將 Python 包安裝到他們的主資料夾中。剩下的認證失敗的故障是由於操作外部檔案和資料夾的許可權不足。修復方法是預先設定正確的訪問模式(例如,在啟動 Shell 指令碼中執行“chmod”)並在編碼的早期保證其有效化。

結論 5:執行環境維度中的大多數故障是由本地和平臺之間的環境差異造成的。許多差異(安裝的軟體、儲存路徑、授予的許可權等。) 使 DL 程式容易出錯。

含義:鼓勵開發人員使用自定義 Docker 映像,並預先安裝所有所需的軟體,修改程式碼以獲得更多的環境適應性,並儘早驗證路徑/任務。

5.2 不合適的模型引數/結構(IPS)

43 個(10.75%)小樣本集中的深度學習特定故障都是由不適當的模型引數(例如學習速率和批次大小)或模型結構引起的。

5.2.1GPU 儲存不足

這 39 個故障中的大多數是由於批次大小過大和/或模型過於複雜。圖 4 顯示了一個示例。更大的批次大小和更復雜的模型可以提高模型學習效能。然而,它們顯著增加 GPU 記憶體消耗。目前,由於缺乏必要的工具支援,開發人員很大程度上依靠他們的領域知識來選擇最優的模型配置。例如,在某些情況下,開發人員必須使用使記憶體有效的 1×1 核卷積[39]。 目前有一些正在進行的工作可以用來解決記憶體不足的問題。例如,GPU 記憶體消耗是靜態估計的某些計算機視覺任務[34]。另一種很有前途的技術是 GPU 記憶體虛擬化,其中資料在必要時在主機和 GPU 之間[36,44]自動交換。TensorFlow 還具有基本的 GPU 記憶體交換機制(即“swapmemory”引數),它是在某些模型層(例如 tf.nn.dynamic中啟用的 RNN[4])。交換應該有效地實現,否則資料延遲會減慢計算速度。

結論 6:GPU 退出記憶體故障主要是由過大的批處理大小和/或過複雜的模型引起的。

含義:考慮到可用的 GPU 記憶體和預期的學習效能,開發人員應該主動選擇最優模型引數和結構。GPU 記憶體的評估和虛擬化是兩種很有前途的技術。

5.2.2Tensor Mismatch&Loss NaN

雖然在小樣本集中只有 4 個這樣的故障,但它們非常具有 DL 的特異性,值得更多的調查。

兩個 Tensor Mismatch 故障中的一個是由變數名不匹配引起的 儲存的模型檔案和構造的模型。與開發人員溝通後,發現其根本原因是 Pytorch 中單個 GPU 和多 GPU 之間的不同的變數命名規則。更特別地,儲存的模型檔案來自多 GPU 訓練作業,而構造的模型用於單 GPU 推理。模型恢復無法匹配這些變數名。修復的方法是在構造的模型中使用匹配的變數名或切換到多 GPU 推理。另一次故障在圖 5 中顯示,其根本原因來自初始輸入資料與構造模型之間的形狀不匹配。修復方法是將資料排列到正確的形狀。

Loss NaN 故障根源於深度學習演算法的隨機性。其中之一發生在培訓和驗證階段開始後很長時間。我們聯絡了開發人員尋求幫助,很難發現根本原因。開發人員告訴我們,這項工作是微調一個預先訓練的模型。然而,如果這種預先訓練的模型有某些有問題的引數,梯度可能導致不良的訓練情況,最終導致 NaN 的損失。一個快速的解決辦法是嘗試一個新的預先訓練的模型從候選集。另一個可能的根本原因是學習率過大,其修復方法只是降低其價值。開發人員也提出 Loss NaN 有時是由於初始輸入或中間結果中的特殊資料所致。把它們過濾掉可以解決問題。Loss NaN 故障是不確定的。因此,修復在很大程度上取決於領域知識。

5.3 API 錯誤解析(APIM)

19(4.75%)的故障是由於錯誤地理解了框架/圖書館 API 所做的複雜假設。圖 6 顯示了由不正確的 API 引數值觸發的框架 API 誤用故障。錯誤資訊是“ValueError: Variable attweights/kernelweightsconv already exists, disallowed. Did you mean to set reuse=True or reuse= tf.AUTOREUSE in VarScope?”。因為 TensorFlow 變化“kernelweightsconv”(第 25 行)能夠在幾個 GPU 之間共享(第 16、19、20 行),其父範圍(第 24 行)應該用顯式設定為“TF”的引數“重用”來構造。autoreuse”。開發人員不知道這個假設,忘記設定“重用”引數。因此,使用了預設值,TensorFlow 執行時第二次無法建立變數。

一些故障是由內部 API 的演變引起的。軟體升級後,DL 相關元件之間的介面發生了變化,從而破壞了內部相容性。開發者可能會認為他們的程式仍然有效,因為這些變化對他們來說是看不見的。圖 7 表示了一個失敗的 Keras[12]作業,錯誤訊息“TypeError: softmax() got an unexpected keyword argument ‘axis’ while using layers.Dense”。執行日誌表明 Keras2.2.2 安裝在 Tensor Flow1.3Docker 容器中。開發人員可能認為這是最新版本的 Keras 將與 TensorFlow1.3 相容。然而,Keras2.2.2 升級了 Softmax 實現,並要求 TensorFlow1.5 或更高版本。修復方法是將 Keras 降級為相容版本 TensorFlow1.3。此外,為了管理包之間的複雜依賴關係,DL 平臺可以提供全域性包管理器和依賴檢查器。

結論 7:開發人員可能不完全理解框架/庫 API 所做的複雜假設,這是由於 DL 相關軟體的快速發展,導致了與框架相關的失敗 API 誤用,非法論證等。這種內部相容性問題通常是程式看不見的。

含義:開發人員需要更深入地理解框架/庫 API。一個定製的 Docker 影象可以幫助減輕這些故障的一部分。

5.4 特殊資料(ED)

在小樣本集中,24(6%)故障是由異常資料引起的。圖 8 展示了這樣一個例子。開發人員希望獲得 ROC(接收器操作特性)下的區域的 URE(即 AUC)。然而,在“標籤”變數(第 12 行)中只存在一個類別,不能滿足計算 AUC 的多類別要求。主動編寫異常資料處理程式碼可以幫助避免這種型別的故障。例如,圖 8 中的故障可以用“try-catch”來修復以捕獲丟擲的異常,從而避免在錯誤場景中計算 AUC。

DL 開發人員可以學習分散式資料並行程式設計實踐:提交前的手動資料集清理、異常資料處理的防禦程式設計和輸入資料抽樣進行本地測試[25]。需要更多的抽樣工具,這可以幫助開發人員對具有代表性的資料進行抽樣,以不僅確保分佈,而且還需要一些角落案例來形成更好的本地測試。理想情況下,DL 平臺還應該提供資料模式檢查器,以自動化確保作業執行前資料的正確性,從而提高使用者經驗。

結論 8:特殊的資料處理問題對於深度學習程式設計很重要。DL 開發人員可以學習分散式資料並行程式設計實踐來避免這個問題。

含義:特殊資料處理程式碼可以改進。DL 框架可以提供資料集 API 來處理這個問題。可以使用資料驗證過程或工具來在訓練之前取樣和檢查資料的有效性。

5.5 常見程式設計錯誤(CPE)

在小樣本集中,近一半(174;43.5%)的故障是由常見的程式設計錯誤引起的。其中大多數(例如,第 4.3 節中的路徑連線示例)易於理解和掌握,且可以透過引用程式碼中的錯誤訊息和故障站點進行快速修復。然而,一些故障相當複雜,需要徹底檢查程式碼邏輯。圖 9 顯示了一個 NLP 工作故障:Key Not Found。原始程式簡化很多便於演示。在模型評估階段,異常被丟擲第 21 行;然而,在這裡或在相同的情況下沒有發現任何線索。在閱讀了完整的原始碼後,我們注意到第 1 行和第 6 行的兩個提示,它們遠離原始故障站點。事實證明,開發商錯誤地禁用了在程式入口[42]RC 失敗的程式碼需要用到的波束搜尋。修復方法是為“beam_width”變數新增一個檢查。

根據我們的觀察,DL 開發人員經常使用他們的程式碼和指令碼中許多引數作控制實驗。然而,有時缺少或存在不合適的 argument 可能違反程式碼中的隱式假設並導致不相容的配置。失敗結果包括非法爭論和型別錯配,根據我們的統計,這在 CPE 中占主導地位 如圖 3 所示。一種可能的解決方案是執行正式的程式碼審查或高階靜態程式碼分析,以更早地檢測程式設計錯誤。

六、對當前測試和 debug 實踐的使用者研究6.1 研究設計

為了找出 DL 作業失敗的原因以及如何解決它們,我們需要更好地理解測試和除錯 DL 作業的當前實踐。更具體地說:

(1)測試實踐。我們會的 我們想知道開發人員是否在與 Philly 相同的環境中本地測試他們的程式。如果沒有,他們目前的測試環境是什麼。我們還想知道挑戰的發展 測試 DL 程式時,ERS 面臨。

(2)除錯做法。我們想知道開發人員目前是如何除錯失敗的工作的,他們是如何檢測隨機 nat 導致的非確定性錯誤的 對於 DL,他們希望從除錯工具中獲得什麼支援,以及“捕獲和複製”工具是否有用。

為了回答上述問題,我們對 6 名代表微軟的開發者進行了深入的面對面訪談。所有受訪者都是具有 0.5 至 5 年 DL 經驗的演算法工程師或研究人員。他們在與遊戲,計算機視覺,自然語言處理,語音,圖形和廣告相關的不同產品和任務上工作。表 2 顯示了受訪者的人口統計資料及其在 DL 中的經驗。請注意,雖然只有 6 名開發人員,這項研究的成本是巨大的,因為每次面談是一對一的,持續 1-3 小時。

6.2 測試實踐

由於 Philly 不提供本地模擬器,一個挑戰是獲得與 Philly 相當的測試環境(具有相同的硬體和 DL 相關軟體)。我們首先研究開發人員如何從硬體、開發環境和輸入資料三個方面進行 DL 測試。四名受訪者(U1、U2、U5、U6)手頭有幾個 GPU。然而,這種 GPU 記憶體要小得多,在效能上要比 Philly 的要慢得多。考慮到硬體的限制,所有受訪者都承認在本地測試中減少了批次大小、模型複雜度和 GPU 計數。關於這個開發環境,U3 說,由於缺乏強大的 GPU 等原因,他把 Philly 作為試驗檯。這可能解釋了一些簡單的 bug 的存在,這些 bug 可以在提交作業之前解決。其他人有自己的本地工作站。他們透過引用 Philly 提供的標準 DL 工具鏈的 Docker 影象來手動設定一個本機 PythonDL 環境。此外,他們模擬了 Philly 的環境變數,如輸入/輸出目錄。關於輸入資料檢查,三個人(U1,U4,U6)將使用一個取樣較小的資料集進行測試,因為原始輸入資料的噪聲較大。除了 U3,他們總是在本地機器上放置資料檔案。

受訪者還告訴我們關於 DL 測試中的測試空間的挑戰。由於 DL 的隨機性,有大量的超引數組合需要測試。例如,U2 用來向 Philly[35]提交一堆自動 ML 作業。然而,他們只能負擔得起一個非常小的候選物件的測試。

此外,受訪者描述了在不同 DL 階段測試的挑戰。他們通常更多地關注培訓管道的正確性(例如,資料讀取,模型構建和序列化)。四位受訪者(U2-U5)對模型驗證和評估階段的關注不夠。他們可能會在第一個模型檢查點之後停止測試 儲存成功。為了進一步研究不同 DL 階段的故障,我們將 DL 作業的執行分為 4 個階段,並分析了小樣本集的故障發生情況,如圖所示 烏爾 10。在“初始化”階段發生的故障數量佔總故障的 30.8%,它們只消耗了 GPU 總服務時間的 0.9%。在“模型評估”階段發生的故障數量佔總故障的 24,但它們消耗了 GPU 總服務時間的 81%。這些結果表明,在模型驗證和評估中實際上發生的許多故障都可以被測試。

發現 9:由於深度學習的特點,目前的 DL 測試實踐往往是不夠的。面臨三大挑戰:

(1)無法比較的測試環境;

(2)測試空間很大;

(3)在不同 DL 階段進行測試的必要性。

含義:鼓勵開發人員測試更多的案例和所有 DL 階段。平臺的本地模擬器,估計 GPU 記憶體消耗和使用可以用於 DL 測試的測試資料生成器。

6.3 除錯實踐

我們也對開發人員如何解決故障感興趣。六位受訪者使用傳統的程式碼編輯器(例如 VisualStudio 程式碼)和除錯方法(例如日誌記錄、斷點和單個用於除錯 DL 程式的 step。所有這些都對 Philly 的失敗作業採用了類似的除錯實踐:它們首先檢查日誌檔案,理解問題上下文,並將原始碼/指令碼中的故障定位。對於明顯的錯誤,它們只需將修復方法應用於程式碼(例如,校正物件型別)、資料(例如,用全新的資料集替換)和實驗配置。對於複雜的漏洞,它們轉向更多的除錯方法(例如的除錯方法(例如掉異常資料),並透過利用領域知識(例如,降低 Loss NaN 的學習速率)或框架文件(例如,圖 6 中描述的示例)來解決它們。還有一些 DL 特定的工具來幫助除錯,例如 TensorFlow 偵錯程式[6]和 Tensor Board[5,45]。開發人員可以使用這些工具跟蹤 Inf/NaN 值並定位生成它的運算子。仍然有一些故障難以在本地複製,因此開發人員必須透過一個嘗試和錯誤的過程來除錯它們,反覆向 Philly 提交修改後的程式並觀察結果。

對於 GPU OOM 來說,減少批處理大小通常是開發人員對這個問題的第一個解決方案,然後是隨後的解決方案:降低網路結構的複雜性。它們還具有一些特定域的引數,如 NLP 中的最大序列長度和圖形中的影象解析度,這些引數都可以用於降低模型的複雜性。

對於 Loss NaN,開發人員通常試圖透過列印中間結果和檢查計算來複制它。這個過程通常沒有任何除錯工具支援,涉及許多耗時的手工工作。

U1、U2、U3 和 U4 提到他們想要一個工具來視覺化變數值的變化,他們認為這將有助於除錯和提高模型學習效能。全部受訪者認為,提供一個重放機制是很好的,它可以在計算過程中捕獲一些有用的資料,並在出現故障時重放它們。這將有助於找到與 DL 和異常資料的隨機性質有關的錯誤。

結論 10:在許多情況下,當前的 DL 除錯實踐對於故障定位是無效的。由於本地和平臺之間的差異,現有的除錯工具可能無法很好地應對工作環境以及 DL 的隨機性。

含義:開發人員需要更多的 DL 特定除錯工具。一個很好的重放機制,用於儲存中間結果並恢復它們,並在稍後重新執行,這可能有助於除錯。記憶體使用評估工具可以補充當前的除錯方法。

七、討論7.1 我們工作的普適性

雖然我們的研究完全是在微軟進行的,但我們相信我們的失敗類別是普遍存在的,我們的大部分結果可以推廣到其他 DL 平臺。主要原因是在 Philly 執行的大多數深度學習程式都使用常見的程式設計正規化(例如 Python 語言、隨機演算法、框架和工具包庫),並針對常見的應用程式 (例如影象/影片/語音識別和 NLP)。此外,Philly 的硬體、系統架構和作業提交/執行機制[9,23,47]也被廣泛採用。

例如,調查結果 1 和 6 顯示 GPU 出於記憶體故障。眾所周知,具有複雜網路結構和大批次的 DL 模型可以提高模型的學習效能,但也顯著增加記憶體消耗[13,18]。因此,我們認為發現 1 和 6 是一般的其他平臺提供 GPU,甚至其他 AI 加速器,如 TPU。

另一個例子,調查結果 2 和 5 是與環境相關的故障,這對 Philly 的工作來說並不罕見,即使 Philly 透過標準 DL 工具鏈的 Docker 影象建立了一個密封的作業執行環境。潛在的原因是這樣的密封環境不可能總是與開發人員使用的本地環境相同。我們相信這些發現也適用於其他平臺,因為開發人員也有可能犯同樣的錯誤。例如,GoogleCloudAI 的故障排除網頁列出了幾個類似的環境故障。

7.2 未來研究方向

基於我們的研究,我們提出以下未來的研究工作:

(1)平臺改善

避免不必要的重試。自動重試是各種平臺中常見的設計,主要用於從非確定性系統故障中恢復。開發人員也可以利用這種機制進行非確定性深度學習特定失敗(例如,Loss NaN)。然而,如果一個失敗決定性地植根於 DL,多次重新執行作業顯然是不必要的,只會浪費資源。該平臺可以設計更精細的啟發式演算法來推斷是否一份失敗的工作值得重試,避免不必要的工作。

本地模擬器。從調查結果 2 和 5 中,我們可以看到,對環境差異的不認識導致了近一半的失敗。因此,為本地開發提供一個平臺模擬器是可取的。本地模擬器可以表現為平臺的單節點實現,該平臺匯出相同的環境 變數,訪問分散式儲存,並模擬一個或多個 GPU 裝置。

(2)工具支援

GPU 記憶體消耗的估計。從記憶體故障中除錯和修復 GPU 是相當有挑戰性的。選擇滿足記憶體消耗要求的良好模型引數/結構,很大程度上取決於開發人員的領域知識或採用一種嘗試和錯誤策略(即提交幾個具有不同模型配置的作業)。可以開發一個估計器來基於當前資料分佈、模型結構和批處理大小等特性推斷 GPU 記憶體消耗。透過分析原始碼和歷史 GPU 消耗可以建立預測模型記憶。這些工具可以幫助開發人員更好地估計 DL 程式的記憶體使用情況,並減少記憶體不足發生的情況。

靜態程式分析。靜態程式分析是一種在執行程式的情況下檢測程式碼缺陷的 UL 技術。它將有很大的潛力,積極主動地處理許多型別的工作故障,包括框架 API 誤用,TensorMismatch 以及那些在一般程式碼錯誤等。跨功能呼叫執行全程式分析可以減少錯誤警報。

資料合成。根據結論 8,發展一種透過[24]擴充套件符號執行技術來測試資料處理邏輯魯棒性的資料綜合工具是有用的。該工具可以生成符合初始輸入 di 的特殊資料集用於觸發潛在的 bug。

(3)框架改善

自動 GPU 記憶體管理。雖然 DL 框架隱藏了 GPU 的大部分複雜性,但開發人員仍然需要手動 GPU 記憶體管理來進行資料放置和消耗控制。框架可以建立一個自動 GPU 記憶體管理機制,就像 OSES 對主儲存器所做的那樣。例如,GPU 上的凍結資料可以自動交換出來[36,44]以避免 GPU 記憶體耗盡。另一個例子是,該機制可以預取出即將進行的計算中使用的輸入資料和模型分割槽。

重放機制。除錯 LossNaN 等非確定性故障是有挑戰性的,因為很難複製相同的失敗執行。框架可以使用現有的重放技術[20]記錄精確的執行順序和與環境的互動。因此 當開發人員想要跟蹤故障時,她可以確定性地重放到故障狀態,這可以極大地促進故障診斷。

八、相關工作

機器學習/深度學習 bug。Thung 等人[40]和 Sun 等人。[38]對機器學習系統中的 bug 進行了實證分析。這樣的系統缺陷也會導致工作失敗;然而,我們的研究集中在程式/指令碼錯誤上,這些錯誤是由 DL 應用程式開發人員編寫的。Zhang 等人[49]對 GitHub 和堆疊溢位進行了研究,以研究 TensorFlow 程式的 bug。ISLAM 等人[22]將工作擴充套件到更多的 DL 框架。他們發現的一些 bug(例如,由於 API 進化而產生的 bug)與我們的觀察一致。我們的研究分析了現實世界的工業具有多個 DL 框架的作業(例如,TensorFlow、PyTorch 和 CNTK)。我們發現許多不同型別的錯誤發生在基於雲的 DL 平臺上,這是開發人員透過本地測試不容易被發現的。

實證研究。對大資料平臺和軟體系統[25,46,48,50]的故障進行了一些實證研究。例如,肖等人[46]學習非類似 SQL 的 Map Reduce 程式中的錯誤。Li 等人[25]分析了分散式資料並行程式中的程式碼/資料缺陷。周等人[50]對服務質量進行了實證研究 一個生產大資料計算平臺的起訴,它有各種型別的問題,包括硬體故障和使用者錯誤。張[48]分析了大型軟戰中的斷層分佈系統。我們的研究更多地集中在生產計劃失敗的深度學習工作。

叢集基礎設施。許多研究[19,23,33,47]旨在提高 GPU 叢集的深度利用率 透過研究獨特的工作特點來學習。Jeon 等人[23]率先了解低 GPU 利用率的多租戶叢集。如此低的利用率來自幫派排程 [29]資源區域性性和工作失敗。這些作業故障分佈在基礎設施、DL 框架和使用者程式碼之間。除了對失敗症狀進行分類外,我們的工作還研究了 DL 程式故障並對其根源進行了深入的分析。

測試。最近,在測試 DL 模型方面有大量的工作。例如,DeepXplore[32]提出了一個新的度量指標用於評估深度神經網路的覆蓋範圍。Deeptest[41]進一步引入了一個特定領域域的自動測試工具,透過對影象資料的真實轉換來最大化神經元的覆蓋。TF X[8]構建了一個機器學習管道,它簡化了使用者在部署中的工作,其中包括一組用於資料分析、轉換和驗證的系統元件。因此,平臺可以顯著減少培訓失敗,提高模型質量。我們的工作提供了對 DL 作業程式故障的系統分析,可以幫助社群設計更好、更實用的用於 DL 測試和除錯工具包。

九、總結

與其他計算機程式一樣,深度學習程式也可能無法執行。本文描述了第一個關於深度學習工作程式失敗的實證研究。我們手動檢查微軟的 4960 個失敗作業中收集的故障資訊,並將它們分類為 20 個類別。此外,我們在 400 個故障樣本上確定了常見的根本原因和錯誤修復解決方案。為了更好地瞭解當前深度學習程式的測試和除錯實踐,我們還與開發人員進行訪談。根據我們的發現,我們建議可能的研究主題和工具支援,可以促進深度學習培訓和測試。我們相信我們的工作可以幫助理解 DL 的質量問題,為今後的深度學習發展提供有價值的指導方針。

29
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 【20201007】Python操作MySQL資料庫