MNN介紹
端側智能現在已經不是新鮮話題,不管是從數據安全出發,還是從實時性能考慮,端側深度學習算法推理都有其不可替代的優勢。之前已經有一段時間的端側推理框架熱潮,google、Facebook、百度、騰訊、小米以及一些名氣不大但是實力很強的小公司,都開源了自家的端側推理框架,阿里MNN在18年年底開源,有後來居上的趨勢和決心,不僅工程結構的完備性和規範性很好,開發團隊和應用場景也有一定的優勢。
MNN是一個輕量級的深度神經網絡推理引擎,在端側加載深度神經網絡模型進行推理預測。目前,MNN已經在阿里巴巴的手機淘寶、手機天貓、優酷等20多個App中使用,覆蓋直播、短視頻、搜索推薦、商品圖像搜索、互動營銷、權益發放、安全風控等場景。此外,IoT等場景下也有若干應用。
目的
之前在兩個手機上跑了一下MNN的benchmark,結果如下
CPU優化的效率看着還是蠻喜人的。
作爲應用開發者,我們對常用的前端框架做了一個封裝,包括coreml、NCNN、MACE等,統一接口輸入和輸出,以及cvtColor、rotate、resize等CV操作。在iOS上,我們自身模型使用ncnn的性能並不能令人滿意,在看到MNN之後,就想把MNN也加到我們的統一推斷框架中,來提升性能。
編譯
相比較Android的CMake+NDK交叉編譯,iOS上MNN提供了完整的Xcode工程,非常方便
或者跑demo工程
完整的demo工程如下:
編譯結果
使用project/ios編譯出來的MNN.framework,大小6.4M:
使用demo的playground編譯出來的libMNN.a,大小5.6M,mnn.metallib 583kb:
使用
在我們的工程中添加MNN頭文件和庫,就可以像demo中一樣使用MNN的功能,我們主要用到了一下幾個功能:
基本對象
std::shared_ptr<MNN::Interpreter> _net = MNN::Interpreter::createFromFile(model.UTF8String);;
MNN::Session *_session = _net->createSession(config);;
MNN::CV::ImageProcess *_process;
_net包括網絡信息,類似NCNN的Net對象,_session處理會話,類似NCNN的Extractor對象,_process負責處理圖像。
圖像預處理
MNN提供了很完整的圖像預處理方法,包含在core/cv目錄下,主要接口是
auto pretreat = std::shared_ptr<MNN::CV::ImageProcess>(
MNN::CV::ImageProcess::create(MNN::CV::RGBA, MNN::CV::BGR, means, 3, normals, 3));
auto input = _net->getSessionInput(_session, nullptr);
pretreat->convert(rgba, w, h, 0, input);
先傳入一系列參數,創建一個MNN::CV::ImageProcess
對象或指針
然後使用MNN::CV::ImageProcess
的convert方法來對圖像進行處理
也可以通過構造一個ImageProcess::Config變量
然後通過
來構造ImageProcess對象。
cvtColor
通過ImageProcess的create構造函數參數來解決,第一個參數是待處理圖像的格式,第二個是目標格式。
resize
需要設置一個matrix
MNN::CV::Matrix matrix;
matrix.postScale((w - 1) / 223.0, (h - 1) / 223.0);
pretreat->setMatrix(matrix);
其中w是輸入圖像的寬,h是高,第一個223.0是模型input的寬-1,第二個是模型input的高-1,因爲這個模型輸入是224*224,所以兩個都是223.0.
需要注意的是,如果不需要resize,則調用matrix.poseScale(1.0,1.0)
。
歸一化
構造means和norms
const float means[3] = {103.94f, 116.78f, 123.68f};
const float normals[3] = {0.017f, 0.017f, 0.017f};
和cvtColor一樣,當做ImageProcess的構造參數傳入。
如果不需要歸一化,可以將means都設爲0,normals爲1.0
RUN
_net->runSession(_session);
這個接口足夠簡潔。
輸出
拿到float *data指針,也就成功了一大半,爲什麼說是一大半而不是全部呢?以爲這裏還有一個非常重要的環節:數據排布,經過不完全測試,得到一個結論,MNN的輸出排布是NCHW。
測試結果
在鋪墊了那麼多之後,發現測試結果並不理想,我們只對純CPU做了測試,並與coreml做了對比: