1 需求
MNN 提供了模型转换工具 MNNConverter,期望可以基于简单的参数配置即可实现不同模型向Mnn模型的快速转换。
-->但转过模型的同学应该都能认识到:模型转换至今 还常常不是 一件可以完全自动化 的工作。
-->继而,我们常常面临的挑战是:基于 模型转换工具 进行 特定模型 的 模型转换 定制化修改。
-->既然要频繁大量地修改代码,一个调试环境是必须的。今天我们来解决的就是 模型转换的调试环境构建问题。
2 构建工程
我们将构建一个可以进行 onnx --> mnn 调试的Xcode工程,步骤如下:
1)编译 MnnConverter -->
2)创建基于 CommandLine 的 Xcode 工程 -->
3)链接libprotobuf.a -->
4)添加头文件查找路径 -->
5)调试文件拖拽 -->
6)main文件修改 -->
7)测试
2.1 编译 MnnConverter
首先我们需要成功 编译MnnConverter,此部分的坑请自行淌入~
MnnConverter 编译官方教程
2.2 创建基于 CommandLine 的 Xcode 工程
如下图创建一个 基于Command Line Tool 的 Xcode工程,起名如:MnnConverterDebug
2.3 链接libprotobuf.a
一般 2.1 Mnn Converter 编译成功的话 则 protobuf 应该已经安装成功了,可以确认下你的protobuf 安装路径,比如我的在:/usr/local/Cellar/protobuf/3.7.1/include/,完成后效果如下图:
Tips
你可能发现有在添加 libprotobuf.a 时,有些系统路径无法直接找到(比如 /usr/local),此时可以在桌面创建一个 指向目标路径的软连接,然后通过这个目录软连接就可以进入目标路径了。
2.4 添加头文件查找路径
我们不需要把所有头文件都显式链接到工程中,只要让工程能找得到就好了。这么做:
1) 一方面因为很多头文件我们完全不关注,
2)另一方面也能减少Mnn更新造成的调试工程配置修改代价。
参考查找路径如下:
$(PROJECT_DIR)/../MNN/tools/converter/build
$(PROJECT_DIR)/../MNN/tools/converter/build/source/onnx
$(PROJECT_DIR)/../MNN/tools/converter/source
$(PROJECT_DIR)/../MNN/tools/converter/source/common
$(PROJECT_DIR)/../MNN/tools/converter/source/include
$(PROJECT_DIR)/../MNN/tools/converter/source/IR
$(PROJECT_DIR)/../MNN/tools/converter/source/MNN
$(PROJECT_DIR)/../MNN/tools/converter/source/onnx
$(PROJECT_DIR)/../MNN/tools/converter/source/optimizer
配置效果如下图:
2.5 调试文件拖拽
一些文件是编译依赖的,一些是我们可调试过程需要参考或修改的,将他们拖入工程。
需要拖拽的文件如下:
MNN/tools/converter/build/source/onnx/onnx.pb.cc
MNN/tools/converter/source/cli.cpp
MNN/tools/converter/source/config.cpp
MNN/tools/converter/source/onnx
MNN/tools/converter/source/MNN
MNN/tools/converter/source/optimizer
MNN/tools/converter/source/common
拖拽过程中建议不要勾选 Copy items if needed。
完成后效果如图:
2.6 main文件修改
1) main 文件是基于 MNN/tools/converter/source/MNNConverter.cpp 文件内容裁剪修改的。(基于 onnx-->mnn 的转换调试需求)
2)记得将 main 文件的 后缀改为.mm
3)分别修正 __ONNX_MODEL_PATH、 __MNN_MODEL_PATH 为 onnx模型全路径 和 目标mnn模型全路径
示例如下:
//
// main.m
// MNNConverterDebug
//
// Created by Chris Yang on 2019/7/19.
// Copyright © 2019 Chris. All rights reserved.
//
#include "cli.hpp"
#include "MNN_generated.h"
#include "addBizCode.hpp"
#include "caffeConverter.hpp"
#include "optimizer.hpp"
#include "writeFb.hpp"
#define __ONNX_MODEL_PATH "....../model.onnx"
#define __MNN_MODEL_PATH "....../model.mnn"
int onnx2MNNNet(const std::string inputModel, const std::string bizCode, std::unique_ptr<MNN::NetT>& netT);
int main(int argc, char *argv[]) {
/* 1 参数模拟 */
int tmp_argc = 9;
char * tmp_argv[20];
for (int i = 0; i < 20; i++) {
tmp_argv[i] = (char *)malloc(256);
}
strcpy(tmp_argv[0], "./MNNConvert");
strcpy(tmp_argv[1], "-f");
strcpy(tmp_argv[2], "ONNX");
strcpy(tmp_argv[3], "--modelFile");
strcpy(tmp_argv[4], __ONNX_MODEL_PATH);
strcpy(tmp_argv[5], "--MNNModel");
strcpy(tmp_argv[6], __MNN_MODEL_PATH);
strcpy(tmp_argv[7], "--bizCode");
strcpy(tmp_argv[8], "MNN");
/* 2 参数解析 */
modelConfig modelPath;
Cli::initializeMNNConvertArgs(modelPath, tmp_argc, (char **)tmp_argv);
Cli::printProjectBanner();
/* 3 模型转换 onnx --> mnn */
std::cout << "Start to Convert Other Model Format To MNN Model..." << std::endl;
std::unique_ptr<MNN::NetT> netT = std::unique_ptr<MNN::NetT>(new MNN::NetT());
onnx2MNNNet(modelPath.modelFile, modelPath.bizCode, netT);
/* 4 模型优化 */
std::cout << "Start to Optimize the MNN Net..." << std::endl;
std::unique_ptr<MNN::NetT> newNet = optimizeNet(netT);
writeFb(newNet, modelPath.MNNModel, modelPath.benchmarkModel);
std::cout << "Converted Done!" << std::endl;
return 0;
}
2.7 测试
按照上面的步骤,你的工程应该可以 正常编译通过,那么,开始 快乐地打断点调试吧!
关于怎么进行较为 复杂的模型转换定制化修改,有机会我这边再整理在后续的文章中分享
3 工程Demo
使用步骤参考
1) 将 Mnn的Git工程 根目录设置为MNN
2)将 MnnConverterDebug 放置到和 MNN 同级目录下
3)修改 main.mm 中的 onnx、mnn 文件全路径
4)运行工程