400-650-1086
首頁 > 最新資訊 > IT新聞 > 正文

如何從系統(tǒng)層面優(yōu)化深度學(xué)習(xí)計算?

admin 2018-05-21 10:12:04 0

【新智元導(dǎo)讀】在圖像、語音識別、自然語言處理、強化學(xué)習(xí)等許多技術(shù)領(lǐng)域中,深度學(xué)習(xí)已經(jīng)被證明是非常有效的,并且在某些問題上已經(jīng)達到甚至超越了人類的水平。然而,深度學(xué)習(xí)對于計算能力有著很大的依賴,除了改變模型和算法,是否可以從系統(tǒng)的層面來優(yōu)化深度學(xué)習(xí)計算,進而改善計算資源的使用效率?本文中,來自微軟亞洲研究院異構(gòu)計算組資深研究員伍鳴與大家分享他對深度學(xué)習(xí)計算優(yōu)化的一些看法。

深度學(xué)習(xí)在近幾年里取得了巨大的進步,它已經(jīng)或者是有望成功地被應(yīng)用在我們許多生活場景中,比如自動駕駛、安防、翻譯、醫(yī)療等等。可以說,計算機的計算和通信能力的大幅提升是促使深度學(xué)習(xí)成功的重要因素。

深度學(xué)習(xí)為什么依賴于超大的計算能力?

首先,深度學(xué)習(xí)本質(zhì)上是基于統(tǒng)計的科學(xué),所以大規(guī)模的樣本數(shù)據(jù)對于深度學(xué)習(xí)的效果是至關(guān)重要的。其次,更大規(guī)模和更復(fù)雜的神經(jīng)網(wǎng)絡(luò)模型已經(jīng)被證明非常有效,并在產(chǎn)品中有廣泛的使用,這同時也產(chǎn)生了對計算能力的更大要求和消耗。舉個例子,具有8層神經(jīng)元的AlexNet網(wǎng)絡(luò)2012年在ImageNet數(shù)據(jù)集上取得16%的錯誤率,該網(wǎng)絡(luò)的一次迭代運行大約需要1.4 GFLOP的計算量。而微軟提出的使用152層神經(jīng)元的殘差網(wǎng)絡(luò)(ResNet)于2015年在該數(shù)據(jù)集上取得3.5%的錯誤率,其一次迭代的計算量大約是22.6GFLOP,是AlexNet的16倍。在當(dāng)今的生產(chǎn)環(huán)境中,圖像、語音以及自然語言處理相關(guān)的模型,例如人臉識別、語音轉(zhuǎn)文字、機器翻譯等,即使給予相當(dāng)多的計算資源,很多仍需要幾周的時間才能完成訓(xùn)練。

再次,深度學(xué)習(xí)模型是迅速迭代的。在AI領(lǐng)域,每年學(xué)術(shù)界和工業(yè)界都會提出大量的新模型。對每一個實際的問題,開發(fā)者需要不斷嘗試不同的模型和算法,甚至對于同一種模型算法,也需要去反復(fù)調(diào)試超參數(shù)以獲得最好的預(yù)測效果??上攵?,如果模型的每次訓(xùn)練都要幾周的時間,那么尋找最優(yōu)模型的過程會非常漫長和痛苦。

另外,模型的線上推理具有更加極致的性能要求。線上的服務(wù)具有硬性的服務(wù)等級協(xié)議(SLA),所以在實際部署大型模型時,需要手工重新優(yōu)化在深度學(xué)習(xí)框架(如TensorFlow)上已經(jīng)訓(xùn)練好的模型,導(dǎo)致大量額外工程開銷的產(chǎn)生。

由此可見,進一步優(yōu)化深度學(xué)習(xí)計算對于深度學(xué)習(xí)的快速發(fā)展和成功應(yīng)用起著至關(guān)重要的作用。

深度學(xué)習(xí)計算優(yōu)化的挑戰(zhàn)和機會

目前,優(yōu)化深度學(xué)習(xí)的計算存在以下幾個主要的挑戰(zhàn):

1)單機單計算單元(如GPU)的資源限制往往不能滿足對大規(guī)模數(shù)據(jù)和模型的處理要求,那么就需要使用多機多計算單元來橫向擴展計算的規(guī)模。如何才能最大限度地減少通信的開銷從而最大化多機的并行度?

2)如何優(yōu)化神經(jīng)網(wǎng)絡(luò)的計算使得它能夠把單個硬件計算單元的效率發(fā)揮到極致?

3)雖然許多硬件計算單元(GPU、FPGA等)的計算能力很強大,但是它們的內(nèi)存資源(即設(shè)備內(nèi)存)非常稀缺。當(dāng)它們不能提供模型運行所需要的內(nèi)存資源時,要么運算不能夠進行下去,要么就需要將計算所需的數(shù)據(jù)在主存和設(shè)備內(nèi)存之間倒來倒去,帶來很大的運行開銷。如何才能更好地利用有限的設(shè)備內(nèi)存資源從而不給計算效率帶來負面的影響?

4)深度學(xué)習(xí)開發(fā)者和研究人員通常只想關(guān)注神經(jīng)網(wǎng)絡(luò)模型和算法本身,并不想被復(fù)雜的優(yōu)化問題分散精力。這意味著深度學(xué)習(xí)框架這樣的系統(tǒng)軟件最好能夠?qū)崿F(xiàn)自動優(yōu)化,而對模型開發(fā)者透明。那么,如何對特定的優(yōu)化做合理的抽象使其更加靈活通用、更加容易地集成在系統(tǒng)框架中便是需要認真考慮的問題。

事實上,任何方面的優(yōu)化問題都可以從模型算法和系統(tǒng)兩個角度來看待。一方面,我們可以通過改變模型和算法來優(yōu)化其對計算資源的使用效率從而改進其運行速度。這樣的優(yōu)化對特定的算法往往非常有效,但卻不容易擴展應(yīng)用到其它算法中。而另一方面,也就是微軟亞洲研究院異構(gòu)計算組正在進行的研究,則是在系統(tǒng)中實施模型算法無關(guān)的優(yōu)化,這樣的優(yōu)化,通??梢詾楦嗟膽?yīng)用帶來性能的好處,同時也符合我們在前文提到的透明性的要求。

以系統(tǒng)優(yōu)化助力深度學(xué)習(xí)計算

為了能夠更好地理解系統(tǒng)這一層面的優(yōu)化,我們先來簡單介紹一下深度學(xué)習(xí)框架系統(tǒng)的背景知識。當(dāng)今工業(yè)界流行的深度學(xué)習(xí)系統(tǒng)(包括TensorFlow、PyTorch、CNTK、MxNet、Caffe等)大都采用分層的體系結(jié)構(gòu)設(shè)計。在前端提供高級語言(例如Python)的接口抽象,允許用戶方便地描述神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu),也就是深度學(xué)習(xí)的模型。描述好的模型在被系統(tǒng)運行前,首先會被轉(zhuǎn)換成數(shù)據(jù)流圖(Data-flow Graph)。在這個數(shù)據(jù)流圖中,節(jié)點是特定的矩陣操作(也就是Operator,如Sigmoid、Matrix Multiplication等),而連接不同節(jié)點的邊則是操作節(jié)點的輸入和輸出矩陣。這個數(shù)據(jù)流圖也可以被看成是深度學(xué)習(xí)計算的中間表達。然后,深度學(xué)習(xí)系統(tǒng)的后端將這個數(shù)據(jù)流圖映射到實際硬件上進行高效地執(zhí)行,而大部分系統(tǒng)層面的優(yōu)化就是在這個階段完成的。

加速分布式深度學(xué)習(xí)訓(xùn)練

分布式訓(xùn)練的主要瓶頸在于多機之間的通信開銷。如今計算機網(wǎng)絡(luò)的硬件技術(shù)已經(jīng)有了很大的發(fā)展,InfiniBand的RDMA網(wǎng)卡(Remote Direct Memory Access,這是一種硬件的網(wǎng)絡(luò)技術(shù),它使得計算機訪問遠程的內(nèi)存時無需遠程機器上CPU的干預(yù))已經(jīng)可以提供50~100Gbps的網(wǎng)絡(luò)帶寬和微秒級的傳輸延遲。目前許多以深度學(xué)習(xí)為目標(biāo)應(yīng)用的GPU機群都部署了這樣的網(wǎng)絡(luò)。然而深度學(xué)習(xí)系統(tǒng)如何才能充分利用好硬件提供的通信能力使分布式的訓(xùn)練獲得更大的性能提升呢?另外,使用RDMA的軟件接口進行通信能夠繞過TCP/IP協(xié)議棧,減少了操作系統(tǒng)內(nèi)核態(tài)的運行開銷。在這樣的網(wǎng)絡(luò)通信技術(shù)的支持下,任何與通信相關(guān)的計算處理的開銷都會變得非常顯著,而這正是許多原先基于TCP/IP而設(shè)計的網(wǎng)絡(luò)通信機制中所存在的問題。

RPC(Remote Procedure Call,遠程過程調(diào)用)是一個被廣泛使用的多機之間的通信抽象原語,它的主要設(shè)計目標(biāo)是通用性。在沒有考慮RDMA的情況下,很多深度學(xué)習(xí)框架都會采用RPC的機制(例如gRPC)來實現(xiàn)多機之間的通信。然而,RPC需要維護一個內(nèi)部的私有緩存,從而不得不引入用戶數(shù)據(jù)的存儲空間和內(nèi)部緩存之間的數(shù)據(jù)拷貝。這種內(nèi)存拷貝的開銷在使用RDMA網(wǎng)絡(luò)的情況下會變得非常明顯。我們通過micro-benchmark觀察到,跟使用基于TCP/IP的gRPC相比,直接通過RDMA的接口傳輸消息(對不同的消息大?。┛梢杂?到10倍的性能提升。

那么針對深度學(xué)習(xí)的應(yīng)用負載,如何才能更好地利用RDMA硬件的能力?首先,我們來分析一下深度學(xué)習(xí)應(yīng)用的幾個特點:

1)Tensor是深度學(xué)習(xí)計算中最主要的數(shù)據(jù)結(jié)構(gòu),大量的計算開銷都是花在對Tensor的處理上。Tensor是一種比較簡單的數(shù)據(jù)結(jié)構(gòu),主要由meta-data和payload兩部分組成。Payload就是基本元素的數(shù)組,而meta-data就是Tensor的shape信息,也就是維度和每一維的大小。這種簡單的數(shù)據(jù)結(jié)構(gòu)在傳輸?shù)臅r候其實不太需要復(fù)雜的序列化和反序列化的功能。

2)在相當(dāng)多的情況下,Tensor是稠密的,并且其大小也是比較大的,也就是說在傳輸這樣的Tensor的時候并不需要對其進行額外的批處理。

3)深度學(xué)習(xí)的訓(xùn)練過程是迭代的。每個迭代處理一個mini-batch。在不同的迭代之間,數(shù)據(jù)流圖和很多Tensor的shape信息并不發(fā)生改變,并且其中不少的shape信息是可以在運行時前就靜態(tài)決定的。

基于以上幾個特點,我們可以對數(shù)據(jù)流圖進行分析,找到那些可以靜態(tài)決定shape信息的Tensor,以便在運行前,在接收端預(yù)先為其分配RDMA可訪問的內(nèi)存空間,并將其相應(yīng)的可遠程訪問的地址傳送給發(fā)送端。這樣一來,在運行時,發(fā)送端可以通過單邊的RDMA請求將Tensor的數(shù)據(jù)直接傳輸?shù)浇邮斩?,從而完全避免了沒有必要的額外內(nèi)存拷貝,達到零拷貝的通信過程。我們將這種機制在TensorFlow上進行實驗, 和基于TCP/IP的gRPC相比,這一方法在一系列典型模型上均取得了多倍的性能改進。甚至和針對RDMA優(yōu)化過的gRPC相比,我們的方法仍然能夠取得超過50%的性能提升。

另外,我們在分布式深度學(xué)習(xí)方向上關(guān)注的另一個問題是如何自動地對資源無關(guān)的數(shù)據(jù)流圖做優(yōu)化的分布式執(zhí)行,也就是自動劃分數(shù)據(jù)流圖中的計算任務(wù)并為其分配相應(yīng)的計算資源,以使計算效率最優(yōu)化。Google的Jeff Dean團隊在這個方向上已經(jīng)做了很好的先驅(qū)性工作。但局限于模型并行和單機多卡的運行環(huán)境,目前這仍然是一個非常重要并且大有可為的方向,需要結(jié)合數(shù)據(jù)并行,分布式及異構(gòu)環(huán)境來綜合考慮。

提升單個計算單元的運算效率

前面提到過,使用深度學(xué)習(xí)框架來實現(xiàn)的模型算法,在運行時前會被轉(zhuǎn)換成數(shù)據(jù)流圖。不少具有實際應(yīng)用價值的模型都非常復(fù)雜,由它們所轉(zhuǎn)換出來的數(shù)據(jù)流圖通常是由成千上萬的操作節(jié)點構(gòu)成,其中包含了很多運算量非常小的節(jié)點,也就是說它們的輸入矩陣的大小很小,或者是其計算邏輯的復(fù)雜度相對于對輸入數(shù)據(jù)訪問的復(fù)雜度來說很低。大量這樣的操作節(jié)點會引入以下一些運行時開銷,并且這樣的開銷會非常顯著。

1)深度學(xué)習(xí)系統(tǒng)運行時需要根據(jù)數(shù)據(jù)流圖中節(jié)點的依賴關(guān)系來調(diào)度節(jié)點的執(zhí)行。調(diào)度每個節(jié)點的系統(tǒng)開銷和操作節(jié)點計算量的大小并沒有直接關(guān)系,因此對于由許多小的操作節(jié)點構(gòu)成的計算流圖來說,系統(tǒng)調(diào)度所帶來的額外開銷就會相對比較大;

2)對于在GPU上運行的計算來說,每個操作節(jié)點的實現(xiàn)都對應(yīng)著一個GPU的內(nèi)核函數(shù),而這個內(nèi)核函數(shù)的每一次執(zhí)行需要CPU調(diào)用顯卡驅(qū)動來啟動,因此也帶來了常數(shù)量級的額外開銷。這個開銷相對于計算量小的內(nèi)核函數(shù)的執(zhí)行來說是非常明顯的;

3)計算量小的操作節(jié)點往往難以挖掘出足夠的數(shù)據(jù)并行性,因此不能充分利用處理器硬件中的計算資源。

解決這一問題的主要思路是內(nèi)核融合(Kernel Fusion)。一些手工的優(yōu)化方法就運用了這一思想,比如NVIDIA基于CuDNN的RNN庫函數(shù)。它把整個循環(huán)神經(jīng)網(wǎng)絡(luò)實現(xiàn)成一個GPU的內(nèi)核函數(shù),因此獲得了非常好的性能。然而它的缺點也非常明顯,那就是不夠靈活和通用,無法應(yīng)用在其它網(wǎng)絡(luò)或一些變種的循環(huán)神經(jīng)網(wǎng)絡(luò)中。而我們更加關(guān)注的是如何在深度學(xué)習(xí)的系統(tǒng)中自動地對任意的網(wǎng)絡(luò)模型實施優(yōu)化。

目前在學(xué)術(shù)界和工業(yè)界已經(jīng)存在一些系統(tǒng)采用編譯的方法生成融合的內(nèi)核代碼,比如TVM、Halide和Taco等。這些系統(tǒng)使用Tensor Algebra作為前端表示方法,每個Tensor Algebra表達式進而可以被編譯成相應(yīng)的內(nèi)核代碼。而Tensor Algebra可以作為更低一層的中間表達被集成到深度學(xué)習(xí)系統(tǒng)中,也就是說高層的數(shù)據(jù)流圖可以先轉(zhuǎn)換成由Tensor Algebra表達式組成的代碼塊,再被編譯成可執(zhí)行的代碼。然而,這些系統(tǒng)對于可以進行融合的操作節(jié)點有很多限制,不能很好地融合多個非pointwise的操作,例如多個矩陣乘操作。然而,我們發(fā)現(xiàn)如果打破這一限制從而融合更多操作節(jié)點是可以帶來更多顯著的性能提升的。

在GPU的運行環(huán)境下融合多個非pointwise的操作具有一定的挑戰(zhàn)性,因為非pointwise的操作中輸入矩陣的每個元素都可能依賴于前一個操作的輸出矩陣中的許多不同位置的元素值,所以在這兩個操作之間需要插入Barrier同步原語。而在GPU中實現(xiàn)Barrier需要保證該內(nèi)核的所有線程塊在運行時都是保持活動狀態(tài)的,這意味著我們必須要求融合后的內(nèi)核采用有限個數(shù)的線程塊,但同時又能夠處理遠超過線程塊數(shù)量的數(shù)據(jù)塊。

為了解決這一問題,我們嘗試采用persistent-thread的線程塊模型,也就是說在融合后的內(nèi)核的整個生命周期啟動固定數(shù)目的線程塊并讓它們保持活動狀態(tài)。我們的優(yōu)化系統(tǒng)在產(chǎn)生融合的內(nèi)核代碼的過程中類似于解決一個裝箱(bin-pack)問題,即把待融合的子數(shù)據(jù)流圖中的每一個操作節(jié)點所要處理的數(shù)據(jù)塊分派給適當(dāng)?shù)幕顒泳€程塊,從而使得每個線程塊的負載盡可能均衡,并且保持操作節(jié)點的運算在原數(shù)據(jù)流圖中的并行性。

為了生成優(yōu)化的GPU內(nèi)核函數(shù),一個重要的考慮因素是線程塊和數(shù)據(jù)塊的合理劃分。然而這又依賴于一些非常復(fù)雜的因素,比如操作節(jié)點運算中計算和訪存復(fù)雜度的比率、GPU的shared memory的大小、寄存器文件的大小及分配方法等等。因此一個最優(yōu)的選擇是很難通過靜態(tài)的方法決定的。幸運的是,深度學(xué)習(xí)的迭代性以及需要相當(dāng)多的迭代才能收斂的特性使得我們可以利用早期的迭代過程來收集運行時的動態(tài)信息以幫助優(yōu)化系統(tǒng)做更明智的決定。

克服設(shè)備內(nèi)存資源限制

設(shè)備內(nèi)存的大小往往限制了可以處理的模型規(guī)模,解決這一問題的一個思路是對模型進行壓縮和量化。如今學(xué)術(shù)界和工業(yè)界已經(jīng)有大量的研究工作提出不同的壓縮和量化的方法,然而,在實際的應(yīng)用場景中使用壓縮和量化仍然是個繁瑣的迭代過程。在這個過程中,用戶可能會進行以下幾個方面的嘗試。

1)不同的壓縮方法。比如,是根據(jù)模型的參數(shù)值是否趨近于零,還是將其轉(zhuǎn)換成某種貢獻值之后趨近于零?壓縮時是不是考慮一定的結(jié)構(gòu)化(如果是面向GPU,可能需要壓縮成塊狀稀疏矩陣來提高運行效率)?量化的值點是根據(jù)值域平均劃分還是基于某種聚類來劃分?

2)不同的壓縮程度。要考慮在哪些層的神經(jīng)元參數(shù)上做壓縮,因為并不是所有層對壓縮后模型效果的敏感程度是一樣的;選擇不同的壓縮率或量化的比特數(shù)。

3)為了保持在大的壓縮率下仍然取得好的模型效果,壓縮過程可能需要是漸進的,比如一次壓縮10%,然后重新訓(xùn)練,重復(fù)此過程直到取得目標(biāo)的壓縮率。那么每次漸進過程的壓縮率就是一個需要調(diào)整的參數(shù)。

顯然,這樣一個繁瑣的過程需要一個好的工具來使之變得方便。這也是我們組正在關(guān)注的一個問題。我們正在嘗試擴展TensorFlow的API來使用戶可以在模型腳本中直接控制量化和壓縮的方法、對象、程度和過程。

壓縮和量化通常是用來解決模型部署時的性能和內(nèi)存資源不足的問題,而解決模型訓(xùn)練時內(nèi)存不夠的問題的思路之一是用計算來換內(nèi)存。比如,如果數(shù)據(jù)流圖中某一個操作節(jié)點的計算量很小,但是輸出的中間結(jié)果數(shù)據(jù)量很大,一個更好的處理方式是不在內(nèi)存中保存這個中間結(jié)果,而在后面需要用到它的時候再重新執(zhí)行這個操作節(jié)點的計算。當(dāng)然,重新計算還是引入了一定的額外開銷。

事實上,還存在另外一種解決這個問題的思路,就是將大的輸入數(shù)據(jù)就保存在CPU端的主存里,并將操作節(jié)點實現(xiàn)成流式的處理,將大的輸入數(shù)據(jù)分段拷貝進GPU的設(shè)備內(nèi)存,并通過異步的拷貝使得對每一分段的計算時間和下一分段的拷貝時間能夠重疊起來,從而掩蓋住數(shù)據(jù)拷貝的開銷。對于矩陣乘法這樣的操作,由于計算復(fù)雜度相對于訪存復(fù)雜度較高,當(dāng)分段較大的時候,計算時間和拷貝時間是可以達到完美重疊的。然而,如果所要進行的操作不是矩陣乘法,而是一些簡單的pointwise操作,計算的復(fù)雜度就沒有辦法和內(nèi)存拷貝的開銷相抵消。所以這種做法還需要跟內(nèi)核融合相結(jié)合。比如將矩陣乘法和后續(xù)的pointwise操作相融合,每一個分段的計算都會把該分段的矩陣乘和pointwise操作都做完,然后再處理下一個分段。

來源:機房監(jiān)控 http://www.dr4xxf.cn/   本文采集于網(wǎng)絡(luò),如有問題有聯(lián)系刪除

售前咨詢

專線:劉剛 13911133352

E-mail:112417434@qq.com

北京金恒智能系統(tǒng)工程技術(shù)有限責(zé)任公司 版權(quán)所有 Copyright 2007-2020 by Create-china.com.cn Inc. All rights reserved.

法律聲明:未經(jīng)許可,任何模仿本站模板、轉(zhuǎn)載本站內(nèi)容等行為者,本站保留追究其法律責(zé)任的權(quán)利!

電話:86+10-62104277/2248/4249 傳真:86+10-62104193-819 京ICP備10010038號-2網(wǎng)站XML

智慧機房

在線體驗

CREATE·機房監(jiān)控 體驗端  用戶名:Admin    密碼:12345 點擊體驗
在線咨詢 電話咨詢