機器之心發布
來源:AWS雲計算
大多數人都喜歡在筆記本電腦上做原型開發。當想與人協作時,通常會將代碼推送到 GitHub 並邀請協作者。當想運行實驗並需要更多的計算能力時,會在雲中租用 CPU 和 GPU 實例,將代碼和依賴項複製到實例中,然後運行實驗。如果您對這個過程很熟悉,那麼您可能會奇怪:為什麼一定要用 Docker 容器呢?
運營團隊中優秀的 IT 專家們可以確保您的代碼持續可靠地運行,並能夠根據客戶需求進行擴展。那麼對於運營團隊而言,容器不就成了一種罕見的工具嗎?您能夠高枕無憂,無需擔心部署問題,是因為有一群基礎設施專家負責在 Kubernetes 上部署並管理您的應用程式嗎?
在本文中,AWS會嘗試說明為什麼您應該考慮使用 Docker 容器進行機器學習開發。在本文的前半部分,將討論在使用複雜的開源機器學習軟體時遇到的主要難題,以及採用容器將如何緩和這些問題。然後,將介紹如何設置基於 Docker 容器的開發環境,並演示如何使用該環境來協作和擴展集群上的工作負載。
機器學習開發環境:基本需求
首先了解一下機器學習開發環境所需的四個基本要素:
計算:訓練模型離不開高性能 CPU 和 GPU。存儲:用於存儲大型訓練數據集和您在訓練過程中生成的元數據。框架和庫:提供用於訓練的 API 和執行環境。原始碼控制:用於協作、備份和自動化。
作為機器學習研究人員、開發人員或數據科學家,您可以在單個 Amazon Elastic Compute Cloud (Amazon EC2) 實例或家庭工作站上搭建滿足這四種要素的環境。
那麼,此設置有什麼問題嗎?
其實也談不上有問題。因為幾十年來,大多數開發設置都是如此:既沒有集群,也沒有共享文件系統。
除了高性能計算 (HPC) 項目的一小群研究人員能夠將開發的代碼放在超級計算機上運行之外,絕大多數人都只能依靠自己專用的計算機進行開發。
事實證明,與傳統軟體開發相比,機器學習與 HPC 具有更多的共同點。與 HPC 工作負載一樣,若在大型集群上運行機器學習工作負載,執行速度更快,實驗速度也更快。要利用集群進行機器學習訓練,您需要確保自己的開發環境可移植,並且訓練在集群上可重複。
為什麼需要可移植的訓練環境?
在機器學習開發流程中的某個階段,您會遇到以下兩個難題:
您正在進行實驗,但您的訓練腳本發生了太多次的更改導致無法運行,並且只用一臺計算機無法滿足需求。您在具有大型數據集的大型模型上進行訓練,但僅在一臺計算機上運行使您無法在合理的時間內獲得結果。
這兩個原因往往會讓您希望在集群上運行機器學習訓練。這也是科學家選擇使用超級計算機(例如 Summit 超級計算機)進行科學實驗的原因。要解決第一個難題,您可以在計算機集群上獨立且異步地運行每個模型。要解決第二個難題,您可以將單個模型分布在集群上以實現更快的訓練。
這兩種解決方案都要求您能夠在集群上以一致的方式成功復現開發訓練設置。這一要求很有挑戰性,因為集群上運行的作業系統和內核版本、GPU、驅動程序和運行時以及軟體依賴項可能與您的開發計算機有所不同。
您需要可移植的機器學習環境的另一個原因是便於協作開發。通過版本控制與協作者共享訓練腳本很容易。但在不共享整個執行環境(包括代碼、依賴項和配置)的情況下保證可重複性卻很難。這些內容將在下一節中介紹。
機器學習、開源和專用硬體
機器學習開發環境面臨的挑戰是,它們依賴於複雜且不斷發展的開源機器學習框架和工具包以及同樣複雜且不斷發展的硬體生態系統。雖然這兩者都是我們需要的積極特質,但它們卻在短期內構成了挑戰。
在進行機器學習訓練時,您有多少次問過自己以下這些問題:
我的代碼是否利用了 CPU 和 GPU 上的所有可用資源?我是否使用了正確的硬體庫 和硬體庫版本?當運行環境大同小異時,為什麼我的訓練代碼在自己的計算機上可以正常工作,而在同事的計算機上就會崩潰?我今天更新了驅動程序,現在訓練變慢/出錯了。這是為什麼?
如果您檢查自己的機器學習軟體堆棧,會發現自己的大部分時間都花在了紫紅色框(即圖中的我的代碼)上。這部分包括您的訓練腳本、實用程序和幫助例程、協作者的代碼、社區貢獻等。如果這還不夠複雜,您還會注意到您的依賴項包括:
迅速演進的機器學習框架 API;機器學習框架依賴項,其中有很多是獨立的項目;CPU 專用庫,用於加速數學例程;GPU 專用庫,用於加速數學例程和 GPU 間通信例程;以及需要與用於編譯上述 GPU 庫的 GPU 編譯器協調一致的 GPU 驅動程序。
由於開源機器學習軟體堆棧的高度複雜性,在您將代碼移至協作者的計算機或集群環境時,會引入多個故障點。在下圖中,請注意,即使您控制對訓練代碼和機器學習框架的更改,也可能無法顧及到較低級別的更改,從而導致實驗失敗。
最終,白白浪費了您的寶貴時間。
為什麼不使用虛擬 Python 環境?
您可能會認為,conda 和 virtualenv 之類的虛擬環境方法可以解決這些問題。沒錯,但是它們只能解決部分問題。有些非 Python 依賴項不由這些解決方案管理。由於典型機器學習堆棧十分複雜,因此很大一部分框架依賴項(例如硬體庫)都在虛擬環境範圍之外。
使用容器進行機器學習開發
機器學習軟體是具有多個項目和參與者的零散生態系統的一部分。這可能是件好事,因為每個人都可以從自己的參與中獲益,並且開發人員始終擁有充分的選擇。不利方面是要應對一些問題,例如一致性、可移植性和依賴項管理。這就是容器技術的用武之地。在本文中,我不想討論容器的常規優勢,而想講講講機器學習如何從容器中獲益。
容器不僅可以完全封裝您的訓練代碼,還能封裝整個依賴項堆棧甚至硬體庫。您會得到一個一致且可移植的機器學習開發環境。通過容器,在集群上開展協作和進行擴展都會變得更加簡單。如果您在容器環境中開發代碼和運行訓練,不僅可以方便地共享您的訓練腳本,還能共享您的整個開發環境,只需將您的容器映像推送到容器註冊表中,並讓協作者或集群管理服務提取容器映像並運行,即可重現您的結果。
應將/不應將哪些內容包含在您的機器學習開發容器中
這個問題沒有正確答案,您的團隊如何運營由您來決定,但是關於可以包含哪些內容,有以下幾個方案:
只包含機器學習框架和依賴項:這是最簡潔的方法。每位協作者都可以獲得相同執行環境的相同副本。他們可以在運行時將自己的訓練腳本克隆到容器中,也可以掛載包含訓練代碼的卷。機器學習框架、依賴項和訓練代碼:當擴展集群上的工作負載時,首選此方法。您可以獲得一個可在集群上擴展的可執行的機器學習軟體單元。根據您對訓練代碼的組織方式,您可以允許腳本執行多種訓練變體,以運行超參數搜索實驗。
共享您的開發容器也非常輕鬆。您可以按以下方式進行共享:
容器映像:這是最簡單的方法。這種方法允許每位協作者或集群管理服務(例如 Kubernetes)提取容器映像,對映像進行實例化,然後直接執行訓練。Dockerfile:這是一種輕量型方法。Dockerfile 中包含關於創建容器映像時需要下載、構建和編譯哪些依賴項的說明。可以在您編寫訓練代碼時對 Dockerfile 進行版本控制。您可以使用持續集成服務(例如 AWS CodeBuild),自動完成從 Dockerfile 創建容器映像的過程。
Docker 中心提供了廣泛使用的開源機器學習框架或庫的容器映像,這些映像通常由框架維護人員提供。您可以在他們的存儲庫中找到 TensorFlow、PyTorch 和 MXNet 等。在決定從哪裡下載以及下載哪種類型的容器映像時,要十分謹慎。
大部分上遊存儲庫都會將其容器構建為在任何位置均可使用,這意味著這些容器需要與大部分 CPU 和 GPU 架構兼容。如果您確切知曉將在怎樣的系統上運行容器,最好選擇已經針對您的系統配置進行優化的合格容器映像。
使用 Jupyter 和 Docker 容器設置您的機器學習開發環境
AWS 使用常用的開源深度學習框架來託管可用於計算優化型 CPU 和 GPU 實例的 AWS Deep Learning Containers。接下來,我將說明如何使用容器通過幾個步驟設置開發環境。在此示例中,我假設您使用的是 Amazon EC2 實例。
第 1 步:啟動您的開發實例。
C5、P3 或 G4 系列實例都適合用於機器學習工作負載。後兩者每個實例最多可提供多達八個 NVIDIA GPU。有關如何啟動實例的簡要指南,請閱讀 Amazon EC2 入門文檔(https://amazonaws-china.com/cn/ec2/getting-started/)。
選擇 Amazon 系統映像 (AMI) 時,請選擇最新的 Deep Learning AMI,該 AMI 中包含所有最新的深度學習框架、Docker 運行時以及 NVIDIA 驅動程序和庫。儘管使用安裝在 AMI 本地的深度學習框架看似方便,但使用深度學習容器會讓您距離可移植性更強的環境更近一步。
第 2 步:通過 SSH 連接到實例並下載深度學習容器。
第 3 步:實例化容器並設置 Jupyter。
第 4 步:使用基於容器的開發環境。
容器原本是無狀態的執行環境,因此請將您的工作保存在調用 docker run 時使用 -v 標誌指定的掛載目錄中。要退出容器,請停止 Jupyter 伺服器並在終端上鍵入 exit。要重新啟動已停止的容器,請運行:
docker start tf-dev
按照第 3 步中的說明設置隧道,即可繼續進行開發。
現在,假設您要對基本容器進行更改,例如,按照第 3 步所示,將 Jupyter 安裝到容器中。最簡單的方法是跟蹤所有自定義安裝並在 Dockerfile 中進行捕獲。這使您可以重新創建容器映像,並從頭進行更改。這還可用於記錄更改,並且可與剩餘代碼一起進行版本控制。
在對開發過程造成最小幹擾的情況下執行此操作的更快方法是,通過運行以下命令將這些更改提交到新的容器映像中:
sudodockercommittf-devmy-tf-dev:latest
注意:容器純粹主義者會認為這不是保存更改的建議方法,應將這些更改記錄在 Dockerfile 中。這是一個很好的建議,也是通過編寫 Dockerfile 跟蹤您的自定義設置的好做法。如果您不這樣做,則會面臨以下風險:隨著時間流逝,您將失去對更改的跟蹤,並將依賴於一個「工作」映像,就像依賴於無法訪問原始碼的已編譯二進位文件一樣。
如果您想與協作者共享新容器,請將其推送到容器註冊表,例如 Docker Hub 或 Amazon Elastic Container Registry (Amazon ECR)。要將其推送到 Amazon ECR,請先創建一個註冊表,登錄,然後推送您的容器:
aws ecr create-repository --repository-name my-tf-dev$(aws ecr get-login --no-include-email --region <REGION>)docker tag my-tf-dev:latest <ACCOUNT_ID>.dkr.ecr.<REGION>.amazonaws.com/my-tf-dev:latestdocker push <ACCOUNT_ID>.dkr.ecr.<REGION>.amazonaws.com/my-tf-dev:latest
現在,您可以與協作者共享此容器映像,並且您的代碼應該能像在計算機上一樣工作。這種方法的額外好處是您現在可以使用同一容器在集群上運行大規模工作負載。我們來了解一下如何做到這一點。
機器學習訓練容器並在集群上擴展它們
大多數集群管理解決方案(例如 Kubernetes 或 Amazon ECS)都會在集群上調度和運行容器。另外,您也可以使用完全託管的服務,例如 Amazon SageMaker,在其中您可以根據需要配置實例,並在作業完成時自動將其銷毀。此外,該服務還提供用於數據標籤的完全託管的服務套件、託管的 Jupyter 筆記本開發環境、託管的訓練集群、超參數優化、託管模型託管服務以及將所有這些結合在一起的 IDE。
要利用這些解決方案並在集群上運行機器學習訓練,您必須構建一個容器並將其推送到註冊表。
如果您如上所述採用基於容器的機器學習開發,那麼您盡可放心,您開發時所用的容器環境將按計劃在集群上大規模運行,而不會出現框架版本問題和依賴項問題。
要在 2 個節點上使用 Kubernetes 和 KubeFlow 運行分布式訓練作業,您需要在 YAML 中編寫一個如下所示的配置文件:
使用 TensorFlow 和 Horovod API 進行分布式訓練的 Kubernetes 配置文件的摘錄,可在 Github 上找到。請注意,屏幕截圖未顯示完整文件。
在映像部分下,您將使用訓練腳本指定 docker 圖像。在命令下,您將指定訓練所需的命令。由於這是一項分布式訓練作業,因此您將使用 mpirun 命令運行 MPI 作業。
您可以按以下步驟將此作業提交到 Kubernetes 集群(假設集群已設置並正在運行,並且您已安裝 KubeFlow):
多疑善思,但不要驚慌失措
機器學習社區發展迅猛。新的研究成果在發布後的數周或數月之內就會在開源框架中的 API 中實施。由於軟體迅速演進,及時更新並保持產品的質量、一致性和可靠性頗具挑戰。因此,請保持多疑善思,但不要驚慌失措,因為您不是單人作戰,並且社區中有許多最佳實踐可用來確保您從最新信息中受益。
轉向容器化機器學習開發是應對這些挑戰的一種途徑,希望在本文中我已經解釋清楚了這一點。
現在,創建AWS帳戶即可體驗免費產品服務,包括以下內容: