Caffe、TensorFlow、MXnet三库对比
Caffe、TensorFlow、MXnet三庫對比
Google開源了他們內部使用的深度學習框架TensorFlow,結合之前開源的MXNet和Caffe,對三個開源庫做了一些討論。本文首先對三個庫有個整體的比較,再針對一些三者設計的不同數據結構、計算方式、gpu的選擇方式等方面做了比較詳細的討論。
表格1是三者的一些基本情況的記錄和比較。其中示例指的是官方給出的example是否易讀易理解,因為TensorFlow直接安裝python包,所以一開始沒有去下源代碼,從文檔中找example不如另外兩個下源碼直接。實際上TensorFlow更加像一套獨立的python接口,它不止能夠完成CNN/RNN的功能,還見到過有人用它做Kmeans聚類。這個表主觀因素比較明顯,僅供參考。
1.基本數據結構
caffe的數據存儲類blob,當把數據可以看成是一個N維的c數組,它們的存儲空間連續。例如存儲圖片是4維(num, channel, height, width),變量(n,k,h,w)在數組中存儲位置為((n*K+k)*H+h)*W+w。blob有以下三個特征:
-
兩塊數據,一個是原始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的速度比很多開源框架都要差一點。
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已經能夠很好的解決顯存不夠的問題,再加上模型并行會有額外的通信開銷,因此開源框架采用了數據并行,用來提高并行度。
Caffe — Deep learning in PracticeCaffe能做什么?
-
定義網絡結構
-
訓練網絡
-
C++/CUDA?寫的結構
-
cmd/python/Matlab接口
-
CPU/GPU工作模式
-
給了一些參考模型&pretrain了的weights
?
為什么選擇caffe?
-
模塊化做的好
-
簡單:修改結構無需該代碼
-
開源:共同維護開源代碼
?
環境:
-
$ lsb_release -a?
Distributor ID: Ubuntu?
Description: Ubuntu 12.04.4 LTS?
Release: 12.04?
Codename: precise
-
$ cat /proc/version?
Linux version 3.2.0-29-generic (buildd@allspice) (gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5) ) #46-Ubuntu SMP Fri Jul 27 17:03:23 UTC 2012
-
Vim + Taglist + Cscope
?
整體結構:
定義CAFFE為caffe跟目錄,caffe的核心代碼都在$CAFFE/src/caffe?下,主要有以下部分:net, blob, layer, solver.
-
net.cpp:?
net定義網絡,?整個網絡中含有很多layers,?net.cpp負責計算整個網絡在訓練中的forward, backward過程,?即計算forward/backward?時各layer的gradient。
?
-
layers:?
在$CAFFE/src/caffe/layers中的層,在protobuffer (.proto文件中定義message類型,.prototxt或.binaryproto文件中定義message的值)?中調用時包含屬性name,?type(data/conv/pool…),?connection structure (input blobs and output blobs),layer-specific parameters(如conv層的kernel大小)。定義一個layer需要定義其setup, forward?和backward過程。
?
-
blob.cpp:?
net中的數據和求導結果通過4維的blob傳遞。一個layer有很多blobs,?e.g,
-
對data,weight blob大小為Number ? ? ? * Channels * Height * Width,?如256*3*224*224;
-
對conv層,weight blob大小為?? ? ? Output?節點數?* Input?節點數?* Height * Width,如AlexNet第一個conv層的blob大小為96 ? ? ? x 3 x 11 x 11;
-
對inner product?層,?weight blob大小為?? ? ? 1 * 1 * Output節點數?* Input節點數;?bias blob大小為1 ? ? ? * 1 * 1 * Output節點數(?conv層和inner product層一樣,也有weight和bias,所以在網絡結構定義中我們會看到兩個blobs_lr,第一個是weights的,第二個是bias的。類似地,weight_decay也有兩個,一個是weight的,一個是bias的);?
-
?
blob中,mutable_cpu/gpu_data()?和cpu/gpu_data()用來管理memory,cpu/gpu_diff()和?mutable_cpu/gpu_diff()用來計算求導結果。
?
-
slover.cpp:?
結合loss,用gradient更新weights。主要函數:?
Init(),?
Solve(),?
ComputeUpdateValue(),?
Snapshot(), Restore(),//快照(拷貝)與恢復?網絡state?
Test();
?
在solver.cpp中有3中solver,即3個類:AdaGradSolver,?SGDSolver和NesterovSolver可供選擇。
?
關于loss,可以同時有多個loss,可以加regularization(L1/L2);
?
Protocol buffer:
上面已經將過,?protocol buffer在?.proto文件中定義message類型,.prototxt或.binaryproto文件中定義message的值;
Caffe?
Caffe的所有message定義在$CAFFE/src/caffe/proto/caffe.proto中。
Experiment?
在實驗中,主要用到兩個protocol buffer: solver的和model的,分別定義solver參數(學習率啥的)和model結構(網絡結構)。
?
技巧:
-
凍結一層不參與訓練:設置其blobs_lr=0
-
對于圖像,讀取數據盡量別用HDF5Layer(因為只能存float32和float64,不能用uint8,?所以太費空間)
?
訓練基本流程:
數據處理?
法一,轉換成caffe接受的格式:lmdb, leveldb, hdf5 / ? ? ?.mat, list of images, etc.;法二,自己寫數據讀取層(如https://github.com/tnarihi/tnarihi-caffe-helper/blob/master/python/caffe_helper/layers/data_layers.py)
定義網絡結構
配置Solver參數
訓練:如?caffe train -solver solver.prototxt ? ? ?-gpu 0
(有刪節....)
TensorFlowTensorFlow是谷歌基于DistBelief進行研發的第二代人工智能學習系統,其命名來源于本身的運行原理。Tensor(張量)意味著N維數組,Flow(流)意味著基于數據流圖的計算,TensorFlow為張量從圖象的一端流動到另一端計算過程。TensorFlow是將復雜的數據結構傳輸至人工智能神經網中進行分析和處理過程的系統。
TensorFlow可被用于語音識別或照片識別等多項機器深度學習領域,通過對2011年開發的深度學習基礎架構DistBelief進行了各方面的改進,它可在小到一部智能手機、大到數千臺數據中心服務器的各種設備上運行。TensorFlow將完全開源,任何人都可以用。
支持算法:
ensorFlow 表達了高層次的機器學習計算,大幅簡化了第一代系統,并且具備更好的靈活性和可延展性。TensorFlow一大亮點是支持異構設備分布式計算,它能夠在各個平臺上自動運行模型,從電話、單個CPU / GPU到成百上千GPU卡組成的分布式系統。?
從目前的文檔看,TensorFlow支持CNN、RNN和LSTM算法,這都是目前在Image,Speech和NLP最流行的深度神經網絡模型。
MXNetMXNet is a deep learning framework designed for both efficiency and flexibility. It allows you to mix the flavours of deep learning programs together to maximize efficiency and your productivity。
mxnet 有潛力成為一個非常優秀的深度學習的框架。足夠靈活,速度足夠快,擴展新的功能比較容易。mxnet 透過 parameter server 能夠直接做到多機多卡并行,透過 mshdow 可以寫一份代碼同時可以在 cpu 和 gpu 上面運行。總體來說, mxnet 是一套非常棒的深度學習的工具。
小結上面針對三個框架的不同方面進行了一些分析與比較,可以看出TensorFlow和MXNet有一些相似的地方,都是想做成更加通用的深度學習框架,貌似caffe2也會采用符號計算,說明以后的框架會更加的偏向通用性和高效,個人最喜歡的是caffe,也仿造它和cuda-convnet的結構寫過卷積網絡,如果是想提高編程能力可以多看看這兩個框架的源碼。而MXNet給人的感覺是非常用心,更加注重高效,文檔也非常的詳細,不僅上手很容易,運用也非常的靈活。TensorFlow則是功能很齊全,能夠搭建的網絡更豐富而不是像caffe僅僅局限在CNN。總之框架都是各有千秋,如何選擇也僅憑個人的喜好,然而google這個大殺器一出現引起的關注度還是最大的,雖然現在單機性能還不夠好,但是看著長長的開發人員名單,也只能說大牛多就是任性。
from:http://www.wtoutiao.com/p/1derBi1.html
........本文轉載整理自互聯網。
參考:
[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三库对比的全部內容,希望文章能夠幫你解決所遇到的問題。