假设你已经安装好onnx,并且成功配置。这章说的是加载onnx并推理的过程,输入的input已经是处理过后的。
下面举几个例子

图像分类推理

最常见的形式就是图像分类网络,输入是个图片mat(3x224x224),输出是个一维(1x7)向量。

int yolov5_onnx_model(Mat blob)
{
#ifdef _WIN32
const wchar_t* model_path = L"E://c++//mmpose//resnet18.onnx";
#else
const char* model_path = "E://c++//mmpose//resnet18.onnx";
#endif

	//environment (设置为VERBOSE(ORT_LOGGING_LEVEL_VERBOSE)时,方便控制台输出时看到是使用了cpu还是gpu执行)
	Ort::Env env(ORT_LOGGING_LEVEL_WARNING, "OnnxModel");
	Ort::SessionOptions session_options;
	// 使用1个线程执行op,若想提升速度,增加线程数
	session_options.SetIntraOpNumThreads(1);
	//CUDA加速开启(由于onnxruntime的版本太高,无cuda_provider_factory.h的头文件,加速可以使用onnxruntime V1.8的版本)
		//OrtSessionOptionsAppendExecutionProvider_CUDA(session_options, 0);
		// ORT_ENABLE_ALL: 启用所有可能的优化
	session_options.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_ALL);

	//load  model and creat session


	//printf("Using Onnxruntime C++ API\n");
	Ort::Session session(env, model_path, session_options);
	// print model input layer (node names, types, shape etc.)
	Ort::AllocatorWithDefaultOptions allocator;


	//model info
	// 获得模型又多少个输入和输出,一般是指对应网络层的数目
	// 一般输入只有图像的话input_nodes为1
	size_t num_input_nodes = session.GetInputCount();
	// 如果是多输出网络,就会是对应输出的数目
	size_t num_output_nodes = session.GetOutputCount();
	//printf("Number of inputs = %zu\n", num_input_nodes);
	//printf("Number of output = %zu\n", num_output_nodes);
	//获取输入name
	const char* input_name = session.GetInputName(0, allocator);
	//std::cout << "input_name:" << input_name << std::endl;
	//获取输出name
	const char* output_name = session.GetOutputName(0, allocator);
	//std::cout << "output_name: " << output_name << std::endl;
	// 自动获取维度数量
	auto input_dims = session.GetInputTypeInfo(0).GetTensorTypeAndShapeInfo().GetShape();
	auto output_dims = session.GetOutputTypeInfo(0).GetTensorTypeAndShapeInfo().GetShape();
	//std::cout << "input_dims:" << input_dims[0] << std::endl;
	//std::cout << "output_dims:" << output_dims[0] << std::endl;
	std::vector<const char*> input_names{ input_name };
	std::vector<const char*> output_names = { output_name };
	std::vector<const char*> input_node_names = { "images" };  //自己打开onnx模型看下,名称不一样会报错
	std::vector<const char*> output_node_names = { "output" };


	clock_t startTime, endTime;
	//创建输入tensor
	auto memory_info = Ort::MemoryInfo::CreateCpu(OrtAllocatorType::OrtArenaAllocator, OrtMemType::OrtMemTypeDefault);
	std::vector<Ort::Value> input_tensors;
	input_tensors.emplace_back(Ort::Value::CreateTensor<float>(memory_info, blob.ptr<float>(), blob.total(), input_dims.data(), input_dims.size()));
	/*cout << int(input_dims.size()) << endl;*/
	startTime = clock();

	//推理(score model & input tensor, get back output tensor)
	auto output_tensors = session.Run(Ort::RunOptions{ nullptr }, input_node_names.data(), input_tensors.data(), input_names.size(), output_node_names.data(), output_node_names.size());
	endTime = clock();
	assert(output_tensors.size() == 1 && output_tensors.front().IsTensor());
	//除了第一个节点外,其他参数与原网络对应不上程序就会无法执行
	//第二个参数代表输入节点的名称集合
	//第四个参数1代表输入层的数目
	//第五个参数代表输出节点的名称集合
	//最后一个参数代表输出节点的数目
	//获取输出(Get pointer to output tensor float values)
	float* floatarr = output_tensors[0].GetTensorMutableData<float>();
	// 得到最可能分类输出
	vector<float> preds;
	for (int i = 0; i < 7; i++)
	{
		preds.push_back(floatarr[i]);
	}

	// 得到分类最大id
	int classid = 0;
	for (int i = 0; i < preds.size(); i++) {
		if (preds[i] > preds[classid]) {
			classid = i;
		}
	}

	return classid;
}

——————————————————————

vector输入mat输出

这里展示的是不同输入输出的改动,例如我输入的是176448的热图,输出是25200*7的矩阵。和之前不同的是,这里直接设置了输入输出的维度,没和之前一样读取。输出读取的时候因为输出不是一维的,也有点不一样。

这里示例的是输入三维,换成一维vector也一样,重点就是按顺序拉成一维的就行。

Mat resnet18_onnx_model(vector<vector<vector<float>>> heatmaps)
{
	// onnx模型路径
#ifdef _WIN32
	const wchar_t* model_path = L"E://c++//mmpose//yolov5.onnx";
#else
	const char* model_path = "E://c++//mmpose//yolov5.onnx";
#endif


	//这四行是设置onnx环境,尽量不要去动
	Ort::Env env(ORT_LOGGING_LEVEL_WARNING, "OnnxModel"); // OnnxModel可以改成test其他东西,反正日志我是不去看的
	Ort::SessionOptions session_options;
	session_options.SetIntraOpNumThreads(1);	// 使用1个线程执行op,若想提升速度,增加线程数
	session_options.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_ALL); // ORT_ENABLE_ALL: 启用所有可能的优化

	//加载模型,开启session
	Ort::Session session(env, model_path, session_options);
	Ort::AllocatorWithDefaultOptions allocator;


	//创建输入tensor,输入的维度,我是17*64*48维的特征,onnx模型的输入要拉成一维
	std::vector<int64_t> input_node_dims = { 1, 17, 64, 48 };
	size_t input_tensor_size = 1 * 17 * 64 * 48;
	std::vector<float> input_tensor_values(input_tensor_size);
	for (int i = 0; i < input_node_dims[1]; i++) {
		for (int j = 0; j < input_node_dims[2]; j++) {
			for (int k = 0; k < input_node_dims[3]; k++) {
				input_tensor_values.push_back(heatmaps[i][j][k]);
			}
		}
	}

	auto memory_info = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault);
	Ort::Value input_tensor = Ort::Value::CreateTensor<float>(memory_info, input_tensor_values.data(), input_tensor_size, input_node_dims.data(), input_node_dims.size());
	assert(input_tensor.IsTensor());

/* 这部分不写也一样能运行,只要写input和output.name
	// 创建输出tensor
	std::vector<Ort::Value> ort_inputs;
	ort_inputs.push_back(std::move(input_tensor));
	std::vector<int64_t> output_node_dims = { 1, 7 };
	size_t output_tensor_size = 1 * 7;
	std::vector<double> output_tensor_values(output_tensor_size);
	Ort::Value output_tensor = Ort::Value::CreateTensor<double>(memory_info, output_tensor_values.data(), output_tensor_size, output_node_dims.data(), output_node_dims.size());
*/

	//推理(score model & input tensor, get back output tensor)
	auto output_tensors = session.Run(Ort::RunOptions{ nullptr }, input_node_names.data(), ort_inputs.data(), ort_inputs.size(), output_node_names.data(), output_node_names.size());

	//获取输出(Get pointer to output tensor float values)
		Ort::Value& det_out = output_tensors.at(0);
	// 得到最可能分类输出
	Mat newarr = Mat_<float>(25200, 7); //定义一个矩阵,我onnx的输出是25200x7
	for (int i = 0; i < newarr.rows; i++)
	{
		vector<float> out;
		for (int j = 0; j < newarr.cols; j++) //矩阵列数循环
		{
			newarr.at<float>(i, j) = det_out.At<float>({ 0, i, j });
		}
	}
	
	return newarr;
}
Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐