近期,在如今所在的公司從事人臉識別的工做。使用的深度學習工具是caffe。後須要將算法佈置到項目中去甚至是ARM上去。即使caffe有本身的libcaffe庫能使用,可是這個庫自己帶有反向學習功能,而實際上deploy並不須要,故deploy時明顯能夠對caffe進行瘦身。另caffe有衆多的依賴項,尤爲是依賴protobuf使得我在工做中有諸多不便(protobuf不但2和3版本兼容很差,某些老的protobuf也沒法被更新的protobuf使用,這樣會致使以前的網絡可能沒法被更新的caffe識別到)。算法
簡化caffe實際上並不複雜。咱們能夠理一理須要作的事情:網絡
我命名個人Net是 XYZNet,那麼XYZNet可以計算,最少須要兩類資源:框架
1:每一層的類型和其參數 2:每一層的權值(weights)和偏移值(bias),注意偏移值也能夠是沒有的。函數
以上兩類資源都來自於你定義的caffe模型和訓練好的model。能夠簡單將caffe的這些參數導出成二進制文件而後加載到XYZNet中。工具
因爲層來源於文件,獲得是每個層的類型,故須要有一個能動態生成層對象的運行時結構。這樣就能在讀取文件時,建立每個層的實例化對象,並將其指針保存至XYZNet的vector中。學習
爲了能執行forward的計算,每個層須要知道其輸入的數據信息和輸出的數據的大小,這些資源須要提早分配好或計算獲得,以方便forward的計算,這裏把能預處理的操做放在這裏會比較合適。故每個層都對應一個SetUp函數,來處理這些工做。spa
剩下的就是每個層的forward的工做了。這部分的處理,便可以將caffe的對應代碼COPY過來,也能夠在掌握原理的狀況下本身適當編寫,由於有些層的caffe代碼,實在是對於僅僅保留forward計算的時候,是能夠簡化許多的。設計
在分析以上須要作的事情後,就能夠簡單設計其forwrad框架了:指針
設計一個父類:baselayer,全部的具體層都繼承於它。它須要最少3個函數:InitLayer 從文件中讀取模型參數和訓練好的權值model;SetUp 根據輸入的數據的尺寸信息,計算出輸出的尺寸信息並分配資源,這裏也許會計算出中間的臨時變量的值;Forward 函數,計算結果。在XYZNet中將有一個vector<baselayer* >,用來保存各類層的實例化對象。對象
創建一個鏈表,鏈表中包含層的類型名稱和每個層的構造函數,這樣查找鏈表就能根據類型名建立層的實例化對象(caffe用的是map<string,func>,func是構造函數,這樣來建立層的實例對象的)。
關於資源分配,爲了能有效利用內存空間,創建一個內存管理類,每一次一個層須要分配輸出數據空間時,將向這個管理類申請內存,並告訴管理類本身輸出數據的名稱,這段內存將由這個管理類管理,層自己將並不關心這個數據空間。而一個層須要輸入數據時,將也像這個管理類提出申請,它須要提供本身輸入數據的名稱字符串,管理類將返回字符串對應的數據交給這個層,當層計算結束時,管理類將會知道本層輸入數據已經計算完畢,它會作一些工做,以保障這個數據塊能被其餘層做爲輸出數據佔用。
在forward的時候,首先須要申請獲得輸入輸出數據存儲空間,完成後將告訴內存管理器輸入數據能夠被釋放。由於在forward計算中,輸入的數據也就是caffe的bottom數據不少時候其數據是能夠釋放掉的,這樣實際上能節約內存空間。
以上分析,大體能有一個清晰的forward設計思路。
一下是框架示意圖: