Mnn Converter Debug ---- 基于Xcode 构建以 onnx-->mnn 为例的 模型转换调试工程

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

Mnn Converter Debug ---- 基于Xcode 构建以 onnx-->mnn 为例的 模型转换调试工程_第1张图片
选择Command Line Tool
Mnn Converter Debug ---- 基于Xcode 构建以 onnx-->mnn 为例的 模型转换调试工程_第2张图片
起名如:MnnConverterDebug

2.3 链接libprotobuf.a

一般 2.1 Mnn Converter 编译成功的话 则 protobuf 应该已经安装成功了,可以确认下你的protobuf 安装路径,比如我的在:/usr/local/Cellar/protobuf/3.7.1/include/,完成后效果如下图:

Mnn Converter Debug ---- 基于Xcode 构建以 onnx-->mnn 为例的 模型转换调试工程_第3张图片
链接libprotobuf.a

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

配置效果如下图:


Mnn Converter Debug ---- 基于Xcode 构建以 onnx-->mnn 为例的 模型转换调试工程_第4张图片
添加头文件查找路径

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

Mnn Converter Debug ---- 基于Xcode 构建以 onnx-->mnn 为例的 模型转换调试工程_第5张图片
不要勾选Copy items if needed

完成后效果如图:

Mnn Converter Debug ---- 基于Xcode 构建以 onnx-->mnn 为例的 模型转换调试工程_第6张图片
拖拽的文件/文件夹

2.6 main文件修改

1) main 文件是基于 MNN/tools/converter/source/MNNConverter.cpp 文件内容裁剪修改的。(基于 onnx-->mnn 的转换调试需求)
2)记得将 main 文件的 后缀改为.mm
3)分别修正 __ONNX_MODEL_PATH、 __MNN_MODEL_PATHonnx模型全路径目标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& 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 netT = std::unique_ptr(new MNN::NetT());
    onnx2MNNNet(modelPath.modelFile, modelPath.bizCode, netT);
    
    /* 4 模型优化 */
    std::cout << "Start to Optimize the MNN Net..." << std::endl;
    std::unique_ptr newNet = optimizeNet(netT);
    writeFb(newNet, modelPath.MNNModel, modelPath.benchmarkModel);
    std::cout << "Converted Done!" << std::endl;
    
    return 0;
}

2.7 测试

按照上面的步骤,你的工程应该可以 正常编译通过,那么,开始 快乐地打断点调试吧!

关于怎么进行较为 复杂的模型转换定制化修改,有机会我这边再整理在后续的文章中分享

3 工程Demo

工程Demo Git链接

使用步骤参考
1) 将 Mnn的Git工程 根目录设置为MNN
2)将 MnnConverterDebug 放置到和 MNN 同级目录下
3)修改 main.mm 中的 onnx、mnn 文件全路径
4)运行工程

你可能感兴趣的