以下是错误代码,它会在
ort_session.Run
中引发错误
#include "gtest/gtest.h"
#include "onnx_helper.h"
#include "ndarray.h"
#include "opencv_helper.h"
#include "vector_helper.h"
#include <iostream>
#include <opencv2/opencv.hpp>
#include <onnxruntime_cxx_api.h>
class OnnxHelper2Test : public testing::Test {
protected:
// static void SetUpTestCase() {
// }
};
std::pair<std::vector<float>, Shape> handle_input_img(const std::string &input_img_path) {
// Load the image using OpenCV
cv::Mat input_mat = cv::imread(input_img_path);
// Convert to float
cv::cvtColor(input_mat, input_mat, cv::COLOR_BGR2RGB);
input_mat.convertTo(input_mat, CV_32F);
// Normalize
input_mat /= 255.0;
// Convert the preprocessed image to a vector of floats
Ndarray<float> input_img = mat_to_ndarray(input_mat);
// std::string r = xarr_to_str(xa);
input_img.transpose({2, 0, 1});
// const std::string &xa_str1 = xarr_to_str(xa);
// std::cout << xa_str1 << std::endl;
input_img.expand_dims(0);
// const std::string &xa_str2 = xarr_to_str(xa);
// std::cout << xa_str2 << std::endl;
return {input_img.data, input_img.shape};
}
void handle_out_img(Ort::Value &output_tensor, const std::string &out_img_path) {
// Post-process the output
auto out_img = tensor_to_ndarray(output_tensor).get_sub(0);
auto out_shape = out_img.shape;
// float *data_ptr = const_cast<float *>(tensor_data);
// cv::Mat out_img(out_shape[2], out_shape[3], CV_32FC3, data_ptr);
// Transpose the image
out_img.transpose({1, 2, 0});
// Scale the image to the range [0, 255]
out_img *= 255;
out_img.clip(0, 255);
std::vector<uint8_t> out_img_int_data(out_img.data.begin(), out_img.data.end());
// Save the output image using OpenCV
auto out_mat = cv::Mat(out_img.shape[0], out_img.shape[1], CV_8UC3,
out_img_int_data.data()); // CV_8UC3 means 8u uint8_t + channel 3
cv::cvtColor(out_mat, out_mat, cv::COLOR_RGB2BGR);
cv::imwrite(out_img_path, out_mat);
}
// Method to set up the ONNX Runtime session
Ort::Session newSess(const std::string &onnx_model_path) {
Ort::Env env(ORT_LOGGING_LEVEL_WARNING, "onnxruntime");
Ort::SessionOptions se_opts;
OrtCUDAProviderOptions cudaProviderOpts;
cudaProviderOpts.gpu_mem_limit = 2 * 1024 * 1024 * 1024;
se_opts.AppendExecutionProvider_CUDA(cudaProviderOpts);
se_opts.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED);
se_opts.SetExecutionMode(ExecutionMode::ORT_SEQUENTIAL);
Ort::Session ort_session(env, onnx_model_path.c_str(), se_opts);
return ort_session;
}
int main(int argc, char **argv) {
// Load the ONNX model
auto d = "/home/roroco/Dropbox/cpp/cpp_lib/test/fix/onnx";
std::string onnx_model_path = std::format("{}/RealESRGAN_x4plus_anime_6B.onnx", d);
// // Set up the ONNX Runtime session
// Ort::Env env(ORT_LOGGING_LEVEL_WARNING, "onnxruntime");
// Ort::SessionOptions se_opts;
// OrtCUDAProviderOptions cudaProviderOpts;
// cudaProviderOpts.gpu_mem_limit = 2 * 1024 * 1024 * 1024;
// se_opts.AppendExecutionProvider_CUDA(cudaProviderOpts);
// se_opts.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED);
// se_opts.SetExecutionMode(ExecutionMode::ORT_SEQUENTIAL);
// Ort::Session ort_session(env, onnx_model_path.c_str(), se_opts);
auto ort_session = newSess(onnx_model_path);
Ort::AllocatorWithDefaultOptions allocator;
std::string input_name = ort_session.GetInputNameAllocated(0, allocator).get();
std::string out_name = ort_session.GetOutputNameAllocated(0, allocator).get();
// Perform inference
std::vector<const char *> input_names = {input_name.c_str()};
std::vector<const char *> out_names = {out_name.c_str()};
Ort::MemoryInfo memoryInfo = Ort::MemoryInfo::CreateCpu(OrtAllocatorType::OrtArenaAllocator,
OrtMemType::OrtMemTypeDefault);
// Load and preprocess input image
std::string input_img_path = std::format("{}/small.jpg", d);
auto [input_tensor_vector, input_shape] = handle_input_img(input_img_path);
// Create the input tensor
Ort::Value input_tensor = Ort::Value::CreateTensor<float>(
memoryInfo,
input_tensor_vector.data(),
input_tensor_vector.size(),
input_shape.data(),
input_shape.size());
// Create a vector of input tensors
std::vector<Ort::Value> input_tensors = {};
input_tensors.push_back(std::move(input_tensor));
std::vector<Ort::Value> out_tensors = ort_session.Run(Ort::RunOptions{nullptr}, input_names.data(),
input_tensors.data(), input_tensors.size(),
out_names.data(), out_names.size());
// Handle the output image
const std::string &out_path = std::format("{}/out.jpg", d);
handle_out_img(out_tensors[0], out_path);
std::cout << std::format("out to {}", out_path);
}
当我不使用 newSess 并将所有 newSess 代码放入 main 中时,它可以工作,以下是正确的代码
#include "gtest/gtest.h"
#include "onnx_helper.h"
#include "ndarray.h"
#include "opencv_helper.h"
#include "vector_helper.h"
#include <iostream>
#include <opencv2/opencv.hpp>
#include <onnxruntime_cxx_api.h>
class OnnxHelper2Test : public testing::Test {
protected:
// static void SetUpTestCase() {
// }
};
std::pair<std::vector<float>, Shape> handle_input_img(const std::string &input_img_path) {
// Load the image using OpenCV
cv::Mat input_mat = cv::imread(input_img_path);
// Convert to float
cv::cvtColor(input_mat, input_mat, cv::COLOR_BGR2RGB);
input_mat.convertTo(input_mat, CV_32F);
// Normalize
input_mat /= 255.0;
// Convert the preprocessed image to a vector of floats
Ndarray<float> input_img = mat_to_ndarray(input_mat);
// std::string r = xarr_to_str(xa);
input_img.transpose({2, 0, 1});
// const std::string &xa_str1 = xarr_to_str(xa);
// std::cout << xa_str1 << std::endl;
input_img.expand_dims(0);
// const std::string &xa_str2 = xarr_to_str(xa);
// std::cout << xa_str2 << std::endl;
return {input_img.data, input_img.shape};
}
void handle_out_img(Ort::Value &output_tensor, const std::string &out_img_path) {
// Post-process the output
auto out_img = tensor_to_ndarray(output_tensor).get_sub(0);
auto out_shape = out_img.shape;
// float *data_ptr = const_cast<float *>(tensor_data);
// cv::Mat out_img(out_shape[2], out_shape[3], CV_32FC3, data_ptr);
// Transpose the image
out_img.transpose({1, 2, 0});
// Scale the image to the range [0, 255]
out_img *= 255;
out_img.clip(0, 255);
std::vector<uint8_t> out_img_int_data(out_img.data.begin(), out_img.data.end());
// Save the output image using OpenCV
auto out_mat = cv::Mat(out_img.shape[0], out_img.shape[1], CV_8UC3,
out_img_int_data.data()); // CV_8UC3 means 8u uint8_t + channel 3
cv::cvtColor(out_mat, out_mat, cv::COLOR_RGB2BGR);
cv::imwrite(out_img_path, out_mat);
}
// Method to set up the ONNX Runtime session
Ort::Session newSess(const std::string &onnx_model_path) {
Ort::Env env(ORT_LOGGING_LEVEL_WARNING, "onnxruntime");
Ort::SessionOptions se_opts;
OrtCUDAProviderOptions cudaProviderOpts;
cudaProviderOpts.gpu_mem_limit = 2 * 1024 * 1024 * 1024;
se_opts.AppendExecutionProvider_CUDA(cudaProviderOpts);
se_opts.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED);
se_opts.SetExecutionMode(ExecutionMode::ORT_SEQUENTIAL);
Ort::Session ort_session(env, onnx_model_path.c_str(), se_opts);
return ort_session;
}
int main(int argc, char **argv) {
// Load the ONNX model
auto d = "/home/roroco/Dropbox/cpp/cpp_lib/test/fix/onnx";
std::string onnx_model_path = std::format("{}/RealESRGAN_x4plus_anime_6B.onnx", d);
// Set up the ONNX Runtime session
Ort::Env env(ORT_LOGGING_LEVEL_WARNING, "onnxruntime");
Ort::SessionOptions se_opts;
OrtCUDAProviderOptions cudaProviderOpts;
cudaProviderOpts.gpu_mem_limit = 2 * 1024 * 1024 * 1024;
se_opts.AppendExecutionProvider_CUDA(cudaProviderOpts);
se_opts.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED);
se_opts.SetExecutionMode(ExecutionMode::ORT_SEQUENTIAL);
Ort::Session ort_session(env, onnx_model_path.c_str(), se_opts);
// auto ort_session = newSess(onnx_model_path);
Ort::AllocatorWithDefaultOptions allocator;
std::string input_name = ort_session.GetInputNameAllocated(0, allocator).get();
std::string out_name = ort_session.GetOutputNameAllocated(0, allocator).get();
// Perform inference
std::vector<const char *> input_names = {input_name.c_str()};
std::vector<const char *> out_names = {out_name.c_str()};
Ort::MemoryInfo memoryInfo = Ort::MemoryInfo::CreateCpu(OrtAllocatorType::OrtArenaAllocator,
OrtMemType::OrtMemTypeDefault);
// Load and preprocess input image
std::string input_img_path = std::format("{}/small.jpg", d);
auto [input_tensor_vector, input_shape] = handle_input_img(input_img_path);
// Create the input tensor
Ort::Value input_tensor = Ort::Value::CreateTensor<float>(
memoryInfo,
input_tensor_vector.data(),
input_tensor_vector.size(),
input_shape.data(),
input_shape.size());
// Create a vector of input tensors
std::vector<Ort::Value> input_tensors = {};
input_tensors.push_back(std::move(input_tensor));
std::vector<Ort::Value> out_tensors = ort_session.Run(Ort::RunOptions{nullptr}, input_names.data(),
input_tensors.data(), input_tensors.size(),
out_names.data(), out_names.size());
// Handle the output image
const std::string &out_path = std::format("{}/out.jpg", d);
handle_out_img(out_tensors[0], out_path);
std::cout << std::format("out to {}", out_path);
}
我认为两个代码是相同的,为什么第一个代码会引发错误
它没有在文档中明确说明它确实如此,但我想
Ort::Session
保留对 env
的引用,一旦 newSess
返回,它就是一个悬空引用。您需要在 env
之外创建 newSess
:
Ort::Session newSess(Ort::Env& env, const std::string &onnx_model_path) {
Ort::SessionOptions se_opts;
OrtCUDAProviderOptions cudaProviderOpts;
cudaProviderOpts.gpu_mem_limit = 2 * 1024 * 1024 * 1024;
se_opts.AppendExecutionProvider_CUDA(cudaProviderOpts);
se_opts.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_EXTENDED);
se_opts.SetExecutionMode(ExecutionMode::ORT_SEQUENTIAL);
Ort::Session ort_session(env, onnx_model_path.c_str(), se_opts);
return ort_session;
}
Ort::Env env(ORT_LOGGING_LEVEL_WARNING, "onnxruntime");
auto ort_session = newSess(env, onnx_model_path);