機器學習開發的靈藥—Docker容器

2020-12-25 機器之心Pro

機器之心發布

來源: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帳戶即可體驗免費產品服務,包括以下內容:

相關焦點

  • docker容器的啟動方式
    .更快速的啟動時間:傳統的虛擬機技術啟動應用服務往往需要數分鐘,而Docker 容器應用,由於直接運行於宿主內核,無需啟動完整的作業系統,因此可以做到秒級、甚至毫秒級的啟動時間。大大的節約了開發、測試、部署的時間。    .一致的運行環境:開發過程中一個常見的問題是環境一致性問題。
  • Docker系列教程02-操作Docker容器
    t分配一個tty偽終端,支持終端登錄2)啟動容器使用docker create命令新建的容器處理停止狀態,可使用docker start啟動它。[root@qll251 ~]# docker run -it ubuntu /bin/bashroot@8b18b6758bb6:/#docker run相當於執行了兩個步驟:將鏡像放入容器中(docker create),然後啟動容器(docker start)。
  • 誰是容器中的「戰鬥機」?Docker與Chef、LXC等容器對比
    以下是我研究 docker 和 LXC 後總結的一些區別。 標準的配置方法 每個 LXC "容器" 之間或許不兼容,但是 docker 採用了一種標準的配置方法使得由不同 docker 創建出的 LXC 能夠完全兼容。 基於應用 LXC 的定位是作為一種虛擬機的替代方案。
  • Docker 容器的網絡
    嘗試運行下面的命令:$ docker run -itd --name=networktest ubuntu74695c9cea6d9810718fddadc01a727a5dd3ce6a69d09752239736c030599741通過檢查網絡,可以非常容易的找到你容器的
  • 【Docker】系列教程02-操作Docker容器
    ~]# docker run -it ubuntu /bin/bashroot@8b18b6758bb6:/#docker run相當於執行了兩個步驟:將鏡像放入容器中(docker create),然後啟動容器(docker start)。
  • docker鏡像及容器命令
    運行容器docker run <容器名>3. 查看容器列表docker ps -a4.後臺運行容器docker run -d <容器名>-d 後臺執行5.暴露容器埠docker run -d -P <容器名>5.1 自定義埠暴露docker run -d -p 2020:80 2021:443 <容器名>
  • 如何開始docker - docker架構及創建容器
    docker的組成docker是採用C/S模式,使用遠程API來管理創建docker。容器的創建過程: 鏡像倉庫 ->pull 鏡像到本地 -> 本地鏡像 -> run容器 from 鏡像 -> 創建容器並執行程序->程序退出->容器退出1、dockerd服務端(守護進程),dockerd是docker的守護進程。
  • 雲計算核心技術Docker教程:Docker容器使用
    要退出客戶端程序,直接輸入 exit:查看所有的容器命令如下:$ docker ps -a使用 docker start 啟動一個已停止的容器:$ docker start <容器 ID>$ docker run -itd --name ubuntu-test ubuntu /bin/bash要停止一個容器運行使用如下命令:$ docker stop <容器 ID>要重啟一個容器運行使用如下命令:
  • Docker應用之CockroachDB數據存儲:開發和部署容器的力量
    cockroachdb/cockroach:部署鏡像,即使你沒有實際的開發,它仍然會運行在CockroachDB集群中。它是基於BusyBox的,並且有著更複雜的構建過程。開發容器靜態的連接二進位文件和測試功能。主要二進位文件放入一個最小的容器中,測試功能可以被安裝在這個容器中來檢查功能是否可用。
  • 攻擊和審計Docker容器01
    Docker容器鏡像是一個輕量級,獨立的可執行軟體包,包含運行應用程式所需的一切:代碼,運行時,系統工具,系統庫和設置。容器鏡像在運行時成為容器,在Docker容器的情況下- 鏡像在Docker Engine上運行時成為容器。適用於基於Linux和Windows的應用程式,無論基礎架構如何,容器化軟體都將始終運行相同。容器將軟體與其環境隔離開來,並確保它可以統一工作,儘管開發和演示之間存在差異。
  • 理解docker鏡像與容器
    docker有兩個重要的概念:鏡像,容器。首先在說一下docker鏡像的存儲位置/var/lib/docker/,在aufs/layer/下可以看到ubuntu15.04鏡像的分層,正是這四層組成了ubuntu15.04鏡像。
  • docker-4:mac使用docker部署開發用rocketmq
    為了開發方便,有時需要在本地部署rocketmq,使用docker是一個高性價比的方式,故有此文。>回到工程根目錄執行腳本生成各種配置文件:sh stage.sh 4.7.1然後進入生成的目錄:cd stages/4.7.1隻是本地開發用,所以single足夠:sh .
  • Docker入門知識|Docker資源容器 與 VM虛擬機的區別與聯繫
    圖:docker的服務邏輯值得強調的是,Docker是基於原生多cpu系統開發出來的容器,多任務處理,多資源整合天生強項!正因為這樣的因素,編寫他的開發工具,GO-lang也因此功成名就。細說Docker。Docker 是世界領先的軟體容器平臺。開發人員利用 Docker 消除了協作編碼時「只在我的機器上可正常工作」的問題。
  • 通過容器化一個Python Web應用學習Docker容器技術
    它最主要的作用,就是限制一個進程組能夠使用的資源上限,包括 CPU、內存、磁碟、網絡帶寬等等。Docker正是利用這個特性限制容器使用宿主上的CPU、內存。docker ps -a的輸出結果,一共包含7列數據,分別是CONTAINER ID、IMAGE、COMMAND、CREATED、STATUS、PORTS和NAMES。
  • 下一代容器工具podman介紹及與Docker的比較
    Linux容器介紹Linux容器是與系統其他部分隔離開的一系列進程。運行這些進程所需的所有文件都由另一個鏡像提供,這意味著從開發到測試再到生產的整個過程中,Linux 容器都具有可移植性和一致性。因而,相對於依賴重複傳統測試環境的開發渠道,容器的運行速度要快得多。
  • 用docker命令創建一個容器以及容器的暫停和恢復
    docker命令創建一個容器docker創建容器的命令是create,用法和run類似。例如:docker create --name newnginx nginx:latest,這句命令的意思是使用nginx的鏡像來創建一個名叫newnginx的容器。
  • 容器到底是個啥?(附Docker學習資源匯總)
    Docker是輕量級容器管理引擎,它的出現為軟體開發和雲計算平臺之間建立了橋梁。我們如果把容器對標為虛擬機的話,Docker可以對標為hypervisor管理層,它是一個容器管理引擎技術,而不是容器本身。這一點是經常被混淆的。
  • CoreOS實踐指南(七):Docker容器管理服務
    有了第一桶金的Alex這次準備幹一票大的,他計劃開發一個足以顛覆傳統的伺服器系統的Linux發行版。為了提供能夠從任意作業系統版本穩定無縫地升級到最新版系統的能力,Alex急需解決應用程式與作業系統之間的耦合問題。因此,當時還名不見經傳的Docker容器引起了他的注意,憑著敏銳直覺,Alex預見了這個項目的價值,當仁不讓地將Docker做為了這個系統支持的第一套應用程式隔離方案。
  • Docker 添加容器到一個網絡
    通過網絡,在默認情況下為容器提供了完全獨立的環境。在你第一次運行一個容器的時候,你可以將容器添加到一個網絡中。例如,我們希望運行一個容器來運行 PostgreSQL 資料庫,並且傳遞 --net=my_bridge 標記來到你新網絡的連接中,可以運行下面的命令:$ docker run -d --net=my_bridge --name db training/postgres如果你檢查你的
  • 阿里P8架構師談:Docker鏡像和Docker容器的關係?
    1.什麼是Docker鏡像A:從整體的角度來講,一個完整的Docker鏡像可以支撐一個Docker容器的運行,在 Docker容器運行過程中主要提供文件系統視角。相信很多愛好者都會和我一樣,有這樣一個認識:Docker 鏡像代表一個容器的文件系統內容;第二階段:初步接觸聯合文件系統。聯合文件系統的概念,讓我意識到鏡像層級管理的技術,每一層鏡像都是容器文件系統內容的一部分。