轻量级深度神经网络推理引擎MNN已开源,感兴趣的同学可以移步至项目体验:
https://github.com/alibaba/MNN
MNN的特点是轻量、通用、易用、高效:
轻量性主体功能(模型推理CPU+GPU)无任何依赖,代码精简,可以方便地支配到移动设备和各种嵌入式设备中。iOS平台:功能全开的MNN静态库 armv7+arm64大小12MB旁边,链接天生可实行文件增加大小2M旁边。裁剪主体功能后静态库大小6.1M ,链接天生可实行文件增加大小 600 KB。Android平台:主体功能 armv7a - c++_shared 动态库大小800KB旁边。支持采取 Mini 编辑选项进一步降落包大小,大约能在上述库体积根本上进一步降落 25% 旁边。支持模型FP16/Int8压缩与量化,可减少模型50%-75% 的体积通用性支持Tensorflow、Caffe、ONNX、Torchscripts等主流模型文件格式,支持CNN/RNN/GAN/Transformer 等主流网络构造。支持多输入多输出,支持任意维度的输入输出,支持动态输入(输入大小可变),支持带掌握流的模型。算子丰富,支持178个Tensorflow Op、52个Caffe Op、142个Torchscipts Op、158个ONNX Op(ONNX 基本完全支持)。支持做事器/个人电脑/手机及具有POSIX接口的嵌入式设备,支持利用设备的 CPU/GPU 打算,支持部分设备的 NPU 打算(IOS 11 + CoreML/Huawei + HIAI)。支持Windows/iOS 8.0+/Android 4.3+/Linux及具有POSIX接口的操作系统。高性能对iOS/Android/PC/Server 的CPU架构进行了适配,编写SIMD代码或手写汇编以实现核心运算,充分发挥CPU的算力,单线程下运行常见CV模型基本达到设备算力峰值。iOS设备上基于Metal实现算子以支持GPU加速,常用模型上快于苹果原生的CoreML。Android上供应了OpenCL、Vulkan两套方案,针对主流GPU(Adreno和Mali)做了深度调优,个中OpenCL侧重于推理性能极致优化,Vulkan方案看重较少的初始化韶光。广泛利用了 Winograd 卷积算法提升卷积性能,首次在业界工程实践中实现转置卷积的Winograd算法优化与矩阵乘的Strassen算法优化并取得加速效果。支持低精度打算(int8/fp16/bf16)以提升推理性能。并对ARMv8.2和AVX512架构的干系指令进行了适配,这两种架构下有更好的加速效果。易用性支持利用MNN的算子进行常用的数值打算,覆盖numpy常用功能。供应MNN CV模块,支持图像仿射变换与归一化等MNN_CV库,支持常用的图像处理(armv7a架构下小于100k)。支持各平台下的模型演习,尤其是移动端上的模型演习。支持python接口。1.2 技能寻衅
MNN面临的技能寻衅,如上图所示,紧张是两个抵牾:
AI运用须要的繁芜功能支持与受限定的程序体积之间的抵牾
AI模型本身包含多种算子,并在不断演进,如ONNX的算子数目前有160个旁边,Tensorflow靠近2000个,MNN须要以更精简的代码去实现AI模型所须要的这些算子。AI运用撤除模型推理之外,也包含数据前后处理所须要的数值打算与图像处理模块,算法工程师常用的Numpy与OpenCV库在移动端上每每由于体积占用过大而不能利用,对应功能也须要MNN支持。AI运用须要的强大算力支撑与碎片化的打算资源之间的抵牾
AI 模型每每打算量很大,须要MNN对设备上的打算资源深入适配,持续做性能优化,以充分发挥设备的算力。打算资源包括CPU、GPU、DSP和NPU ,它们本身编程办法是碎片化的,须要MNN逐个适配,开拓本钱高,也会使程序体积膨胀。二、架构设计为了应对性能与功能层面的寻衅,MNN 设计了预推理与表达式两个核心模块:
预推理模块可以降落打算资源的差异性,在任意的打算资源上探求到较优的打算方案。表达式模块可以抹等分歧演习框架的算子差异,并将模型演习、图像处理、数值打算等功能转换为推理所须要的张量打算图,从而可用 MNN 进行推理。2.1 预推理MNN 在加载模型之后,会根据用户设定的输入形状,对模型中的算子做一遍预处理,降落算子种类,探求最优打算策略,做资源分配。这个过程称为预推理。
预推理比较推理过程是轻量的,若用户设定的输入形状不变,预推理不须要重复实行,可以降落推理延时。
如上图所示,预推理紧张包括如下步骤:
策略搜索:对核心算子,根据输入输出的大小,按预设的评估函数打算各种实现策略的本钱,选择最优的打算策略。资源分配:根据网络图的拓扑顺序,打算所需的最小资源分配方案,并进行资源申请。几何打算:MNN为了应对打算资源碎片化的问题所创造的新机制。在这一机制下,能够大大降落多算子,多后端情形下的实现本钱,同时能够通过在线的算子领悟提升模型性能。其核心思想是利用一个通用算子来描述内存映射关系,从而方便开拓之利用根本算子组合成繁芜算子,降落繁芜算子的实现本钱。在模型中的内存映射可以描述为张量平面的映射关系如下:1)张量平面在内存中的线性地址为:,因此可以利用offset和stride[]来描述内存张量平面;
2)对付张量平面内存映射,当取张量维度为3时,映射关系为:
即可用三层嵌套循环实现该映射关系。
因此利用Region来描述张量平面,布局Raster算子来实现张量平面映射;实现了内存映射的元算子。在有了内存映射元算子后,im2col, transpose, concat, split等操作在后端中均可用Raster算子实现;conv3d,pool3d等也可以通过Raster与matmul,pool2d等组合实现,也不须要新增算子,可以大大降落实现的事情量。
同时由于利用了通用的映射表达各种内存映射关系,可以通过循环变换自动化探求可领悟算子,如:Permute(0, 2, 1) + Permute(1, 0, 2)可以自动化合并为Permute(2, 0, 1),减少冗余,提升性能。
2.2 表达式MNN 须要对接各种演习框架导出的模型格式,有如下特点:
演习框架随版本变迁会有不同的导出格式演习框架随版本变迁有大量的算子新增与修正不同演习框架的算子重合度高,但不完备一样框架
导出办法
导出成功率
算子数(不完备统计)
冗余度
Caffe
Caffe
高
52
低
Tensorflow
Pb - 1.x
高
1566
高
Tflite
中
141
低
MLIR
中
Pytorch
Onnx
中
165
低
Torchscripts
较高
566
高
Torch PKL + Python
高
为了抹平演习框架不同的差异,比较明确的做法便是定义MNN自己一套算子并实现前端,基于基于此对接各个演习框架。
这个MNN的前端便是表达式模块,对应的MNN模型转换流程优化如下:
由于 AI 模型的算子数逐渐丰富,推理引擎(或称张量打算引擎)与图像处理和数值打算正在趋同,如 Tensorflow 实现了 numpy 库,OpenCV 也通过 GAPI 的办法,将图像处理表示为打算图,由内置的张量打算引擎实现。
MNN 也基于表达式去实现了 Numpy 和 OpenCV 常用功能,详细见下文。
2.3 整体架构MNN可以分为主体(推理引擎)和工具两大部分。
1)主体:亦即推理引擎,卖力AI模型(张量打算图)的加载与实行,可分为调度(预推理)与实行(推理)两层。
2)工具:
MNN-Converter:模型转换工具,由Frontends和Graph Optimize构成。前者卖力支持不同的演习框架,MNN当前支持Tensorflow(Lite)、Caffe、ONNX(PyTorch/MXNet的模型可先转为ONNX模型再转到MNN)和Torchscripts;后者通过算子领悟、算子替代、布局调度等办法优化图,一样平常离线运行。MNN-Compress: 模型压缩工具,在一定的精度偏差容许下,对模型进行压缩,减少模型体积,提升运行性能。MNN-Express :支持带掌握流的模型运行,支持调用 MNN 的算子进行自定义的打算。MNN-CV :类似 OpenCV ,但核心打算功能基于 MNN 实现的图像处理算法库MNN-Train :MNN 演习模块,支持各平台演习三、性能优化MNN 的架构设计可以降落性能优化的本钱,但性能优化本身仍旧是MNN中最困难繁芜的事情,须要深入理解模型构造、算子实现、硬件架构,剖析模型运行中的打算冗余,并将其尽可能地压制。
3.1 冗余剖析深度学习推理中存在的打算冗余大致可分为以下几类:
构造冗余:模型构造中的无效打算节点,也是惟一可以无损去除的冗余类型精度冗余:深度学习推理引擎的数据单元是张量,一样平常是32位浮点数组,32位浮点的范围在很多场景是存在冗余的,每每可以压缩到16位或者8位乃至更低;另一方面,浮点数组中也可能存大量的0或者其他重复数据,也有优化空间。算法冗余:算子的实现算法本身存在打算冗余,比如均值模糊的滑窗实现并发冗余:未充分利用打算资源的并发能力(SIMD/多线程/GPU等等),导致打算资源闲置,亦或受并发能力本身的限定,须要打算多余的数据(比如打算长度为3 ,但SIMD单元为4的向量加法)调度冗余:利用多线程、GPU或者其他异构打算资源时,在CPU端须要组织打算,分拆任务,传输打算信息,该行为产生额外的打算冗余读写冗余:在一些打算场景重复读写内存,或者内存访问不连续导致不能充分利用硬件缓存,产生多余的内存传输3.2 构造/精度3.2.1 图优化与模型量化
构造冗余与精度冗余的压制一样平常须要离线工具赞助,MNN对应供应了图优化、模型压缩工具,在端上则供应了部分架构的低精度的打算支持。
图优化:基于一系列预先写好的模板,去除模型中的冗余打算,比如Convolution与BatchNormal/Scale的合并,Dropout去除等。图优化能在特定场景下带来相称大的打算收益,但相称依赖根据先验知识编写的模板,比较于模型本身的繁芜度而言注定是稀疏的,无法完备去除构造冗余模型量化:通过把模型中的常量压缩成FP16或Int8 ,可以降落模型大小,进一步地可以压缩模型中的变量(featuremap),亦即为模型中每层的输入输出探求FP16/Int8到FP32的映射关系,这样可以在模型运行时用低精度进行打算加速低精度打算:MNN在ARMv7a/ARMv8上实现了int8,BF16的加速,分别约30%/10%加速效果。ARMv8.2 架构上用 fp16 vec ,sdot ,分别有100%和200%的加速效果。在支持VNNI指令集的x64架构下则有 200% 的性能提升。3.2.2 稀疏打算加速为了适配SIMD优化,MNN通过权重矩阵稀疏化设计,演习得当的稀疏化分布,使权重矩阵呈现出“半构造化”稀疏的特性,而不是在行、列方向完备随机化稀疏,避免了向量vector用不满、数据复用低的弊端。如下图所示的BCSR(Block Compressed Sparse Row ) 格式:
图中白色代表的零元素,实际打算可以跳过,减少打算开销。
MNN实现了对稠密模型权重稀疏化演习的功能,导入MNN Python压缩工具包(mnncompress),设定mnncompress须要的参数,运行将原模型中权重部分数值稀疏化为0。须要把稳的是稀疏化0元素的分布模式须要符合分块形态,才能最大化发挥加速性能。
在常规的CPU GPU中并没有稀疏指令支持,我们须用常规向量指令实现打算加速,在MNN中我们设计实现了稀疏算子,最大化提取复用代码、扩展差异化后端。并且稀疏化算子对用户无感知,无需增加认知本钱。
在后端方面,为最大化向量并行加速,设计了灵巧的“半构造化”分块大小,例如对付AVX2可以用float32 x 8 的分块大小,同时为ARM NEON和x86 AVX2/AVX512指令实现了多种稀疏后端内核汇编代码。
第一点,CV模型在ARM端得到3.16x-4.13x加速比(0.9稀疏度),跨机型、跨模型加速效果都比较显著,详见参考资料大图。
第二点,在实际业务模型中验证了业务精度指标,丢失有限、可接管。
第三点,推理耗时随稀疏度增加线性低落,跨模型、cpu同等;在小米6上,稀疏分块1x4加速临界值优化到0.3,中高端机型乃至稀疏度0.1的时候可达临界值。
3.3 并发/算法/读写
这几类冗余的压制每每是相互冲突的,须要打算方法与内存排布的精心设计与内核打算的深度调优,探求一个平衡点。
3.3.1 NC4HW4 内存布局深度学习的CV算子每每具有如下打算特性,在C方向上打算可并行,但须要读取HW方向相邻数据。为了充分利用SIMD加速能力,MNN设计了NC4HW4布局,以兼顾SIMD利用和内存访问连续的需求。
3.3.2 Strassen矩阵乘算法与Winograd卷积算法
算法方面,MNN 采取Strassen算法加速矩阵乘法打算,Winograd算法加速卷积打算。
3.3.3 汇编优化与GPU内核优化
为了降落读写冗余,MNN 在CPU的汇编代码中做最大数目的循环展开,并手排指令减少相依数据依赖。
GPU则在内存、并发数、内核方面优化,在读写/并发冗余的压制上找到平衡点。
3.4 调度
MNN 的预推理模块可以较好地降落调度冗余,我们把算子的实行拆分为onResize和onExecute两个部分,在预推理过程中实行onResize,在推理过程中实行onExecute,视各种GPU的API设计不同,可以不同程度地降落调度冗余。
对付OpenCL ,可以减少Kernel参数的设定,将打算资源的申请转移到预推理过程中;对付Metal,可进一步降落命令提交频率;对付Vulkan,可进一步把命令缓冲的创建全部转移到预推理中,最小化调度冗余。四、易用性
MNN在针对端侧开拓的特点,在具有高性能与轻量性的同时还具有针对算法职员非常友好的易用性。MNN供应的Python部分接口不仅具备MNN模型推理的根本能力,同时还供应了算法开拓职员在前后处理中利用频率最高的根本库numpy与opencv的能力,用户在移动端仅利用MNN便可以完玉成套算法的迁移与支配。
4.1 MNN移动端PythonMNN的Python接供词给的能力如下:
MNN:供应模型加载,推理能力;MNN.expr:供应MNN的根本打算能力,动态构图能力;MNN.numpy:供应与numpy用法同等的部分numpy函数;MNN.opencv:供应与cv2用法同等的部分opencv函数。个中MNN与MNN.expr为MNN的核心能力,MNN.numpy和MNN.opencv是基于MNN的核心能力进行的扩展功能,在用法上更加贴近算法常用库,在实现上复用MNN核心功能,低本钱(200K内)大幅降落算法支配难度。
4.2 算法支配实例
利用以上能力可以将做事端代码便捷的迁移到移动端而不依赖其他Python库,代码如下:
import MNNimport MNN.cv as cv2import MNN.numpy as npdef inference(model_path, img_path): net = MNN.nn.load_module_from_file(model_path, ["data"], ["prob"]) image = cv2.imread(img_path) image = image[..., ::-1] image = cv2.resize(image, (224, 224)) image = image - (103.94, 116.78, 123.68) image = image (0.017, 0.017, 0.017) image = image.astype(np.float32) input_var = MNN.expr.convert(image, MNN.expr.NC4HW4) output_var = net.forward(input_var) output_var = MNN.expr.convert(output_var, MNN.expr.NHWC) print("output belong to class: {}".format(np.argmax(output_var)))
在移动端能够仅利用MNN便可以无缝支配做事真个算法,Python化支配对付算法工程师具有非常高的易用性,同时还具有更好的动态性,方便算法的热更新,热修复等;降落了端侧算法支配门坎,提升了端侧算法支配的效率。
五、总结与展望MNN 通过独特的架构设计,结合各种性能优化的事情,办理了业务场景下深度学习支配的问题。后续也将持续努力,优化架构,改良算法,不断降落算法工程师AI支配的门槛,持续为各种业务带来增量代价。
参考资料
https://github.com/alibaba/MNN
https://arxiv.org/pdf/2002.12418.pdf
https://arxiv.org/abs/2205.14833
https://www.yuque.com/mnn/cn
https://mp.weixin.qq.com/s/vv2RZHcinKwPyq5_qzNxTg
https://mp.weixin.qq.com/s/mYphx3JKiOEGtWS-H9P7Dg
https://www.khronos.org/assets/uploads/developers/presentations/Alibaba-Xiaying_geometry_outside_Apr21.pdf
https://www.tensorflow.org/guide/tf_numpy
https://numpy.org/
https://docs.opencv.org/4.x/d0/d1e/gapi.html
https://www.tensorflow.org/xla