基于OnnxRuntime推理类C++
前言
近来可能有几个项目需要使用C++做模型推理的任务,为了方便模型的推理,基于OnnxRuntime封装了一个推理类,只需要简单的几句话就可以完成推理,方便后续不同场景使用。
OnnxRuntime的安装配置(VS)
下载Onnxruntime
这里有所有的onnxruntime下载链接:https://github.com/microsoft/onnxruntime/tags
由于版本差异比较大,如果是安装gpu版本要查看设备的cudnn版本选择对应的版本下载,我这里使用的是cpu版本,为1.11.1。
下载后解压到自己的目录,例如 D:\onnxruntime-win-x64-1.11.1
Visual Studio项目配置
-
打开项目,右击点击属性,打开C/C++属性,添加解压后的include文件路径。注意debug和release的选择。
-
点击链接器,在附加库目录添加解压后的lib文件路径
-
点击链接库下的输入,在附加依赖项中将lib文件中的.lib文件名都添加进去
-
将lib中的dll添加到对应的活动配置下去。使用Debug就放到Debug,Release就放到Release。跟你生成的exe同级
OnnxRuntime推理类
接口API
• static OnnxInfer* getInstance()
返回唯一的OnnxInfer实例指针。
• void OnnxInfer::loadModel(const char* modelpath, const char* inputname, const char* outputname)
函数功能:加载模型到内存。
参数 | 说明 |
---|---|
modelpath | 模型的加载路径,文件后缀名为 .onnx |
inputname | 模型的输入名,可以在https://netron.app/可视化模型查看 |
outputname | 模型的输出名,同上。目前多个输出名只能选择一个。 |
• void OnnxInfer::setImgParameter(int channel, int height, int width)
函数功能:为图推理模式设置输出输出的维度。
参数 | 说明 |
---|---|
channel | 模型推理图片时的输入图片通道数 |
height | 模型推理图片时的输入图片高度 |
width | 模型推理图片时的输入图片宽度 |
• float* OnnxInfer::inferImg(void *img)
参数 | 说明 |
---|---|
img | float 类型的三维数组变量(float[C][H][W])(指针即可) |
返回值 | 说明 |
---|---|
float* | 浮点数指针,总长度对应模型输出总数。根据需要添加后处理 |
• void OnnxInfer::setFigureParameter(int size)
函数功能:为数推理模式设置输出输出的维度。参数说明参考图推理即可。
• float* OnnxInfer::inferFigure(void* figures)
函数功能:进行数推理,返回推理结果。参数说明参考图推理即可。
调用样例
#include <onnxinfer.h>
#define C 7
#define H 16
#define W 16
using namespace std;
int main()
{
OnnxInfer* infer = OnnxInfer::getInstance();//获取类对象指针
infer->loadModel("model\\test.onnx","input","output");//初始化模型
infer->setImgParameter(C,H,W);//设置图推理参数
float[C][H][W] arr;//推理的输入,根据需要构造
float* out = infer->inferImg(arr);//推理返回结果
return 0;
}
源码
onnxinfer.h
#pragma once
#ifndef _ONNXINFER_H_
#define _ONNXINFER_H_
#include <onnxruntime_cxx_api.h>
#include <vector>
#include <iostream>
class OnnxInfer
{
private:
static OnnxInfer* instance; //单例模式
private:
OnnxInfer() {ImgParameterPre = false;FigureParameterPre = false;};//空构造函数
~OnnxInfer() {};//析构函数
OnnxInfer(const OnnxInfer&);//拷贝构造
OnnxInfer& operator=(const OnnxInfer&);//赋值构造
public:
//返回唯一的私有实例
static OnnxInfer* getInstance() {
if (instance == NULL) {
instance = new OnnxInfer();
}
return instance;
};
private:
//静态嵌套类,保证程序结束执行指针释放,避免内存泄漏。
class Deletor {
public:
~Deletor() {
if (OnnxInfer::instance != NULL)
delete OnnxInfer::instance;
}
};
static Deletor deletor;
private:
Ort::Session *session; //推理模型
const char* inputname; //模型的输入名
const char* outputname;//模型的输出名
int height; //图推理中图片的高度
int width; //图推理中图片的宽度
int channel; //图推理的通道数
int size; //数推理中向量的维度
bool ImgParameterPre; //图参数是否初始化的标志
bool FigureParameterPre; //数参数是否初始化的标志
public:
void loadModel(const char* modelpath, const char* inputname, const char* outputname);//根据路径加载模型
void setImgParameter(int channel, int height, int width);//设置图推理模式下的输入输出维度
void setFigureParameter(int size);//设置数推理模式下的输入输出维度
float* inferImg(void *img);//图推理,返回结果
float* inferFigure(void *figures);//数推理,返回结果
};
#endif
onnxinfer.cpp
include "onnxinfer.h"
//初始化静态成员
OnnxInfer* OnnxInfer::instance = NULL;
void OnnxInfer::loadModel(const char* modelpath, const char* inputname, const char* outputname)
{
//char转wchar_t
size_t charNum = 0;
while (modelpath[charNum++] != '\0');
wchar_t* model_path = new wchar_t[++charNum];
mbstowcs_s(NULL, model_path, charNum, modelpath, _TRUNCATE);
Ort::Env env(ORT_LOGGING_LEVEL_WARNING, "Default");
Ort::SessionOptions session_options;
session_options.SetIntraOpNumThreads(1);
session = new Ort::Session(env, model_path, session_options);
this -> inputname = inputname;
this -> outputname = outputname;
}
void OnnxInfer::setImgParameter(int channel, int height, int width)
{
this->ImgParameterPre = true;
this->channel = channel;
this->height = height;
this->width = width;
}
void OnnxInfer::setFigureParameter(int size)
{
this->FigureParameterPre = true;
this->size = size;
}
float* OnnxInfer::inferImg(void *img)
{
if (!this->ImgParameterPre) {
std::cout << "未设置输入输出维度" << std::endl;
}
std::array<int64_t, 4> input_shape{ 1, channel, height, width };
auto memory_info = Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeDefault);
const char* input_names[] = { this->inputname };
const char* output_names[] = { this->outputname };
Ort::Value input_tensor{ nullptr };
input_tensor = Ort::Value::CreateTensor<float>(memory_info, (float*)img, channel*height*width, input_shape.data(), input_shape.size());
std::vector<Ort::Value> output_tensor = session->Run(Ort::RunOptions{ nullptr }, input_names, &input_tensor, 1, output_names, 1);
float* out = output_tensor[0].GetTensorMutableData<float>();
return out;
}
float* OnnxInfer::inferFigure(void* figures)
{
if (!this->FigureParameterPre) {
std::cout << "未设置输入输出维度" << std::endl;
}
std::array<int64_t, 2> input_shape{ 1, size };
auto memory_info = Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeDefault);
const char* input_names[] = { this->inputname };
const char* output_names[] = { this->outputname };
Ort::Value input_tensor{ nullptr };
input_tensor = Ort::Value::CreateTensor<float>(memory_info, (float*)figures, size, input_shape.data(), input_shape.size());
std::vector<Ort::Value> output_tensor = session->Run(Ort::RunOptions{ nullptr }, input_names, &input_tensor, 1, output_names, 1);
float* out = output_tensor[0].GetTensorMutableData<float>();
return out;
}