本篇文章将详细说明如何将onnx模型转换为在ncnn中可以使用的fp16半精度模型。

本文所使用的操作系统为Windows,使用的全部是ncnn发布包中自带的工具。首先使用onnx2ncnn将onnx模型转换为ncnn的param和bin模型,然后使用ncnnoptimize工具将上一步转换的param和bin模型转换为fp16的param和bin模型。

1 使用onnx2ncnn将onnx模型转换为ncnn中的param和bin

这个部分可以参考我的另一篇文章:NCNN – 在windows上转换onnx模型为ncnn的param,bin格式

主要使用的以下转换命令:

onnx2ncnn.exe ./input_mobile.onnx ./out_mobile.param ./out_mobile.bin

2 使用ncnnoptimize转换fp16模型

这个ncnnoptimize依然是在ncnn发布包的bin目录下,这个工具主要是对ncnn中的算子进行合并和优化,并且可以指定输出模型的精度。

主要的使用命令如下

ncnnoptimize.exe ./input.param ./input.bin ./out.param ./out.bin flag

其中flag参数为0则指fp32,参数为1则指fp16,参数65536也是指生成fp16模型,所以转换为fp16模型的命令如下

ncnnoptimize.exe ./input.param ./input.bin ./out.param ./out.bin 1

或者

ncnnoptimize.exe ./input.param ./input.bin ./out.param ./out.bin 65536

生成完成之后,可以发现fp16模型比原始的fp32模型文件大小差不多减少了一半。

3 ncnn中加载fp16模型

可以考虑为ncnn::net的opt加上

m_net.opt.use_fp16_arithmetic = true;
m_net.opt.use_fp16_packed = true;
m_net.opt.use_fp16_storage = true;

完整的示例代码可参考如下,也可参考其他开源项目代码

bool NanoDet::load_model(AAssetManager *mgr, const char *param, const char *bin, bool is_use_gpu)
{
    m_net.clear();
    m_blob_pool_allocator.clear();
    m_workspace_pool_allocator.clear();

#if NCNN_VULKAN
    m_can_use_gpu = is_use_gpu && ncnn::get_gpu_count() > 0;
    m_net.opt.use_vulkan_compute = m_can_use_gpu;
#endif
    m_net.opt.num_threads = ncnn::get_big_cpu_count();
    m_net.opt.blob_allocator = &m_blob_pool_allocator;
    m_net.opt.workspace_allocator = &m_workspace_pool_allocator;
    m_net.opt.use_fp16_arithmetic = true;
    m_net.opt.use_fp16_packed = true;
    m_net.opt.use_fp16_storage = true;

    int load_res = -1;
    load_res = m_net.load_param(mgr, param);
    if(load_res != 0)
        return false;
    load_res = m_net.load_model(mgr, bin);
    if(load_res != 0)
        return false;
    return true;
}