Pytorch使用c++调用模型

您所在的位置:网站首页 django调用pytorch模型 Pytorch使用c++调用模型

Pytorch使用c++调用模型

2023-09-15 00:22| 来源: 网络整理| 查看: 265

之前说过一个c++上调用pytorch现在又反过来了~~ 其实还是仅用c代码哈 生产环境还是用这个

C++推理框架ncnn为例,介绍一下部署的大致流程

PyTorch模型 --> ONNX格式 --> C++推理框架

其它C++推理框架的思路类似,唯一的学习成本是推理框架本身的API。

一、PyTorch模型转ONNX

ONNX is an open format built to represent machine learning models. ONNX defines a common set  of operators - the building blocks of machine learning and deep  learning models - and a common file format to enable AI developers to  use models with a variety of frameworks, tools, runtimes, and compilers.

简单来说,可以把ONNX当做一个中间格式。绝大多数的机器学习/深度学习框架都可以将自身的模型转换成ONNX,同样也能把ONNX转换成自身框架的格式,如下图所示。

图1 不同框架的模型利用ONNX进行相互转换 

ONNX官网地址:https://onnx.ai/

在PyTorch中,可以用如下方法非常方便地将一个PyTorch模型存储为ONNX格式:

import torch # 指定输入尺寸,ONNX需要这个信息来确定输入大小 # 参数对应于 (batch_size, channels, H, W) dummy_input = torch.randn(1, 3, 224, 224, device="cuda") # model为模型自身 # dummy_input根据自己的需求更改其尺寸 # "model.onnx"为输出文件,更改为自己的路径即可 torch.onnx.export(model, dummy_input, "model.onnx")

torch.onnx.export还有一些额外的参数可以实现更灵活的使用方法,详见https://pytorch.org/docs/stable/onnx.html。本文的示例足以让您能够成功部署自己的模型。

需要注意的是,ONNX的目的是“通用”,所以难免会在一些情况出现算子不兼容的情况。具体的表现是,当你把某个框架(例如PyTorch)的模型转成ONNX后,再将ONNX转成另一框架模型(例如ncnn)时,可能会报错(xxx算子不支持)。不兼容的情况多种多样,这里不举例说明了,需要具体情况具体分析。

一些有效的解决方法:

使用ONNXSIM对ONNX模型进行精简。非常有效。个人建议:只要使用了ONNX,都用ONNXSIM对ONNX模型进行处理一次。Github地址:https://github.com/daquexian/onnx-simplifier。使用非常方便,使用“pip install onnxsim”安装,然后使用命令“onnxsim input_onnx_model_path output_onnx_model_path”即可。代码中调用也很简单,参考Git地址里的示例。

避免依赖于中间变量的尺寸来进行运算。比如,在一些Image to Image的任务中,可能会根据中间tensor的尺寸来对另一些tensor进行resize。这时我们的做法是先去获取中间tensor的尺寸H、W,然后将它们作为参数送给其它方法。当遇到这种运算时,ONNX似乎会创建两个与H、W相关的变量,但它们的值会绑定为用dummy_input去forward一次时得到的H、W。这个值一旦绑定就不会改变。所以后续当使用不同尺寸输入时极大概率会报错(这点没有仔细验证过,但看中间结果很像是这种情况)。

另外强烈建议使用一些网络可视化工具。当遇到模型转换报错时可以用来方便定位出错的位置。个人比较喜欢的是netron,地址:https://github.com/lutzroeder/netron

放一张仓库中的图,效果如下:

二、ONNX转ncnn

ncnn是腾讯开源的轻量级推理框架。简单易用是它最大的特点。但当功耗、时耗是主要考虑点的时候,需要多尝试其它框架,如TensorFlow Lite。

ncnn地址:https://github.com/Tencent/ncnn

ncnn提供了将onnx转换为ncnn格式的工具。可以在此处找到:https://github.com/Tencent/ncnn/releases。例如,在Windows下,可以下载https://github.com/Tencent/ncnn/releases/download/20221128/ncnn-20221128-windows-vs2017.zip。解压后在x64或x86的bin文件夹中能够找到onnx2ncnn.exe。在命令行中使用如下命令即可将onnx转换为ncnn格式:

onnx2ncnn.exe onnx_model_path [ncnn.param] [ncnn.bin]

onnx_model_path 替换为自己的onnx模型地址。后两个参数可选。如果不写,那么会在onnx2ncnn.exe同目录下产生转换后的ncnn模型文件:一个.param文件和一个.bin文件。也可以自己填后两个参数来自己指定文件输出路径。

三、在ncnn下进行模型推理

在任何框架下推理都只需要两步:加载模型和将数据转化为框架格式。

ncnn下加载模型的方法为(还有其它方法):

ncnn::Net model;  // 定义一个模型 model.load_param("model.param");   // 加载模型的param文件 model.load_model("model.bin");        // 加载模型的bin文件

加载模型后,只需要将数据转化为ncnn的格式即可。ncnn模型输入的格式是ncnn::Mat。

OpenCV的Mat转ncnn::Mat的方法全列于此处:

https://github.com/Tencent/ncnn/wiki/use-ncnn-with-opencv

如:

// cv::Mat a(h, w, CV_8UC3); ncnn::Mat in = ncnn::Mat::from_pixels(a.data, ncnn::Mat::PIXEL_BGR2RGB, a.cols, a.rows);

在JNI中要将一个android bitmap转换为ncnn::Mat可参考官方示例:https://github.com/nihui/ncnn-android-squeezenet/blob/master/app/src/main/jni/squeezencnn_jni.cpp

代码如:

// ncnn from bitmap ncnn::Mat in = ncnn::Mat::from_android_bitmap(env, bitmap, ncnn::Mat::PIXEL_BGR);

有了模型和输入,最后forward一次,再取结果即可:

ncnn::Extractor ex = model.create_extractor(); // input_name 可以通过netron对.param或.bin文件进行查看 // 将input_name替换为模型的第一个输入位置的名字即可  ex.input(input_name, in); ncnn::Mat out;  // 用来存放输出结果 // output_name可以通过netron对.param或.bin文件进行查看 // 将output_name替换为模型的输出位置的名字即可 ex.extract(output_name, out);

只要是转换模型,大多数路径都是如此,学习成本并不高。主要是学习推理框架的成本。芯片厂商自身的推理框架相对复杂点,各种奇奇怪怪的条条框框。

whaosoft aiot http://143ai.com  



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3