我们通常会遇到想让ncnn加载tensorflow、pytorch训练的深度学习模型,但实际上,ncnn是无法直接加载tensorflow或者pytorch模型的。
但我们可以通过一种变通的手段让ncnn加载它们,方法就是先将tensorflow、pytorch训练的模型转成通用深度学习模型onnx,然后再利用ncnn工具onnx2ncnn
将onnx格式的模型转成ncnn模型。
下面我们以keras训练的模型(.keras)为例,向你详细介绍一下具体的操作步骤。
keras模型转onnx
将keras模型转onnx还是比较简单的,首先我们安装tf2onnx
包,命令如下:
1 | pip install tf2onnx |
之后我们写一段python代码,如下:
1 | import tf2onnx |
上面这段代码非常简单, 它首先加载.keras模型,之后调用tf2onnx中convert类的from_keras(…)方法将keras模型转成onnx模型,最后调用onnx.save_model(…)将onnx格式模型保存成文件。
代码中唯一要注意的是,onnx_model是一个二元组,其中第一项才是真正的model,因此我们在将其保存成文件时,要通过[0]找到真正的模型。
至此,我们就将keras模型转成了onnx模型。接下来,咱们来看看如何将onnx转成ncnn模型。
onnx转ncnn
其实,onnx转ncnn也比较简单,ncnn就给我们提供了相应的工具,叫作onnx2ncnn
。下面,我们就来看一下具体该如何操作:
第一,我们需要从git上下载ncnn源码,命令如下:
1 | git clone https://github.com/Tencent/ncnn.git |
代码下载好后,接下来咱们来安装依赖库。要想将onnx2ncnn编译出来,我们需要安装几个依赖包,如opencv、protobuf等。
具体的安装命令如下所示:
1 | apt install libopencv-dev libprotobuf-dev protobuf-compiler |
当依赖库安装好后,我们就可以编译onnx2ncnn
了,编译指令如下:
1 | cd ncnn |
上面命令行中,第一步是进行到ncnn源码中,然后创建build子目录,执行cmake .. 生成Makefile,然后执行make进行编译,最终将编译好的程序安装到默认目录下(build下的tools目录)。
不出意外的话,此时我们就可以在build/install/bin中看到onnx2ncnn工具了。
接下来,我们可以使用onnx2ncnn
将onnx模型转成ncnn可以识别的模型,命令如下:
1 | ./onnx2ncnn /tf/model.onnx /tf/ncnn_model.param /tf/ncnn_model.bin |
这条命令非常简单,onnx2ncnn的第一个参数是要转换的onnx模型,而第二个参数是转换后的ncnn模型参数,而第三个参数是转换后的权重。
现在有了ncnn模型,后面我们就可以使用ncnn加载这个模型,然后进行预测了。
加载ncnn模型
总的来说,我觉得ncnn有些接口定义的确实不中pytorch和keras友好,咱们来看看ncnn是如何加载网络,并进行推理的吧!
首先我们先装好ncnn包,命令如下:
1 | pip install ncnn |
接下来,咱们来看一下如何加载模型,代码如下:
1 | import ncnn |
模型加载好后,接下来使用加载好的模型做下推理吧!代码如下:
1 | ex = model.create_extractor() |
咱们来看一下这段代码中每一行的含义是什么:
- ex = model.create_extractor(): 这一行创建了一个 ncnn 模型的提取器(Extractor)。提取器用于设置模型的输入、执行推理,并获取输出。
- ncnn_img = ncnn.Mat.from_pixels(preprocess_img.data, ncnn.Mat.PixelType.PIXEL_GRAY, preprocess_img.shape[1], preprocess_img.shape[0]): 这一行将经过预处理的图像数据转换为 ncnn::Mat 对象。from_pixels 方法用于从原始像素数据创建一个 ncnn::Mat,并指定像素类型为 PIXEL_GRAY,表示单通道黑白图像。
- ex.input(“flatten_input”, ncnn_img): 这一行将转换后的图像数据设置为模型的输入。”flatten_input” 是模型中定义的输入 blob 的名称,您需要确保与模型中的实际输入名称一致。
- output = ncnn.Mat(): 这一行创建了一个空的 ncnn::Mat 对象,用于存储模型的输出结果。
- ex.extract(“dense_1”, output): 这一行执行模型推理,将输入传递给模型并获取输出。”dense_1” 是模型中定义的输出 blob 的名称,您需要确保与模型中的实际输出名称一致。
总的来说,在推理这块ncnn的API确实不够简练!
小结
本文简要的向你介绍了如何让ncnn加载keras模型,从中你可以知道ncnn是无法直接加载keras模型的,必须要绕一下,先将keras模型转成通用模型onnx,然后再利用ncnn工具将onnx转成ncnn模型,这样才能加载。