TensorFlow、MXNet、PaddlePaddle三個開源庫對比
本文從定位、框架使用、分散式構成三個方面比較了TensorFlow、MXNet、PaddlePaddle三個框架。
從深度學習開始流行,到深度學習框架的迭代,到各類實際應用的出現,不過短短几年時間。TensorFlow剛出的那段時間,簡單對比過TensorFlow、MXNet、caffe三個框架,有些看法可能也不夠準確,到了今天,TensorFlow、MXNet作為國內風頭很盛的框架迭代了多個版本, caffe幾乎沒怎麼更新了, 因此就不再討論caffe了,而是看看百度推出的開源框架PaddlePaddle,本文主要對比一下TensorFlow[1]、MXNet[2]、PaddlePaddle[3]在用戶實現上的一些異同。先從三個框架的定位開始。
1. 定位
其實發展到現在,各個框架對自己的定位都不相同,硬要說哪個框架最好沒什麼必要,結合自身需求找到合適的用就夠了(實驗室的伺服器不太方便拿來折騰,本文就不比較運算速度了,可以參考[4][5])。而框架的定位從它們的網站標題中就完全可以看出來。
TensorFlow: An open-source software library for Machine Intelligence
TensorFlow想做的是人工智慧的演算法引擎,它不僅提供了深度學習的基本元件例如卷積、pooling、lstm等,提供很多基本計算操作,在這一年還圍繞著演算法開發推出了TensorFlow Serving用於將演算法動態部署到線上[6]、想取代scikit-learn的tf.contrib.learn[7]、將不同尺寸的輸入處理成相同規模用於批處理的TensorFlow Fold[8]、在移動平台上跑演算法[9]、支持Java/Go語言的介面、分散式實例等等。這些都可以看出TensorFlow在不斷擴張版圖,它不只是一個框架提供一些API供用戶調用,也同時在圍繞著演算法推出各種配套服務。也許由於TensorFlow的擴張,做優化的人不夠多,導致現在運行效率就算是分散式版本都比其他框架都要慢[4],而且版本間有時候函數介面還老不兼容。最新的1.0的版本說Inception v3神經網路的訓練速度提升了58倍[10],個人覺得tf底層實現不會大改,如果要提速可能需要針對各個網路單獨設計優化版本。
MXNet: Flexible and Efficient Library for Deep Learning
MXNet對自己的定位是一個flexible和efficient的深度學習框架,它的重點放在了深度學習演算法上面,而針對兩個特性,前者是說它支持命令式和聲明式兩種編程方式[11],比如說做一道菜,TensorFlow就必須按照規定好的步驟熱鍋、放油、放菜、放鹽等一步步執行,而MXNet則能在中間過程做點別的事情,假如味道淡了再放點調味料,假如又想加別的菜了也可以加進去,所以說它更靈活,其次還體現在支持多種語言,從最早的R/Julia到現在增加了對Go/Matlab/Scala/Javascript的支持。高效性則是指MXNet的分散式並行計算性能好、程序節省內存,在[4][5]中可以看到在多GPU上表現非常好,幾乎能做到線性加速。內存方面比較能說明問題的是這個框架一推出的時候就支持在移動設備上運行神經網路[12]。TensorFlow開始橫向拓展服務時,MXNet仍舊繼續優化技術,提供更多的operators、優化內存相關操作、提高並行效率等[13]。並且去年十月份提出了NNVM[14],將代碼實現和硬體執行兩個部分隔離開,使得不同的框架不同語言實現的代碼可以無差別執行在不同硬體之上。但這一年MXNet都沒有產生一個大的社區,有同學說遇到問題還需要自己去查閱修改源碼,導致使用門檻還是有一些高。但是16年11月份亞馬遜將MXNet選為了官方框架,後續估計會提供非常簡潔的雲計算服務,用戶只需要提交網路配置文件和數據就夠了,使用會成為一件簡便的事情。
PaddlePaddle: Open and Easy-to-Use Deep Learning Platform for Enterprise and Research
PaddlePaddle是16年9月份開源的,它對自己的定位是easy to use,這點做的很好,它將一些演算法封裝的很好,如果僅僅只需要使用現成的演算法(VGG、ResNet、LSTM、GRU等等),源碼都不用讀,按照官網的示例執行命令,替換掉數據、修改修改參數就能跑了,特別是NLP相關的一些問題,使用這個庫比較合適,並且沒有向用戶暴露過多的python介面。它的中文文檔相對友好,但是中英文文檔數量都有點少,主程序是個c++程序,所以源碼閱讀還挺方便,但是由於像caffe一樣按照功能來構造整個框架,二次開發要從c++底層寫起,使用已有的演算法沒問題,但想做一些新功能會麻煩一些。做科研的話這個庫可能不是很合適,它的文檔比較注重怎麼用它已經實現好的網路,而不是怎麼寫網路,比較適合需要成熟穩定的模型來處理新數據的情況。它的分散式部署做的很好,目前是唯一支持Kubernetes的深度學習庫(感興趣可以參考[15])。
2. 使用構成
這個部分簡單談談從我們用戶角度來看各個框架是怎麼設計和使用的。
tensorflow出發點是將一個演算法表示成一張有向計算圖,並提供了TensorBoard這樣一個工具用於可視化演算法[16],如下圖的節點和連線,包括了計算、數據以及控制關係。演算法中涉及到的任何計算都抽象成符號operation,例如圖中的conv、concat、add等橢圓形的計算節點,而演算法涉及到的數據則是tensor,它在節點之間流動,連線上還展示了這個tensor的shape,有向圖中還有一種數據節點variable,它表示的是某個變數(權重或者輸入輸出),可以通過它來控制tensor的讀寫,它能像tensor一樣作為計算節點的輸入。tensor的流動通過連接有向圖的實線表示,控制依賴control dependencies通過虛線箭頭表示,箭頭的起始節點執行完畢才執行結束節點,session控制tensor流動到何處停止。因此使用TensorFlow需要先定義計算圖,然後再把數據往裡傳得到輸出。它沒有一個嚴格的前向傳輸後向傳輸的概念,求解梯度通過optimizer來控制,如果數據flow到了optimizer的位置,會對前面需要求導的變數自動求導並更新。
圖1 TensorFlow計算圖(圖片來源[17])
MXNet也是將演算法表達成了有向計算圖,將數據和計算表達成有向圖中的節點,與TensorFlow不同的是,MXNet將計算圖中每一個節點,包括數據節點variable、基本計算floor、神經網路操作pooling都封裝在symbol裡面,而TensorFlow將數據節點、基本計算、神經網路操作封裝成了不同的類,所以它們之間流通需要通過tensor,而MXNet計算圖的節點輸出類型統一是symbol,通過outputs訪問symbol中的NDarray數據。當構建好計算圖的節點、連接方式,就通過executor來啟動計算,包括計算圖的前向計算輸出和反向計算導數。MXNet為訓練深度學習實現了Model/Module兩個類,Model在executor上又封裝了一層,實現了feedforward功能,將forward和backward整合在了一起,用戶直接調用feedforward.fit即可完成訓練、更新參數。而Module的介面好像也差不多,官網說Model只是為了提供一個介面方便訓練,Module是為了更高一層的封裝。
paddle的架構挺像caffe的,基於神經網路中的功能層來開發的,一個層包括了許多複雜的操作,例如圖1中右邊展開的所有操作合起來可以作為這裡的一個卷積層。它將數據讀取DataProvider、功能層Layers、優化方式Optimizer、訓練Evaluators這幾個分別實現成類,組合層構成整個網路,但是只能一層一層的累加還不夠實用,為了提高靈活性,額外設置了mixed_layer用來組合不同的輸入,如下圖2所示。但是這種比較粗粒度的劃分就算能組合不同輸入也不會像上面的靈活,比如add和conv這種操作在上面兩種框架中是屬於同一層面的,而在pd中則會是conv裡面包含add。看得出paddle在儘可能簡化構造神經網路的過程,它甚至幫用戶封裝好了networks類,裡面是一些可能需要的組合,例如卷積+batchNorm+pooling。它希望提供更簡便的使用方式,用戶不需要更改什麼主體文件,直接換數據用命令行跑。
圖2 PaddlePaddle功能層(圖片來源[18])
3. 分散式實現
首先說說深度學習演算法實現分散式需要幹什麼,分散式就是將一個參數巨多、數據居多的神經網路分成一些小任務放在多個機器多個顯卡上面執行,針對這兩個特性有兩種解決方案,參數多就把網路切分放在不同設備上,數據量大就多台機器同時執行相同代碼處理不同數據,前者稱為模型並行後者稱為數據並行[19]。神經網路相對其他分散式問題的特殊之處在於,不同機器上的網路參數在訓練時都會獨立的求導更新,然而這些參數在新的迭代開始之前要保證相對一致(由於可以非同步更新,不同機器之間可以不完全一樣,但肯定不能差別過大),因此就出現了Parameter Server[20],它保存了神經網路的權重等參數,決定了何時接收對這些數據的修改,決定了何時將修改後的數據發放到不同機器的計算節點上。假設需要訓練圖3中的神經網路,其中節點b和e是網路參數,machine 0和machine 1構成了模型並行,machine01和machine23構成了數據並行,中間的是參數伺服器,用於收發參數。目前三個框架都說支持模型並行和數據並行,從用戶實現上來看還是各有不同。
圖3 分散式神經網路
tf不同的功能以job劃分,例如運行整個computation graph是一個功能,作為parameter server存儲更新交換參數是一個功能。job由一系列task組成,每個task是一個進程,它完成指定的工作,計算、傳輸、讀寫等等。在tf的分散式實現中,用戶要實現的分散式程序主要是兩個部分,分別是graph的配置和集群的配置,client需要定義computation graph的結構,節點放在哪個job/task上,並且創建session,通過session請求graph計算到什麼地方,一個client對應一個computation graph,如果採用了數據並行,那麼就會產生多個graph。集群配置確定了有多少台機器,哪台機器執行哪個task。具體的代碼實現參考[21]。
tf沒有專門實現paramter server,而是實現了server,server對象負責交換數據,但不是只交換網路的參數,只要涉及到不同設備間要交換的數據都是由server管理,例如下圖中machine0的device 0和device 1之間交換網路的輸入輸出,因此,在實現神經網路時一般需要將網路參數放在稱為ps的job中,從而在網路運行時自動的更新參數。一個task會實例化一個server對象,不同機器之間交換數據的協議有多種,例如gRPC、RDMA等。然後手動在不同的機器上分別執行程序,如下圖所示。
圖4 TensorFlow各台機器涉及到的內容
MXNet通過kvstore實現parameter server從而實現多機運行程序,設備之間傳輸是通過確定數據所在的context後相互交換NDArray。從15年推出的時候就已經支持分散式了,它將網路分散式訓練的過程已經封裝好,用戶只需要確定網路的配置,哪些操作放在哪個GPU之上,開放給用戶的介面是Module類的fit函數,這個函數內部會自動創建kvstore對象,在訓練的時候梯度和權重會自己push/pull。啟動分散式程序也不需要自己手動在多台機器上執行命令,MXNet封裝好了launch.py,傳入機器個數、主機ip等就能在一台機器上啟動多台機器運行程序。
圖5 MXNet各台機器涉及到的內容
PaddlePaddle的分散式結構主要有兩個部分,trainer和parameter server。前者是配置網路,功能層、優化演算法的python介面封裝在了trainer_config_helpers類中,用戶可以使用這些介面配置自己的網路,後者沒有將介面放出來給用戶使用,而是在c++程序中實現的,再通過python來調用c++程序。pd給的例子中通過fabric庫來啟動分散式程序,可以做到在一台機器上啟動多台機器。在parameter server的使用上,pd針對一個網路可以擁有多個參數伺服器ps,每個ps負責一部分的網路參數,與所有的trainers進行交換數據,如下圖所示。
圖5 PaddlePaddle分散式結構(圖片來源[22])
4. 小結
零零碎碎聊了一些各個框架中我比較關注的內容,作為Caffe的真愛粉,這三個框架我沒有什麼偏好,各有各的優點各有各的缺點,都有很多值得學習的地方。寫之前對PaddlePaddle的印象還挺不錯的,沒想到文檔資料並不多,github上面的star雖然有4400+,但是感覺用的人好少,官方的文件對這個框架本身的東西介紹也少,重心放在了怎麼使用上面。就使用上來看,周圍的同學反而用Keras的比較多,有條件的話其實都下載試一試才能確定哪個更適合自己。
個人理解有限,如果文章有不對的地方,歡迎批評指正。
-馬上學習AI挑戰百萬年薪-
※DeepMind提出「SACX」學習範式,訓練機器人解決稀疏獎勵任務
※清華大學楊殿閣教授:高級別自動駕駛所需要的關鍵技術突破
TAG:AI講堂 |