阿里巴巴推断框架MNN在iOS上的使用小结

MNN介绍

端侧智能现在已经不是新鲜话题,不管是从数据安全出发,还是从实时性能考虑,端侧深度学习算法推理都有其不可替代的优势。之前已经有一段时间的端侧推理框架热潮,google、Facebook、百度、腾讯、小米以及一些名气不大但是实力很强的小公司,都开源了自家的端侧推理框架,阿里MNN在18年年底开源,有后来居上的趋势和决心,不仅工程结构的完备性和规范性很好,开发团队和应用场景也有一定的优势。

MNN是一个轻量级的深度神经网络推理引擎,在端侧加载深度神经网络模型进行推理预测。目前,MNN已经在阿里巴巴的手机淘宝、手机天猫、优酷等20多个App中使用,覆盖直播、短视频、搜索推荐、商品图像搜索、互动营销、权益发放、安全风控等场景。此外,IoT等场景下也有若干应用。

目的

之前在两个手机上跑了一下MNN的benchmark,结果如下
[外链图片转存失败(img-amoWAQfw-1562123546316)(evernotecid://1CA468D3-8108-4F95-9FF0-B3384CD16BE9/appyinxiangcom/22266324/ENResource/p285)]
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做了对比:
在这里插入图片描述

发布了42 篇原创文章 · 获赞 33 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/gaussrieman123/article/details/94554281