在Android端實現基於OPENGL ES 的深度學習前向傳播框架

github項目地址

首先感謝夕陽嘆大神提供的思路,大家先可以去https://blog.csdn.net/jxt1234and2010/article/details/71056736看看,基本把實現的流程都說了一遍,我照着思路實現了一下,同時參考了一下CnnDroid

這個項目斷斷續續寫了快4個月了,最近忙起來了,可能沒什麼時間完善了,先用blog記錄一下思路,要有機會再完善了。

目前整個項目只實現了卷積,池化,全連接,concat,flat(和tensorflow的flat邏輯不一樣),softmax,卷積部分實現了常規卷積,GEMM卷積(mat4級別的),winograd卷積。整個項目沒能達到夕陽嘆大神實現版本的效率,能力有限也不知道怎麼優化了,希望能有OpenGL的大神能review下我寫的shader,是不是實現上有問題,感激不盡。

大致的benchmark,個人時間有限就只與NCNN對比了一下運行squeezenet

ncnn沒時間編譯了,直接用的ncnn-mobile

cpu ncnn(4線程) mine
高通660 60ms 70ms
高通710 - 35ms
高通835 - 40ms

測試標準都是除去前10次後,然後前向運行100次耗時取均值。測試手機爲小米note3,注意不同rom對opengl效率有影響,最好用最新的開發版或正式版。

基本實現流程:

1.輸入層:

輸入層使用RGBA16F格式的 GL_TEXTURE_2D_ARRAY 存儲,紋理深度爲1,紋理寬高同輸入矩陣的寬高維度,通常輸入矩陣的channel爲1或者3,所以將輸入矩陣傳入紋理時,需要對其不足的通道補零。

2.卷積層

卷積層的輸出紋理爲RGBA16F的 GL_TEXTURE_2D_ARRAY,紋理深度爲輸出 ceil(channel/4),紋理高寬同輸出高寬維度。

卷積層的kernel也使用紋理存儲,紋理深度同輸入紋理。最開始我是按照夕陽嘆的思路用的ssbo,但是效率很慢,原因未知。換成紋理後效率有所提升。就我測試,基本運算有一半以上的耗時花在了從紋理讀取數據上了,這部分不知道有沒有優化空間。

kernel的維度爲  n x (kernel_area + 1)x d。 n爲kernel的數量,kernel_area 爲kernel的截面積,d爲輸入紋理的深度,因爲kernel的channel需要與輸入channel相同。每一個kernel均存儲爲紋理上的1行,紋理每行的最後一列的第一個值用於存儲改行kernel的bias。

常規卷積的邏輯爲每個計算器計算1個輸出,所以計算器座標同輸出座標。

GEMM卷積爲mat4級別的,所以一個計算器會同時計算4個輸出值。

winograd卷積的kernel紋理時存儲GgGt矩陣,存儲邏輯同上。winograd實現時是將輸出轉變爲nxn個2x2的輸出,所以一個計算器也會計算4個輸出值

3.池化層

池化層的輸出紋理爲RGBA16F的 GL_TEXTURE_2D_ARRAY,紋理深度爲輸出 ceil(channel/4),紋理高寬同輸出高寬維度。

池化層的計算器座標與輸出紋理一一對應,每個座標的計算器只進行對應座標的池化運算。

4.concat層

沒有判斷輸入channel是否爲4對齊,現在就實現了2個輸入,並且輸入channel均爲4對齊的情況。通用的concat有時間再補上吧。

5.全連接層

全連接爲了直接接卷積或池化的輸出,輸出紋理的格式設置爲 1 x 1 x d, d爲全連接層的神經元數量,輸出紋理的深度就爲ceil(d/4)。同樣每個神經元的kernel也用紋理的1行存儲,最後一列用於存儲bias。

6.flat層

這層主要是爲了方便讀取最終結果,opengl通過framebuffer讀取數據時,只能讀取一個深度紋理上的數據。所以通過flat將紋理所有深度上的數據,移動到一個深度的紋理上。

7.softmax層

沒什麼東西了,直接實現的softmax公式。

 

目前在ARM Mail GPU上還有bug,cifa10的10分類模型能跑,squeezeNet就輸出0,原因還沒找到,手邊也沒有這種GPU的手機,應該也沒機會修復了。

順便記錄一下ARM opengl編程遇到的一點小坑:

1.arm 下 opengles 的計算器localsize 最大值爲128,而高通的爲1024

2.arm 下shader定義image時必須設置精度(也許也可以直接在全局設置,我沒試),而高通不需要

layout(binding = 0, rgba16f) readonly uniform highp image2DArray input_image;

紋理精度設置爲highp或lowp,效率沒變化。

3.shader的shared變量空間比高通的小(具體多少沒查到,也沒手機試),高通的手機爲1000 個 float。

 

裏面包括一個cifar10 10分類和squeezeNet 1000分類的模型。

cifar10的權重提取自CnnDroid

squeezenet的權重提取自squeezenet

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章