陸忠華,孫琨,2,王彥棡,王玨,劉芳*
1. 中國科學院計算機網絡信息中心,北京 100190
2. 中國科學院大學,北京 100049
近年來,深度學習已經廣泛地應用于語音識別,機器翻譯,計算機視覺等領域,都取得了很好的效果。隨著深度學習理論的興起,多種深度學習的編程框架不斷涌現。TensorFlow、Caffe、PyTorch 等深度學習框架在架構、性能、模型構建等許多方面都差異甚大。每種框架都有其特別適用的領域,而統(tǒng)一管理調度這些框架的平臺卻非常缺乏,極少數支持的平臺,例如騰訊的 DI-X 平臺,非開源,對自身的業(yè)務支持性很好,但是可擴展性不足。
另一方面,深度學習理論的發(fā)展離不開 GPU 硬件的進步。GPU (Graphics Processing Unit,圖形處理器)是一種專門的圖像運算處理器,主要工作于個人計算機、高性能服務器或移動設備之上,為它們加速各種 3D 圖像和特效的處理[1]。對于很多科學計算而言,性能主要取決于 GPU 的浮點計算能力[2],特別是對深度學習任務來說。但是,由于涉及 GPU 的計算很多本身就需要巨大的計算量,單機通常無法在短時間內完成,因此 GPU 的集群化管理和使用成為一種必然的趨勢。
深度學習的模型訓練需要海量數據,海量數據的預處理需要用大數據技術進行處理。大數據處理框架中最為流行的當屬 Hadoop 和 Spark[3]。Hadoop和 Spark 均支持 Hadoop YARN (Yet Another Resource Negotiator) 作為資源管理器[4]。Hadoop YARN 的出現使得資源的管理和調度更加簡單,大大簡化了集群結構,并且使其具備了多種任務類型的可擴展性。
在各種強烈的實際需求推動下,無論是支持GPU 計算的深度學習框架 TensorFlow,還是分布式計算平臺 Hadoop,都獲得了很好的發(fā)展。
TensorFlow 是從谷歌誕生的技術框架。通過TensorFlow,開發(fā)人員可以不用從底層開始編寫代碼,而可以通過各種接口,方便快速地實現各種神經網絡架構。在工業(yè)界和學術界,TensorFlow 均得到了廣泛使用。
同樣地,在大數據領域,開發(fā)人員在 Hadoop 框架的支持下能夠實現運行于大規(guī)模集群上的分布式應用程序。Hadoop 的核心之一是資源管理器 YARN,YARN 作為通用平臺,可以進行多資源管理和調度,使得在其上構建多個多種應用程序成為可能。
隨著大數據和深度學習的關系越來越緊密,分開的大數據和深度學習框架已難以無縫滿足現實的需要。因此針對大數據和深度學習相結合的研究,包括研究 GPU 資源調度方式、集群可用性、集群穩(wěn)定性以及集群的可擴展性等,是很有必要和時代性的。以 Hadoop 系統(tǒng)為基礎,把 GPU 資源融合至YARN 管理技術中,可便捷地構建出異構環(huán)境下的高可用性集群。
在本文之前,已經有許多研究機構和公司在傳統(tǒng)的調度系統(tǒng)上與深度學習相結合。比如曙光的SothisAI,IBM 的 LSF,商湯的內部系統(tǒng),都是從傳統(tǒng)的 slurm 調度系統(tǒng)出發(fā),Hadoop 社區(qū)的下一代 3.0版本將支持GPU資源的管理和調度。
本文將基于以上幾點,結合傳統(tǒng)的大數據集群框架 Hadoop YARN,對在 Hadoop 平臺上實現 GPU資源的管理與調度并使其具備執(zhí)行深度學習框架TensorFlow 的能力進行可行性研究及實現。
深度學習需要管理和調度的首要資源是 GPU,現有的 Hadoop Yarn 只支持 CPU 和內存的管理和調度。為了使 Yarn 與 TensorFlow 相結合,需要做的首先是擴展 YARN,使其在原有基礎上支持 GPU 的管理和調度。
YARN 主要由四部分組成,分別是 ResourceManager、NodeManager、ApplicationMaster 和 Container[5]。Y A R N 從整體上可以看做是主從結構,其中ResourceManager 為主結構,NodeManager為從結構。各個 NodeManager 上資源的統(tǒng)一管理和調度是由ResourceManager 負責的。
YARN 的基本架構如圖 1 所示。
從圖 1 中可以看出,ResourceManager 是一個全局的資源管理器,Client、NodeManager 均與其進行交互,ResourceManager 負責的是整個系統(tǒng)的資源管理和分配。用戶通過 Client 提交的每個應用程序,均包含一個 ApplicationMaster。NodeManager可以看做是每個節(jié)點上的資源和任務管理器,負責各個節(jié)點的資源使用情況以及各個 Container 的運行狀態(tài),并與 ResourceManager 進行交互[5]。NodeManager 同時處理 ApplicationMaster 上附加的各種實際請求,例如 Container 的啟動、停止等。Container 則可以看做是 YARN 在多維度資源的封裝,Container 的具體封裝是根據應用程序的需求動態(tài)生成的。
CPU 和內存是當前 Hadoop YARN 已經支持管理和分配的兩種資源類型。在配置文件里設置好節(jié)點可被使用的 CPU 核數和內存總量,NodeManager會在啟動時向 ResourceManager 注冊這些信息。為了使 GPU 可以作為資源進行調度,首先需要在配置選項中增加 GPU 選項以及是否使用 GPU,在ResourceManager 中 ResourceType.java 增加 GPU 的資源類型。
圖1 YARN 的基本架構圖Fig. 1 The basic architecture of YARN
DRF 算法,全稱主資源公平調度 (Dominant Resource Fairness) 算法,是 YARN 進行資源管理和調度的主要算法,可以支持多維資源調度。DRF 算法,在管理和調度 CPU 和內存兩種資源的情況下,已經被實踐證明非常適合應用于多維資源管理和調度的復雜環(huán)境中。因此為了使 YARN 調度器可以支持 GPU 的調度,本文主要是在 DRF 的基礎上進行擴展。
DRF 算法中,主資源指的是各所需資源在相應總資源中所占比例最大的資源,DRF 算法的基本設計思想是將多維資源管理調度問題轉化為單資源管理調度問題,將所有主資源中最小的主資源進行最大化。其算法偽代碼如下:
算法 1 DRF 偽代碼
舉例說明如下。
假設系統(tǒng)總共有 9 個 CPU、18GB RAM 和 2 塊GPU,有兩個用戶 A 和 B,分別運行了兩種任務,兩種任務所需的資源量分別為 <1CPU,4GB,0GPU>,<3CPU,1GB,1GPU>。A 用戶每次需要消耗總 CPU的 1/9,內存的 2/9 和 GPU 的 0,內存占的比例最大,所以 A 的主資源為內存。對于用戶 B,每次需要消耗總 CPU 的 3/9,總內存的 1/18,總 GPU 的 1/2。因此 B 的主資源為 GPU。
<a,b,c>,其中 a 表示 CPU 的個數,b 表示內存的大小,c 表示 GPU 的塊數。
由表 1 可以看出,用戶 A 獲得的總資源量為<3,12,0>,可成功運行 3 個任務,用戶 B 獲取的資源量為 <6,2,2>,可成功運行 2 個任務。系統(tǒng)剩余的資源量為 <0,4,0>。
TensorFlow 是現在主流的深度學習框架之一。TensorFlow 可以很好地滿足單用戶使用,在多用戶情況下,會發(fā)生資源使用沖突。因此本文把 Hadoop YARN 作為資源調度層,TensorFlow 作為 YARN 之上的應用程序,YARN 調度后的資源供 TensorFlow所使用,可以滿足多用戶同時使用,極大提高系統(tǒng)的復用率。以下是關鍵實現步驟。
如圖 2 所示,整個系統(tǒng)包括三種組件:
Client:客戶端:負責作業(yè)的啟動和作業(yè)執(zhí)行狀態(tài)的獲取。
ApplicationMaster (AM):負責輸入數據分片、啟動及管理 Container、執(zhí)行日志保存等;
Container:作業(yè)實際執(zhí)行的地方,取代原生TensorFlow 分布式程序需要在每個實際節(jié)點上手動啟動 PS (Parameter Server) 和 Worker 進程,變?yōu)镃ontainer 自動啟動,并把進程的運行狀態(tài)定時向 AM進行匯報,同時還負責應用程序的輸出等。
其中 PS (parameter server):負責保存和更新參數,該角色依托于作業(yè)采用的 TensorFlow 深度學習框架,僅在分布式模式下啟動。Worker:執(zhí)行作業(yè)訓練邏輯,負責作業(yè)輸出保存。
表1 DRF 資源調度Table 1 DRF resource scheduling
圖2 TensorFlow on YARN 架構圖Fig. 2 TensorFlow on YARN architecture diagram
客戶端提交應用程序的關鍵主要有以下幾點。
(1) 初始化
對用戶提交應用程序腳本的信息進行識別,并進行相應的初始化,主要包括應用程序中,PS 所需的個數和 CPU 核數,worker 所需的個數,CPU 核數和GPU 個數。每個 ps 和 worker 的參數設置均一樣,同時包括應用程序的名稱,類型,輸入,輸出。以及啟動應用程序的命令。
(2) 對應用程序的監(jiān)控
Client 首先通過 getNewApplicationResponse() 和getApplicationId() 獲取唯一的 Application ID,然后往數據結構 ApplicationSubmissionContext 中放入啟動ApplicationMaster 所需的所有信息。
ApplicationMaster 可以看做是相對獨立的第三方,與 ResourceManager 和 NodeManager 兩個服務都要進行交互,ApplicationMaster 與 ResourceManager交互,可以獲得任務所需的計算資源,與 NodeManager交互,可以實際啟動計算任務,并對其進行監(jiān)控。ApplicationMaster 和 ResourceManager、NodeManager之間的交互均可通過相應的 RPC 函數進行注冊、通訊。需要特別注意的是,原生的 TensorFlow 分布式程序所需的節(jié)點是在代碼里固定的,配置方法如下:
采用 YARN 進行調度后,代碼里留下的是從環(huán)境中獲取具體服務器地址的接口。
因此在 ApplicationMaster 需要把從 YARN 調度獲取的節(jié)點資源轉換為相應 JSON 格式。轉換方法主要是通過鍵值對 HashMap。HashMap 中 key 指的是角色,value 指的是實際使用的節(jié)點地址,包括 IP 和端口。
現有的 TensorFlow 分布式框架能夠支持不夠靈活的分布式計算,需要在程序里指定好具體的節(jié)點和端口,并且在每個節(jié)點均要手動分發(fā),對于集群不具有管理和調度能力。
除卻管理和調度能力外,TensorFlow 是一種很好的深度學習編程框架,因此在實際運行計算任務時,在 Container 級別可以直接復用現有的 TensorFlow框架,從而不改變原有程序運行的結果。這要求TensorFlow 框架在每個節(jié)點上均得到同樣版本的安裝。
本文中 YARN 修改不涉及改 TensorFlow 分布式實際操作,只是把集群的管理交給了 YARN,需要的ps 和 worker 個數由代碼腳本設置,YARN 獲取相應腳本后,向 ResourceManager 獲取相應的可用計算服務器資源,然后把 PS 和 Worker 可獲取的具體服務器地址包裝成 JSON 格式,傳送給 TensorFlow 分布式框架,最后在 Container 層具體執(zhí)行。
10 臺曙光 W780-G20 GPU 服務器,每臺配置 2顆 Intel Xeon 2650v4 處理器,每個單節(jié)點配置 8 塊P100 GPU 加速卡,總共有 80 塊 NVIDIA Tesla P100 GPU 加速卡。計算存儲網絡方案采用 In fi niband 高速網絡,配置 1 臺 108 口 56Gb/s FDR 大端口模塊化 IB交換機,系統(tǒng)節(jié)點之間以 56Gb/s FDR 線速交換,采用大端口模塊。
Centos7.2,CUDA8.0,cudnn-v5.0,Python2.7,nccl2.0,OpenCV2.4.13,TensorFlow1.1.0,Hadoop2.7.3,java 1.8.0_65 等。
MNIST 數據集是采集阿拉伯數字 0-9 的手寫數字數據,每幅圖片均為 0 到 9 中 10 個數字的任意一個,黑白像素。
MNIST 數據集可在http://yann.lecun.com/exdb/mnist/ 獲取,它包含了四個部分:
Training set images:train-images-idx3-ubyte.gz(9.9MB,解壓后 47MB,包含 60,000 個樣本)
Training set labels:train-labels-idx1-ubyte.gz(29KB,解壓后 60KB,包含 60,000 個標簽)
Test set images:t10k-images-idx3-ubyte.gz(1.6MB,解壓后 7.8MB,包含 10,000 個樣本)
Test set labels:t10k-labels-idx1-ubyte.gz (5KB,解壓后 10KB,包含 10,000 個標簽)
應用程序主要分為兩部分,一部分為單機TensorFlow 程序,另一部分為分布式 TensorFlow程序。
(1) 單機 TensorFlow 程序
單機 TensorFlow 程序,用于手寫數字識別。網絡架構為卷積神經網絡,兩層卷積,兩層池化。網絡結構用 [a,b,c,d]表示,[a,b]表示卷積核的大小,c 表示上一層的深度,d 表示下一層的深度。第一層卷積為 [5,5,1,32],第二層卷積為 [5,5,32,64],池化層皆為 [1,2,2,1]。原生的 TensorFlow 分布式程序和使用 YARN 調度的 TensorFlow 分布式程序,兩者代碼完全一樣。單機 TensorFlow 程序主要參數設置如下:batch_size =64,learning_rate = 0.1,training_epochs = 20。
(2) 分布式 TensorFlow 程序
分布式 TensorFlow 程序,用于手寫數字識別。網絡架構為全連接神經網絡,一層隱藏層。輸入節(jié)點784 個,中間一層隱藏層 100 個,輸出節(jié)點 10 個。分別編寫了原生的 TensorFlow 分布式程序和使用 YARN調度的 TensorFlow 分布式程序,兩者參數設置完全一樣,主要代碼一樣,不同之處在于原生 TensorFlow分布式程序使用的節(jié)點是在程序里指定好了,并手動在各個指定節(jié)點上分別啟動的,使用 YARN 調度的 TensorFlow 分布式程序是由 YARN 自動分配的,程序里并不指定到各個具體節(jié)點,在一個節(jié)點上即可完成。程序主要參數設置如下:batch_size = 100,learning_rate = 0.0005,training_epochs = 20,其他初始隨機變量其他 worker 均與第一個 worker 的參數相同。
原生的 TensorFlow 分布式運行方法以下簡稱原生 TF,使用 YARN 調度的 TensorFlow 分布式運行方法以下簡稱 YarnTF。
單機下,原生 TF 和 YarnTF 兩者都測試了 GPU塊數在 1,2,4,8 下的程序完成時間。每種情況均進行了 10 組實驗,共計 100 組實驗。每種情況的最后結果去除 10 組實驗中的最高、最低值,取剩下 8組的平均值。
分布式下,原生 TF 和 YarnTF 兩者都測試了單個 ps,1,2,3,4,8 個 worker 下以及兩個 ps,1,2,3,4,8 個 worker 下程序完成時間。每種情況均進行 10 組實驗,共計 100 組實驗,每組實驗的程序完成時間取 worker 中最遲完成的時間。每種情況的最后結果均去除 10 組實驗中的最高、最低值,取剩下 8 組的平均值。
測試時運行同樣程序,在單機不同 GPU 塊數下,程序運行時間。可得表 2 所示結果。
表2 單機多卡下不同框架運行總時間 (單位:秒)Table 2 Total time for running different frames under a single machine
根據表 3 可得單機多卡不同框架下平均每個 epoch運行時間。
以1塊 GPU 為基準,可得不同 GPU 塊數下的加速比。
表4 單機多卡下不同框架加速比 (單位:秒)Table 4 Speedup ratio of single-machine multi-card under different frames
根據表 4 可得單機多卡下不同框架加速比。
根據圖 3 和圖 4,可以看出單機多卡下,YarnTF是非常有效的,與原生 TF 具有非常相似的加速比,YarnTF 所花的純計算機運行時間比原生 TF 要高,主要是 YarnTF 在資源調度要花一定時間,考慮到手工操作時間,實際總時間 YarnTF 要小于原生 TF。
worker 數可以看做是使用的計算節(jié)點數,每個worker 均在不同的節(jié)點上,并占滿每個節(jié)點的 8 塊GPU??傻帽?5 所示結果。
圖3 單機多卡不同框架下平均每個 epoch 運行時間Fig. 3 Average epoch running time of single-machine multicardunder different frames
圖4 單機多卡下不同框架加速比Fig. 4 Speedup ratio of single-machine multi-card under different frames
根據表 6 可得單 ps 多 worker 下不同框架平均每個 epoch 運行時間。
由圖 5 可以看出,不同 worker 下,每個 epoch實際運行時間 YarnTF 均大于原生 TF,這是因為YarnTF 的資源分配是動態(tài)的,只有在調度后才能確定程序運行的具體資源,這部分比原生 TF 多了一些時間,另外應用程序在運行過程中均需要與ApplicationMaster 和客戶端進行通信,這部分也比原生 TF 多了一些時間。不過考慮到 YarnTF 的資源為自動分配,并在單節(jié)點啟動,而非手動啟動,原生TF 實際總運行時間 (考慮非計算機實際運行時間) 會大于 YarnTF,而且隨著 worker 的增加,非計算機實際運行時間會大大增加。
表5 單 ps 多 worker 下不同框架運行總時間 (單位:秒)Table 5 The total running time of different frames under a single ps multi-worker
表6 單ps多worker下不同框架平均每個epoch運行時間(單位:秒)Table 6 Average epoch running time for different frames under a single ps multi-worker
圖5 單 ps 多 worker 下不同框架平均每個 epoch 運行時間Fig. 5 Average epoch running time for different frames under a single ps multi-worker
以 1 個 ps,1 個 worker 為基準,可得不同worker 下得加速比。
根據表 7 可得單 ps 多 worker 下不同框架加速比。
如圖 6 所示,YarnTF 和原生 TF 的加速比曲線是類似的,表明 YarnTF 實際運行中增加的損耗并不以增加原生 TF 損耗為代價,YarnTF 具有同樣的加速效果。
表7 單ps多worker下不同框架加速比 (單位:秒)Table 7 Speedup ratioof Single ps multi-worker in different frames
圖6 單 ps 多 worker 下不同框架加速比Fig.6 Speedup ratioof Single ps multi-worker in different frames
worker 數可以看做是使用的計算節(jié)點數,每個worker 均在不同的節(jié)點上,并占滿每個節(jié)點的 8 塊GPU。可得 2ps 多 worker 下不同框架平均每個 epoch運行時間。
表8 2ps多worker下不同框架運行總時間 (單位:秒)Table 8 Total running time of different frames under 2ps multi-worker
表 9 和表 6 進行對比,2ps 下多個 worker 每個epoch 運行時間在 worker 數較少時,均大于 1ps 下每個 epoch 運行時間,表明此時多個 ps 和多 worker 損耗的通信時間并不值得。2ps 下 8worker,每個 epoch運行時間比 1ps 下 8worker 下速度更快,表明此時2ps 和多 worker 通信之間的損耗低于多 workerGPU加速的價值。
根據表 9 可得 2ps 多 worker 下不同框架平均每個 epoch 運行時間。
圖7 的結果與圖 5 類似,YarnTF 的計算機實際運行時間均大于原生 TF。以 2ps,1 個 worker 為基準,可得不同 worker 下得加速比。
根據表 10 可得 2ps 多 worker 下不同框架加速比。
圖8 表明 2ps 多 worker 下,YarnTF 同樣是非常有效的。
從圖 4、圖 6 和圖 8 的加速比來看,無論是單機版,還是分布式版本,YarnTF 都是非常有效的。YarnTF 和原生 TF 具有類似的趨勢,表明 YarnTF 加速效果與原生 TF 加速效果相似。從圖 3、圖 5 和圖7 來看,無論是單機還是分布式版本,使用 YARN 調度都會比原生 TensorFlow 程序運行時間多,多余損耗主要用在了 YARN 的資源管理和調度上,但是考慮到原生 TensorFlow 分布式程序需要在程序里指定固定節(jié)點,并且需要在每個節(jié)點上手動式分發(fā),這會浪費大量的非計算機實際使用時間。多用戶使用下,YarnTF的可復用性更強,用戶不用知道其他用戶用了哪些節(jié)點,而原生 TensorFlow 用戶間需要提前商量好各節(jié)點的使用權。因此使用 YARN 調度 TensorFlow 分布式程序會極大提高平臺 GPU 的復用能力。
本文實現了大數據框架與深度學習框架的結合,使得 Tensorflow 可以用 YARN 進行調度,實際測試結果表明用 YARN 調度 TensorFlow 是可行的,并且非常有效的。下一步的工作主要有兩部分:(1)盡可能減少用 YARN 調度 TensorFlow 分布式程序中資源管理和調度的損耗。(2) 在 YARN 已經支持TensorFlow 的基礎上,使其支持更多深度學習框架,例如 Caffe、MXNet 等。
表9 2ps多worker下不同框架平均每個epoch運行時間(單位:秒)Table 9 Average epoch running time for different frames under 2ps multi-worker
表10 2ps多worker下不同框架加速比 (單位:秒)Table 10 Speedup ratio of 2ps multi-worker for different frames
圖7 2ps 多 worker 下不同框架平均每個 epoch 運行時間Fig. 7 Average epoch running time for different frames under 2ps multi-worker
圖8 2ps 多 worker 下不同框架加速比Fig. 8 Speedup ratio of 2ps multi-worker for different frames
[1]劉德波. 基于 YARN 的 GPU 集群系統(tǒng)研究 [D]. 中山大學, 2014.
[2]丁藝明, 劉波. 利用 GPU 進行高性能數據并行計算 [J].程序員, 2008(4): 97-99.
[3]孫成剛, 李崢, 唐冬冬等. 基于 GPU 的高性能并行計算應用 [J]. 電子信息對抗技術, 2012, 27(2): 69-73.
[4]懷特, 周敏奇, 等. Hadoop 權威指南:第 2 版 [M]. 清華大學出版社, 2011.
[5]董西成. Hadoop 技術內幕: 深入解析 YARN 架構設計與實現原理 [J]. 中國科技信息, 2014(1): 158-158.
[6]張凱, 秦勃, 劉其成. 基于 GPU-Hadoop 的并行計算框架研究與實現 [J]. 計算機應用研究, 2014, 31(8): 2548-2550.
[7]MBARUSHIMANA Emmanuel. 調度和優(yōu)化大數據計算框架基于 CPU/GPU 集群 [D]. 北京理工大學, 2015.
[8]裴浩. 基于 GPU 的 Hadoop 平臺優(yōu)化實現 [J]. 福建電腦,2017, 33(3): 41-42.
[9]Abadi M. TensorFlow: learning functions at scale[J]. Acm Sigplan Notices, 2016, 51(9): 1-1.
[10]Jue Wang, Fei Gao, Jose Luis Vazquez-Poletti,Jianjiang Li, Preface of High Performance Computing or Advanced Modeling and Simulation of Materials, Computer Physics Communication, Elsevier Publisher, issue 211,2017 (IF: 3.653).
[11]Jue Wang, Chun Liu, Yuehui Huang, Auto tuning for new energy dispatch problem: A case study, Future Generation Computer Systems, Elsevier Publisher,issue 54, 501-506, 2016.1 (IF: 2.430).