从PyTorch到C++部署:手把手教你用OnnxRuntime封装一个图像分类推理类
2026/4/6 16:48:46 网站建设 项目流程
从PyTorch到C部署手把手教你用OnnxRuntime封装一个图像分类推理类在工业级应用中将深度学习模型封装成可复用的组件是提升开发效率的关键。本文将以图像分类任务为例演示如何用C和OnnxRuntime构建一个高内聚、低耦合的推理类实现从模型加载到预测的全流程封装。1. 设计推理类架构一个优秀的推理类应该具备以下特性资源自动管理利用RAII机制处理模型会话和内存接口简洁对外暴露最少的必要方法扩展性强支持不同的预处理和后处理逻辑线程安全可在多线程环境中安全调用class OnnxInferenceEngine { public: // 初始化环境并加载模型 OnnxInferenceEngine(const std::string model_path, bool use_gpu false, int intra_op_threads 4); // 执行图像分类预测 std::string predict(const cv::Mat input_image); // 获取输入输出张量信息 struct TensorInfo { std::vectorint64_t shape; std::string name; }; TensorInfo get_input_info() const; TensorInfo get_output_info() const; private: // ONNX运行时环境 Ort::Env env_; Ort::Session session_; // 输入输出配置 std::vectorconst char* input_names_; std::vectorconst char* output_names_; // 图像预处理 cv::Mat preprocess(const cv::Mat image); };2. 实现核心组件2.1 构造函数与资源初始化构造函数需要处理三件关键任务配置会话选项GPU/CPU、线程数等加载ONNX模型提取模型输入输出信息OnnxInferenceEngine::OnnxInferenceEngine(const std::string model_path, bool use_gpu, int intra_op_threads) : env_(ORT_LOGGING_LEVEL_WARNING, InferenceEngine) { Ort::SessionOptions session_options; session_options.SetIntraOpNumThreads(intra_op_threads); session_options.SetGraphOptimizationLevel(ORT_ENABLE_EXTENDED); if (use_gpu) { OrtSessionOptionsAppendExecutionProvider_CUDA(session_options, 0); } // 加载模型 session_ Ort::Session(env_, model_path.c_str(), session_options); // 获取输入输出信息 Ort::AllocatorWithDefaultOptions allocator; input_names_.push_back(session_.GetInputName(0, allocator)); output_names_.push_back(session_.GetOutputName(0, allocator)); }2.2 图像预处理模块预处理流程需要与训练时保持一致典型步骤包括颜色空间转换BGR→RGB尺寸调整缩放到模型输入尺寸归一化像素值标准化格式转换HWC→NCHWcv::Mat OnnxInferenceEngine::preprocess(const cv::Mat image) { cv::Mat processed; // 1. 颜色空间转换 cv::cvtColor(image, processed, cv::COLOR_BGR2RGB); // 2. 获取模型输入尺寸并调整 auto input_shape get_input_info().shape; cv::resize(processed, processed, cv::Size(input_shape[3], input_shape[2])); // 3. 归一化处理 processed.convertTo(processed, CV_32F, 1.0/255); cv::subtract(processed, cv::Scalar(0.485, 0.456, 0.406), processed); cv::divide(processed, cv::Scalar(0.229, 0.224, 0.225), processed); // 4. 转换维度顺序 return cv::dnn::blobFromImage(processed); }2.3 推理执行接口predict方法封装了从预处理到后处理的完整流程std::string OnnxInferenceEngine::predict(const cv::Mat input_image) { // 1. 预处理 cv::Mat blob preprocess(input_image); auto input_info get_input_info(); // 2. 创建输入张量 Ort::MemoryInfo memory_info Ort::MemoryInfo::CreateCpu( OrtArenaAllocator, OrtMemTypeDefault); Ort::Value input_tensor Ort::Value::CreateTensorfloat( memory_info, blob.ptrfloat(), blob.total(), input_info.shape.data(), input_info.shape.size() ); // 3. 执行推理 auto outputs session_.Run( Ort::RunOptions{nullptr}, input_names_.data(), input_tensor, 1, output_names_.data(), 1 ); // 4. 后处理 const float* output_data outputs[0].GetTensorDatafloat(); int pred_class std::max_element(output_data, output_data outputs[0].GetTensorTypeAndShapeInfo().GetElementCount()) - output_data; return class_names_[pred_class]; // 返回类别标签 }3. 高级功能实现3.1 动态批处理支持通过修改输入张量形状可以实现动态批处理void OnnxInferenceEngine::set_batch_size(int batch_size) { auto shape get_input_info().shape; shape[0] batch_size; // 修改batch维度 // 更新会话配置 Ort::SessionOptions new_options; new_options.AddConfigEntry(session.dynamic_batch_size, 1); session_ Ort::Session(env_, model_path_, new_options); }3.2 多模型并行支持使用Ort::Session池实现多模型并行推理class MultiModelInference { public: void add_model(const std::string name, const std::string model_path) { models_.emplace(name, std::make_uniqueOnnxInferenceEngine(model_path)); } std::string predict(const std::string model_name, const cv::Mat image) { return models_.at(model_name)-predict(image); } private: std::unordered_mapstd::string, std::unique_ptrOnnxInferenceEngine models_; };4. 性能优化技巧4.1 内存分配策略对比策略类型分配方式适用场景优缺点默认分配器OrtDeviceAllocator常规推理实现简单但频繁分配释放开销大内存池OrtArenaAllocator高吞吐场景减少内存碎片提升分配效率自定义分配器OrtCustomAllocator特殊硬件完全控制内存生命周期实现复杂4.2 线程配置建议// 最优线程数 CPU物理核心数 - 1 const int optimal_threads std::thread::hardware_concurrency() - 1; // IO绑定操作使用独立线程池 Ort::ThreadingOptions threading_options; threading_options.SetGlobalIntraOpNumThreads(optimal_threads); threading_options.SetGlobalInterOpNumThreads(1); // 单线程用于IO操作4.3 模型量化实践通过ONNX Runtime的量化工具减小模型体积# 将FP32模型量化为INT8 python -m onnxruntime.quantization.preprocess \ --input model.onnx \ --output model_quantized.onnx \ --opset 13量化后模型通常可获得3-4倍的推理速度提升同时保持90%以上的原始精度。5. 工程化部署方案5.1 跨平台编译配置使用CMake管理项目依赖find_package(OpenCV REQUIRED) find_package(ONNXRuntime REQUIRED) add_executable(inference_demo src/main.cpp src/onnx_inference.cpp) target_link_libraries(inference_demo PRIVATE ${OpenCV_LIBS} onnxruntime)5.2 容器化部署Dockerfile配置示例FROM nvidia/cuda:11.8.0-base # 安装基础依赖 RUN apt-get update \ apt-get install -y libopencv-dev \ rm -rf /var/lib/apt/lists/* # 拷贝ONNX Runtime库 COPY onnxruntime-linux-x64-gpu-1.15.0 /usr/local/onnxruntime # 设置环境变量 ENV LD_LIBRARY_PATH/usr/local/onnxruntime/lib:$LD_LIBRARY_PATH # 拷贝应用程序 COPY build/inference_demo /app/ WORKDIR /app CMD [./inference_demo]5.3 性能监控指标关键监控指标建议延迟单次推理耗时P99指标吞吐量QPSQueries Per Second资源利用率GPU/CPU使用率内存占用峰值内存消耗可通过Prometheus Grafana搭建监控看板实时跟踪这些指标。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询