Caffe、TensorFlow、MXnet三個開源庫對比+主流分類模型對比


庫名稱 開發語言 支持接口 安裝難度(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上進行計算,從而完成高速並行。在調用者的眼中代碼可能只是一個單線程的,數據只是分配到了一塊內存中,但是背后執行的過程實際上是並行的。MXnet在這分布式計算這點上做的比較好,可以充分利用多GPU資源。將指令(加減等)放入中間引擎,然后引擎來評估哪些數據有依賴關系,哪些能並行處理。定義好數據之后將它綁定到網絡中就能處理它了。

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

圖1 caffe的網絡結構(來源[7])

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")

1

圖2 MXNet的網絡結構(圖來源[2])

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也能動態改變。

1

圖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

[7] Blobs, Layers, and Nets: anatomy of a Caffe model

[8] Deep Learning in a Single File for Smart Devices


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM