环境配置1. 首先要查看我们电脑显卡的版本去安装对应的 cuda 和 cuDNNcuDNN的安装网址cuDNN Archive | NVIDIA Developerhttps://developer.nvidia.com/rdp/cudnn-archiveCuda和cuDNN安装教程(超级详细)-CSDN博客https://blog.csdn.net/jhsignal/article/details/111401628我这里CUDA的版本是 11.8使用的cuDNN版本是 8.5.0。这里注意当我们下载cuDNN后得到一个压缩包解压后得到bin、include、lib三个文件夹分别合并到 CUDA 11.8 的安装目录。检查方法在我的CUDA 下载目录下面先确认 cuda_runtime.h 真的存在C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8\includeCUDA 驱动验证打开 PowerShell输入nvidia-smi确认输出中能识别到 NVIDIA 显卡以及CUDA Version 是11.8CUDA runtime 完整性验证进入 CUDA 自带测试工具目录我这里是C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8\extras\demo_suite按住 Shift 右键打开 PowerShell输入 .\deviceQuery.exe 按住 Shift 右键打开 PowerShell输入.\deviceQuery.exe最终输出Result PASS说明 CUDA 安装完全正常。2. 下载对应版本的onnxruntime记住要选择GPU 版本我们这里 选择了 1.16.3 版本onnxruntimehttps://github.com/microsoft/onnxruntime在解压后ONNX Runtime lib 目录下的所有 dll 全部复制到目标文件中编译变动Windows 上做 GPU 深度学习必须使用 MSVC 的 cl.exe 编译器绝对不能用 MinGW 的 g。约束点 详细说明 1. 预编译库的编译器绑定 我们用的所有依赖库OpenCV、ONNX Runtime GPU、CUDA官方提供的 Windows 预编译包全都是用 MSVC 编译的。- OpenCV 的 opencv_world4120.lib/.dll 是 MSVC 编译的- ONNX Runtime 的 onnxruntime.lib/.dll 是 MSVC 编译的- CUDA 的 cudart.lib/cudnn.lib 也是 MSVC 编译的g 无法识别和链接这些 MSVC 编译的库会直接报 “无法解析的外部符号” 链接错误。 2. CUDA 的宿主编译器限制 NVIDIA 的 nvccCUDA 代码编译器在 Windows 上官方只支持 MSVC 作为 “宿主编译器”即编译 C 部分代码的编译器。虽然理论上可以强行配置 nvcc 配合 g但步骤极其繁琐且官方不保证稳定性很多 CUDA 高级特性会失效。 3. ONNX Runtime GPU 的 Windows 构建规则 ONNX Runtime 的 GPU 版本在 Windows 上仅针对 MSVC 工具链进行了优化和测试。如果非要用 g你必须自己从源码编译 ONNX Runtime配置 MinGW 工具链、CUDA 支持这对新手来说难度极大成功率极低。cl.exe 是 Visual Studio 自带的 MSVC 编译器在安装 VS2022 时勾选「使用 C 的桌面开发」就会自动安装。绝对不能直接用普通的 PowerShell 或 cmd 运行 cl.exe必须使用 VS 自带的「x64 Native Tools Command Prompt for VS 2022」这里我的编译命令是cl /EHsc test_ort.cpp /I F:/opencv/opencv/build/include /I F:\onnxruntime\onnxruntime-win-x64-gpu-1.16.3\onnxruntime-win-x64-gpu-1.16.3\include /link /LIBPATH:F:/opencv/opencv/build/x64/vc16/lib /LIBPATH:F:\onnxruntime\onnxruntime-win-x64-gpu-1.16.3\onnxruntime-win-x64-gpu-1.16.3\lib opencv_world4120.lib onnxruntime.lib 部分 作用 cl 调用 MSVC 编译器 /EHsc 启用标准 C 异常处理必须加否则 OpenCV/ONNX Runtime 会报错 test_ort.cpp 你的源代码文件 /I ... 指定头文件搜索路径I 是 Include 的缩写 /link 告诉编译器后面的参数是给链接器的 /LIBPATH:... 指定库文件搜索路径 opencv_world4120.lib onnxruntime.lib 要链接的依赖库文件这里要注意一点就是之前使用g 的编译命令 C:/Program Files/mingw64/bin/g.exe -g main_test.cpp yolov5_dnn.cpp -o main_test.exe -I F:/opencv/opencv/build/x64/install/include -L F:/opencv/opencv/build/x64/install/x64/mingw/lib -lopencv_world4120 -stdc17 -Wall -Wno-overloaded-virtualONNX Runtime 的核心流程Ort::Value ONNX Runtime 的万能数据容器张量 / Tensor创建运行环境Ort::Env env(ORT_LOGGING_LEVEL_WARNING, MyOnnxApp); 日志级别ORT_LOGGING_LEVEL_WARNING只打印警告不刷屏也可以用 INFO、ERROR 第二个参数给这个环境起个名字不影响功能配置会话参数SessionOptions给模型运行时 “设置参数、开开关、调性能” 的配置工具 创建方法Ort::SessionOptions session_options; 最常用的4个配置 // 设置线程数 session_options.SetIntraOpNumThreads(1); 填 1 单线程嵌入式 / 小模型常用 填 4 4 线程更快 填 std::thread::hardware_concurrency() 自动用满 CPU 核心 // 开启所有图优化必开速度快很多 session_options.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_ALL); ONNX Runtime 会自动优化模型结构 融合算子删掉无用节点 优先级别有4种 ORT_DISABLE_ALL → 不优化最慢 ORT_ENABLE_BASIC → 基础优化 ORT_ENABLE_EXTENDED → 进阶优化 ORT_ENABLE_ALL → 全开最强 // 启用 CUDA GPU你有 RTX3060一定要加 OrtCUDAProviderOptions cuda_options; session_options.AppendExecutionProvider_CUDA(cuda_options); //设置模型加载方式 session_options.SetSessionMemPattern(OrtSessionMemPattern_ORT);加载 ONNX 模型Ort::Session session(env, Lyolov8.onnx, session_options); 第二个参数模型路径Windows 推荐用宽字符 L 常用成员函数 // 获取输入输出数量 size_t num_inputs session.GetInputCount(); size_t num_outputs session.GetOutputCount(); // 获取输入/输出名字后续 Run 要用到 Ort::AllocatorWithDefaultOptions allocator; std::string input_name session.GetInputName(0, allocator); std::string output_name session.GetOutputName(0, allocator); // 获取输入/输出形状比如 [1,3,640,640] auto input_shape session.GetInputTypeInfo(0).GetTensorTypeAndShapeInfo().GetShape();准备输入 Tensor把你的数据比如图像数组包装成 ORT 能识别的 Tensor 创建输入 Tensor 常用方式 // 假设输入是1×3×640×640 的 float 数组 std::vectorfloat input_data(1 * 3 * 640 * 640); std::vectorint64_t input_dims {1, 3, 640, 640}; // 创建 Tensor Ort::Value input_tensor Ort::Value::CreateTensorfloat( allocator, input_data.data(), input_data.size(), input_dims.data(), input_dims.size() ); //参数的具体信息 Ort::Value input_tensor Ort::Value::CreateTensorfloat( memory_info, // 第1个参数内存信息 input_data.data(), // 第2个参数数据起始地址 tensor_size, // 第3个参数总元素个数张量长度 input_shape.data(), // 第4个参数形状数组NCHW input_shape.size() // 第5个参数维度数量几维数组 );执行推理 取输出std::vectorOrt::Value Run( const char* const* input_names, const Ort::Value* input_values, size_t num_inputs, const char* const* output_names, size_t num_outputs ); 示例 const char* in_names[] {input_name.c_str()}; const char* out_names[] {output_name.c_str()}; // 推理 std::vectorOrt::Value outputs session.Run( in_names, input_tensor, 1, out_names, 1 ); auto output_tensors session.Run( Ort::RunOptions{ nullptr }, // 运行选项默认空 input_names.data(), // 输入名字 input_tensor, // 输入张量 1, // 几个输入1 output_names.data(), // 输出名字 1 // 几个输出1 ); // 取输出数据假设输出是 float float* preds output_tensors[0].GetTensorMutableDatafloat(); 拿到模型输出的「原始浮点数组首地址」 .GetTensorMutableDatafloat() → 把输出数据变成 float* 类型指针 → 指向一大块连续内存[1,25200,85] 所有数值 auto out_shape output_tensors[0].GetTensorTypeAndShapeInfo().GetShape(); 获取输出的形状返回的是一个 vectorint64_t里面存着 3 个数字 out_shape[0] 1 out_shape[1] 25200 out_shape[2] 85
ONNXRUNTIME部署
环境配置1. 首先要查看我们电脑显卡的版本去安装对应的 cuda 和 cuDNNcuDNN的安装网址cuDNN Archive | NVIDIA Developerhttps://developer.nvidia.com/rdp/cudnn-archiveCuda和cuDNN安装教程(超级详细)-CSDN博客https://blog.csdn.net/jhsignal/article/details/111401628我这里CUDA的版本是 11.8使用的cuDNN版本是 8.5.0。这里注意当我们下载cuDNN后得到一个压缩包解压后得到bin、include、lib三个文件夹分别合并到 CUDA 11.8 的安装目录。检查方法在我的CUDA 下载目录下面先确认 cuda_runtime.h 真的存在C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8\includeCUDA 驱动验证打开 PowerShell输入nvidia-smi确认输出中能识别到 NVIDIA 显卡以及CUDA Version 是11.8CUDA runtime 完整性验证进入 CUDA 自带测试工具目录我这里是C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8\extras\demo_suite按住 Shift 右键打开 PowerShell输入 .\deviceQuery.exe 按住 Shift 右键打开 PowerShell输入.\deviceQuery.exe最终输出Result PASS说明 CUDA 安装完全正常。2. 下载对应版本的onnxruntime记住要选择GPU 版本我们这里 选择了 1.16.3 版本onnxruntimehttps://github.com/microsoft/onnxruntime在解压后ONNX Runtime lib 目录下的所有 dll 全部复制到目标文件中编译变动Windows 上做 GPU 深度学习必须使用 MSVC 的 cl.exe 编译器绝对不能用 MinGW 的 g。约束点 详细说明 1. 预编译库的编译器绑定 我们用的所有依赖库OpenCV、ONNX Runtime GPU、CUDA官方提供的 Windows 预编译包全都是用 MSVC 编译的。- OpenCV 的 opencv_world4120.lib/.dll 是 MSVC 编译的- ONNX Runtime 的 onnxruntime.lib/.dll 是 MSVC 编译的- CUDA 的 cudart.lib/cudnn.lib 也是 MSVC 编译的g 无法识别和链接这些 MSVC 编译的库会直接报 “无法解析的外部符号” 链接错误。 2. CUDA 的宿主编译器限制 NVIDIA 的 nvccCUDA 代码编译器在 Windows 上官方只支持 MSVC 作为 “宿主编译器”即编译 C 部分代码的编译器。虽然理论上可以强行配置 nvcc 配合 g但步骤极其繁琐且官方不保证稳定性很多 CUDA 高级特性会失效。 3. ONNX Runtime GPU 的 Windows 构建规则 ONNX Runtime 的 GPU 版本在 Windows 上仅针对 MSVC 工具链进行了优化和测试。如果非要用 g你必须自己从源码编译 ONNX Runtime配置 MinGW 工具链、CUDA 支持这对新手来说难度极大成功率极低。cl.exe 是 Visual Studio 自带的 MSVC 编译器在安装 VS2022 时勾选「使用 C 的桌面开发」就会自动安装。绝对不能直接用普通的 PowerShell 或 cmd 运行 cl.exe必须使用 VS 自带的「x64 Native Tools Command Prompt for VS 2022」这里我的编译命令是cl /EHsc test_ort.cpp /I F:/opencv/opencv/build/include /I F:\onnxruntime\onnxruntime-win-x64-gpu-1.16.3\onnxruntime-win-x64-gpu-1.16.3\include /link /LIBPATH:F:/opencv/opencv/build/x64/vc16/lib /LIBPATH:F:\onnxruntime\onnxruntime-win-x64-gpu-1.16.3\onnxruntime-win-x64-gpu-1.16.3\lib opencv_world4120.lib onnxruntime.lib 部分 作用 cl 调用 MSVC 编译器 /EHsc 启用标准 C 异常处理必须加否则 OpenCV/ONNX Runtime 会报错 test_ort.cpp 你的源代码文件 /I ... 指定头文件搜索路径I 是 Include 的缩写 /link 告诉编译器后面的参数是给链接器的 /LIBPATH:... 指定库文件搜索路径 opencv_world4120.lib onnxruntime.lib 要链接的依赖库文件这里要注意一点就是之前使用g 的编译命令 C:/Program Files/mingw64/bin/g.exe -g main_test.cpp yolov5_dnn.cpp -o main_test.exe -I F:/opencv/opencv/build/x64/install/include -L F:/opencv/opencv/build/x64/install/x64/mingw/lib -lopencv_world4120 -stdc17 -Wall -Wno-overloaded-virtualONNX Runtime 的核心流程Ort::Value ONNX Runtime 的万能数据容器张量 / Tensor创建运行环境Ort::Env env(ORT_LOGGING_LEVEL_WARNING, MyOnnxApp); 日志级别ORT_LOGGING_LEVEL_WARNING只打印警告不刷屏也可以用 INFO、ERROR 第二个参数给这个环境起个名字不影响功能配置会话参数SessionOptions给模型运行时 “设置参数、开开关、调性能” 的配置工具 创建方法Ort::SessionOptions session_options; 最常用的4个配置 // 设置线程数 session_options.SetIntraOpNumThreads(1); 填 1 单线程嵌入式 / 小模型常用 填 4 4 线程更快 填 std::thread::hardware_concurrency() 自动用满 CPU 核心 // 开启所有图优化必开速度快很多 session_options.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_ALL); ONNX Runtime 会自动优化模型结构 融合算子删掉无用节点 优先级别有4种 ORT_DISABLE_ALL → 不优化最慢 ORT_ENABLE_BASIC → 基础优化 ORT_ENABLE_EXTENDED → 进阶优化 ORT_ENABLE_ALL → 全开最强 // 启用 CUDA GPU你有 RTX3060一定要加 OrtCUDAProviderOptions cuda_options; session_options.AppendExecutionProvider_CUDA(cuda_options); //设置模型加载方式 session_options.SetSessionMemPattern(OrtSessionMemPattern_ORT);加载 ONNX 模型Ort::Session session(env, Lyolov8.onnx, session_options); 第二个参数模型路径Windows 推荐用宽字符 L 常用成员函数 // 获取输入输出数量 size_t num_inputs session.GetInputCount(); size_t num_outputs session.GetOutputCount(); // 获取输入/输出名字后续 Run 要用到 Ort::AllocatorWithDefaultOptions allocator; std::string input_name session.GetInputName(0, allocator); std::string output_name session.GetOutputName(0, allocator); // 获取输入/输出形状比如 [1,3,640,640] auto input_shape session.GetInputTypeInfo(0).GetTensorTypeAndShapeInfo().GetShape();准备输入 Tensor把你的数据比如图像数组包装成 ORT 能识别的 Tensor 创建输入 Tensor 常用方式 // 假设输入是1×3×640×640 的 float 数组 std::vectorfloat input_data(1 * 3 * 640 * 640); std::vectorint64_t input_dims {1, 3, 640, 640}; // 创建 Tensor Ort::Value input_tensor Ort::Value::CreateTensorfloat( allocator, input_data.data(), input_data.size(), input_dims.data(), input_dims.size() ); //参数的具体信息 Ort::Value input_tensor Ort::Value::CreateTensorfloat( memory_info, // 第1个参数内存信息 input_data.data(), // 第2个参数数据起始地址 tensor_size, // 第3个参数总元素个数张量长度 input_shape.data(), // 第4个参数形状数组NCHW input_shape.size() // 第5个参数维度数量几维数组 );执行推理 取输出std::vectorOrt::Value Run( const char* const* input_names, const Ort::Value* input_values, size_t num_inputs, const char* const* output_names, size_t num_outputs ); 示例 const char* in_names[] {input_name.c_str()}; const char* out_names[] {output_name.c_str()}; // 推理 std::vectorOrt::Value outputs session.Run( in_names, input_tensor, 1, out_names, 1 ); auto output_tensors session.Run( Ort::RunOptions{ nullptr }, // 运行选项默认空 input_names.data(), // 输入名字 input_tensor, // 输入张量 1, // 几个输入1 output_names.data(), // 输出名字 1 // 几个输出1 ); // 取输出数据假设输出是 float float* preds output_tensors[0].GetTensorMutableDatafloat(); 拿到模型输出的「原始浮点数组首地址」 .GetTensorMutableDatafloat() → 把输出数据变成 float* 类型指针 → 指向一大块连续内存[1,25200,85] 所有数值 auto out_shape output_tensors[0].GetTensorTypeAndShapeInfo().GetShape(); 获取输出的形状返回的是一个 vectorint64_t里面存着 3 个数字 out_shape[0] 1 out_shape[1] 25200 out_shape[2] 85