開源背後 | 面對端側推理引擎的挑戰,阿里工程師如何應對?

阿里妹導讀:MNN(Mobile Neural Network)已於今年5月7日在 Github 上正式開源。淘寶無線開發專家——陳以鎏(離青)在 GMTC 全球大前端技術大會爲你們分享了 MNN 開發、開源中的思考與總結,經過淘寶在移動 AI 上的實踐經驗,你將會了解移動 AI 的發展情況和應用場景,以及經過端側推理引擎瞭解移動/ IoT 深度優化策略。

開源與背景

人工智能從 2006 年開始,迎來了第三次浪潮。隨着 AlphaGo 在 2016 年、 2017 年前後打敗李世石和柯潔,人工智能完全進入了公衆的視野。人工智能大熱的背後,是大數據的積累,是深度學習的發展,也是設備算力的提高。與此同時,深度學習的框架也在不斷演進 —— 從 Torch、Caffe 到 TensorFlow、PyTorch ,再到更面向移動端的 CoreML、NNAPI、NCNN、MACE 等。淘寶的深度學習推理引擎 MNN 也於 2019 年 5 月宣佈開源。前端

MNN 是一個輕量級的深度學習端側推理引擎,核心解決深度神經網絡模型在端側推理運行問題,涵蓋深度神經網絡模型的優化、轉換和推理。目前,MNN已經在手淘、手貓、優酷、聚划算、UC、飛豬、千牛等 20 多個 App 中使用,覆蓋直播、短視頻、搜索推薦、商品圖像搜索、互動營銷、權益發放、安全風控等場景,天天穩定運行上億次。此外,菜鳥自提櫃等 IoT 設備中也有應用。在 2018 年雙十一購物節中,MNN 在天貓晚會笑臉紅包、掃一掃、明星猜拳大戰等場景中使用。算法

開源地址:https://developer.aliyun.com/...後端

MNN 項目從 2017 年開始啓動,在經歷一年多的開發迭代並經過了淘寶雙十一的考驗後,於 2018 年末啓動開源計劃,在歷時小半年的開源改造後,今年 5 月份正式在 Github 開源。緩存

開源首先仍是由於經歷過雙十一以後,咱們以爲本身作好了準備,開源有助於咱們鞭策本身,把 MNN 作的更好;另外一方面,業界的開源方案,不管是 TensorFlow Lite 、 NCNN 仍是 Mace ,都給了咱們很好的輸入和借鑑,咱們也但願藉着開源,將咱們的思考和創新回饋社區。安全

下文將主要圍繞着 MNN ,來介紹淘寶在移動 AI 上的一些實踐經驗。網絡

挑戰與應對

端側推理引擎面臨的挑戰中,碎片化是最爲顯著的,這種碎片化是多層次、多維度的 。框架

  • 訓練框架上, Caffe 、 TensorFlow 、 PyTorch 、 MXNet 在訓練模型時都很經常使用;
  • 計算設備上, CPU 、 GPU 已經是主流, NPU 、 TPU 漸漸成爲標配, DSP 、 FPGA 在 IoT上也很常見;
  • 算子層面上,衆多參數會造成不一樣的組合,從而對應出不一樣的優化方式,輕量化和通用化須要取捨;

一款優秀的端側推理引擎,就須要在這樣碎片化的環境下,利用設備有限的資源,儘量發揮出設備的性能。爲此,也須要在轉換、調度、執行上加入相應的優化策略。下文,會就其中的部分展開說明。ide

轉換工具

模型優化函數

在模型優化中,MNN 引入了前端的概念來統一訓練框架。不一樣的前端負責加載不一樣訓練框架的模型,統一轉換爲 MNN 的模型格式。對於最經常使用的訓練框架 TensorFlow 和 Caffe ,咱們提供了獨立的前端;其餘訓練框架,好比 MXNet ,則須要先將模型轉換爲 ONNX ,再經過 ONNX 前端加載。這裏,因爲 TensorFlow 的算子顆粒度相比 Caffe 和 ONNX 要更小,咱們引入了圖優化的模塊來對齊算子之間的顆粒度。模型轉換以後,會通過優化器優化,包含算子融合、算子替換、佈局調整等等。以後,能夠選擇對浮點模型執行量化壓縮。目前模型壓縮的模塊尚未開源,咱們會在完善以後,將相關代碼開源。這些步驟都完成以後,會使用 flatbuffer 來保存部署模型。工具

圖優化

這裏以 RNN-GRU cell 爲例,說明一下圖優化。

左圖是 RNN-GRU cell 在 TensorBoard 中的可視化描述。它足足包含了 3584 個節點,而每個節點都表明了必定的數據讀寫或運算,累積起來的總量很是大。然而,全部這些節點能夠打包使用一個大顆粒的算子來替代。這不只大幅下降了部署模型的大小,還能夠在大顆粒算子的實現中聚合大量的計算,避免沒必要要的數據讀寫。

右圖展現的是一個實際業務模型在圖優化先後的性能對比。在華爲 P10 、紅米 3x 、小米 6 上都有 1 倍左右的性能提高。而若是是雙向 GRU ,效果還會更明顯。

算子融合

再以 Convolution、Batchnorm、Scale、ReLU 爲例說明優化器中的算子融合。

首先融合 Convolution 和 Batchnorm,Convolution 的 weight 等於 weight 乘 alpha ,而 bias 等於 bias 乘 alpha 再加 beta ;然後融合 Convolution 和 Scale ,融合過程和 Batchnorm 相似;最後融合 Convolution 和 ReLU ,在輸出結果前,計算激活函數 ReLU 便可。

這樣,四個算子就能夠合併成一個算子。融合的過程避免了三次 tensor 讀寫、兩次 tensor 乘加。優化效果:MobileNet V1 在小米 5 和華爲 P10 上有 20 ~ 40% 的性能提高,效果仍是比較明顯的。

智能調度

總體設計

在調度上, MNN 將每一類計算設備抽象爲一個後端,將算子在特定後端上的實現抽象爲執行器。後端負責特定設備上的資源分配和計算調度,執行器負責具體的實現。後端和算子的添加都經過註冊表來實現,這是一個雙層註冊表結構,拓展起來就相對靈活。

調度時,能夠爲子圖選擇相應的後端,再由後端建立出相應的執行器,組成管線;也能夠爲子圖選擇後端組,實現混合調度。好比,在 GPU 上不宜實現排序算子時,能夠回退到 CPU 來執行。

目前, MNN 在 CPU 上實現了 76 個算子, Metal 上有 55 個, OpenGL 覆蓋了基礎的 CNN 網絡, OpenCL 和 Vulkan 分別有 29 和 31 個。

緩存管理

在建立完執行器以後,子圖和管線已經就緒。下來,須要計算出全部 tensor 的形狀,在相應的後端上完成內存的分配。然後,在準備執行器時,再爲全部的執行器預先在後端上申請好必要的 buffer。運行結束後,返回 tensor 便可。

因爲推理所需的全部內存在準備期就已經申請完畢,在後續推理時,若是輸入的形狀不變,就能夠複用 tensor 和 buffer,從而避免頻繁地申請、釋放內存;只有輸入形狀改變的時候,才須要從形狀計算開始,調整一次內存分配。同時,因爲使用後端統一管理緩存,後端內的執行器之間,緩存就能夠充分複用的,這就大大減小了內存的需求量。此外,MNN 分配內存時,默認按照32位對齊,內存對齊有利於數據讀寫。

執行優化

數據佈局與滑窗卷積

數據佈局對性能影響巨大。

先來看一看在 NCHW 的佈局下,怎麼利用 SIMD 加速 3x3 的 depth-wise 卷積。

首先,讀取數據時,須要一次性讀取四個 float 做爲第一行的數據,後兩行的讀取也是類似的;此時,讀取出的三行數據已經足夠計算兩列輸出,即,能夠複用部分數據;然後,爲了提升數據複用,會再讀取出第四行數據,一次計算兩行兩列,即,能夠引入循環展開;然而,殘留的 5~25 和 21~25 亮度眼邊界沒法利用 SIMD 計算,只能逐一循環讀寫完成計算;按照這樣的方式,就能夠相應完成後幾個通道的計算。

可是, NCHW 佈局下,沒法充分利用 SIMD 進行加速,同時,實現優化分支越多,佔用包大小也就越多。

再來看一看 NC/4HW4 佈局下,利用 SIMD 加速的狀況又是怎樣的。

這裏的 "C/4" 指的是按照 4 個通道對齊的方式重排數據。重排全部輸入和權重數據後,每次 SIMD 讀寫都自然是 4 個通道的輸入數據和 4 個通道的權重數據。這樣,不論 kernel、stride、dilation 怎麼變化,咱們均可以簡單地使用 for 循環和 SIMD 的一套通用優化完成卷積計算。既不會有邊緣數據沒法加速的問題,也不會對包大小形成影響。

Winograd

對於對於 KxK 卷積,可使用 Winograd 算法進一步加速。MNN 中支持 2x2 到 7x7 的 Winograd 實現。Winograd 計算時,須要把輸出拆分紅 NxN 的小塊,把輸入拆分紅 (N+K-1)x(N+K-1) 的小塊。這樣,問題就能夠簡化爲兩個小矩陣的卷積。

再套用 Winograd 的公式,將矩陣間的卷積運算轉換爲矩陣點乘運算。在這個過程當中,除了矩陣點乘外,還引入三個矩陣轉換,分別是輸入矩陣 d 、權重矩陣 g 和結果矩陣 Y’ 的轉換。其中,權重轉換時, G 矩陣能夠利用中國剩餘數定理計算, GgGT 就能夠在準備執行器時提早計算;輸入轉換和輸出轉換時用到的 A 和 B 矩陣須要根據 N 和 K 計算,咱們在代碼中內置了幾種優化後的組合,因此實際計算時,這兩個轉換並不須要通過複雜的矩陣乘法。

這樣,原來矩陣卷積所須要的 9x4 次乘法計算就能夠用矩陣點乘的 4x4 次乘法計算代替。只考慮乘法耗時的話,加速了 2.25 倍。示例中, K=3,N=2 ,但實際使用時,能夠選擇更大的 N 值,獲取高的加速倍數,但也要相應消耗更多的內存。

Strassen

MNN 多是端側推理引擎中,第一個應用 Strassen 算法優化矩陣乘法的。

Strassen 在計算矩陣乘法時,首先須要將矩陣平均拆分紅四個小矩陣。這裏使用 a11 ~ a2二、b11 ~ b2二、c11 ~ c22 表明四個小矩陣,計算過程一共須要8次小矩陣乘法運算。

這裏能夠引入中間小矩陣, s1 ~ s四、t1 ~ t四、m1 ~ m七、u1 ~ u7 。其中,只有 m1 ~ m7 包含小矩陣乘法,一共 7 次小矩陣乘法運算。而其餘的,只包含小矩陣的加減法。也就是說,經過 4 + 4 + 7 次小矩陣加減法,替代了一次小矩陣乘法。

與原來的矩陣乘法相比, Strassen 的時間複雜度從 n 的 3 次方,下降到 n 的 2.81 次方。在矩陣較大時,矩陣乘法遠遠慢於矩陣加減法,收益就更明顯。

在 MNN 中,咱們會遞歸使用 Strassen 。也就是說,遞歸拆分矩陣。在矩陣足夠大時,繼續拆分;在矩陣不夠大時,使用普通的矩陣算法。這裏使用減免的矩陣乘法開銷做爲收益,使用小矩陣 s 、小矩陣 t 、小矩陣 u 矩陣的加減法開銷之和做爲代價,收益大於代價時,就能夠考慮使用 Strassen 算法。

鏈路優化

鏈路優化能夠舉一個 19 年春節淘寶掃年貨的例子。在得到手機相機輸入後,每一幀的圖像首先須要通過一次預處理,將圖片縮放到年貨檢測模型的輸入大小上,然而再通過推理,斷定圖像有沒有年貨,若是有,就發放相關權益。這個過程當中,圖片預處理的耗時也不容忽視。下降這個耗時,就能夠幫助咱們提高幀率,從而改進用戶體驗。爲此,咱們引入了一個輕量級的 2D 圖片處理庫,能夠高效地完成色值變化、色彩空間的轉換或者仿射變換等。這樣, MNN 的用戶就再也不須要爲圖片處理引入 libyuv 或者 opencv 了。

性能比較

通過種種優化後,這是咱們在性能上交出的答卷。

MobileNet V2 ,在 OPPO r17 和 iPhone 7Plus 上作了一系列的性能對比。

如圖, MNN 的性能在 CPU 和 GPU 上都有必定的優點。

小結

總的來講, MNN 吸納了前人的經驗,也結合本身對端側推理引擎的認知,作了許多創新。綜合考慮性能、模型和後端的拓展性、緩存、 CPU 和 GPU 的算子實現,以及 CV 庫等方面的表現,在端側推理引擎中, MNN 是值得移動 AI 用戶嘗試的選擇。

後續規劃

在後續計劃上,轉換部分,咱們計劃追加更多算子和更多圖優化匹配模板,也計劃將模型量化工具開源;調度部分,咱們計劃分步實現端側訓練和邊緣學習,計算設備自動選擇也在籌劃中;執行部分,仍是會持續優化現有各端算子的實現,也計劃優化量化卷積、矩陣乘算法,計劃在 CV 庫上直接支持 GPU ,咱們也考慮將現有 NC/4HW4 實現的算法,整理爲獨立的高性能計算庫,算法自動選擇一樣在籌劃中;其餘部分,咱們會持續建設項目的可用性,持續加入更多的文檔和示例。

淘寶基礎平臺部-端智能團隊歡迎推理引擎研發工程師、AR技術研發工程師、高性能計算研發工程師的加入。對新技術感興趣,善於創新突破,渴望用新技術給用戶帶來創新體驗的同窗請聯繫咱們,簡歷投遞至chengfei.lcf@alibaba-inc.com。



本文做者:陳以鎏(離青)

原文連接

本文來自雲棲社區合做夥伴「阿里技術」,如需轉載請聯繫原做者。

相關文章
相關標籤/搜索