【开源】Caffe、TensorFlow、MXnet三个开源库对比
from:http://www.wtoutiao.com/p/1cbxddO.html
最近Google開源了他們內部使用的深度學習框架TensorFlow[1],結合之前開源的MXNet[2]和Caffe[3],對三個開源庫做了一些討論,其中只有Caffe比較仔細的看過源代碼,其他的兩個庫僅閱讀官方文檔和一些研究者的評論博客有感,本文首先對三個庫有個整體的比較,再針對一些三者設計的不同數據結構、計算方式、gpu的選擇方式等方面做了比較詳細的討論。表格1是三者的一些基本情況的記錄和比較。其中示例指的是官方給出的example是否易讀易理解,因為TensorFlow直接安裝python包,所以一開始沒有去下源代碼,從文檔中找example不如另外兩個下源碼直接。實際上TensorFlow更加像一套獨立的python接口,它不止能夠完成CNN/RNN的功能,還見到過有人用它做Kmeans聚類。這個表主觀因素比較明顯,僅供參考。??????????????????????????
庫名稱 | 開發語言 | 支持接口 | 安裝難度(ubuntu) | 文檔風格 | 示例 | 支持模型 | 上手難易 |
Caffe | c++/cuda | c++/python/matlab | *** | * | *** | CNN | ** |
MXNet | c++/cuda | python/R/Julia | ** | *** | ** | CNN/RNN | * |
TensorFlow | c++/cuda/python | c++/python | * | ** | * | CNN/RNN/… | *** |
????????1.基本數據結構
庫名稱 | 數據結構名稱 | 設計方式 |
Caffe | Blob | 存儲的數據可以看成N維的c數組,有(n,k,h,w)四個維數,一個blob里面有兩塊數據空間保存前向和后向求導數據 |
MXNet | NDArray | 提供cpu/gpu的矩陣和矢量計算,能夠自動并行 |
TensorFlow | tensor | 相當于N維的array或者list,維數可變,數據類型一旦定義不能改變 |
????????caffe的數據存儲類blob,當把數據可以看成是一個N維的c數組,它們的存儲空間連續。例如存儲圖片是4維(num, channel, height, width),變量(n,k,h,w)在數組中存儲位置為((n*K+k)*H+h)*W+w。blob有以下三個特征[4]:
-
兩塊數據,一個是原始data,一個是求導值diff
-
兩種內存分配方式,一種是分配在cpu上,一種是分配在gpu上,通過前綴cpu、gpu來區分
-
兩種訪問方式,一種是不能改變數據,一種能改變數據
????????Caffe最讓我覺得精妙的地方在于一個blob保存前向和后向的數據。雖然就代碼本身而言,前向數據是因為輸入數據不同而改變,后向求導是因為求導不同而改變,根據SRP原則,在一個類里面因為兩個原因而改變了數據這種是不合適的設計。但是從邏輯層面,前向數據的改變引起了反向求導的不同,它們實際上是一起在改變,本身應該是一個整體。所以我很喜歡這個設計,雖然基本上其他框架中都是將兩個數據給分離出來,caffe2也不知是否保留。
????????MXNet的NDArray類似numpy.ndarray,也支持把數據分配在gpu或者cpu上進行運算。但是與numpy和caffe不同的是,當在操作NDArray,它能自動的將需要執行的數據分配到多臺gpu和cpu上進行計算,從而完成高速并行。在調用者的眼中代碼可能只是一個單線程的,數據只是分配到了一塊內存中,但是背后執行的過程實際上是并行的。將指令(加減等)放入中間引擎,然后引擎來評估哪些數據有依賴關系,哪些能并行處理。定義好數據之后將它綁定到網絡中就能處理它了。
????????TensorFlow的tensor,它相當于N維的array或者list,與MXNet類似,都是采用了以python調用的形式展現出來。某個定義好的tensor的數據類型是不變的,但是維數可以動態改變。用tensor rank和TensorShape來表示它的維數(例如rank為2可以看成矩陣,rank為1可以看成向量)。tensor是個比較中規中矩的類型。唯一特別的地方在于在TensorFlow構成的網絡中,tensor是唯一能夠傳遞的類型,而類似于array、list這種不能當成輸入。
????????值得一提的是cuda-convnet采用的數據結構是NVMatrix,NV表示數據分配在gpu上,即將所有變量都當成矩陣來處理,它只有兩維,它算是最早用cuda實現的深度學習框架,而上面三種框架都采用了多維可變維的思想,這種可變維在用矩陣做卷積運算的時候是很有效的。
????????2.網絡實現方式
????????Caffe是典型的功能(過程)計算方式,它首先按照每一個大功能(可視化、損失函數、非線性激勵、數據層)將功能分類并針對部分功能實現相應的父類,再將具體的功能實現成子類,或者直接繼承Layer類,從而形成了XXXLayer的形式。然后將不同的layer組合起來就成了net。
????????
????????圖1 caffe的網絡結構
????????MXNet是符號計算和過程計算混合[5],它設計了Symbol大類,提供了很多符號運算的接口,每個symbol定義了對數據進行怎樣的處理,symbol只是定義處理的方式,這步還并未真正的執行運算。其中一個需要注意的是symbol里面有Variable,它作為承載數據的符號,定義了需要傳遞什么樣的數據給某個Variable,并在后續的操作中將數據綁定到Variable上。下面的代碼是一個使用示例,它實現了將激勵函數連接到前面定義好的net后面,并給出了這一個symbol的名字和激勵函數類型,從而構造出net。下圖左邊部分是定義symbol的合集,中間將數據綁定到Variable上之后變成了右邊真正的執行流程圖。
????????
net = mx.symbol.Activation(data=net, name='relu1', act_type="relu")????????
????????圖2 MXNet的網絡結構
????????TensorFlow選擇的是符號計算方式,它的程序分為計算構造階段和執行階段,構造階段是構造出computation graph,computation graph就是包含一系列符號操作Operation和Tensor數據對象的流程圖,跟mxnet的symbol類似,它定義好了如何進行計算(加減乘除等)、數據通過不同計算的順序(也就是flow,數據在符號操作之間流動的感覺)。但是暫時并不讀取輸入來計算獲得輸出,而是由后面的執行階段啟動session的run來執行已經定義好的graph。這樣的方式跟mxnet很相似,應該都是借鑒了theano的想法。其中TensorFlow還引入了Variable類型,它不像mxnet的Variable屬于symbol(tf的operation類似mxnet的symbol),而是一個單獨的類型,主要作用是存儲網絡權重參數,從而能夠在運行過程中動態改變。tf將每一個操作抽象成了一個符號Operation,它能夠讀取0個或者多個Tensor對象作為輸入(輸出),操作內容包括基本的數學運算、支持reduce、segment(對tensor中部分進行運算。例如tensor長度為10,可以同時計算前5個,中間2個,后面三個的和)、對image的resize、pad、crop、filpping、transposing等。tf沒有像mxnet那樣給出很好的圖形解釋或者實例(可能因為我沒找到。。),按照自己的理解畫了一部分流程圖。有點疑惑的是,為什么要設計Variable,tf給出的一個alexnet的example源碼中,輸入數據和權重都設置成了Variable,每一層的輸出并未直接定義,按照tf的說法,只有tensor類型能夠在網絡中傳遞,輸出的類型應該是tensor,但是由于輸入和權重改變了,輸出應該也在隨著改變,既然如此,為何不只設計一個tensor,讓tensor也能動態改變。
????????
????????圖3 TensorFlow的computation graph
????????就設計而言,TensorFlow相對于其他兩個更像是一種通用的機器學習框架,而不是只針對cnn或rnn,但就現在的性能而言,tf的速度比很多開源框架都要差一點[6]。
????????3.分布式訓練
????????Caffe和TensorFlow沒有給出分布式的版本,MXNet提供了多機分布式,因而前兩者只有如何控制使用多gpu。Caffe通過直接在執行指令后面加上-gpu 0,1來表示調用兩個gpu0和1,只實現了數據并行,也就是在不同的gpu上執行相同網絡和不同數據,caffe會實例化多個solver和net讓每次處理的batch_size加倍。TensorFlow則能夠自己定義某個操作執行在哪個gpu上,通過調用with tf.device(‘/gpu:2’)表示接下來的操作要在gpu2上處理,它也是數據并行。MXNet通過執行腳本時指定多機節點個數來確定在幾臺主機上運行,也是數據并行。MXNet的多gpu分配和它們之間數據同步是通過MXNet的數據同步控制KVStore來完成的。
????????KVStore的使用首先要創建一個kv空間,這個空間用來在不同gpu不同主機間分享數據,最基本的操作是push和pull,push是把數據放入這個空間,pull是從這個空間取數據。這個空間內保存的是key-value([int, NDArray]),在push/pull的時候來指定到哪個key。下面的代碼將不同的設備上分配的b[i]通過key3在kv空間累加再輸出到a,從而完成了對多gpu的處理。這個是個非常棒的設計,提供了很大的自由度,并且為開發者減少了控制底層數據傳輸的麻煩。
????????
gpus = [mx.gpu(i) for i in range(4)] b = [mx.nd.ones(shape, gpu) for gpu in gpus] kv.push(3, b) kv.pull(3, out = a)????????之前有看過一篇論文,如何將卷積網絡放在多gpu上訓練,論文中有兩種方法,一種是常用的數據并行,另一種是模型并行。模型并行指的是將一個完整的網絡切分成不同塊放在不同gpu上執行,每個gpu可能只處理某一張圖的四分之一。采用模型并行很大程度上是因為顯存不夠放不下整個網絡的數據,而現在gpu的功能性能提高,一個gpu已經能夠很好的解決顯存不夠的問題,再加上模型并行會有額外的通信開銷,因此開源框架采用了數據并行,用來提高并行度。
????????4.小結
????????上面針對三個框架的不同方面進行了一些分析與比較,可以看出TensorFlow和MXNet有一些相似的地方,都是想做成更加通用的深度學習框架,貌似caffe2也會采用符號計算[5],說明以后的框架會更加的偏向通用性和高效,個人最喜歡的是caffe,也仿造它和cuda-convnet的結構寫過卷積網絡,如果是想提高編程能力可以多看看這兩個框架的源碼。而MXNet給人的感覺是非常用心,更加注重高效,文檔也非常的詳細,不僅上手很容易,運用也非常的靈活。TensorFlow則是功能很齊全,能夠搭建的網絡更豐富而不是像caffe僅僅局限在CNN。總之框架都是各有千秋,如何選擇也僅憑個人的喜好,然而google這個大殺器一出現引起的關注度還是最大的,雖然現在單機性能還不夠好,但是看著長長的開發人員名單,也只能說大牛多就是任性。
????????參考:
????????[1]http://tensorflow.org/
????????[2]http://mxnet.readthedocs.org/en/latest/index.html
????????[3]http://caffe.berkeleyvision.org/
????????[4][caffe]的項目架構和源碼解析
????????[5]如何評價Tensorflow和其它深度學習系統
????????[6]Imagenet Winners Benchmarking
總結
以上是生活随笔為你收集整理的【开源】Caffe、TensorFlow、MXnet三个开源库对比的全部內容,希望文章能夠幫你解決所遇到的問題。

- 上一篇: 大数据驱动下的微博社会化推荐
- 下一篇: TensorFlow 相关 URL