張凱,車漾
阿里巴巴科技(北京)有限公司,北京 100102
最近10年,深度學(xué)習技術(shù)和應(yīng)用發(fā)展風起云涌,百花齊放。尤其在機器視覺、自然語言理解、語音識別等領(lǐng)域,一大批成熟的人工智能模型和服務(wù)正落地應(yīng)用于各行各業(yè)。越來越多的行業(yè)發(fā)掘出大量需求,需要利用企業(yè)日積月累的海量業(yè)務(wù)數(shù)據(jù),高效便捷地訓(xùn)練深度學(xué)習和機器學(xué)習模型。
與此同時,云計算在IaaS、PaaS和SaaS等層次已經(jīng)發(fā)展得相當成熟,并逐步進入云原生時代。在云原生技術(shù)體系中,以Docker為代表的Linux容器技術(shù)和以Kubernetes為代表的容器編排管理技術(shù)在應(yīng)用開發(fā)、交付、運維的生命周期中逐漸成為業(yè)界的事實標準。同時,應(yīng)用微服務(wù)架構(gòu)的自動化部署,運行時動態(tài)彈性伸縮,完善的日志、監(jiān)控、告警等運維體系等,都成為現(xiàn)代軟件開發(fā)運維的基礎(chǔ)需求。
深度學(xué)習和人工智能應(yīng)用往往需要使用大量GPU、張量處理器(tensor processing unit,TPU),甚至神經(jīng)元處理器(neural processing unit,NPU)這類定制的高性能異構(gòu)計算設(shè)備來迭代處理海量的訓(xùn)練數(shù)據(jù),最終得到滿足準確率和性能要求的模型。由于數(shù)據(jù)規(guī)模較大、模型復(fù)雜度較高,訓(xùn)練過程一般較漫長。因此,優(yōu)化GPU等異構(gòu)計算設(shè)備的利用效率、加快訓(xùn)練數(shù)據(jù)處理速度,成為提升深度學(xué)習和人工智能應(yīng)用生產(chǎn)率和成本優(yōu)化的關(guān)鍵因素。
Kubernetes容器編排管理技術(shù)對于GPU、TPU、NPU等高性能異構(gòu)計算設(shè)備資源的支持日趨成熟??紤]到云計算在成本優(yōu)化、資源規(guī)模和彈性伸縮方面的優(yōu)勢,配合Docker容器技術(shù)擅長的輕量級和標準化應(yīng)用交付能力,業(yè)界主流的生產(chǎn)人工智能模型和應(yīng)用的技術(shù)方案會采用容器集群結(jié)合云計算平臺的GPU資源的架構(gòu),進行分布式深度學(xué)習模型訓(xùn)練。
在“云上”執(zhí)行訓(xùn)練任務(wù),通常會在帶有GPU設(shè)備的計算服務(wù)節(jié)點上進行。訓(xùn)練數(shù)據(jù)會被存放在各種異構(gòu)的云存儲服務(wù)中,如對象存儲服務(wù)、遠程文件系統(tǒng)服務(wù)等。這種典型的計算和存儲分離的分布式計算架構(gòu)有利于增強計算和存儲的彈性擴展能力,但同時也會帶來數(shù)據(jù)訪問時延增大的問題。如果考慮數(shù)據(jù)敏感性、隱私保護和安全合規(guī)的要求,訓(xùn)練數(shù)據(jù)通常也會被存放在私有數(shù)據(jù)中心中。這樣勢必要求深度學(xué)習模型訓(xùn)練平臺采用混合云的架構(gòu),統(tǒng)一使用“云上”計算資源來訪問“云下”數(shù)據(jù)。而這種“本地存儲+云上計算”的訓(xùn)練模式進一步增大了計算和存儲分離架構(gòu)帶來的遠程數(shù)據(jù)訪問時延,進而導(dǎo)致深度學(xué)習模型訓(xùn)練整體性能的顯著下降。
本文首先概述深度學(xué)習訓(xùn)練系統(tǒng)中典型的數(shù)據(jù)訪問方法;然后提出基于容器和分布式緩存技術(shù)的深度學(xué)習訓(xùn)練系統(tǒng)架構(gòu),以及訓(xùn)練任務(wù)與緩存數(shù)據(jù)互感知的協(xié)同調(diào)度方法TDCS(task and data co-located scheduling);之后介紹使用Alluxio加速訓(xùn)練的實驗結(jié)果和性能瓶頸,并針對Alluxio進行參數(shù)調(diào)優(yōu),獲得了初步性能提升;筆者還提出TDCS任務(wù)與數(shù)據(jù)協(xié)同調(diào)度方法,并給出TDCS的具體策略設(shè)計和實現(xiàn)細節(jié);最后提供多組實驗數(shù)據(jù)驗證TDCS的效果,實驗表明TDCS有效增強了容器環(huán)境下分布式緩存系統(tǒng)的可擴展性,可以顯著加速深度學(xué)習訓(xùn)練。
為了規(guī)避計算和存儲分離架構(gòu)帶來的數(shù)據(jù)訪問時延,典型做法是在開始模型訓(xùn)練之前,將訓(xùn)練數(shù)據(jù)復(fù)制到GPU計算節(jié)點本地的磁盤存儲中,如普通機械硬盤或者NVMe SSD等高速存儲設(shè)備;或者將數(shù)據(jù)提前復(fù)制到部署在計算節(jié)點上的分布式存儲系統(tǒng)中,如Ceph、GlusterFS。隨后計算任務(wù)就相當于從本地讀取訓(xùn)練數(shù)據(jù),有效緩解了數(shù)據(jù)訪問時延對GPU計算性能的影響。然而,這種額外的數(shù)據(jù)遷移過程會面臨如下問題。
● 把訓(xùn)練數(shù)據(jù)復(fù)制到GPU節(jié)點的方式低效且難以管理。如果是手動復(fù)制,非常容易出錯。
● 深度學(xué)習訓(xùn)練數(shù)量很大,且可能持續(xù)增加。“云上”GPU計算節(jié)點配置的磁盤容量有限,經(jīng)常出現(xiàn)無法存放全量訓(xùn)練數(shù)據(jù)的情況。
● 將訓(xùn)練數(shù)據(jù)存放在多個GPU計算節(jié)點上的分布式存儲系統(tǒng)內(nèi),可以解決數(shù)據(jù)容量問題,但分布式存儲系統(tǒng)自身的運維成本和難度都很大;并且,存儲系統(tǒng)與計算節(jié)點耦合,本身也會產(chǎn)生計算、網(wǎng)絡(luò)、I/O等本地資源的爭搶和干擾問題。
業(yè)界已經(jīng)有一些工作通過基于緩存機制的方法[1-3]來解決上述復(fù)制訓(xùn)練數(shù)據(jù)到計算節(jié)點方案存在的問題。與這些工作不同,本文設(shè)計并實現(xiàn)了一種Kubernetes容器編排技術(shù)和分布式緩存技術(shù)相結(jié)合的深度學(xué)習模型訓(xùn)練系統(tǒng)。該系統(tǒng)架構(gòu)可以滿足云計算環(huán)境下大規(guī)模容器化深度學(xué)習系統(tǒng)對訓(xùn)練任務(wù)的加速要求。該系統(tǒng)的基礎(chǔ)架構(gòu)如圖1所示。
圖1 基于容器和分布式緩存的深度學(xué)習模型訓(xùn)練系統(tǒng)的基礎(chǔ)架構(gòu)
基于容器和分布式緩存的深度學(xué)習模型訓(xùn)練系統(tǒng)架構(gòu)的核心模塊包括如下幾個。
● Kubernetes。Kubernetes是業(yè)界非常主流的容器集群管理和編排引擎。其系統(tǒng)架構(gòu)和API已經(jīng)成為容器平臺的事實標準。Kubernetes非常廣泛地用于構(gòu)建深度學(xué)習訓(xùn)練平臺。它提供了通過容器兼容不同深度學(xué)習計算框架的靈活性,動態(tài)調(diào)度訓(xùn)練任務(wù)和按需擴展GPU資源的能力,以及完善的集群管理能力。Kubernetes中最重要的子模塊是Kube-scheduler。該子模塊負責在Kubernetes容器集群中統(tǒng)一調(diào)度深度學(xué)習訓(xùn)練任務(wù)和分布式緩存系統(tǒng)。本文通過擴展Kube-scheduler,實現(xiàn)了TDCS方法。
● Kubeflow。Kubeflow是Kubernetes技術(shù)生態(tài)中最流行的支持機器學(xué)習和深度學(xué)習任務(wù)的開源項目。Kubeflow的目標是使機器學(xué)習、深度學(xué)習的完整工作流程在Kubernetes集群上能夠簡便地部署、高效地運行,并且使整個工作流可移植和可擴展。Kubeflow為主流的深度學(xué)習框架TensorFlow[4-5]的分布式訓(xùn)練提供了兩種支持模式,分別是參數(shù)服務(wù)器模式和Ring Allreduce[6]模式。Kubeflow同時支持訓(xùn)練任務(wù)使用CPU和GPU運行。
● 分布式緩存系統(tǒng)。分布式緩存系統(tǒng)設(shè)計的初衷是解決大數(shù)據(jù)處理流水線中,不同計算框架在通過磁盤文件系統(tǒng)(如HDFS)交換數(shù)據(jù)時,系統(tǒng)I/O操作方面的瓶頸[7]。業(yè)界已存在一些用于實現(xiàn)分布式緩存系統(tǒng)的技術(shù)。本文設(shè)計的深度學(xué)習訓(xùn)練系統(tǒng)選擇使用Alluxio作為分布式緩存技術(shù)的具體實現(xiàn)。Alluxio是面向混合云環(huán)境的開源數(shù)據(jù)編排與緩存系統(tǒng)[8]。它利用多個計算節(jié)點本地的內(nèi)存和磁盤資源構(gòu)成統(tǒng)一的分布式緩存系統(tǒng),從而為計算任務(wù)提供就近、可重用的數(shù)據(jù)訪問服務(wù)。
為了提升深度學(xué)習的訓(xùn)練性能,本文先對Alluxio進行系統(tǒng)參數(shù)調(diào)優(yōu),獲得初步的訓(xùn)練加速效果。為了繼續(xù)將緩存加速效果擴展到更大規(guī)模的訓(xùn)練場景,本文結(jié)合Kubernetes容器集群的調(diào)度和彈性伸縮能力、Alluxio緩存引擎的部署和運行機制,提出了一種訓(xùn)練任務(wù)與緩存數(shù)據(jù)互感知的協(xié)同調(diào)度方法TDCS,并在容器化深度學(xué)習系統(tǒng)中進行實現(xiàn)。
TDCS通過多層資源分配策略來感知任務(wù)與數(shù)據(jù)間的關(guān)聯(lián)性,從而實現(xiàn)訓(xùn)練任務(wù)和緩存數(shù)據(jù)的雙向親和性調(diào)度。通過感知任務(wù)運行時拓撲,實現(xiàn)彈性伸縮緩存容量和數(shù)據(jù)分布策略。在經(jīng)典的圖像分類模型訓(xùn)練實驗中,TDCS可以實現(xiàn)2~3倍的訓(xùn)練加速,并且隨著計算資源的增加,TDCS能夠持續(xù)加速訓(xùn)練任務(wù)。本文對使用128塊GPU卡的訓(xùn)練任務(wù)進行實驗,發(fā)現(xiàn)TDCS依然帶來了可觀的性能提升。
使用分布式緩存加速諸如深度學(xué)習的大規(guī)模數(shù)據(jù)處理任務(wù),在獲得性能提升的同時,會產(chǎn)生其他方面的問題,如整體成本的上升[9]、加速效果的波動等。本文實現(xiàn)了基于Kubernetes容器編排技術(shù)和Alluxio分布式緩存技術(shù)的深度學(xué)習訓(xùn)練系統(tǒng)。實驗發(fā)現(xiàn),Alluxio分布式緩存可以在一定條件下加速訓(xùn)練任務(wù)。但在擴大任務(wù)規(guī)模、增加參與計算的GPU資源后,緩存加速效果很快達到瓶頸,無法隨資源量的增加而持續(xù)提升。如果要實現(xiàn)資源量和訓(xùn)練任務(wù)性能的線性加速,則需要對緩存系統(tǒng)進行優(yōu)化。
下面首先介紹使用Alluxio加速深度學(xué)習訓(xùn)練任務(wù)的實驗方法;然后對實驗結(jié)果進行分析,提出影響加速效果的原因和優(yōu)化手段,并驗證初步優(yōu)化的結(jié)果。
本文使用阿里云托管Kubernetes服務(wù),部署含有多個GPU節(jié)點的Kubernetes容器集群作為實驗環(huán)境。使用4臺服務(wù)器,每臺服務(wù)器上有8塊NVIDIA Tesla V100 GPU卡,共提供32塊GPU卡的算力。訓(xùn)練程序通過Alluxio提供的POSIX接口讀取遠程數(shù)據(jù)存儲,并緩存到本地Alluxio緩存中。每臺服務(wù)器可為Alluxio提供40 GB內(nèi)存存儲,實驗環(huán)境共提供160 GB分布式緩存空間。
使用圖像分類模型ResNet50[10]與圖像識別數(shù)據(jù)集ImageNet[11]進行模型訓(xùn)練實驗。ImageNet數(shù)據(jù)集包含128萬余張圖片及其標注數(shù)據(jù),總數(shù)據(jù)量約為144 GB。使用TensorFlow作為深度學(xué)習訓(xùn)練框架,Horovod[12]作為分布式訓(xùn)練通信框架。每塊GPU卡處理訓(xùn)練數(shù)據(jù)的batch_size為256。訓(xùn)練任務(wù)執(zhí)行標準TensorFlow benchmark測試程序,當達到預(yù)定訓(xùn)練輪數(shù)時,任務(wù)自動停止,同時檢查訓(xùn)練所得模型的圖像分類精確度以及訓(xùn)練速度(每秒處理圖片數(shù))。
對實驗中模型精確度達到業(yè)界標準情況下的訓(xùn)練速度結(jié)果進行評估。分別使用合成數(shù)據(jù)(即synthetic)和Alluxio緩存系統(tǒng)訪問存儲服務(wù)中的真實數(shù)據(jù)(即Alluxio)進行模型訓(xùn)練,并對比性能結(jié)果,如圖2所示。橫軸表示任務(wù)使用GPU卡數(shù)量,縱軸表示訓(xùn)練速度。合成數(shù)據(jù)是訓(xùn)練程序在內(nèi)存中生成的數(shù)據(jù),節(jié)省了I/O開銷,可作為訓(xùn)練性能的理論上限。
由圖2可以看出,使用1~2塊GPU卡訓(xùn)練時,兩者性能差距在可以接受的范圍內(nèi);但當GPU卡增加到4塊時,二者性能差距比較明顯;當GPU卡數(shù)量達到8塊時,使用Alluxio緩存系統(tǒng)訪問存儲服務(wù)中的數(shù)據(jù)的訓(xùn)練速度下降至使用合成數(shù)據(jù)的28.77%。通過監(jiān)控觀測到GPU服務(wù)器的系統(tǒng)資源利用率并不高,這說明使用Alluxio默認配置實現(xiàn)的分布式緩存系統(tǒng)無法支持GPU訓(xùn)練規(guī)模化擴展。這成為深度學(xué)習訓(xùn)練平臺能力的瓶頸。
通過分析Alluxio的系統(tǒng)架構(gòu)和實現(xiàn)方法,發(fā)現(xiàn)造成無法支撐訓(xùn)練任務(wù)性能彈性擴展的主要原因有如下3個。
● Alluxio的文件操作需要進行多次遠程過程調(diào)用(remote procedure call,RPC)才能獲取到數(shù)據(jù)。
● 默認情況下,Alluxio優(yōu)先將全量數(shù)據(jù)緩存在本地節(jié)點。當本地緩存容量飽和時,就會驅(qū)逐已緩存數(shù)據(jù)。如果被驅(qū)逐數(shù)據(jù)很快又被任務(wù)讀回,就會導(dǎo)致同一份數(shù)據(jù)頻繁寫入和刪除,形成數(shù)據(jù)震蕩。
● 緩存系統(tǒng)提供的用戶空間文件系統(tǒng)(filesystem in userspace,F(xiàn)USE)接口雖然易于使用,但是讀寫性能并不理想。在深度學(xué)習訓(xùn)練任務(wù)多線程高并發(fā)讀寫下,需要優(yōu)化FUSE的配置參數(shù)。
在分析了上述性能瓶頸后,本文首先調(diào)整一系列Alluxio系統(tǒng)參數(shù)。實驗結(jié)果表明,Alluxio緩存系統(tǒng)的性能得到一定程度的提升。
4.3.1 優(yōu)化FUSE文件系統(tǒng)參數(shù)
Linux系統(tǒng)上的FUSE實現(xiàn)分為兩層,包括運行在用戶態(tài)的libfuse和運行在內(nèi)核態(tài)的FUSE模塊。本文分別進行調(diào)優(yōu)。第一個優(yōu)化手段是升級Linux內(nèi)核版本。高版本Linux系統(tǒng)內(nèi)核對FUSE模塊內(nèi)置了許多優(yōu)化,比如Linux Kernel 4.19版的FUSE讀性能比3.10版提升20%。第二個優(yōu)化手段是調(diào)整libfuse的參數(shù),包括如下兩種。
● 增大參數(shù)entry_timeout和attr_timeout的值,避免libfuse本地讀取文件的inode和dentry信息頻繁過期,導(dǎo)致大量讀文件操作穿透到Alluxio的遠程元數(shù)據(jù)管理節(jié)點。
● 適當調(diào)大libfuse線程池參數(shù)max_idle_threads的值(默認為10),避免訓(xùn)練任務(wù)高并發(fā)訪問緩存數(shù)據(jù)時,libfuse可用線程頻繁地創(chuàng)建和銷毀,引入過多CPU開銷。
4.3.2 優(yōu)化Alluxio參數(shù)
深度學(xué)習訓(xùn)練任務(wù)讀取的訓(xùn)練數(shù)據(jù)量往往很大,并發(fā)壓力也非常大。本文針對緩存數(shù)據(jù)驅(qū)逐策略、元數(shù)據(jù)操作效率和容器環(huán)境下客戶端讀取緩存數(shù)據(jù)的方法,進行多組Alluxio系統(tǒng)參數(shù)配置。
第一組是參數(shù)優(yōu)化,避免Alluxio頻繁驅(qū)逐緩存數(shù)據(jù),造成數(shù)據(jù)震蕩,包括如下3種。
● alluxio.user.ufs.block.read.location.policy。默認值為alluxio.client.block.policy.LocalFirstPolicy,表示優(yōu)先將數(shù)據(jù)保存在Alluxio客戶端節(jié)點。本文設(shè)置為alluxio.client.block.policy.LocalFirstAvoidEvictionPolicy。同時設(shè)置alluxio.user.block.avoid.eviction.policy.reserved.size.bytes參數(shù),保證在節(jié)點本地固定保留適量緩存數(shù)據(jù)不被驅(qū)逐。
● alluxio.user.file.passive.cache.enabled。默認值為true,導(dǎo)致Alluxio節(jié)點額外復(fù)制已經(jīng)在其他節(jié)點上緩存過的數(shù)據(jù)。本文將該屬性置為false,避免多余的本地緩存副本。
● alluxio.user.file.readtype.default。默認值為CACHE_PROMOTE,會導(dǎo)致緩存數(shù)據(jù)在節(jié)點的各存儲層間(如內(nèi)存與磁盤)遷移。本文將該參數(shù)值改為CACHE,避免數(shù)據(jù)遷移和數(shù)據(jù)加鎖開銷。
第二組也是參數(shù)優(yōu)化,配置Alluxio客戶端緩存遠程文件元數(shù)據(jù)的策略。客戶端緩存元數(shù)據(jù)信息,可避免頻繁地對Alluxio服務(wù)端進行RPC訪問,具體包括如下4種。
● alluxio.user.metadata.cache.enabled,設(shè)置為true,表示開啟客戶端元數(shù)據(jù)緩存。
● alluxio.user.metadata.cache.max.size,設(shè)置客戶端可緩存元數(shù)據(jù)的最大值。
● alluxio.user.metadata.cache.expiration.time,設(shè)置客戶端元數(shù)據(jù)緩存的有效時間。
● alluxio.user.worker.list.refresh.interval,設(shè)置Alluxio服務(wù)端同步所有緩存節(jié)點狀態(tài)的時間間隔,本文設(shè)為2 min。
第三組是配置容器本地訪問Alluxio緩存系統(tǒng)的方法。容器環(huán)境下Alluxio支持兩種短路讀寫方式來實現(xiàn)本地訪問緩存數(shù)據(jù),包括UNIX Socket和直接文件訪問。本文使用直接文件訪問方式,使Alluxio客戶端讀取本地緩存節(jié)點的性能更優(yōu)。
4.3.3 優(yōu)化Alluxio容器中的JVM參數(shù)
通過Kubernetes部署Java應(yīng)用容器,如果不指定容器請求的CPU資源量,容器內(nèi)Java虛擬機(Java virtual machine,JVM)識別到的可用CPU核數(shù)可能有誤,進而影響容器內(nèi)的Alluxio可用線程數(shù)。本文將JVM參數(shù)-XX:ActiveProcessorCount設(shè)置為容器內(nèi)Alluxio進程可使用的CPU資源數(shù)量。
本文還調(diào)整了JVM垃圾回收(JVM garbage collection,JVM GC)和JIT(just in time)相關(guān)參數(shù),包括-XX:ParallelGCThreads、-XX: ConcGCThreads和-XX:CICompilerCount,將其設(shè)置為較小值,避免線程頻繁切換,影響Alluxio進程的性能。
優(yōu)化上述系統(tǒng)參數(shù)后,在一臺配置8塊GPU卡的服務(wù)器上再次訓(xùn)練ResNet50模型。如圖3所示,訓(xùn)練速度明顯加快,與使用合成數(shù)據(jù)的訓(xùn)練速度僅相差3.3%左右。并且,這樣的加速效果可以接近線性地擴展到4臺服務(wù)器(共32塊GPU卡)的實驗中。
圖3 優(yōu)化分布式緩存系統(tǒng)加速分布式訓(xùn)練的實驗結(jié)果
然而,實驗中發(fā)現(xiàn),繼續(xù)增加GPU資源后,緩存加速的擴展性瓶頸再次出現(xiàn)。這使得優(yōu)化Alluxio系統(tǒng)參數(shù)的方法只能對使用少于32塊GPU卡的ResNet50訓(xùn)練任務(wù)產(chǎn)生良好的加速效果。同時,本文前述實驗都使用阿里云SSD云盤作為數(shù)據(jù)存儲。雖然SSD云盤可以提供300 MB/s以上的I/O吞吐性能,但是單塊云盤容量有限,且成本較高。如果在更大量級的訓(xùn)練數(shù)據(jù)集上執(zhí)行更大規(guī)模的分布式訓(xùn)練任務(wù),SSD云盤并不是最佳選擇。實際上,在大規(guī)模分布式訓(xùn)練場景中,使用具有較高性價比的阿里云對象存儲服務(wù)(object store service,OSS)是更常用的方案。本文后續(xù)實驗也將采用OSS作為訓(xùn)練數(shù)據(jù)集的存儲方案。
目前,典型分布式緩存技術(shù)實現(xiàn)多用靜態(tài)架構(gòu)進行部署,比如Alluxio。在初始化部署之后,緩存系統(tǒng)的拓撲和容量就固定了。在運行過程中,Alluxio不會主動對緩存數(shù)據(jù)的訪問頻率和系統(tǒng)資源的使用情況進行動態(tài)擴展,無法降低系統(tǒng)壓力。Alluxio也不會感知上層訪問應(yīng)用,無法做到根據(jù)不同應(yīng)用狀態(tài)和數(shù)據(jù)訪問特點同步調(diào)整緩存系統(tǒng)的部署拓撲和緩存策略。因此,在前面的實驗中,盡管優(yōu)化Alluxio系統(tǒng)的參數(shù)后,可以加速最多使用32塊GPU卡的訓(xùn)練任務(wù),但是,增加更多GPU卡參與計算后,受到緩存系統(tǒng)靜態(tài)部署的限制,以及訓(xùn)練任務(wù)運行拓撲動態(tài)變化的干擾,加速效果再次遇到瓶頸。
經(jīng)過分析深度學(xué)習訓(xùn)練任務(wù)的特點發(fā)現(xiàn),一方面,在單個任務(wù)運行周期內(nèi)以及多個任務(wù)運行過程之間,都存在計算與數(shù)據(jù)的時間相關(guān)性;另一方面,對于一個訓(xùn)練任務(wù)使用的計算資源,可能會按需進行彈性伸縮。例如,當集群資源空閑時,可通過擴展利用更多GPU資源,加快訓(xùn)練任務(wù)的整體進程;當集群資源緊張時,對低優(yōu)先級任務(wù)進行資源回收。分布式緩存系統(tǒng)會優(yōu)先部署在計算發(fā)生的本地節(jié)點上,通過就近讀取,節(jié)省大量遠程數(shù)據(jù)I/O損耗。這使得計算與緩存數(shù)據(jù)之間還存在空間相關(guān)性。
利用計算與緩存數(shù)據(jù)的時間和空間相關(guān)性,本文設(shè)計了深度學(xué)習訓(xùn)練任務(wù)與分布式緩存數(shù)據(jù)互相感知的協(xié)同調(diào)度方法TDCS。TDCS分別針對單任務(wù)、多任務(wù)和彈性伸縮任務(wù),實現(xiàn)了多維度的統(tǒng)一管理和調(diào)度策略,具體包括訓(xùn)練數(shù)據(jù)預(yù)加載策略、多任務(wù)緩存數(shù)據(jù)共享策略、分布式緩存彈性策略等。筆者在前文所述基于Kubernetes容器和分布式緩存的深度學(xué)習模型訓(xùn)練系統(tǒng)之上,實現(xiàn)了TDCS方法。通過增加預(yù)加載控制器Preloader、緩存數(shù)據(jù)管理器CacheManager、彈性伸縮控制器CacheScaler等組件,完成訓(xùn)練任務(wù)和分布式緩存系統(tǒng)的統(tǒng)一管理和調(diào)度。支持TDCS方法的完整系統(tǒng)架構(gòu)如圖4所示。
圖4 使用TDCS分布式緩存的容器化深度學(xué)習訓(xùn)練系統(tǒng)架構(gòu)
對于單個訓(xùn)練任務(wù),通常以多輪迭代方式執(zhí)行。訓(xùn)練任務(wù)在給定數(shù)據(jù)集上循環(huán)執(zhí)行算法,不斷調(diào)整參數(shù),使得算法提取和比對特征的準確率最終達到目標。這種迭代執(zhí)行具有明顯的時序特征。由于每輪迭代執(zhí)行都會讀取全量訓(xùn)練數(shù)據(jù),各輪之間會有大量數(shù)據(jù)需重復(fù)計算。因此,通過分布式緩存,將盡可能多的訓(xùn)練數(shù)據(jù)保存在計算節(jié)點本地,之后就可以避免每輪計算都反復(fù)從遠程存儲系統(tǒng)讀取數(shù)據(jù)造成的損耗。然而,對于首次執(zhí)行的任務(wù),還存在“冷啟動”問題。第一輪迭代周期內(nèi)尚未有任何數(shù)據(jù)被緩存,執(zhí)行計算的同時必須從遠程存儲系統(tǒng)中拉取所有訓(xùn)練數(shù)據(jù),性能明顯低于后續(xù)迭代。
針對“冷啟動”,TDCS設(shè)計實現(xiàn)了訓(xùn)練數(shù)據(jù)集Preloader,負責在任務(wù)計算開始之前,預(yù)先讀取部分或者全部訓(xùn)練數(shù)據(jù)進入緩存系統(tǒng)。TDCS允許使用者指定是否啟用預(yù)加載功能,以及預(yù)加載的具體策略。策略包括啟動預(yù)加載的時間、預(yù)加載數(shù)據(jù)量或其占整個訓(xùn)練數(shù)據(jù)集的比例,以及預(yù)加載特定部分的訓(xùn)練數(shù)據(jù)(如僅加載遠程文件系統(tǒng)中特定路徑下的數(shù)據(jù))。
訓(xùn)練平臺的用戶可以提交針對某個訓(xùn)練數(shù)據(jù)集的預(yù)加載指令,Preloader響應(yīng)并依據(jù)預(yù)加載策略,在計算啟動之前就開始將部分或者全部訓(xùn)練數(shù)據(jù)拉取到分布式緩存系統(tǒng)中。預(yù)加載數(shù)據(jù)過程與用戶提交的訓(xùn)練任務(wù)的執(zhí)行是解耦的,可以完全串行,也可以部分并行。TDCS通過Preloader解決了單個訓(xùn)練任務(wù)的“冷啟動”問題,保證整個訓(xùn)練過程沒有明顯的讀取數(shù)據(jù)時延。
深度學(xué)習在很多領(lǐng)域取得了非常好的效果,如圖像分類、物體檢測、自然語言理解等領(lǐng)域。一個領(lǐng)域內(nèi)經(jīng)常會有多種深度學(xué)習算法在演進。而訓(xùn)練同一類領(lǐng)域模型的多種算法經(jīng)常會使用同樣的數(shù)據(jù)集。比如,在視覺識別領(lǐng)域,幾乎所有深度學(xué)習算法會將ImageNet作為訓(xùn)練數(shù)據(jù)的基線。對于同一種算法模型,也需要多次提交任務(wù),使用同一份訓(xùn)練數(shù)據(jù)反復(fù)實驗。依據(jù)每個任務(wù)的實驗結(jié)果,不斷調(diào)整模型結(jié)構(gòu)和參數(shù),最終得到表現(xiàn)穩(wěn)定的模型版本。因此,在深度學(xué)習訓(xùn)練平臺上,會有很多任務(wù)重復(fù)使用相同數(shù)據(jù)進行訓(xùn)練。根據(jù)這些任務(wù)提交的時序特征,可在任務(wù)之間共享緩存數(shù)據(jù),從而提升多個相關(guān)任務(wù)的性能。
TDCS利用多任務(wù)間的時序特征,設(shè)計了任務(wù)與緩存數(shù)據(jù)的親和性調(diào)度策略,即把后序提交的任務(wù)分配到已緩存其目標數(shù)據(jù)的計算節(jié)點上,保證后序任務(wù)可以直接重用本地緩存數(shù)據(jù)。具體地,如果在ti時刻提交任務(wù)T1,使用數(shù)據(jù)集D1訓(xùn)練。假設(shè)訓(xùn)練平臺調(diào)度器Scheduler為T1分配了計算節(jié)點集合S1={N1,N2,N3},緩存系統(tǒng)會在節(jié)點集合S1上保存D1的緩存D1'。在tj(j≥i)時刻,提交任務(wù)T2,也使用數(shù)據(jù)集D1進行訓(xùn)練。
TDCS的任務(wù)調(diào)度器Scheduler為T2分配計算節(jié)點的算法流程如下。這樣可以最大限度地保證T2計算與本地緩存數(shù)據(jù)的親和性。
● Scheduler查詢CacheManager后,得知集群中已存在數(shù)據(jù)集D1的緩存數(shù)據(jù)D1',且D1'部署在節(jié)點集合S1上。
● Scheduler根據(jù)T2的計算資源要求,在集群中找到符合執(zhí)行任務(wù)條件的備選節(jié)點集合S2,假設(shè)為{M1,M2,M3,M4,M5}。
● Scheduler計算集合S1與S2的交集,得到高優(yōu)先級備選節(jié)點集合S3。
● Scheduler使用貪心算法,總是更多地選擇S3中的節(jié)點,并將其分配給任務(wù)T2。
在實現(xiàn)多任務(wù)共享緩存數(shù)據(jù)調(diào)度策略時,會存在“緩存熱點”和“緩存清理”問題。
● 緩存熱點:考慮到在特定時期有大量類似T2的任務(wù)需要幾乎同時執(zhí)行,如果多個任務(wù)同時訪問緩存數(shù)據(jù)D1',會導(dǎo)致S1內(nèi)節(jié)點的訪問壓力過大,使這些節(jié)點成為“熱點”。
● 緩存清理:考慮到計算節(jié)點本地內(nèi)存和磁盤存儲容量有限,緩存數(shù)據(jù)D1'勢必會從S1節(jié)點上被逐步驅(qū)逐,或者徹底刪除。任務(wù)T2的提交時刻tj不確定,導(dǎo)致緩存數(shù)據(jù)的利用率不穩(wěn)定。極端情況下,每次T2被提交的時候,D1'都已被刪除,緩存完全無法被多任務(wù)共享。
為了解決這兩個問題,TDCS設(shè)計實現(xiàn)了緩存數(shù)據(jù)管理器CacheManager,負責根據(jù)用戶指定策略,管理對緩存數(shù)據(jù)的訪問和清理緩存數(shù)據(jù)。
首先,CacheManager控制緩存數(shù)據(jù)D1'的并發(fā)訪問數(shù)上限。用戶可以選擇配置應(yīng)對并發(fā)任務(wù)數(shù)超過限制的策略。不同于參考文獻[13]提出的優(yōu)化緩存系統(tǒng)內(nèi)部數(shù)據(jù)分布算法的方法,以及參考文獻[14]提出的利用存儲系統(tǒng)中數(shù)據(jù)塊間的關(guān)聯(lián)性指導(dǎo)Alluxio緩存策略CPR(cache prefet repace),TDCS避免侵入修改分布式緩存引擎,而選擇在其外部增加控制訪問緩存任務(wù)量和緩存供給量的邏輯,實現(xiàn)緩存負載穩(wěn)定和均衡。由CacheManager與Scheduler配合,動態(tài)調(diào)整超限并發(fā)任務(wù)的資源分配,以及緩存數(shù)據(jù)副本數(shù)量。為此,CacheManager提供了Suspend和Clone兩種策略。
● Suspend:表示暫時掛起新任務(wù)對D1'的訪問。此時,CacheManager會通知Scheduler,將超限任務(wù)放入等待隊列。當并發(fā)訪問D1'的任務(wù)數(shù)量降到上限以內(nèi)時,CacheManager會通知Scheduler將等待隊列中的任務(wù)移出隊伍,將其盡量調(diào)度到D1'所在的節(jié)點上。
● Clone:表示CacheManager在集群中復(fù)制一份新的緩存數(shù)據(jù)D1'',供新任務(wù)讀取。Scheduler查詢CacheManager后,得到D1存在可被訪問的緩存數(shù)據(jù)D1''及其所處節(jié)點集合Si。根據(jù)最大限度地保證計算與緩存數(shù)據(jù)親和性的原則,新任務(wù)會被盡可能多地調(diào)度到Si的節(jié)點上,避免出現(xiàn)緩存熱點。
其次,CacheManager支持3種緩存清理策略,包括:鎖定資源,不清理緩存;定時清理;最近最少使用(least recently used,LRU)清理。
用戶可以根據(jù)計算節(jié)點的可用存儲資源量、任務(wù)提交計劃、多任務(wù)的相關(guān)性等因素,配置清理策略。例如,在特定時段,存在許多使用相同訓(xùn)練數(shù)據(jù)的任務(wù)需要執(zhí)行,為了保證總是有緩存數(shù)據(jù)用于加速訓(xùn)練計算讀取,可以選擇不清理緩存,也可以選擇定時清理,具體時間間隔可以根據(jù)任務(wù)執(zhí)行計劃和可用存儲資源量來設(shè)置。而對于集群中存在多個訓(xùn)練數(shù)據(jù)集的緩存情況,可以選擇CacheManager按照LRU算法,優(yōu)先清理最近最少訪問的緩存數(shù)據(jù)。還可以擴展CacheManager模塊,以支持更多復(fù)雜的緩存清理策略,比如參考文獻[15]提出的兼顧最近訪問時間和歷史訪問頻率的緩存替換策略等。
通常訓(xùn)練平臺內(nèi)會有很多任務(wù)同時運行,它們共享了集群計算資源,尤其是寶貴的GPU資源。為了提升GPU利用率,訓(xùn)練平臺調(diào)度器會動態(tài)調(diào)整分配給任務(wù)的GPU資源。例如,回收低優(yōu)先級任務(wù)占用的部分GPU節(jié)點,將其分配給高優(yōu)先級任務(wù)。訓(xùn)練過程中,任務(wù)需要具有彈性伸縮的能力。為高優(yōu)先級任務(wù)動態(tài)分配更多計算節(jié)點時,若將分布式緩存系統(tǒng)彈性擴展到這些新增節(jié)點上,則可以擴大緩存總?cè)萘?,進而支撐更大規(guī)模的并發(fā)讀取,提升任務(wù)整體的訓(xùn)練性能。
TDCS設(shè)計了CacheScaler,負責彈性擴展、收縮分布式緩存系統(tǒng),使緩存系統(tǒng)的部署位置與訓(xùn)練任務(wù)的運行節(jié)點保持同步,保證計算所需緩存數(shù)據(jù)總是在本地就可讀取。CacheScaler可通過如下3種觸發(fā)方法來彈性伸縮分布式緩存系統(tǒng)。
● API觸發(fā)伸縮活動。用戶可以調(diào)用CacheScaler的API,主動觸發(fā)擴展和收縮緩存。
● 事件觸發(fā)伸縮活動。CacheScaler通過事件訂閱機制,發(fā)現(xiàn)、響應(yīng)訓(xùn)練任務(wù)的計算資源量變化事件,自動觸發(fā)擴展和收縮緩存。
● 監(jiān)控觸發(fā)伸縮活動。本文的訓(xùn)練平臺基于Kubernetes容器編排和管理技術(shù)構(gòu)建。利用集群監(jiān)控系統(tǒng),根據(jù)監(jiān)控指標的變化情況,調(diào)用Kubernetes的HPA(horizontal pod autoscaler)組件,主動伸縮緩存系統(tǒng)。典型的監(jiān)控指標是緩存系統(tǒng)容量使用率。當緩存系統(tǒng)容量使用率(即緩存數(shù)據(jù)量的占比)達到給定閾值時,就會自動觸發(fā)擴展緩存;反之,當緩存系統(tǒng)容量使用率長期保持低水平時,可以選擇通過HPA觸發(fā)收縮緩存。
TDCS通過CacheScaler、Kubernetes集群監(jiān)控和HPA等組件支持分布式緩存的彈性策略,使緩存數(shù)據(jù)能夠更靈活地配合訓(xùn)練任務(wù)彈性伸縮,既提供了高訓(xùn)練性能,也保證了較高的資源利用率。實驗表明,TDCS幫助Alluxio支持從使用8塊NVIDIA V100 GPU卡計算的深度學(xué)習訓(xùn)練任務(wù)擴展到使用128塊NVIDIA V100 GPU卡的任務(wù)。
為了在前文實驗基礎(chǔ)之上,驗證TDCS進一步提升訓(xùn)練任務(wù)性能的效果,本文使用相同的ResNet50圖像分類模型和ImageNet圖像識別數(shù)據(jù)集,在不同數(shù)量的GPU資源上測試了多組分布式訓(xùn)練任務(wù)。如圖5所示,4組實驗數(shù)據(jù)分別使用8、32、64、128塊NVIDIA Tesla V100 GPU卡進行分布式訓(xùn)練。每組實驗都對比了使用4種不同緩存配置的訓(xùn)練速度。
圖5 使用TDCS協(xié)同調(diào)度分布式緩存加速ResNet50模型訓(xùn)練的實驗結(jié)果對比
配置1:不使用緩存,任務(wù)直接讀取遠程OSS數(shù)據(jù)。
配置2:使用默認配置Alluxio讀取OSS數(shù)據(jù)。
配置3:在配置2的基礎(chǔ)上增加TDCS訓(xùn)練數(shù)據(jù)預(yù)加載策略。
配置4:在配置3的基礎(chǔ)上增加TDCS多任務(wù)緩存數(shù)據(jù)共享策略。
其中,使用配置3、4的實驗中,都使用了TDCS分布式緩存彈性策略。
總體來看,使用TDCS協(xié)同調(diào)度增強的分布式緩存之后,實驗任務(wù)的訓(xùn)練速度能達到直接讀取OSS數(shù)據(jù)的任務(wù)速度的2.2~3.7倍。在所有實驗中,使用默認配置的Alluxio讀取訓(xùn)練數(shù)據(jù)后,都會比不使用緩存的訓(xùn)練速度有大幅提升,加速比范圍為25%~200%。在增加使用TDCS訓(xùn)練數(shù)據(jù)預(yù)加載策略后,相比僅使用默認Alluxio的加速比會提升7%~102%。在繼續(xù)增加使用TDCS多任務(wù)共享緩存調(diào)度策略后,訓(xùn)練速度依然還有4%~7%的提升。特別地,當使用默認配置的Alluxio加速8塊GPU卡上的訓(xùn)練任務(wù)時,由于計算資源不足,已經(jīng)出現(xiàn)瓶頸,繼續(xù)增加使用TDCS的協(xié)同調(diào)度策略并不能進一步明顯地提升訓(xùn)練性能。
本文針對云環(huán)境下,計算、存儲分離架構(gòu)帶來的數(shù)據(jù)讀取性能瓶頸問題,提出基于分布式緩存結(jié)合Kubernetes容器技術(shù)加速深度學(xué)習訓(xùn)練的方法和架構(gòu)。在應(yīng)用Alluxio分布式緩存系統(tǒng),并進行Alluxio系統(tǒng)參數(shù)優(yōu)化后,獲得初步的訓(xùn)練加速效果。受限于Alluxio靜態(tài)部署的系統(tǒng)架構(gòu),加速效果無法擴展到大規(guī)模分布式訓(xùn)練任務(wù),進而提出TDCS訓(xùn)練任務(wù)與緩存數(shù)據(jù)協(xié)同調(diào)度方法和其在Kubernetes容器集群架構(gòu)下的系統(tǒng)實現(xiàn)。通過增加訓(xùn)練數(shù)據(jù)預(yù)加載策略、多任務(wù)緩存數(shù)據(jù)共享策略以及分布式緩存彈性策略,TDCS可以保證在容器環(huán)境下給深度學(xué)習訓(xùn)練任務(wù)帶來2~3倍的加速,并且加速效果可以擴展到使用128塊NVIDIA GPU卡的大規(guī)模分布式訓(xùn)練場景。