工程的完整github链接为:Github链接
最近由于项目和研究需要,需要选用一些开发更加灵活的框架。在tensorflow、keras和mxnet之间,我最终还是选择了mxnet。首先是出于以下几点考虑,第一是框架规模,mxnet对比其他框架,体积小、功能全;第二是灵活性,mxnet支持动态、静态的DNN开发模式,比较适合我在工程及研究中切换角色(之前虽然使用tf,但更多适合是围绕其生态来开发项目,很少用来做research);第三是mxnet及其生态的设计理念,设计新颖大胆,应为DNN的主流及最终发展方向;最后是上手速度快,mxnet我用了2小时就基本能达到小规模的项目开发及research的程度。
在选定了训练的框架后,结合之前我做过的一些MNN的小项目,我打算尝试结合mxnet及MNN来打通嵌入式端项目部署的一套工具链。这里我称之为工具链,实际上是指CNN算法项目从模型训练---->模型导出----->模型转换------>在线部署的一整套流程。目前市面上已经有了很多优秀的开源嵌入式端部署框架,如MNN、TVM、NCNN、MACE等等,这里我们选择MNN作为嵌入式端的部署框架,选取简单的视觉任务MNIST,来跟大家从头到尾讨论这个部署流程:
- 离线训练
离线训练我们采用的是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 + 静态部署的案例,尽量还原真实项目情况。另外,欢迎大家留言讨论、关注本专栏及公众号,谢谢大家!
- 参考
- https://github.com/alibaba/MNN
- https://mxnet.incubator.apache.org/versions/master/tutorials/gluon/mnist.html
- https://mxnet.incubator.apache.org/versions/master/tutorials/onnx/export\_mxnet\_to\_onnx.html?highlight=onnx
- https://github.com/xindongzhang/MNN-APPLICATIONS/tree/master/applications/mnist
推荐阅读
- 自己动手写CNN Inference框架之 (一) 开篇
- 自己动手写CNN Inference框架之 (二) conv2d
- 自己动手写CNN Inference框架之 (三) dense
- 自己动手写CNN Inference框架之 (四) avgpool
专注嵌入式端的AI算法实现,欢迎关注作者微信公众号和知乎嵌入式AI算法实现专栏。
更多嵌入式AI相关的技术文章请关注极术嵌入式AI专栏