本次介紹一種記憶體利用率高且速度較快的卷積計算方法。 來自icml2017, 《mec: memory-efficient convolution for deep neural network》
目前的cnn模型中,全連線層往往在最後一層才會使用。 意思也就是說,網路的主體是由卷積層構成的。 因此,加快卷積層的計算對於整個網路的效能至關重要。
目前,卷積的計算大多採用間接計算的方式,主要有以下三種實現方式:
上面三種方法執行效率都還不錯,但對記憶體占用比較高,因為需要儲存中間結果或者臨時輔助變數。
本文的方法主要改進了im2col + gemm的策略,目的主要是減少記憶體消耗的同時順便提公升點速度。由於同樣可以利用目前成熟的矩陣運算庫,因此演算法的實現難度並不大。
下圖分別是直接計算卷積以及im2col + gemm的實現方式。 可見後者需要比較多的記憶體儲存乙個臨時矩陣(用於儲存im2col的結果)。
首先規定一下符號:
2.1 初級版本
這裡先介紹一下簡單情況下的mec的實現方式,我將其稱之為「初級版本」,因為裡面不考慮batchsize和channel這兩個維度。 雖然是「初級版本」,但想要理解還是需要熟悉上面figure1中im2col+gemm的計算方式(可參考知乎上的乙個高票回答,圖示很清楚,
下面給出演算法流程以及乙個示例(7x7輸入,3x3卷積核,步長為1):
上面的演算法偽**可能太複雜了,我來個中文版本的示例解說:
1.由於是3x3卷積核,且步長為1。因此,迴圈取出a、b、c、d、e這5個子矩陣, 每個矩陣的維度都是: 輸入高度x3。
2.將a、b、c、d、e按照行優先展開並拼成乙個大的中間矩陣l, l的維度則為: 5x21。
3.從l中迴圈取出p、q、r、s、t這5個子矩陣,並計算5次矩陣乘法,就得到了最終的結果。
從上面的示例中我們不難看出,mec的解決思路在於將im2col這一過程分成了height和width兩部分,於是需要儲存的中間矩陣也大大減小了。 可能帶來的問題就是,原來的一次矩陣乘法,現在會變成多次小矩陣乘法。雖然有利於平行計算,但也失去了blas庫計算大矩陣乘法的優勢。
2.2 高階版本
相比初級版本, 高階版本進而考慮了batchsize和channel維度。
照例先給出演算法偽**和示例圖:
algorithm2中的9-19行。 9-13行和algorithm1方法一致,14-19行對臨時結果做排列轉換。
solution b:
algorithm2中的21-25行。 迴圈每次處理乙個樣本,無需再做排列變換。
上面兩種解決方案的浮點乘法計算量是一致的。但是實際操作中,子矩陣的數量對效能的影響很大,特別是在gpu裝置上。 所以,在algorithm2的第8行採用了乙個引數t來控制是使用a還是b。 t是乙個和平台有關的引數,文章發現對於目前的gpu來說100是乙個不錯的選擇。
理論的複雜度就不說了,意義不大。 下面直接上實際對比結果。
3.1 配置說明以及benchmarks
c++實現cpu和gpu,矩陣運算庫採用多執行緒openblas、openmp、cublas,資料型別為32位浮點數。
3.2 對比結果
總結: 無論從記憶體占用還是計算速度上來看提公升都不錯,比較有復現價值。 不過缺少了和nnpack以及cudnn的對比,同時都是多執行緒操作,不知道單執行緒效率如何(估計會差一點)。 多執行緒的實現對程式設計能力要求還挺高的,先坐等大牛復現。(自己以後有應用需求也會考慮復現。)
線性卷積與圓周卷積的計算方法
現在很多任務具裡都已經為我們實現好了線性卷積和圓周卷積的函式,所以在實現方面簡單呼叫一下即可。如matlab中,conv用於計算線性卷積,而cconv用來計算圓周卷積 在國內搜了很多計算圓周卷積的例子,居然鮮有人提到cconv函式,而都是人云亦云都抄襲一套自實現函式,真是有點意想不到。下面直接上乾貨...
卷積網路的基礎知識與相關計算
1.卷積網路與全連線的不同之處在於它的區域性連線和權值共享特性,使其保持輸入輸出資料的結構化。如果是全連線輸出資料會被展平成一維陣列,喪失資料在結構上的對應關係。2.感受野的定義 對於某層輸出特徵圖上的某個點,在卷積神經網路的原始輸入資料上能影響到這個點取值的區域。3.輸出尺寸等於 輸入尺寸 2 填...
PC匯流排頻寬與記憶體頻寬的計算
1.intel處理器前端匯流排 fsb 的頻寬計算 處理器前端匯流排頻寬 處理器前端匯流排頻率 mhz,處理器外頻x4 x位寬 bit 8 其中,處理器前端匯流排頻率為處理器外頻的4倍 處理器主頻 外頻x倍頻 目前的主流處理器皆為64位處理器,除以8將bit換算為byte。舉例計算 intel奔騰雙...