基于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项目配置

  1. 打开项目,右击点击属性,打开C/C++属性,添加解压后的include文件路径。注意debug和release的选择。
    在这里插入图片描述

  2. 点击链接器,在附加库目录添加解压后的lib文件路径
    在这里插入图片描述

  3. 点击链接库下的输入,在附加依赖项中将lib文件中的.lib文件名都添加进去
    在这里插入图片描述

  4. 将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)

参数说明
imgfloat 类型的三维数组变量(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;
}
  • 2
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值