美文网首页机器学习
ncnn之模型转换与加密教程

ncnn之模型转换与加密教程

作者: 一个摸鱼AI喵 | 来源:发表于2021-10-06 09:23 被阅读0次

一、模型构造与支持模型

ncnn模型有两个文件:参数文件.param跟模型文件.bin

支持转为ncnn的模型有caffe、darknet、mxnet、onnx(故tensorflow跟pytorch模型都先要转成onnx或者其他格式)

二、模型转换

只能用CMD进入,其他方式无效

命令行中文件明的顺序也是有要求,不能调换顺序,可以理解为先放小的再放大的

在所有工作之前需要先编译ncnn,编译ncnn还需要cmake protoobuf vs2019支持,具体查看cmake_protoobuf_ncnn_opecv安装教程.md

编译后....../ncnn/build-vs2019/tools/下有caffe、darknet、onnx文件夹,里面有各自的转模型工具.exe

2.1 onnx2ncnn

进入onnx工具文件夹,并把onnx模型放入该文件夹中,也可以新建一个文件夹onnxModels放置onnx模型,新建一个文件夹ncnnModels放置ncnn模型

cd onnx
mkdir onnxModels
mkdir ncnnModels
./onnx2ncnn ./onnxModels/resnet18-sim.onnx ./ncnnModels/resnet18.param ./ncnnModels/resnet18.bin 

2.2 mxnet2ncnn

cd mxnet
mkdir mxnetModels
mkdir ncnnModels
mxnet2ncnn.exe ./mxnetModels/mnet12-symbol.json ./mxnetModels/mnet12-symbol.params ./ncnnModels/mnet12-symbol.param ./ncnnModels/mnet12-symbol.bin

或者新建一个脚本文件makemodel.dat

set MXNET_MODEL_DIR=mxnetModels
set NCNN_MODEL_DIR=ncnnModels
mxnet2ncnn.exe %MXNET_MODEL_DIR%/mnet12-symbol.json %MXNET_MODEL_DIR%/mnet12-symbol.params %NCNN_MODEL_DIR%/mnet12-symbol.param %NCNN_MODEL_DIR%/mnet12-symbol.bin
pause

运行即可

2.3 caffe2ncnn

2.3.1 旧版caffe模型转新版caffe模型

因为ncnn只支持转换新版的caffe模型,所以需要对旧版的caffe模型

$ cd caffe/build/tools
$ upgrade_net_proto_text mobilenet_deploy.prototxt mobilenet_deploy_new.prototxt
$ upgrade_net_proto_binary mobilenet.caffemodel mobilenet_new.caffemodel

2.3.2 新版caffe模型转ncnn

//在ncnn
$cd 
$./caffe2ncnn mobilenet_deploy_new.prototxt mobilenet_new.caffemodel mobilenet.param mobilenet.bin

[进行在线模型转换神器] 一键转换 Caffe, ONNX, TensorFlow 到 NCNN, MNN, Tengine (convertmodel.com)

image-20210723165936775.png

三、NCNN模型加密

在ncnn/build-vs2019/tools下有一个ncnn2mem.exe文件,对参数文件和模型文件进行加密会生成param.bin、id.h跟mem.h头文件, 命令行中不需要写param.bin

$ncnn2mem resnet18.param resnet18.bin resnet18.id.h resnet18.mem.h

注意:名字不能以数字开头

resnet18.param.bin    //二进制的模型结构文件
resnet18.id.h        //模型结构头文件
resnet18.mem.h       //模型参数头文件

读取文件

//load非加密的ncnn模型
ncnn::Net net;
net.load_param_bin("resnet18.param");
net.load_model("resnet18.bin");
//load加密的ncnn模型
ncnn::Net net;
net.load_param_bin("resnet18.param.bin");
net.load_model("resnet18.bin");

*在安卓项目中,会加入文件管理器AAssetManager mgr = AAssetManager_fromJava(env, assetManager),模型放入app/src/main/assets文件夹中,会去搜索模型.

但是纯C++项目,相对路径则是按build后所在可执行文件的地址:如vs编译后执行路径在<项目/out/build/x64-Release>下

由于param.bin窥探不到模型结构,因此,需要导入id.h头文件来获取模型的输入和输出

#include "resnet18.id.h"

resnet18.id.h文件如下:

namespace resnet18_param_id {
const int LAYER_x = 0;
const int BLOB_x = 0;
 .
 .
 .
const int LAYER_y = 77;
const int BLOB_y = 85;
} // namespace resnet18_param_id

如上可见,模型的输入为resnet18_param_id::BLOB_x,输出为resnet18_param_id::BLOB_y,定义输入和输出的代码如下:

#include "resnet18.id.h"
ncnn::Mat in;
ncnn::Mat out;
ncnn::Extractor ex = net.create_extractor();
ex.set_light_mode(true);
ex.set_num_threads(4);
ex.input(resnet18_param_id::BLOB_x, in);
ex.extract(resnet18_param_id::BLOB_y, out);

不同网络的输入输出名字不同,按实际名字来

同理,整体预测代码如下:

#include <opencv2/highgui/highgui.hpp>
#include <vector>
#include "net.h"
#include "resnet18.id.h"

using namespace std;

int main()
{
    cv::Mat img = cv::imread("test.jpg");
    int w = img.cols;
    int h = img.rows;
    ncnn::Mat in = ncnn::Mat::from_pixels_resize(img.data, ncnn::Mat::PIXEL_BGR, w, h, 224, 224);
    
    ncnn::Net net;
    net.load_param_bin("resnet18.param.bin");
    net.load_model("resnet18.bin");
    ncnn::Extractor ex = net.create_extractor();
    ex.set_light_mode(true);
    ex.set_num_threads(4);

    ncnn::Mat out;
    ex.input(resnet18_param_id::BLOB_x, in);
    ex.extract(resnet18_param_id::BLOB_y, out);

    ncnn::Mat out_flattened = out.reshape(out.w * out.h * out.c);
    vector<float> score;
    score.resize(out_flattened.w);
    for (int i = 0; i < out_flattened.w; ++i) {
        score[i] = out_flattened[i];
    }
    vector<float>::iterator max_id = max_element(score.begin(), score.end());
    printf("predicted class: %d, predicted value: %f", max_id - score.begin(), score[max_id - score.begin()]);

    net.clear();
    return 0;
}

把模型文件也打包进so

已经生成了id.h和mem.h两个头文件,

resnet18.param.bin    //二进制的模型结构文件
resnet18.id.h        //模型结构头文件
resnet18.mem.h       //模型参数头文件

此处,只需要这两个头文件即可,不需要再调用param和bin文件

从内存加载模型的代码如下:

#include "resnet18.mem.h"
ncnn::Net net;
net.load_param(resnet18_param_bin);
net.load_model(resnet18_bin);

定义输入和输出的代码和第二种方式保持一致,如下:

#include "resnet18.id.h"
ncnn::Mat in;
ncnn::Mat out;
ncnn::Extractor ex = net.create_extractor();
ex.set_light_mode(true);
ex.set_num_threads(4);
ex.input(resnet18_param_id::BLOB_x, in);
ex.extract(resnet18_param_id::BLOB_y, out);

某些使用技巧

Extractor 有个多线程加速的开关,设置线程数能加快计算

ex.set_num_threads(4);

整体预测代码如下:

#include <opencv2/highgui/highgui.hpp>
#include <vector>
#include "net.h"
#include "resnet18.id.h"
#include "resnet18.mem.h"

using namespace std;

int main()
{
    cv::Mat img = cv::imread("test.jpg");
    int w = img.cols;
    int h = img.rows;
    ncnn::Mat in = ncnn::Mat::from_pixels_resize(img.data, ncnn::Mat::PIXEL_BGR, w, h, 224, 224);
    
    ncnn::Net net;
    net.load_param(resnet18_param_bin);
    net.load_model(resnet18_bin);
    ncnn::Extractor ex = net.create_extractor();
    ex.set_light_mode(true);
    ex.set_num_threads(4);

    ncnn::Mat out;
    ex.input(resnet18_param_id::BLOB_x, in);
    ex.extract(resnet18_param_id::BLOB_y, out);

    ncnn::Mat out_flattened = out.reshape(out.w * out.h * out.c);
    vector<float> score;
    score.resize(out_flattened.w);
    for (int i = 0; i < out_flattened.w; ++i) {
        score[i] = out_flattened[i];
    }
    vector<float>::iterator max_id = max_element(score.begin(), score.end());
    printf("predicted class: %d, predicted value: %f", max_id - score.begin(), score[max_id - score.begin()]);

    net.clear();  //卸载模型
    return 0;

Net 有从 FILE* 文件描述加载的接口,可以利用这点把多个网络和模型文件合并为一个,分发时能方便些,内存引用就无所谓了

$ cat alexnet.param.bin alexnet.bin > alexnet-all.bin

#include "net.h"
FILE* fp = fopen("alexnet-all.bin", "rb");
net.load_param_bin(fp);
net.load_model(fp);
fclose(fp);

参考:use ncnn with alexnet.zh · Tencent/ncnn Wiki (github.com)

相关文章

  • 2021-07-14

    编译完成之后,build/tools文件下有模型转换的工具。新建工程,首先将开始编译出的ncnn lib导入工程,...

  • Pytorch转ncnn

    pytorch模型转ncnn ncnn是腾讯公司发布的一款深度学习框架,ncnn 是一个为手机端极致优化的高性能神...

  • NCNN-量化方案汇总

    NCNN量化之ncnn2table和ncnn2int8 一、ncnn2table生成量化表 1、首先准备工作,参考...

  • 深度学习模型转换onnx2ncnn

    我们知道现在的深度学习训练框架(如tensorflow、caffe、pytorch、MXNet等等)都有自己的模型...

  • tensorflow2ncnn模型转换源码分析

    由于ncnn作者nihui大佬说对tensorflow不是特别熟,所以ncnn的github里已经没有tensor...

  • 移动端神经网络部署框架ncnn

    https://github.com/Tencent/ncnn ncnn与tensorflow lite相比有什么...

  • ncnn c++模型测试

    ncnn c++测试 在模型转换完成后,紧接着就要真正在移动端上运行啦,不过在正式放到嵌入式设备上运行时(这一步也...

  • 腾讯云上编译安装ncnn

    服务器环境 ubuntu 20.04 更新系统 安装NCNN需要的依赖 下载NCNN 编译NCNN 安装NCNN

  • mxnet_convert_to_ncnn

    下载ncnn 下载ncnn:推荐使用git工具,不建议直接download zip,后续可能会出现.h与.cpp文...

  • ncnn使用

    使用ncnn部署的模型需要满足:模型的输入及其他层的特征图要满足16字节对齐,width x height要能整除...

网友评论

    本文标题:ncnn之模型转换与加密教程

    本文链接:https://www.haomeiwen.com/subject/anconltx.html