张新栋 · 2020年04月17日

整合mxnet和MNN的嵌入式部署流程

工程的完整github链接为:Github链接

首发:https://zhuanlan.zhihu.com/p/75742333
作者:张新栋

最近由于项目和研究需要,需要选用一些开发更加灵活的框架。在tensorflow、keras和mxnet之间,我最终还是选择了mxnet。首先是出于以下几点考虑,第一是框架规模,mxnet对比其他框架,体积小、功能全;第二是灵活性,mxnet支持动态、静态的DNN开发模式,比较适合我在工程及研究中切换角色(之前虽然使用tf,但更多适合是围绕其生态来开发项目,很少用来做research);第三是mxnet及其生态的设计理念,设计新颖大胆,应为DNN的主流及最终发展方向;最后是上手速度快,mxnet我用了2小时就基本能达到小规模的项目开发及research的程度。

在选定了训练的框架后,结合之前我做过的一些MNN的小项目,我打算尝试结合mxnet及MNN来打通嵌入式端项目部署的一套工具链。这里我称之为工具链,实际上是指CNN算法项目从模型训练---->模型导出----->模型转换------>在线部署的一整套流程。目前市面上已经有了很多优秀的开源嵌入式端部署框架,如MNN、TVM、NCNN、MACE等等,这里我们选择MNN作为嵌入式端的部署框架,选取简单的视觉任务MNIST,来跟大家从头到尾讨论这个部署流程:

  1. 离线训练

离线训练我们采用的是mxnet,使用gluon来进行mnist网络的编写,网络结构如下图所示。完整的代码可以参考文章最后本人的github链接。

class MNIST(mx.gluon.HybridBlock):
    def __init__(self, **kwargs):
        super(MNIST, self).__init__(**kwargs)
        self.conv0  = nn.Conv2D(channels=20, kernel_size=(5,5), activation='relu')
        self.maxp0  = nn.MaxPool2D(pool_size=(2,2), strides=(2,2))
        self.conv1  = nn.Conv2D(channels=50, kernel_size=(5,5), activation='relu')
        self.maxp1  = nn.MaxPool2D(pool_size=(2,2), strides=(2,2))
        self.flaten = nn.Flatten()
        self.dense0 = nn.Dense(units=500, activation='relu')
        self.dense1 = nn.Dense(units=10,  activation=None)
    def hybrid_forward(self, F, x):
        x = self.conv0(x)
        x = self.maxp0(x)
        x = self.conv1(x)
        x = self.maxp1(x)
        x = self.flaten(x)
        x = self.dense0(x)
        x = self.dense1(x)
        return x

2. 导出模型

首先经过第一步的离线训练,我们得到了图的表示及参数文件,分别为json和params后缀。但是该模型文件形式无法和MNN进行交流,所以我们需要导出另外一种可以被MNN解析的模型格式,这里我们选择的是ONNX。如下为导出ONNX的脚本文件:

import mxnet as mx
import numpy as np
from mxnet.contrib import onnx as onnx_mxnet
import logging
logging.basicConfig(level=logging.INFO)
from onnx import checker
import onnx

syms   = './mnist-symbol.json'
params = './mnist-0000.params'

input_shape = (1,1,28,28)

onnx_file = './mnist.onnx'

# Invoke export model API. It returns path of the converted onnx model
converted_model_path = onnx_mxnet.export_model(syms, params, [input_shape], np.float32, onnx_file)

# Load onnx model
model_proto = onnx.load_model(converted_model_path)

# Check if converted ONNX protobuf is valid
checker.check_graph(model_proto.graph)

3. 模型解析

MNN提供了转换ONNX到MNN模型的工具,执行如下脚本即可,关于MNN转换工具编译可以参考Model Conversion。下面是转换脚本:

./MNNConvert -f ONNX --modelFile mnist.onnx --MNNModel mnist.mnn --bizCode MNN

4. 在线部署

在线部署流程在这里,为使用MNN加载解析好的mnn模型参数进行inference等一系列业务操作。关于如何在android上面使用mnn进行部署,本专栏已经有好几篇介绍的文章,这里就不进行赘述了。完整的JNI业务代码可以参考如下链接JNI 业务代码

  • 最后

选取的样例为简单的mnist,里面没有动态op,部署流程基本没有坑,后面我们会选择一些含动态op + 静态部署的案例,尽量还原真实项目情况。另外,欢迎大家留言讨论、关注本专栏及公众号,谢谢大家!

  • 参考
  1. https://github.com/alibaba/MNN
  2. https://mxnet.incubator.apache.org/versions/master/tutorials/gluon/mnist.html
  3. https://mxnet.incubator.apache.org/versions/master/tutorials/onnx/export\_mxnet\_to\_onnx.html?highlight=onnx
  4. https://github.com/xindongzhang/MNN-APPLICATIONS/tree/master/applications/mnist


推荐阅读

专注嵌入式端的AI算法实现,欢迎关注作者微信公众号和知乎嵌入式AI算法实现专栏

WX20200305-192544.png
更多嵌入式AI相关的技术文章请关注极术嵌入式AI专栏

推荐阅读
关注数
18838
内容数
1371
嵌入式端AI,包括AI算法在推理框架Tengine,MNN,NCNN,PaddlePaddle及相关芯片上的实现。欢迎加入微信交流群,微信号:aijishu20(备注:嵌入式)
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息