導讀 : 微軟數(shù)據(jù)科學家Ilia Karmanov做了一個項目,使用高級API測試8種常用深度學習框架的性能(因為Keras有TF,CNTK和Theano,所以實際是10種)。Karmanov希望這個項目能夠幫助數(shù)據(jù)科學家更好地跨框架進行深度學習。
Github地址:https://github.com/ilkarman/DeepLearningFrameworks
Medium文章:https://medium.com/@iliakarmanov/neural-net-in-8-frameworks-lessons-learned-6a5e8e78b481
Karmanov表示,他這個項目的目標是創(chuàng)建一個深度學習框架的羅塞塔石碑,讓數(shù)據(jù)科學家能夠輕松地將他們在一個框架上的專長轉移到另一個框架上(而不是從頭開始學習)。具體說,就是在8種最常用的框架上構建同一個神經網(wǎng)絡。而且,有了這樣一個模型后,也就有了比較各個框架的基準,各個框架的訓練時間和默認選項也變得更加透明。
Karmanov發(fā)現(xiàn),許多在線教程都使用低級別的API,雖然寫很詳細,但對于大多數(shù)用例而言,除非想要創(chuàng)建新的層,否則意義不大。因此,他在項目中使用了最高級別的API,以便更容易地在框架之間進行比較。
結果證明,一旦使用更高級的API,不同框架的代碼結構實際上變得非常相似,并且可以粗略地表示為:
加載數(shù)據(jù);x_train,x_test,y_train,y_test = cifar_for_library(channel_first=?, one_hot=?)
生成CNN符號(通常在最后的dense層上沒有激活)
指定損失(交叉熵與softmax一起),優(yōu)化和初始化權重 + session
使用custom迭代器訓練訓練集中的mini-batch
從測試集中預測全新的mini-batch
評估準確性
本質上這里是在對一系列確定的數(shù)學運算(盡管是隨機初始化的)進行比較,因此在結果中比較各個框架的準確性并沒有什么意義。Karmanov將精度作為一個去匹配(而非對比)的指標,確保比較的是相同的模型架構。
結果:Caffe2、MXNet表現(xiàn)不俗
硬件是Nvidia K80 GPU,環(huán)境是Ubuntu,所有框架都是最新版本:
但是,比較訓練速度意義不大
雖然對10大常用框架進行了對比,但Karmanov進一步在他的Medium文章里解釋了,比較速度并沒有意義:
使用本地數(shù)據(jù)加載器可能會省掉幾秒鐘(實際上意義也不大),因為shuffle是異步執(zhí)行的。但是,對于常規(guī)項目(而不是這里的這個實驗),數(shù)據(jù)不太可能放進RAM里,還需要大量的預處理和數(shù)據(jù)增強。這就是數(shù)據(jù)加載器派上用場的地方。Karmanov表示,Facebook的賈揚清對他的這一項目給予了很多幫助,賈揚清告訴他,F(xiàn)acebook的好幾個in-production網(wǎng)絡,最大瓶頸都是I/O,如果想要實現(xiàn)一流的性能,賈揚清建議最好使用異步I/O,這樣會有很大的幫助。
其次,Karmanov在這個示例中只使用了幾層(conv2d,max_pool2d,dropout,全連接層)。平時工作中的項目可能會有3D卷積、GRU,LSTMS等。
你能很輕松地添加自定義的層,這些層的運行速度會影響你選擇用什么框架。所以在這里比較速度也沒多大用。能夠用Python代碼編寫一個自定義層并快速執(zhí)行它才是研究項目的關鍵
在實際應用中,你會用到TensorBoard這樣的高級日志來查看模型是否收斂,幫助調整超參數(shù)。但在這個例子中并不涉及。
以下是Karmanov在所有框架上匹配訓練精度,參考Github上所有issue/Pull request后的一些見解:
1. 上面的框架(除了Keras),為了方便比較,都嘗試使用相同級別的API,所以都使用相同的生成函數(shù)。對于MXNet和CNTK,我嘗試了一個更高級別的API,使用框架的訓練生成器函數(shù)。這個例子中速度的提升是可以忽略的,因為整個數(shù)據(jù)集作為NumPy數(shù)組加載到RAM中,每個epoch完成的處理是就是一次shuffle。我懷疑框架的生成器運行了異步shuffle。奇怪的是,NXNet和CNTK似乎在batch級別而不是observation級別上shuffle,因此測試精度稍微降低(至少在10個epoch之后)。如果有IO,或者有預處理和數(shù)據(jù)增強的情況,custom生成器對性能的影響將會更大。
2. 啟用CuDNN的auto-tune/窮舉搜索參數(shù)(為固定大小的圖像選擇最有效的CNN算法)能夠大幅提升性能。在Caffe2,PyTorch和Theano,這個功能得手動開啟。CNTK,MXNet和Tensorflow則是默認啟用這項功能。Chainer是什么情況我還不清楚。揚清說,cudnnGet(默認)和cudnnFind之間的性能提升在Titan X GPU上要小得多;在這里,K80 +新的cudnn看來使問題更加突出了。在目標檢測時,不論組合為何,運行cudnnFind都嚴重影響了性能回歸,所以在目標檢測時應該禁用exhaustive_search
3. 使用Keras時,選擇與后端框架匹配的[NCHW]排序非常重要。CNTK是最先是針對通道(channel)運算的,但我不小心把Keras配置為最后用通道了。結果每個批次都必須改變順序,嚴重降低了性能。
4. Tensorflow,PyTorch,Caffe2和Theano需要向pooling層提供一個布爾值,表示有沒有在訓練(這對測試精度有很大影響,72%比77%)。在這種情況下,不應該使用dropout來進行測試。
5. TensorFlow有點煩人,需要做兩個調整:啟用TF_ENABLE_WINOGRAD_NONFUSED,以及將維度最先(而不是最后)提供給通道(data_format='channels_first')可以提升速度。啟用WINOGRAD進行卷積,當然也可以提升TF做后端的Keras
6. 對大多數(shù)函數(shù)而言,Softmax通常跟cross_entropy_loss() 捆綁在一起,如果你在最后的全連接層上需要激活,最好檢查一下,這樣可以節(jié)省時間避免做兩次
7. 不同框架的內核初始化函數(shù)可能會有所不同(我發(fā)現(xiàn)這對準確性有+/- 1%的影響),只要有可能我都會指定xavier/glorot
8. SGD-momentum的實現(xiàn),我需要關閉unit_gain(在CNTK是默認打開的)來匹配其他框架的實現(xiàn)
9. Caffe2對網(wǎng)絡的第一層(no_gradient_to_input = 1)有一個額外的優(yōu)化,通過不計算輸入的梯度,使速度有一個較小的提升。很可能,TensorFlow和MXNet是默認啟用這項功能的。但是,對于一些研究目的和像DeepDream這樣的項目,計算這個梯度可能還是有用的
10. 在max-pooling之后(而不是之前)應用ReLU激活意味著在降維后執(zhí)行計算,這會省掉幾秒鐘的時間。在MXNet上面,這減少了3秒鐘的時間。
你們最喜歡哪種開源框架呢,你們又經常使用哪個呢,歡迎大家投票分享!
聯(lián)系客服