閱讀760 返回首頁    go 阿裏雲 go 技術社區[雲棲]


Jarvis-拍立淘裏麵的深度學習引擎

介紹

深度學習的原理?局部響應歸一化的作用?兄弟今天不是來討論這個的,那都是科學家和算法同學的事兒。作為一個深度學習引擎,使命隻有一個——就是快速準確的計算。那怎麼才能快呢?在編程技能和算法技能沒有蛻變的情況下,使用GPU是一個方便的法門。對於iOS來說,就是使用Metal,對於iOS10+iPhone6以上,那就更厲害了,可以使用Metal Performance Shaders,就是蘋果寫好了卷積給你用,性能不是一般的強悍。對於android,情況變得有些複雜,穀歌本來打算推他自己搞的RenderScript,可惜沒成功,這玩意兒性能不行,看樣子穀歌自己都不玩了,OpenCL還不錯,不過這玩意兒的調優可真不是一般的麻煩,同樣的運算就算是姿勢偏差了一點點,那性能也是天差地別。什麼姿勢這麼重要?比如col-major, row-major啦,說到底,就是內存的存取分配問題。

業務應用

先把實現細節擺一邊,放幾個實際業務的錄屏大家感受下:

一般人都會問一個問題,有什麼計算是必需在前端做而不能在後端做?但反過來也可以問另外一個問題——有什麼計算是必需在後端做而不能在前端做?如果網絡夠快,那麼都可以放在後端做,如果前端運算夠快,那也都可以放在前端做。(別提檢索數據,那是另外一回事)

掃立淘

在手機淘寶拍立淘內,我們增加了智能識別場景對端上智能進行落地。

用戶將攝像頭對準要識別的物體時,會實時對相機取到的幀數據進行檢測,並繪製出黃色瞄點提示用戶當前鏡頭內的主體。這樣可以使取得的圖片主體更加明確清晰,提高召回結果的準確率。
當搜索被觸發後,端上會立刻對當前最後一幀圖像進行檢測並繪製識別區域。

掃商品/掃logo

業務方提供要識別的素材,可以是若幹個品牌logo,也可以是若幹個商品圖片。我們會提供掃碼頁麵給業務方投放到任何運營位。進入掃描頁後,用戶對準logo或者商品,我們會在端上進行特征提取和特征比,並將結果返回給H5頁麵來實現業務方要求的各種效果。

速度對比

android

圖中所列數據都是在nubia Z9(15年出的一款旗艦機,CPU: qualcomm snapdragon 810, GPU:Adreno 430)手機上執行googlenet測得, low is better.

a298901e50c5c446fd99e238f9dce5ce.png

Jarvis GPU implementation的性能是ncnn兩倍以上

CPU使用占比:

9a0549fd9c79b7ff3a9d27834d0c2686.png


10分鍾耗電:

a472ada780ce06df1e85321d6cdb8c27.png



雖然Jarvis GPU的CPU占比很低,不過GPU看起來也是特別耗電的主兒。但在這同等的時間和耗電量之下,Jarvis GPU執行的googlenet次數可是ncnn的2倍以上。

Jarvis googlenet OpenCL實現分層耗時:

ffccacca3a8e34e002df0527e3ff2bfd.png

時間都是被卷積給吃了。 如果要繼續優化,那就繼續瞄準卷積進行射擊。
另外,僅僅兩層LRN就耗掉了相當一部分時間,主要是裏麵的冪函數太費時了

備注:
1. Jarvis CPU使用Eigen OpenMP,4線程
2. ARM Compute Library使用v17.06,即6月份的版本。v17.10還要更慢。ARM Compute Library的OpenCL實現在高通GPU上運行報錯。就目前來說, ARM的CPU實現的表現令人失望,OpenCL的實現在MaliGPU下的表現有待驗證。
3. 以上這些作為對比的庫都是使用他們所帶示例代碼的方式來構建的網絡,也就是說就算他還有什麼性能調優的參數,我也是不知道的

在一般的機器上,如果不使用GPU加速,googlenet在端上基本不可用,太慢。

iOS

測試機器iPhone 6s Plus

3c01a41c676eca855c102a9e686ca698.png

  1. 同樣的CPU代碼(使用Eigen,再往下說是neon),在不開啟OpenMP即多線程的情況下,在iPhone6s上要比高通810快5倍,即使在810上開了omp也是差了3-4倍。
  2. 僅僅把卷積算子中的gemm從Eigen換成Accelerate Framework實現,速度就提升了一大步。再次驗證了一個道理,現在外部開發怎麼都玩不過係統內部的實現。
  3. GPU中Metal的實現,無論如何都和係統自帶的MCNN實現有相當的差距。
  4. MPS的性能是逆天的

架構設計

15ec1418f8df8ff36f6fef626757802d.png

  1. model格式:目前采用protocol.json+二進製model數據文件的方式。框架提供了工具可以將caffe2的格式轉為jarvis格式。
  2. 為了簡單的緣故,現在所有層的輸入和輸出channel都必需是4的倍數,大部分的網絡都是如此。對於第一層輸入,一些網絡接受3channel,框架提供了工具將model擴展為4channel,即在後麵追加0。
  3. 網絡構建:係統會優先使用GPU的Operator,如果相應Operator無GPU實現則會降級使用CPU。 係統會負責數據在CPU和GPU之間的傳遞,調用方是當然不用操心這些 小事 的。
  4. 在安卓上, 分為了三個動態鏈接庫,Jarvis_CPU, Jarvis_OpenCL, Jarvis_JNI。調用方可以根據需要打包相應的so。這樣也使得在手機不支持opencl時不至於整個jarvis庫都加載失敗。
  5. Javis_CPU,iOS和android基本上使用了共同的代碼。不過iOS還有一個accelerate庫的實現,在編譯時選擇。

接口設計

Java:

Session session = new Session(protocol, modelPath);
Tensor input = session.input(0);
float[] input_data = new float[input.size()];
// fill input_data stuff...
input.write(input_data);
session.run();
Tensor output = session.output(0);
float[] output_data = new float[output.size()];
output.read(output_data);

Objective-C

JVSSession *session = [[JVSSession alloc] initWithProtocol:protocolData
                                                 modelPath:modelPath];
[[session inputAtIndex:0] write: input_data];
[session run];

未來演化

雖然所有的深度學習框架都在盡力提高自己的性能,但要與硬件廠商的實現相比那還是有相當大的差距。那硬件廠商的SDK有多快?我不是針對誰,但上麵所有的這些庫在高通驍龍的SNPE和華為的Mate10深度學習引擎麵前都是渣。所以,Jarvis——對於任意一款深度學習框架來說都是如此——的存在價值就是不管一款手機是否帶有廠商自己的深度學習引擎,也不管這個深度學習引擎的API有多麼奇葩,都使用簡單統一的接口將之抹平,讓天下的手機沒有難搞的深度學習。

還是說幾個眼前的點吧:

  1. 首先要提高CPU實現的性能,畢竟CPU是兜底的。首先就是去掉Eigen,又大又慢。然後就是借鑒了, NNPACK,ncnn, xNN, 嗯嗯。不過使用neon的優化還是有很多的潛力可挖,大有可為。

  2. 其次要提高OpenCL實現在非高通GPU上的性能,現在這個版本的性能優化是針對Adreno GPU做的,優化完成後發現在Mali GPU上性能降了一大截,接下來要再次針對Mali優化,最終的目的是要做到針對不同的GPU有不同的性能調優參數。好多工作。

  3. 嚐試同時使用CPU和GPU,這個方案的難點在於數據在CPU和GPU之間的來回傳遞本身也需要耗費時間。一個方案是使用CPU/GPU共享內存,對於Metal來說,使用了共享內存寫入一端的數據即對另外一端可見。對於OpenCL來說,雖說不用再拷貝內存,不過依然要使用Map/Unmap來同步內存。

  4. 二值網絡的應用及實現優化,現在使用float32,使用float16/Int8會不會好一點?參考iDST的BNN

  5. 稀疏化網絡的應用及實現優化,現在算法團隊已經可以在精度損失非常小的情況將網絡稀疏化到80%以上,對於這種網絡,有沒有更優的計算方案?參考支付寶的xNN

最後更新:2017-11-03 11:04:44

  上一篇:go  使用VUE模仿BOSS直聘APP
  下一篇:go  javascript中Ajax的簡單封裝