推薦收藏 | 如何在實際中計劃和執行一個機器學習和深度學習項目

  • 2019 年 10 月 10 日
  • 筆記

導讀

做研究打比賽和真正的做一個機器學習和深度項目是不一樣的,如果你有這方面的困惑的話,可以看看這篇文章。

我們處理Kaggle競賽、黑客馬拉松、業餘數據科學任務甚至是論文的方式,與在專業工作環境中所期望的是不一樣的。在快速原型開發中是沒什麼問題的,但是你還必須知道如何從單個機器學習程式碼過渡到結構化的程式碼版本控制,而這不會損害團隊中的軟體工程師。不幸的是,要遵循這些樣板並不容易。幸運的是,有一套軟體工程和機器學習的最佳實踐和指南來幫助我們改進方法,並成功地完成這項任務。

這篇文章是一系列文章中的第一篇,將致力於形成一條以整體方式引導深度學習項目的路徑。我們將從討論制定一個好的策略來構建深度學習項目的重要性開始。然後,我們將分解負責在生產上開發深度學習項目的單元,並研究第一個單元。

以下是本系列的文章:

  • 如何計劃和進行ML和DL項目
  • 與數據融為一體

為什麼要關注結構化深度學習項目?

這可能是全球所有軟體開發項目的核心。在生產級別上開發軟體項目時,你最有可能是在一個團隊中工作。該團隊將由許多成員組成,他們的職責各不相同——其中一些人將是後端開發人員,一些人將負責文檔,而另一些人將負責單元測試。如果你是一個人,事情會變得更糟——作為一個承包商來開發一個PoC,在那裡,只有你獨自負責PoC的每一個小部件。同樣的理論也適用於深度學習項目,因為歸根結底,我們不僅想推動該領域的進步,而且對使用深度學習開發應用感興趣。當涉及到以適當的規模開發具有深度學習的應用時,它只不過是一個軟體項目。

軟體工程已經存在很久了。已經存在一組與領域無關的通用最佳實踐(軟體工程中的設計模式),然後還有一些非常特定於領域的實踐,12因素應用程式方法論。深度學習實驗是由許多模組組成的,即使是在非常初級的階段。例如數據集構建模型構建模型訓練模型調優模型選擇等等。現在,考慮一下將其擴展到生產環境時可能出現的複雜性。這就是軟體工程的重要性發揮作用的地方。

應用深度學習是一個迭代的過程

深度學習模型的性能可以通過許多不同的方式得到改善。例如,如果缺少數據,可以收集更多的數據,可以訓練更長的時間的網路,可以調整深度學習模型的超參數,等等。但是,當涉及到使用深度學習設計整個系統時,經常會看到這些想法失敗。即使在提高了訓練數據的品質之後,你的模型也可能無法像預期的那樣工作,可能是新的訓練數據不能很好地代表邊緣情況,也可能是訓練數據中仍然存在大量的標籤雜訊,原因有很多。現在,這完全沒問題,但是當這個失敗發生時,花在收集更多數據、標記它、清理它上的時間就被浪費了。我們希望這個儘可能地減少。擁有一套良好的策略將有助於此。

可復現危機

這對於深度學習非常重要,因為神經網路本質上是隨機的。這就是為什麼它們能很好的近似函數的原因之一。由於神經網路固有的隨機性,在同一個實驗中得到不同的結果是完全可能的。例如,今天,你可能在使用網路架構的貓與狗數據集上獲得了90%的精確度,而第二天,在使用相同架構和實驗pipeline的情況下,你將觀察到精確度的±1%的變化。這在生產系統中是不可取的。我們希望結果有一致性,並希望實驗儘可能重現。

當你的實驗結果傳達給你的團隊時,請考慮另一個場景。但是,當其他成員試圖複製你的實驗以便在項目中進一步開發時,他們卻無法這樣做。更糟糕的是,即使固定了隨機數生成器的種子,也不一定能保證重現性。由於依賴項版本、環境設置、硬體配置等原因,結果可能會有所不同。例如,你使用的是 TensorFlow1.13運行了所有的實驗,但是團隊的其他成員使用的是最新的版本(2.0.0-beta0)。這可能會在實驗執行過程中造成大量不必要的問題。在最壞的情況下,整個程式碼庫可能會因為這種依賴關係不匹配而崩潰。另一個例子是,假設你使用GPU的環境中完成了所有實驗,而沒有使用任何執行緒機制載入數據。但是這個環境可能並不總是相同的——你的隊友可能沒有啟用GPU系統。因此,他們可能會得到不同的結果。因此,除了固定隨機種子之外,在整個團隊中維護一個固定的、一致的開發環境也是很重要的。

分別對數據和程式碼進行版本控制

軟體程式碼庫很大,而且是經常變化的。你正在進行的軟體項目很可能像大多數軟體一樣有多個版本。因此,很自然地,這些版本更改的程式碼庫也會彼此不同,這就產生了對版本控制的需求。程式碼庫的版本控制可能比我們想像的要重要得多。例如,你的軟體的最新版本是2.0.1。在執行了嚴格的用戶回饋之後,在你看來,該軟體早期版本中的某個特性要優於當前版本。如果開發人員團隊不能有效地維護這些不同版本的程式碼庫,你將永遠無法輕鬆地在當前版本的軟體中進行更改,或者回滾到以前的工作版本。

說到深度學習,我們不僅有不同版本的程式碼庫,還可能有不同版本的訓練數據。你可能已經開始了包含多個影像的訓練集的實驗,隨著項目的進展,你的團隊決定向訓練集添加更多的影像。你可能會想為什麼要單獨的版本數據?它不能和程式碼版本放在一起完成嗎?

事實上,這一點經常被忽視。如果有的話,你有可能需要比你的數據更頻繁地更改軟體程式碼庫。當將軟體程式碼庫部署到生產伺服器時,如果數據沒有被更改,那麼將數據與程式碼庫一起推送就沒有任何意義。這一點對於項目可能處理的任何卷數據都是實用的。

檢查點的規律

如果你正確地設置了模型檢查點,你可以在深度學習實驗中節省大量的時間。通常,模型檢查點是指在訓練過程中保存你的網路模型。使用不同的策略,有可能不一樣。例如,一個非常常見的模型檢查點策略是記錄在模型訓練過程中驗證損失在哪裡隨著訓練損失的減少而停止,並保存相應模型的權重。這就是所謂的模型檢查點。當你在為深度學習實驗做原型實現時,你能夠重用這些檢查點模型,並且這將絕對避免你從頭開始重複可能花費數小時/天的訓練。

深度學習項目的目錄結構

當你在團隊中工作或作為一個單獨的機器學習實踐者時,將你的深度學習實驗的所有部分放在一個良好的結構中非常重要,這樣其他團隊成員就可以儘可能輕鬆地引用它們。考慮下面的例子:

  • web後端開發人員可能需要將模型權重載入到腳本中,以創建REST API端點
  • 來自單元測試團隊的某人需要來自你的程式碼庫的模型訓練腳本,以便生成特定的測試用例

在上面的例子中,如果團隊成員將大部分時間花在為項目開發尋找正確的文件上,那麼它將影響項目開發的有效性。維護一個良好的目錄結構可以在很大程度上防止類似的問題。另外,請注意,即使團隊同意的項目結構,這也不能代替記錄項目存儲庫/程式碼版本管理。

技術債的高利率

如前所述,深度學習是一個高度實驗性的領域。在他們的深度學習實驗中,總是有很多的可能性和想法可以嘗試。事實上,在實驗階段,我們發現自己正在探索改進性能的可能性領域。當然,可能性越多,複雜性就越大。隨著程式碼基的發展,要跟蹤執行流並記住哪一部分導致了什麼就變得非常困難。這就產生了「技術債務」。這極大地損害了項目的整體開發,因為假設項目團隊中的所有成員都理解您在實驗中嘗試的所有內容是不切實際的。然而,如果您以適當的方式記錄您在試驗階段嘗試的所有內容,那麼跨團隊的溝通就會變得容易得多。提供良好的文檔,採用高品質的程式碼重構實踐通常被認為是「不那麼酷」的開發人員的特徵,因為這些事情需要時間,而且被認為很無聊。在項目環境中,有時最好慢一些進行,這樣就可以儘可能地減少由技術債引起的通訊間隔和較慢的實驗迭代周期。

在下一節中,我們將討論我們可以採取的措施,以檢查上述因素,從而給我們的深度學習項目一個良好的結構。我們將模擬一個試點項目場景,並將在此基礎上進行構建。

如何去構建深度學習項目結構?

為了幫助我們開發關於構建深度學習項目的堅實知識,可以模擬一個示例項目場景。就本文而言,假設你正在為一家專註於時尚的電子商務公司工作。該公司的目標是建立一個服裝分類系統。最終的產品將是一個web應用程式,該應用程式將能夠獲取服裝的影像,並將其類別和評分作為輸出。

經理已經向你提供了有關公司感興趣的性能指標的指導方針,以及其他細節,如推斷時間、深度學習模型的最大大小等等。現在,你需要與由前端開發人員、後端開發人員、數據工程師等組成的其他團隊一起執行。數據工程師已經收集了一些初始數據,你可以使用這些數據開始實驗。但是,你決定與團隊的其他成員開會,就項目的合適的目錄結構達成一致,而不是直接寫程式碼。到目前為止,你應該已經知道為什麼為項目維護目錄結構很重要。

假設基礎設施團隊已經為團隊配置了要使用的機器。如果你獨立工作,請想像你已經為自己配置好了基礎設施。

目錄結構

在這一點上,如果團隊中有一組將要進行短期目標的實驗,那麼將更容易得出什麼目錄結構可能會運行得很好。理想情況下,在這個階段,團隊應該——

  • 擁有數據工程團隊提供的數據
  • 準備一個實驗notebook(或一套notebook)來介紹數據集和初始模型實驗

當項目的業務價值仍然不清楚,並且你需要用更有針對性的問題來理解你的客戶數據時,這就更加有用了。

隨著項目的進展,團隊將開發更多的資產

  • 數據(以及下載和預處理數據的腳本)
  • 實驗
  • 網站後台
  • 實用程式腳本
  • 模型建立和模型訓練腳本

我們必須記住,在這個階段,將涉及到快速構建原型。作為一個深度學習的實踐者,你很可能會嘗試不同的網路拓撲結構、不同的損失函數、不同的訓練策略等等。機器學習中不存在「免費午餐定理」,這一點在深度學習中更適用。因此,為了確保使用可用的數據訓練出一個良好的模型,你可以探索各種可能性和想法。這將導致一些技術債。將有許多文件以無序的方式駐留在項目目錄中——重複和冗餘的程式碼、檢查點和匿名文件夾中的日誌等等。為了解決這個問題,可以遵循一個相對成熟的目錄結構。

web後端

這本質上是為了將最終模型暴露為REST API的端點。它可以包含基本測試,以測試預測是否按照預期的方式進行,即將模型包裝到API端點的所需web伺服器邏輯。與這些腳本一起,與開發環境的Docker映像相關的所有規範都將駐留在這裡。Docker只是我舉的一個例子。它可以是任何有助於將軟體打包為容器的東西。你會擁有一個生產伺服器(如AppEngine、Lambda), API將部署到該伺服器。相應的部署腳本也將位於此目錄中。

腳本

這就是項目中所有的腳本放的地方。這包括檢查程式碼品質的測試、模型預測的測試、部署任務、訓練任務等等。

模型構建和訓練

你可以看到結構中有兩個單獨的目錄—一個包含構建模型所需的所有部分,另一個實際上根據一組模型配置來訓練模型。注意模型網路之間的區別。這是因為神經網路在這裡被認為是一個dummy函數,它只有神經元節點,但它不知道如何操作——如何載入數據,如何向前傳遞,如何產生預測等等。駐留在models中的腳本負責這一點。

注意,這是一個參考結構,它可能因團隊和項目而異。在本文和後續文章中,我們將構建它。

在團隊就一個相互目錄結構達成一致之後,下一個理想的步驟是建立開發工作區——使用環境管理器工具,比如pippipenvDocker

工作區的設置

在前面幾節中,我們已經討論了在整個項目中維護公共開發工作區的重要性。我們不希望看到項目因為依賴關係問題或依賴關係更新而中斷。假設項目將基於Python作為中央程式語言,我們可以利用「pip」和「pipenv」等工具來委託環境管理任務。因此,有必要討論這些工具,以了解它們在這個階段可能有什麼用處。

使用環境管理工具

團隊成員可能已經在他們的機器上安裝了一些依賴項,但是他們可能在版本上有所不同。因此,好的第一步是為項目創建一個虛擬環境或容器,並在整個項目中維護它。項目所需的所有依賴項都應該駐留在這個環境/容器中。

有很多工具可以做到這一點,比如condapipenvpip+virtualenv等等。他們都很受歡迎。根據我的經驗,應該首選pipenv 而不是condapip+virtualenv。這是因為有時可能會發生這樣的情況:Python包(依賴項)已經在Python包索引(PyPI)中發布了,但沒有作為conda包發布。在這種情況下,你可能必須自己構建一個單獨的conda包。

condapipenv都能夠創建獨立的Python環境,但它們解決依賴關係的方式不同。值得注意的是,conda本質上可以安裝任何conda包,而且它可能並不總是Python包。

在設置工作區時可以使用的另一個解決方案是使用Docker。在下一節中,我們將看到如何實現。

使用Docker

Docker使你能夠在容器環境中開發、部署和執行應用程式。我們可以在Docker映像中以獨立的方式封裝開發環境。然後,我們可以將Docker映像作為Docker容器分發。使用Docker是有利的,因為它提供了將整個開發環境打包為一個容器的能力,該容器可以在其他機器上運行。如果我們將我們的項目作為容器運送到其他方,那麼它將特別有用。

在腦海中構建執行流程的景象

深度學習實驗包括從數據準備到建模的一系列不同步驟。每一步都建立在另一步之上。可以有一些步驟是集體迭代的。例如,構建一個模型,然後訓練它,調優它的超參數,評估它和實驗,然後再次回到模型構建步驟。

通常情況下,為了嘗試不同的模型體系結構,我們將以不同的方式預處理數據,使其和相應的模型適應。假設你正在使用一個預先訓練好的VGG16網路開始你的深度學習實驗。為了使數據適合於預訓練的網路,你使用網路所訓練的數據集的統計數據(平均值和標準偏差)對其進行歸一化。然而,這個網路並沒有得到滿意的結果,因此你決定嘗試另一個預訓練網路——這次是針對CIFAR10 dataset訓練的Inception網路。但是在將原始數據提供給Inception網路之前,你忘記使用CIFAR10 dataset的統計數據對其進行歸一化。這確實會導致意想不到的後果,而且你可能無法找出原因。

這就是為什麼在開始執行實驗之前,準備一個關於整個實驗執行流程的心理模型是很重要的。你可以參考它,反覆檢查你的實驗中是否有出乎意料的錯誤。下面是FloydHub團隊在他們的一個內部黑客馬拉松項目中構建的這種心理模型的一個例子。

觀察這個模型是如何精心策劃的。它優雅地概述了團隊在做實驗時要執行的步驟。它仔細地登記了這些操作,然後按階段的方式對這些操作進行隔離。這些操作已經相互關聯,以便團隊能夠跟蹤執行流程。

關於項目結構要考慮的最後一個指針是數據和程式碼庫的版本控制,我們將在接下來討論這個問題。

版本控制

數據的版本控制仍然沒有程式碼庫的版本控制那麼完善。我們已經闡明了為什麼將數據與程式碼庫分離很重要。隨著時間的推移,用於訓練深度學習系統的數據常常會發生變化。考慮以下場景:

  • 團隊可能想用更新的圖片替換舊的圖片
  • 團隊可能想要為已經存在的訓練集添加新的影像
  • 團隊決定結合主動學習來選擇有趣的測試數據點,手工標記它們並添加到現有的訓練集中。

我們現在有一個關於如何構建深度學習項目的軟指南。這些對我的經驗非常有幫助,我真誠地希望它們對你也有幫助。我們重複了很多關於深度學習的實驗。但重要的是要知道,在深入研究之前,有一些基本的工作是需要做的。

數據是機器學習系統的燃料。因此,與數據融為一體非常重要,我真的不能過分強調這一點。在下一節中,我們將深入探討這個問題。我們將嘗試製定一個清單,可以很容易地在你自己的工作中引用。

後面是什麼?

在本文中,我們討論了構建深度學習項目時應該考慮的要點。但這段旅程並沒有就此結束。在下一篇文章中,我們將繼續今天的內容。我們將學習一些在深度學習實驗開始之前應該遵循的一般準則。這將包括與數據融為一體、數據轉換、探索性數據分析、人工基準線等主題。

—END—