分布式机器学习框架:MxNet 前言
一、前言:
Minerva: 高效靈活的并行深度學習引擎
???????? 不同于cxxnet追求極致速度和易用性,Minerva則提供了一個高效靈活的平臺讓開發者快速實現一個高度定制化的深度神經網絡。
???????? Minerva在系統設計上使用分層的設計原則,將“算的快”這一對于系統底層的需求和“好用”這一對于系統接口的需求隔離開來,如圖3所示。在接口上,我們提供類似numpy的用戶接口,力圖做到友好并且能充分利用Python和numpy社區已有的算法庫。在底層上,我們采用數據流(Dataflow)計算引擎。其天然的并行性能夠高效地同時地利用多GPU進行計算。Minerva通過惰性求值(Lazy Evaluation),將類numpy接口和數據流引擎結合起來,使得Minerva能夠既“好用”又“算得快”。
圖 3 Minerva的分層設計
惰性求值
????????? Minerva通過自己實現的ndarray類型來支持常用的矩陣和多維向量操作。在命名和參數格式上都盡量和numpy保持一致。Minerva同時支持讀取Caffe的配置文件并進行完整的訓練。Minerva提供了兩個函數與numpy進行對接。from_numpy函數和to_numpy函數能夠在numpy的ndarray與Minerva的類型之間互相轉換。因此,將Minerva和numpy混合使用將變得非常方便。
數據流引擎和多GPU計算
???????? 從Mapreduce到Spark到Naiad,數據流引擎一直是分布式系統領域研究的熱點。數據流引擎的特點是記錄任務和任務之間的依賴關系,然后根據依賴關系對任務進行調度。沒有依賴的任務則可以并行執行,因此數據流引擎具有天然的并行性。在Minerva中,我們利用數據流的思想將深度學習算法分布到多GPU上進行計算。每一個ndarray運算在Minerva中就是一個任務,Minerva自身的調度器會根據依賴關系進行執行。用戶可以指定每個任務在哪塊卡上計算。因此如果兩個任務之間沒有依賴并且被分配到不同GPU上,那這兩個任務將能夠并行執行。同時,由于數據流調度是完全異步的,多卡間的數據通信也可以和其他任務并行執行。由于這樣的設計,Minerva在多卡上能夠做到接近線性加速比。此外,利用深盟的Parameter Server,Minerva可以輕松將數據流拓展到多機上,從而實現多卡多機的分布式訓練。
圖4 ?Minerva和Caffe在單卡和多卡上訓練GoogLeNet的比較
表1 Minerva在不同網絡模型和不同GPU數目上的訓練速度
數據流引擎和多GPU計算
????????? Minerva采用惰性求值的方式將類numpy接口和數據流引擎結合起來。每次用戶調用Minerva的ndarray運算,系統并不立即執行這一運算,而是將這一運算作為任務,異步地交給底層數據流調度器進行調度。之后,用戶的線程將繼續進行執行,并不會阻塞。這一做法帶來了許多好處:
- 在數據規模較大的機器學習任務中,文件I/O總是比較繁重的。而惰性求值使得用戶線程進行I/O的同時,系統底層能同時進行計算。
- 由于用戶線程非常輕量,因此能將更多的任務交給系統底層。其中相互沒有依賴的任務則能并行運算。
- 用戶能夠在接口上非常輕松地指定每個GPU上的計算任務。Minerva提供了set_device接口,其作用是在下一次set_device調用前的運算都將會在指定的GPU上進行執行。由于所有的運算都是惰性求值的,因此兩次set_device后的運算可以幾乎同時進行調度,從而達到多卡的并行。
Parameter Server: 一小時訓練600T數據
???????? 深盟的組件參數服務器(Parameter Server)對前述的應用提供分布式的系統支持。在大規模機器學習應用里,訓練數據和模型參數均可大到單臺機器無法處理。參數服務器的概念正是為解決此類問題而提出的。如圖5所示,參數以分布式形式存儲在一組服務節點中,訓練數據則被劃分到不同的計算節點上。這兩組節點之間數據通信可歸納為發送(push)和獲取(pull)兩種。例如,一個計算節點既可以把自己計算得到的結果發送到所有服務節點上,也可以從服務節點上獲取新模型參數。在實際部署時,通常有多組計算節點執行不同的任務,甚至是更新同樣一組模型參數。
圖5 參數服務器架構
????????? 在技術上,參數服務器主要解決如下兩個分布式系統的技術難點。
降低網絡通信開銷
???????? 在分布式系統中,機器通過網絡通信來共同完成任務。但不論是按照延時還是按照帶寬,網絡通信速度都是本地內存讀寫的數十或數百分之一。解決網絡通信瓶頸是設計分布式系統的關鍵。
異步執行
???????? 在一般的機器學習算法中,計算節點的每一輪迭代可以劃分成CPU繁忙和網絡繁忙這兩個階段。前者通常是在計算梯度部分,后者則是在傳輸梯度數據和模型參數部分。串行執行這兩個階段將導致CPU和網絡總有一個處于空閑狀態。我們可以通過異步執行來提升資源利用率。例如,當前一輪迭代的CPU繁忙階段完成時,可直接開始進行下一輪的CPU繁忙階段,而不是等到前一輪的網絡繁忙階段完成。這里我們隱藏了網絡通信開銷,從而將CPU的使用率最大化。但由于沒有等待前一輪更新的模型被取回,會導致這個計算節點的模型參數與服務節點處最新的參數不一致,由此可能會影響算法效率。
靈活的數據一致性模型
???????? 數據不一致性需要考慮提高算法效率和發揮系統性能之間的平衡。最好的平衡點取決于很多因素,例如CPU計算能力、網絡帶寬和算法的特性。我們發現很難有某個一致性模型能適合所有的機器學習問題。為此,參數服務器提供了一個靈活的方式用于表達一致性模型。
??????? 首先執行程序被劃分為多個任務。一個任務類似于一個遠程過程調用(Remote Procedure Call, RPC),可以是一個發送或一個獲取,或者任意一個用戶定義的函數,例如一輪迭代。任務之間可以并行執行,也可以加入依賴關系的控制邏輯,來串行執行,以確保數據的一致性。所有這些任務和依賴關系組成一個有向無環圖,從而定義一個數據一致性模型,如圖6所示。
圖6 使用有向無環圖來定義數據一致性模型
????????? 如圖7所示,我們可以在相鄰任務之間加入依賴關系的控制邏輯,得到順序一致性模型,或者不引入任何依賴關系的邏輯控制,得到最終一致性模型。在這兩個極端模型之間是受限延時模型。這里一個任務可以和最近的數個任務并行執行,但必須等待超過最大延時的未完成任務的完成。我們通過使用最大允許的延時來控制機器在此之前的數據不一致性。
圖7 不同數據一致性下運行時間
?圖8展示了在廣告點擊預測中(細節描述見后文),不同的一致性模型下得到同樣精度參數模型所花費的時間。當使用順序一致性模型時(0延時),一半的運行時間花費在等待上。當我們逐漸放松數據一致性要求,可以看到計算時間隨著最大允許的延時緩慢上升,這是由于數據一致性減慢了算法的收斂速度,但由于能有效地隱藏網絡通信開銷,從而明顯降低了等待時間。在這個實驗里,最佳平衡點是最大延時為8。
選擇性通信
??????? 任務之間的依賴關系可以控制任務間的數據一致性。而在一個任務內,我們可以通過自定義過濾器來細粒度地控制數據一致性。這是因為一個節點通常在一個任務內有數百或者更多對的關鍵字和值(key, value)需要通信傳輸,過濾器對這些關鍵字和值進行選擇性的通信。例如我們可以將較上次同步改變值小于某個特定閾值的關鍵字和值過濾掉。再如,我們設計了一個基于算法最優條件的KKT過濾器,它可過濾掉對參數影響弱的梯度。我們在實際中使用了這個過濾器,可以過濾掉至少95%的梯度值,從而節約了大量帶寬。
緩沖與壓縮
???????? 我們為參數服務器設計了基于區段的發送和獲取通信接口,既能靈活地滿足機器學習算法的通信需求,又盡可能地進行批量通信。在訓練過程中,通常是值發生變化,而關鍵字不變。因此可以讓發送和接收雙方緩沖關鍵字,避免重復發送。此外,考慮到算法或者自定義過濾器的特性,這些通信所傳輸的數值里可能存在大量“0”,因此可以利用數據壓縮有效減少通信量。
容災
??????? 大規模機器學習任務通常需要大量機器且耗時長,運行過程中容易發生機器故障或被其他優先級高的任務搶占資源。為此,我們收集了一個數據中心中3個月內所有的機器學習任務。根據“機器數×用時”的值,我們將任務分成大中小三類,并發現小任務(100機器時)的平均失敗率是6.5%;中任務(1000機器時)的失敗率超過了13%;而對于大任務(1萬機器時),每4個中至少有1個會執行失敗。因此機器學習系統必須具備容災功能。
??????? 參數服務器中服務節點和計算節點采用不同的容災策略。對于計算節點,可以采用重啟任務,丟棄失敗節點,或者其他與算法相關的策略。而服務節點維護的是全局參數,若數據丟失和下線會嚴重影響應用的運行,因此對其數據一致性和恢復時效性要求更高。
??????? 參數服務器中服務節點的容災采用的是一致性哈希和鏈備份。服務節點在存儲模型參數時,通過一致性哈希協議維護一段或者數段參數。這個協議用于確保當有服務節點發生變化時,只有維護相鄰參數段的服務節點會受到影響。每個服務節點維護的參數同時會在數個其他服務節點上備份。當一個服務節點收到來自計算節點的數據時,它會先將此數據備份到其備份節點上,然后再通知計算節點操作完成。中間的任何失敗都會導致這次發送失敗,但不會造成數據的不一致。
??????? 鏈備份適用于任何機器學習算法,但會使網絡通信量成倍增長,從而可能形成性能瓶頸。對于某些算法,我們可以采用先聚合再備份的策略來減少通信。例如,在梯度下降算法里,每個服務節點先聚合來自所有計算節點的梯度,之后再更新模型參數,因此可以只備份聚合后的梯度而非來自每個計算節點的梯度。聚合可以有效減少備份所需通信量,但聚合會使得通信的延遲增加。不過這可以通過前面描述的異步執行來有效地隱藏。
?????? 在實現聚合鏈備份時,我們可以使用向量鐘(vector clock)來記錄收到了哪些節點的數據。向量鐘允許我們準確定位未完成的節點,從而對節點變更帶來的影響進行最小化。由于參數服務器的通信接口是基于區段發送的,所有區段內的關鍵字可以共享同一個向量鐘來壓縮其存儲開銷。
圖8 三個系統在訓練得到同樣精度的模型時所各花費的時間
??????? 參數服務器不僅為深盟其他組件提供分布式支持,也可以直接在上面開發應用。例如,我們實現了一個分塊的Proximal Gradient算法來解決稀疏的Logistic Regression,這是最常用的一個線性模型,被大量的使用在點擊預測等分類問題中。
?????? 為了測試算法性能,我們采集了636TB真實廣告點擊數據,其中含有1700億樣本和650億特征,并使用1000臺機器共1.6萬核來進行訓練。我們使用兩個服務產品的私有系統(均基于參數服務器架構)作為基線。圖8展示的是這3個系統為了達到同樣精度的模型所花費的時間。系統A使用了類梯度下降的算法(L-BFGS),但由于使用連續一致性模型,有30%的時間花費在等待上。系統B則使用了分塊坐標下降算法,由于比系統A使用的算法更加有效,因此用時比系統A少。但系統B也使用連續一致性模型,并且所需全局同步次數要比系統A更多,所以系統B的等待時間增加到了50%以上。我們在參數服務器實現了與系統B同樣的算法,但將一致性模型放松至受限延時一致性模型并應用了KKT過濾。與系統B相比,參數服務器需要略多的計算時間,但其等待時間大幅降低。由于網絡開銷是這個算法的主要瓶頸,放松的一致性模型使得參數服務器的總體用時只是系統B的一半。
Rabit:靈活可靠的同步通信
除了Parameter Server提供的異步通信之外,以GBDT和L-BFGS為代表的許多機器學習算法依然適合采用同步通信 (BSP)的方式進行交互。深盟的第二個通信框架Rabit提供了這一選擇。
傳統的同步通信機器學習程序往往采用MPI的Allreduce進行計算,但是因為MPI提供的接口過于復雜使得它并不容易提供容災支持。Rabit簡化了MPI的設計,抽取出機器學習最需要的Allreduce和Broadcast操作并加入了容災的支持,使得基于分布式BSP的機器學習算法可以在部分節點出錯或丟失的情況下快速恢復計算,完成剩下的任務。目前的GBDT算法xgboost就是基于Rabit提供的接口。同時,Rabit具有非常強的可移植性,目前支持在MPI、Hadoop Yarn和SunGrid Engine等各個平臺下直接執行。異步的Parameter Server 接口加上同步的Rabit接口基本涵蓋了各種分布式機器學習算法需要的通信需求,使得我們可以很快地實現各種高效的分布式機器學習算法。
二、MxNet
caffe是很優秀的dl平臺。影響了后面很多相關框架。
cxxnet借鑒了很多caffe的思想。相比之下,cxxnet在實現上更加干凈,例如依賴很少,通過mshadow的模板化使得gpu和cpu代碼只用寫一份,分布式接口也很干凈。
mxnet是cxxnet的下一代,目前實現了cxxnet所有功能,但借鑒了minerva/torch7/theano,加入更多新的功能。
總結
以上是生活随笔為你收集整理的分布式机器学习框架:MxNet 前言的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 用代码实现移除WordPress版本号的
- 下一篇: 分布式机器学习框架:MxNet