java调用onnx模型_Qt ncnn Android部署模型记录

现在有很多模型部署框架了,综合考虑易用性,性能,支持模型转换的类型,成熟程度,考虑使用ncnn进行模型部署。

ncnn开源地址:

Tencent/ncnn​github.com
java调用onnx模型_Qt ncnn Android部署模型记录_第1张图片

这里我使用pytorch训练好的PSENet模型进行部署。

正文

官方pytorch转ncnn说明文档

转换流程如下:

pytorch训练->onnx->onnx-simplifier->ncnn

1. pytorch训练->onnx

注意如果模型中没有sigmoid,而是在后处理中用它,导出onnx时需要在Module里加入sigmoid
注意如果有interpolate操作,align_corners参数设置为False

转换代码如下:

def torch2onnx(model, save_path):
    """
    :param model:
    :param save_path:  XXX/XXX.onnx
    :return:
    """
    model.eval()
    data = torch.rand(1, 3, 224, 224)
    input_names = ["input"]   #ncnn需要
    output_names = ["out"]  #ncnn需要
    torch.onnx._export(model, data, save_path, export_params=True, opset_version=11, input_names=input_names, output_names=output_names)
    print("torch2onnx finish.")

c6d0d8da9ccdf0ba014064febb8418ca.png

2. onnx->onnx-simplifier

2.1 安装onnx-simplifier

pip install onnx-simplifier

2.2 输入命令转换模型

python -m onnxsim pse.onnx pse_sim.onnx

得到以下结果:

00a9dd55f15c6945f1317a3e936eb74e.png

java调用onnx模型_Qt ncnn Android部署模型记录_第2张图片

3. onnx-simplifier->ncnn

3.1 下载安装protobuf

这一步我花了挺长时间的,刚开始在windows编译protobuf,现在cmake-gui中进行cmake,然后打开我的VS2013,然后发现protobuf需要c++11,但是VS2013里没有找到可以设置c++11的地方,于是放弃,转到ubuntu,安装很顺利。

在ubuntu中安装:

./configure
 make
 make check
 sudo make install
 sudo ldconfig # refresh shared library cache.

3.2 下载ncnn源码,在ncnn/tools/onnx目录下,进行make,即

mkdir build
cd build 
cmake ..
make

如果make时报一大堆错,大概如下:

 error: ‘uint8’ does not name a type
error: ‘uint64’ has not been declared
error: ‘uint32’ has not been declared
 error: ‘Cur’ was not declared in this scope

打开这里的CMakeLists.txt文件,加如以下这一句。然后重新cmake,make,通过。

add_compile_options(-std=c++11)

看到build文件夹里有了一个onnx2ncnn可执行文件。

把之前转换得到的onnx模型文件放到这里,输入以下命令进行格式转换:

./onnx2ncnn pse_sim.onnx pse_sim.param pse_sim.bin

得到以下文件:

java调用onnx模型_Qt ncnn Android部署模型记录_第3张图片

4. 在pro中添加相应的ncnn库

ncnn编译

1. 用较低版本NDK编译失败,亲测用r15c可以,如果需要vulkan,需要ndk18以上,但是18以上不支持gcc了,默认clang
2. 较低版本Qt用gcc,高版本用clang,因此高版本应当可以直接用官方公布的最新的编译好的库,用不了的话再自己编译

D:android-ndk-r15cbuildcmakeandroid.toolchain.cmake文件,把415行的-g这行去掉(删除debug编译参数,缩小二进制体积)。

cmake参数:-DANDROID_TOOLCHAIN=gcc是设置gcc编译,不设置这一项的话默认为clang,但是Qt默认是gcc的 (这项参数是我阅读NDK的android.toolchain.cmake文件代码发现的,吐血。。。)

编译ncnn:

如果cmake时报以下错:

 CMAKE_SYSTEM_NAME is 'Android' but 'NVIDIA Nsight Tegra Visual Studio
 Edition' is not installed.

添加这一项参数试试-G "Unix Makefiles"

如果cmake时报以下错:

CMake Error: CMake was unable to find a build program corresponding to "Unix Mak
efiles".  CMAKE_MAKE_PROGRAM is not set.  You probably need to select a differen
t build tool.

cmake时添加这一项`-DCMAKE_MAKE_PROGRAM="%ANDROID_NDK%/prebuilt/windows-x86_64/bin/make.exe"`

完整的过程如下:

mkdir build-android
cd build-android
set ANDROID_NDK=D:android-ndk-r15c
cmake -G "Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE=%ANDROID_NDK%/build/cmake/android.toolchain.cmake -DCMAKE_MAKE_PROGRAM="%ANDROID_NDK%/prebuilt/windows-x86_64/bin/make.exe" -DANDROID_ABI="armeabi-v7a" -DANDROID_ARM_NEON=ON -DANDROID_PLATFORM=android-23 -DANDROID_TOOLCHAIN=gcc ..
make
make install

过程如图:

java调用onnx模型_Qt ncnn Android部署模型记录_第4张图片

编译完成的库就在install文件夹里了

在Qt的pro中正常加入库和头文件路径就行了。添加库后,先弄一个简单的测试程序,通过之后再把模型相关代码加进去。

如果需要opencv-android,直接在opencv的release页面下载编译好的即可。

5. 量化

quantize说明文档在这里

优化工具在ncnn/tools/quantize里面,直接在这里cmake和make的话会报错fatal error: layer.h: 没有那个文件或目录。要在ncnn根目录创建build目录然后cmake,make。

得到以下文件:

java调用onnx模型_Qt ncnn Android部署模型记录_第5张图片

这里出现了可执行文件ncnnoptimize,然后把前面得到的两个文件放到这里,输入以下命令进行转换:

./ncnnoptimize pse_sim.param pse_sim.bin pse_sim_opt.param pse_sim_opt.bin 65536

这里的最后一项参数是指存储类型。

这个issue里说65536对应fp32, 输入其他对应fp16。但是从得到的文件大小来看,是相反的?

45719595596b422ceb16f623f6211848.png

6. 在Qt中使用模型文件

6.1 pro中要加入openmp(不加编译报错)

QMAKE_CXXFLAGS += -fopenmp
QMAKE_LFLAGS += -fopenmp
LIBS += -fopenmp -lgomp

6.2 如果编译报错:(当前Qt中用gcc,但是ncnn库是clang,需要编译一下ncnn,见第4节)

undefined reference to '__kmpc_fork_call'
undefined reference to '__kmpc_for_static_init_4'
undefined reference to '__kmpc_push_num_threads'
undefined reference to '__kmpc_for_static_init_8'

6.3 如果报错:

undefined reference to 'stderr' 

试试提高API版本,我用的是API23,就没有这个问题了

6.4 编译通过后。模型文件(param和bin放到pro同级目录下),通过pro传到assets目录中,打包到apk,在程序运行时把模型文件拷到本地。这个操作可以看我之前的博客:Qt将资源通过assets打包进apk,Qt+opencv部署深度学习模型到windows与android。

6.5 按照ncnn文档中的例子调用模型即可

6.6 pytorch中上采样操作的Size是需要根据数据变化的,但是转为ncnn的param文件中Interp记录的是固定值,对于这个问题我想着一个解决方法是部署时把输入图resize到一个固定尺寸,然后手动修改param文件中Interp里面的尺寸到对应的值。

java调用onnx模型_Qt ncnn Android部署模型记录_第6张图片

另一种方式是看到chineseocr_lite的处理方式,是把输入图片resize到一个正好可以被网络中所有上/下采样倍率整除的尺寸,然后修改param文件的缩放倍率,去掉最后两项(长宽的固定值)。

java调用onnx模型_Qt ncnn Android部署模型记录_第7张图片

6.7 如果模型推理过程中报以下错:

 Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x12600000 in tid 25119

把输入图片尺寸减小试试。

7. 结果展示

虽然检测效果不佳(手机上不能把图片resize太大,之前长边是到2240的,但是在我的手机上最多长边到800),但是先把整个流程先跑通,精度和速度后面再继续优化就行了。

java调用onnx模型_Qt ncnn Android部署模型记录_第8张图片

你可能感兴趣的:(java调用onnx模型)