|
轉(zhuǎn)自:http://blog.csdn.net/stdcoutzyx/article/details/51645396
本片博文是參考文獻(xiàn)[1]的閱讀筆記,特此聲明 TensorFlow,以下簡(jiǎn)稱TF,是Google去年發(fā)布的機(jī)器學(xué)習(xí)平臺(tái),發(fā)布以后由于其速度快,擴(kuò)展性好,推廣速度還是蠻快的。江湖上流傳著Google的大戰(zhàn)略,Android占領(lǐng)了移動(dòng)端,TF占領(lǐng)神經(jīng)網(wǎng)絡(luò)提供AI服務(wù),未來(lái)的趨勢(shì)恰好是語(yǔ)音圖像以及AI的時(shí)代,而Google IO上發(fā)布的Gbot似乎正是這一交叉領(lǐng)域的初步嘗試。 TF的特點(diǎn)之一就是可以支持很多種設(shè)備,大到GPU、CPU,小到手機(jī)平板,五花八門(mén)的設(shè)備都可以跑起來(lái)TF。不得不說(shuō)這一點(diǎn)很有前瞻性,可以預(yù)見(jiàn)的是,mobile-end的用戶將會(huì)享受到越來(lái)越多的AI服務(wù)。說(shuō)個(gè)極端,說(shuō)不定以后某天,單機(jī)版的AlphaGo會(huì)出現(xiàn)也是可以的。 話不多說(shuō),開(kāi)始正文。 Basic Concepts張量(Tensor)名字就是TensorFlow,直觀來(lái)看,就是張量的流動(dòng)。張量(tensor),即任意維度的數(shù)據(jù),一維、二維、三維、四維等數(shù)據(jù)統(tǒng)稱為張量。而張量的流動(dòng)則是指保持計(jì)算節(jié)點(diǎn)不變,讓數(shù)據(jù)進(jìn)行流動(dòng)。這樣的設(shè)計(jì)是針對(duì)連接式的機(jī)器學(xué)習(xí)算法,比如邏輯斯底回歸,神經(jīng)網(wǎng)絡(luò)等。連接式的機(jī)器學(xué)習(xí)算法可以把算法表達(dá)成一張圖,張量從圖中從前到后走一遍就完成了前向運(yùn)算;而殘差從后往前走一遍,就完成了后向傳播。 算子(operation)在TF的實(shí)現(xiàn)中,機(jī)器學(xué)習(xí)算法被表達(dá)成圖,圖中的節(jié)點(diǎn)是算子(operation),節(jié)點(diǎn)會(huì)有0到多個(gè)輸出,下圖是TF實(shí)現(xiàn)的一些算子。 每個(gè)算子都會(huì)有屬性,所有的屬性都在建立圖的時(shí)候被確定下來(lái),比如,最常用的屬性是為了支持多態(tài),比如加法算子既能支持float32,又能支持int32計(jì)算。 核(kernel)TF中還有一個(gè)概念是kernel,kernel是operation在某種設(shè)備上的具體實(shí)現(xiàn)。TF的庫(kù)通過(guò)注冊(cè)機(jī)制來(lái)定義op和kernel,所以可以通過(guò)鏈接一個(gè)其他的庫(kù)來(lái)進(jìn)行kernel和op的擴(kuò)展。 邊(edge)TF的圖中的邊分為兩種:
會(huì)話(Session)客戶端使用會(huì)話來(lái)和TF系統(tǒng)交互,一般的模式是,建立會(huì)話,此時(shí)會(huì)生成一張空?qǐng)D;在會(huì)話中添加節(jié)點(diǎn)和邊,形成一張圖,然后執(zhí)行。 下圖有一個(gè)TF的會(huì)話樣例和所對(duì)應(yīng)的圖示。 變量(Variables)機(jī)器學(xué)習(xí)算法都會(huì)有參數(shù),而參數(shù)的狀態(tài)是需要保存的。而參數(shù)是在圖中有其固定的位置的,不能像普通數(shù)據(jù)那樣正常流動(dòng)。因而,TF中將Variables實(shí)現(xiàn)為一個(gè)特殊的算子,該算子會(huì)返回它所保存的可變tensor的句柄。 Implementation首先是實(shí)現(xiàn)中的幾個(gè)部分:
TF的實(shí)現(xiàn)分為了單機(jī)實(shí)現(xiàn)和分布式實(shí)現(xiàn),在分布式實(shí)現(xiàn)中,需要實(shí)現(xiàn)的是對(duì)client,master,worker process不在同一臺(tái)機(jī)器上時(shí)的支持。此時(shí),關(guān)于這些進(jìn)程的調(diào)度,使用的是原始論文中參考文獻(xiàn)51的調(diào)度方式。關(guān)于分布式和單機(jī)的不同如下圖所示: Single-Device Execution構(gòu)建好圖后,使用拓?fù)渌惴▉?lái)決定執(zhí)行哪一個(gè)節(jié)點(diǎn),即對(duì)每個(gè)節(jié)點(diǎn)使用一個(gè)計(jì)數(shù),值表示所依賴的未完成的節(jié)點(diǎn)數(shù)目,當(dāng)一個(gè)節(jié)點(diǎn)的運(yùn)算完成時(shí),將依賴該節(jié)點(diǎn)的所有節(jié)點(diǎn)的計(jì)數(shù)減一。如果節(jié)點(diǎn)的計(jì)數(shù)為0,將其放入準(zhǔn)備隊(duì)列待執(zhí)行 Multi-Device Execution當(dāng)系統(tǒng)到了分布式情況下時(shí),事情就變得復(fù)雜了很多,還好前述調(diào)度用了現(xiàn)有的框架。那么對(duì)于TF來(lái)說(shuō),剩下的事情就是:
決定設(shè)備使用一個(gè)cost model算法來(lái)進(jìn)行預(yù)估時(shí)間,計(jì)算后使用貪心算法來(lái)分配設(shè)備。在決定設(shè)備的時(shí)候,也可以預(yù)先設(shè)置一些約束,比如,某個(gè)op只能在GPU上執(zhí)行等。 預(yù)估時(shí)間有兩種方法:
跨設(shè)備通信當(dāng)兩個(gè)需要通信的op在不同的機(jī)器上時(shí),就需要跨設(shè)備通信,當(dāng)它們需要通信時(shí),TF會(huì)在它們之間的聯(lián)系中添加Send和Recv節(jié)點(diǎn),通過(guò)Send和Recv之間進(jìn)行通信來(lái)達(dá)到op之間通信的效果。如下所示: 為了優(yōu)化網(wǎng)絡(luò)通信,TF會(huì)將相同的數(shù)據(jù)傳送合并,如a->b和a->c的傳送合并,這一點(diǎn)可以通過(guò)Send和Recv很方便的實(shí)現(xiàn)。而通過(guò)實(shí)現(xiàn)Send和Recv,將master節(jié)點(diǎn)的通信調(diào)度任務(wù)解放出來(lái),master就只需要向圖中的各個(gè)節(jié)點(diǎn)發(fā)出運(yùn)行命令就夠了,增加了系統(tǒng)的可擴(kuò)展性。 Send和Recv通過(guò)TCP或RDMA來(lái)傳輸數(shù)據(jù) 錯(cuò)誤處理在分布式系統(tǒng)中,常見(jiàn)的錯(cuò)誤來(lái)自于兩個(gè)方面:
當(dāng)錯(cuò)誤發(fā)生的時(shí)候,TF會(huì)將整個(gè)圖的計(jì)算停止,并從上一次保存的狀態(tài)重新執(zhí)行。為了保存狀態(tài),每個(gè)Variable的節(jié)點(diǎn)都去連接一個(gè)Save的節(jié)點(diǎn)。這些save節(jié)點(diǎn)會(huì)每隔一段時(shí)間或每隔幾次迭代運(yùn)行一次。
ExtensionsGradient Computation(梯度計(jì)算)連接式的機(jī)器學(xué)習(xí)算法往往需要使用梯度下降法來(lái)求取參數(shù),TF通過(guò)擴(kuò)展圖的方式實(shí)現(xiàn)了自動(dòng)求導(dǎo),TF做法如下: 對(duì)于每張計(jì)算圖,得到從輸入I到輸出C的路徑,并從C到I回溯,回溯過(guò)程中對(duì)于路徑上的每個(gè)節(jié)點(diǎn)A,添加另一個(gè)節(jié)點(diǎn)來(lái)計(jì)算A’來(lái)計(jì)算偏導(dǎo),在計(jì)算偏導(dǎo)的過(guò)程中,A’不僅僅將上一層傳下來(lái)的反向?qū)?shù)作為輸入,還可能將A的輸入和輸出也作為其輸入。 在執(zhí)行前向計(jì)算的時(shí)候,啟發(fā)式的優(yōu)化算法通過(guò)觀察圖中的節(jié)點(diǎn)的計(jì)算順序,來(lái)決定哪種操作放在哪個(gè)節(jié)點(diǎn)上,從而幫助用戶來(lái)內(nèi)存重用;當(dāng)啟發(fā)式的算法無(wú)效的時(shí)候,用戶還可以通過(guò)添加控制依賴來(lái)自行實(shí)現(xiàn)內(nèi)存上的優(yōu)化。 而當(dāng)反向傳播加入的時(shí)候,事情變得有點(diǎn)復(fù)雜,在正向計(jì)算中較前位置的計(jì)算數(shù)據(jù)在反向傳播的后期會(huì)被經(jīng)常用到。這就需要把這些數(shù)據(jù)存在內(nèi)存中,從而整個(gè)圖的內(nèi)存都將被占用,使得本來(lái)就少的GPU內(nèi)存更加的捉襟見(jiàn)肘。 有三種方法來(lái)對(duì)其進(jìn)行優(yōu)化:
Partial Execution(局部執(zhí)行)TF支持部分執(zhí)行,對(duì)于多輸出的TF圖,可能用戶只想獲取一個(gè)輸出,此時(shí)可以指定需要的輸入(feed)和輸出(fetch)值。然后TF會(huì)自動(dòng)計(jì)算該輸出的依賴,然后只計(jì)算必要的部分。 如上圖所示,指定b為輸入,f為輸出,那么此時(shí)d、e是不會(huì)被計(jì)算的。 Control Flow(控制流)雖然TF的圖已經(jīng)有了很強(qiáng)的表達(dá)能力,但還不夠,還需要控制流的表達(dá),比如已經(jīng)實(shí)現(xiàn)的Switch、Merge、Enter、Leave和NextIteration等一系列控制算子。 TF使用和MIT Token-Tagged machine相似的表示系統(tǒng),將循環(huán)的每次迭代標(biāo)記為一個(gè)tag,迭代的執(zhí)行狀態(tài)標(biāo)記為一個(gè)frame,但迭代所需的數(shù)據(jù)準(zhǔn)備好的時(shí)候,就可以開(kāi)始計(jì)算,從而多個(gè)迭代可以同時(shí)執(zhí)行。 對(duì)于分布式系統(tǒng)來(lái)說(shuō),控制循環(huán)的狀態(tài)是一個(gè)大問(wèn)題。而TF使用圖重寫(xiě)的方式來(lái)實(shí)現(xiàn)它,在圖切分的時(shí)候,添加一個(gè)小的狀態(tài)機(jī)來(lái)監(jiān)控迭代的開(kāi)始和結(jié)束, 而對(duì)于有梯度計(jì)算的圖來(lái)說(shuō),在有控制流的情況下,需要記錄各種狀態(tài),比如對(duì)于if算子,需要記錄哪個(gè)分支被運(yùn)行了;而對(duì)于循環(huán),需要記錄循環(huán)了幾次。TF仍然使用圖重寫(xiě)來(lái)實(shí)現(xiàn)記錄狀態(tài)的功能,細(xì)節(jié)不贅述了。 Input Operations(輸入操作)為Input也構(gòu)建了一個(gè)Node,來(lái)管理數(shù)據(jù)從硬盤(pán)到內(nèi)存的過(guò)程。往往需要提前將數(shù)據(jù)讀入進(jìn)來(lái)以減少內(nèi)存瓶頸。 Queues(隊(duì)列)TF實(shí)現(xiàn)了一個(gè)隊(duì)列來(lái)支持異步操作,EnQueue可以阻塞直到隊(duì)列中的空間足夠;DeQueue也可以阻塞直到隊(duì)列中一系列的要求得到滿足。 隊(duì)列有兩個(gè)典型應(yīng)用:
除了FIFO隊(duì)列外,TF還實(shí)現(xiàn)了一個(gè)shuffle隊(duì)列。 Containers(容器)普通的Cotainer可以長(zhǎng)期的存儲(chǔ)可變狀態(tài),但Container不止于此,用Container,甚至不同的會(huì)話中的圖之間也可以通過(guò)Container來(lái)共享狀態(tài)。 OptimizaitonTF給了用戶以極其易用的接口,這就需要底層來(lái)自動(dòng)的做很多優(yōu)化。 Common Subexpression Elimination用戶給出的圖定義中可能會(huì)存在重復(fù)的計(jì)算操作,TF使用Click(原始論文參考文獻(xiàn)12)中的算法來(lái)進(jìn)行圖的重復(fù)表達(dá)式的刪減 Controlling Data Combination and Memory Usage對(duì)于復(fù)雜的網(wǎng)絡(luò)模型,GPU是必須的;而對(duì)于GPU來(lái)說(shuō),它的內(nèi)存是不足的,因而要用良好的管理來(lái)提高GPU內(nèi)存的使用效率。 在這一點(diǎn)上,TF主要關(guān)注數(shù)據(jù)的網(wǎng)絡(luò)傳輸,這主要集中在Recv節(jié)點(diǎn)何時(shí)去遠(yuǎn)程讀取數(shù)據(jù),TF會(huì)自動(dòng)分析圖上的關(guān)鍵路徑,通過(guò)設(shè)置依賴的方式來(lái)使得非關(guān)鍵路徑上的數(shù)據(jù)傳輸如何不影響關(guān)鍵路徑。 Asynchronous Kernels異步核在執(zhí)行后立即返回,同時(shí)會(huì)執(zhí)行一個(gè)回調(diào)函數(shù)。這樣,可以防止等待計(jì)算完成的同時(shí)眼看著沒(méi)有做的IO任務(wù)也不做。即異步核也可以提升并行能力。異步核的典型樣例就是Recv節(jié)點(diǎn)和Enqueue和Dequeue操作。 Optimized Libraries for Kernel Implementations對(duì)于已經(jīng)存在的線性代數(shù)庫(kù)自然是要利用的,但TF團(tuán)隊(duì)對(duì)一些庫(kù)還擴(kuò)展了其對(duì)任意維度的tensor的支持。 常見(jiàn)的線性計(jì)算庫(kù)包括:
Lossy Compression在數(shù)據(jù)傳輸過(guò)程中,為了加快傳輸效率,往往需要對(duì)精度進(jìn)行壓縮。在TF中,傳輸之前將32bit的float轉(zhuǎn)變?yōu)?6float,在傳輸完之后再轉(zhuǎn)回來(lái),轉(zhuǎn)回來(lái)時(shí)用0補(bǔ)齊。 Common Programming Idioms上面講的都是一些系統(tǒng)級(jí)別的優(yōu)化,還有一些機(jī)器學(xué)習(xí)算法所用到的技巧。這里假定用戶都用SGD來(lái)求解機(jī)器學(xué)習(xí)算法。 Data Parallel Training通過(guò)數(shù)據(jù)并行的方式來(lái)提升SGD的效率,比如,假如每次SGD的mini-batch是1000個(gè)樣本,那么,切成10份,每份100個(gè),然后將模型復(fù)制10份,每份都將梯度傳到參數(shù)服務(wù)器上。 數(shù)據(jù)切分也分為同步和異步兩種方式,同步的切分是等待每個(gè)獨(dú)立的model傳上來(lái)的梯度都到齊后再進(jìn)行更新,這樣和一個(gè)大的batch沒(méi)有區(qū)別。異步的切分則是不用等待,每個(gè)獨(dú)立的模型的參數(shù)更新直接更新。 如下圖所示: Model Parallel Training還可以對(duì)模型進(jìn)行切分,讓模型的不同部分執(zhí)行在不同的設(shè)備上,這樣可以一個(gè)迭代的樣本可以在不同的設(shè)備上同時(shí)執(zhí)行。如下圖所示的LSTM模型: Concurrent Steps for Model Computation PipeLine為了充分利用同一臺(tái)設(shè)備的計(jì)算能力,TF會(huì)盡量讓相鄰的計(jì)算在同一臺(tái)設(shè)備上,這樣可以節(jié)省網(wǎng)絡(luò)開(kāi)銷,比如對(duì)于模型并行來(lái)說(shuō),如果放在同一個(gè)設(shè)備上,如下圖所示:
Related WorkTF出現(xiàn)之前,已經(jīng)有很多的類似的平臺(tái)了。
可以這么說(shuō),TF從他們每一個(gè)中都吸取了一些feature和設(shè)計(jì)思想。根據(jù)進(jìn)化論的觀點(diǎn),我不能說(shuō)TF要優(yōu)于他們,而要說(shuō),TF更能適應(yīng)當(dāng)前的需求。在之前寫(xiě)Parameter Server的時(shí)候我就隱隱的感覺(jué)到,一種設(shè)計(jì)的產(chǎn)生是和它的需求緊緊相關(guān)的,TF的設(shè)計(jì)可能會(huì)有很多人想到,但TF卻只能由google設(shè)計(jì)和實(shí)現(xiàn),因?yàn)樾枨蟆6鳷F的產(chǎn)生也是google大一統(tǒng)移動(dòng)和PC和Server的戰(zhàn)略需求。
TF與其他平臺(tái)的區(qū)別于聯(lián)系:
其他還有很多像TF那樣支持?jǐn)?shù)據(jù)流圖的分布式平臺(tái),比如:
Reference[1]. Abadi M, Agarwal A, Barham P, et al. Tensorflow: Large-scale machine learning on heterogeneous distributed systems[J]. arXiv preprint arXiv:1603.04467, 2016. |
|
|
來(lái)自: 雪柳花明 > 《TensorFLow練習(xí)匯總》