閱讀39 返回首頁    go 阿裏雲 go 技術社區[雲棲]


上帝的巴別塔在崩塌?阿裏翻譯一年2500億次調用,節省25億美元

神經網絡機器翻譯(Neural Machine Translation, NMT)模型自2013年在學術界首次被提出後,就不斷快速發展,目前在某些語種和場景下,譯文質量甚至可以達到人工翻譯的水平。

阿裏翻譯團隊自2016年10月起正式開始自主研發NMT模型,2016年11月首次將NMT係統的輸出結果應用在中英消息通訊場景下的外部評測中並取得了不錯的成績,翻譯質量有了大幅度提升。

image


但是,由於NMT模型的結構複雜,且深度神經網絡模型本身的訓練過程一般又會涉及很大量的計算,因此NMT係統往往需要較長的訓練周期,例如,使用3000萬的訓練數據在單塊GPU卡上一般需要訓練20天以上,才能得到一個初步可用的模型。

基於上述問題,2017年2月初開始,阿裏翻譯團隊和阿裏雲Large Scale Learning的穆琢團隊合作,共同開發支持分布式訓練的NMT係統,並於2017年3月底完成了第一個版本的分布式NMT係統。




在2017年4月份的英俄電商翻譯質量優化項目中,分布式NMT係統大大提高了訓練速度,使模型訓練時間從20天縮短到了4天,為項目整體迭代和推進節省了很多時間成本。

圖一:使用不同卡數時,在中英100萬訓練語料上獲得的收斂加速比

image


在4張GPU卡上,可以達到3倍以上的收斂加速比,在8張GPU卡上,可以達到5倍以上的收斂加速比,在16張GPU卡上,可以達到9倍以上的收斂加速比,通過不斷累加GPU卡數,收斂加速比預期還會繼續提升。

圖二:中英2000萬訓練集上,利用2機4卡進行分布式訓練的收斂過程

image


圖三:多種分布式策略的加速效果對比

image


除了基於MA的分布式實現,項目組還嚐試了其他多種分布式實現方法,也都獲得了不同程度的加速效果,包括Downpour SGD、AllReduce SGD以及使用了BMUF(Blockwise Model-Update Filtering, 一種針對Model Average方法的改進方案)策略的Model Average方法。




data parallel數據並行

基於data parallel的同步SGD算法,即使用多個worker均攤整個batch的計算量,且每個GPU(worker)上存儲完整的模型副本。Tensorflow本身提供的PS框架可以直接用於實現此算法。標準的同步SGD算法每次迭代都分為三個步驟,首先,從參數服務器中把模型參數pull到本地,接著用新的模型參數計算本地mini-batch的梯度,最後後將計算出的梯度push到參數服務器。參數服務器需要收集所有workers的梯度,再統一處理更新模型參數。

因此,在ps框架下,同步SGD算法的總通信量 transfer data = 2 * num_of_gpus * size_of_whole_model。通過對模型的大小和一個mini-batch計算時間的評估,發現在單機兩卡的情況下,由於PCIe的帶寬較高(~10GB/s),可以獲得接近2倍的加速比,但兩機兩卡的情況下,計算通信比則為1:1,而隨著機器數的增多,不但沒有帶來加速,反而比單卡更慢。

可見,通信優化是同步SGD算法的主要問題,下麵的具體方案介紹中,我們也展示了相關的實驗結果。

hybrid parallel混合並行

模型並行可以通過模型參數的存儲策略,利用參數的稀疏性,減少參數的實際通信量,對訓練過程進行加速。一般情況下,適用於稀疏模型的訓練,但對於特殊的網絡結構,模型並行可以和數據並行相結合,提高全局的計算通信比,我們這裏稱之為hybrid parallel。以AlexNet舉例來說,可以把模型結構分為全連接層和卷積層兩部分,從而對兩個部分分別分析計算通信比。

全連接層計算通信比極低,毫無擴展性,而卷積層的計算通信比較高,適合使用數據並行,因此hybrid parallel的方案是:多個workers使用數據並行的方式計算卷積層,而隻需一個worker(或極少量workers)計算全連接層,以獲得最高的計算通信比,且卷積層和全連接層中間隻有一個規模很小的feature map需要通信。

通過對NMT的模型中各個層進行profiling,發現網絡中各部分的參數大小相差不大,計算量也相當,不但計算通信比不高,各層結構之間傳遞的feature map也較大,並不適合使用hybrid parallel的方式。

分布式方案的進一步探索

基於以上的分析,我們對分布式方案進行了進一步的探索。為了最大程度的獲得多機多卡的擴展性,我們選擇了Model average、BMUF、downpour等分布式方法。Model average(MA)方法較於簡單的數據並行,有兩個顯著的優勢:一、通信量可以通過同步頻次來調節,兩次同步的間隔可以以step甚至epoch為單位來控製,一般情況下,通信開銷幾乎可以忽略不計,從而獲得線性的計算加速比;二、batch size的大小可以和單機baseline保持一致,基於數據並行的同步SGD,通常為了保持計算通信比而同比增大batch size,導致精度損失。

但是,MA方法、BMUF方法以及基於異步更新的downpour方法,對調參的要求都更高,不同的參數設置,會對模型的收斂結果有較大的影響,計算加速比的提高並不意味著收斂加速比的提高。下文是對各個實現方案的消息介紹和結果展示。

方案概述

Model Average方法,即每個worker負責訓練本地的模型,多個GPU之間通過固定(或動態)的頻率求取各個模型的均值,並以此作為繼續訓練的基礎。

基於Tensorflow的Model Average設計主要分為graph構建和分步run兩部分。

1.首先,由於每個worker需要在各自的進程內進行求解,所以需要在每個worker上分別進行構建forward-backward子圖,這一部分的子圖在上圖中用紅色的箭頭線表示。應當注意,每個worker上應該具有獨立的op和variable。

2.其次,需要在ps上維護一份模型拷貝,並構建Reduce Average的子圖,這一部分的子圖在上圖中用黑色的箭頭線表示。

3.然後,需要構建broadcast的子圖,這一部分的子圖在上圖中用藍色的線表示。(這裏由於美觀,在圖中沒有畫出全部的broadcast依賴關係,ps的variable 1和variable 2都應該和worker 1和worker 2中的variable 1和variable 2建立依賴關係)

4.在構建上述依賴關係後,我們需要通過client啟動Model Average的機製。用戶隻需要通過控製session run的順序來指定每個子圖的求解即可完成。在這裏,紅色的子圖需要每輪都run,而到了一定輪數間隔後開始依次run黑色的子圖和藍色的子圖即可完成Model Average的機製。

在實現上,可以用主worker完成所有子圖的構建,其他worker處於join狀態。在運行時,各個worker會根據圖中的依賴關係驅動起來。


image


超參的調整

當兩機四卡的參數保持和單機單卡baseline參數一致的情況下,從多組實驗中可以觀察到,不同的同步頻次對模型的質量有影響,加速比最快隻達到1.5.通過推導,我們發現,MA方法中每次計算多個worker的模型均值,都相當於把每個訓練樣本對模型梯度的貢獻縮減為原來的1/num_of_gpus, 大大抵消了多卡帶來的加速。因此,MA中的本地訓練learning rate(lr)應該調整為原baseline lr的num_of_gpus倍。

實驗結果

image


其中bs表示batch size,lr表示learning rate,橫坐標是訓練時間,縱坐標代表翻譯質量。

方案概述

上麵提到的Model Average方法在兩卡、四卡、八卡上均獲得了較高的加速比,在不斷並行擴展的過程中,需要根據機器的個數對lr進行調整,然而lr的大小一定有一個適當的範圍,並不能無限的增大,隨著機器數的增多,這種naive MA方法也逐漸暴露出它的局限性。

BMUF(Blockwise Model-Update Filtering)是Model average(naive MA)的一種優化算法,最主要的區別是引入了梯度的曆史量。MA算法等價於在每次同步時,把所有workers上的模型增量加和平均,作為“block gradients”,用於更新參數服務器上的全局參數,而BMUF的“block gradients”則在此基礎之上,增加了另外一項曆史梯度,且曆史梯度的權重為block momentum rate。

具體推導如下:

image


MA:一個mini-batch的訓練數據對最後模型的貢獻公式為:

image


BMUF:一個mini-batch的訓練數據對最後模型的貢獻公式為:

image


從公式中可以看出,MA中單個mini-batch的貢獻在average階段被縮小為原來的N分之1,如果要保持和baseline一樣的貢獻度,則需要增大lr。而BMUF相比baseline的貢獻比為:

image


超參的調整

上文的公式可以指導BMUF訓練過程中參數的調整。BMUF最主要的參數有兩個,一是block learning rate(blr),此超參一般設為1.0,和MA算法一致,二是block momentum rate(bmr),可以通過調整bmr為1-1/N,從而保持lr不變,總的貢獻量和baseline一致。此外,引入了曆史梯度後,還可以結合Nesterov方法,在本地訓練時先對本地的模型更新已知的曆史梯度,再進行訓練,從而進一步加速了收斂。

實驗結果

image


上圖橫坐標代表已訓練的總數據量,即每個計算節點訓練數據量的總和(最理想的情況,收斂曲線應該和baseline重合甚至更高),縱坐標代表模型的翻譯質量。可以看到MA和BMUF在兩機四卡上可以獲得相當的加速比,BMUF的優勢在於,可以通過調節bmr從而把learning rate(lr)可以保持在與單機單卡的baseline一個量級,因為lr有一個較為適當的範圍,不能隨著GPU的增多無限製增大。BMUF的效果在更大的lr以及十六卡的實驗中已得到體現。

方案概述

和MA的設計類似,Downpour SGD的設計也比較自然,同樣分為graph構建和分布run兩部分。在這裏需要注意的是,Downpour SGD方法是一種ASGD的異步分布式訓練方法,其在Apply gradients時是不需要多個worker之間同步的。

下麵具體介紹Downpour的整體流程。

  1. 將ps上的model weights拉到每個worker上。
  2. 每個worker自己求解本地的model,在求解過程中,不但要對本地model進行參數更新,還要將梯度累加到另一組variable中保存。
  3. 當本地worker求解到一定輪數後,將本地存儲的累積梯度異步apply到ps的model參數上。

這種方式在實現上,需要在每個worker上再保存一份variable用來存儲梯度的累積量,並且在構圖時需要對optimizer進行更改,主要體現在需要將AdaDelta計算的梯度在apply到自己的模型上之前先累加到本地的variable中,然後再apply到自身參數中。

這裏還存在一個問題關於累加梯度的問題,因為在AdaDelta的實現中,實際上apply到model上的量包含梯度和delta量兩個部分,因此在累加上有可能需要將這些delta量也考慮進去。在實現時,無需重寫新的optimizer,隻需要將調用apply gradients前後的model weights相減即可得出正確的結果。

Downpour SGD會帶來一些其他的超參數,這其中就包括push gradients和pull weights的間隔輪數,我們稱之為step。另外,若push和pull的step過大,也會導致這期間的累積梯度過大,如果此時直接將累積梯度apply到weights上很可能會出現NAN的情況,因此需要對累積梯度做clipping操作,所以對累加梯度進行clipping的norm值也是一個額外的超參數。

image


超參的調整

由於ASGD帶來的異步性,導致調參的難度相對於同步SGD更為困難,而且Downpour SGD的超參數確實比較多。為了加快訓練的速度,減少每個epoch的迭代時間,我們采用了比較激進的weak scaling的方式,即每個worker都使用較大的batch size。

但是應當注意,雖然增加batch size會使過數據的速度加快,但也會讓每個數據的學習效果降低,這是因為和小batch size相比,我們更新模型的頻率大大降低了,因此我們需要同時加大learning rate。另外,在異步條件下,每個worker計算的累積梯度都有可能成為stale的gradients,這些gradients的表示的方向並不一定最優,相反,有時候會很差。

倘若我們不對這些累積的梯度進行clip,那麼很可能出現NAN的情況,因此我們需要調整累積梯度的clipping norm值。但是clipping norm值越小,梯度值就被削弱的越狠,模型的學習效果就越不好,它與learning rate的調參是一對trade off。最後,用於push和pull的step間隔值不宜過大,因為過大的step會導致過大的累積梯度,如果此時使用較小的clipping norm對累積梯度進行削減,那麼這將意味著如此長輪數計算出來的累積梯度效果將被削減。在實驗中我們發現這個step間隔輪數設置在20左右比較理想。

綜上所述,調參的基本目標是,固定push和pull的step間隔輪數後,選取較大的batch size並適當增加learning rate,逐步調整增加clipping norm的大小,使學習效果達到最大。

實驗結果

其中bs表示batch size,lr表示learning rate,norm將累積梯度做clipping的最大值,fetch為downpour中push和pull的間隔值,縱坐標代表翻譯質量值,橫坐標是訓練時間。

image


方案概述

上文提到,同步SGD算法每次迭代都需要pull參數和push梯度這兩次通信,這樣的一個push+pull的過程對於整個係統來說,等價於一次allreduce操作,通信量相當於2 * nGPUs * model_size,隨著GPU個數的增多,allreduce成為最主要的性能瓶頸。

Ring-allReduce op

Allreduce聚合通信已有較成熟的優化方法,最常用的方法之一有Ring allreduce。其基本思想是將allreduce分拆成reduce_scatter和allgather兩步。

  1. 首先,根據節點數對待通信的message進行分片,分片的數量與通信的節點數相同(不需要額外的參數服務器)。
  2. 開始進行reduce_scatter操作。對worker(i)來說,第j次通信是把自己的第j片message發送給worker(i+1),並把收到的消息累加到message的對應片段。如此經過n-1輪的環狀流水線通信後,每個worker上都有一個分片是reduce了所有workers的結果。
  3. 然後開始allgather操作。第j次通信是把自己的第j+1片message發送給worker(i+1),如此經過n-1輪通信,所有worker的整個message就都經過了reduce操作,即完成了all_reduce操作。

ring-allreduce方法可以使得集群內的通信總量保持在一個常數,略小於2 * mdoel_size,不隨並行規模的增大而增多,有很好的擴展性。

gRPC vs MPI

Ring-allreduce方法能夠帶來性能提升的前提是:latency的開銷相對於bandwidth來說可以忽略不計,因為ring allreduce雖然降低了通信總量,卻增加了通信次數。當前tensorflow的通信協議隻支持gRPC,通信的latency較高不能被簡單忽略,而使用基於支持RDMA的cuda-aware MPI來實現allreduce op,效果則更加顯著。

此外,allreduce操作同樣存在於Model average算法中,同樣可以帶來一定的性能收益。

超參的調整

因為對於同步SGD分布式算法,如果保持Total Batch size不變,每塊GPU卡上的mini batch size會隨著GPU卡數的增多而減小,其計算時間並不是線性減少,因為當batch size足夠小後,計算時間會逐漸趨於平穩,雖然通信已經通過優化而大幅減少,計算的拓展性依然有限。因此,在使用多機多卡的同步SGD時,batch size與GPU個數同比例增大,同理,為了保持單個訓練樣本的貢獻,lr也同比增大。

實驗結果

image


上圖中,多卡同步SGD的總batch size設置為1280,是baseline(batch size=160)的8倍,橫坐標代表已訓練的總數據量,縱坐標代表模型的翻譯質量。在InfiniBand(10GB/s)網絡上,獲得4倍的計算加速比,在萬兆(1GB/s)以太網上,獲得2.56倍計算加速比。但batch size的增大會影響收斂精度,上圖可以看到,收斂的最高點比baseline略低,有明顯的精度損失。




上一階段工作主要集中在模型訓練階段的加速策略上,接下來的工作主要分為兩方麵:一方麵是繼續挖掘分布式訓練的加速潛力,通過係統與算法相結合的優化策略,最大化利用硬件資源,提升收斂加速比,並將分布式優化策略和算法模型本身解耦,實現複雜DL模型分布式加速功能的組件化和通用化。

另一方麵,需要在現有的服務化方案的基礎上,進一步通過模型精度壓縮、網絡結構簡化等方式,在保證模型效果的同時,提高解碼速度,降低線上延時,進而增強線上服務能力,節約服務化所需的硬件成本。

原文鏈接

最後更新:2017-06-16 15:02:46

  上一篇:go  阿裏雲上部署開源PaaS平台Cloud Foundry實戰
  下一篇:go  泰福特助力“中金所技術公司”提供托管機房統一對時服務