资讯动态

onnxruntime-win-x64-1.23.1.zip:C++离线推理部署实战与避坑指南

发布时间:2026/10/31 6:23:14 来源:尧图企业网站定制
简介微软官方发布的 onnxruntime 1.23.1 Windows x64 CPU 预编译包属于安装包类资源专为需要快速集成 ONNX 模型推理能力的 C/C 或 Python 开发者准备。ONNX Runtime 是微软开源的跨平台推理引擎可将 PyTorch、TensorFlow 等训练的模型高效部署到本地并显著提升推理性能。该版本为 CPU 版解压即用特别适合内网环境或官方下载不稳定的情况下作为备份。压缩包共 26 个文件约 74.48 MB包含 14 个头文件、2 个动态库及配套导入库、2 个调试符号文件以及说明文档、许可证、第三方声明和版本标识等目录按头文件目录与库目录清晰组织便于 Visual Studio 等工程直接引用。目前已有 47 人学习下载可用作团队内部共享的离线资源。从工程角度看头文件与库文件分离的结构使依赖关系一目了然可快速接入 CMake 或 Visual Studio 项目同时附带版本核对信息有助于确认环境一致性、快速定位配置问题。无论是快速原型验证还是生产环境部署这套预编译包都能直接复用为开发者节省大量构建时间。1. onnxruntime-win-x64-1.23.1.zip我为什么建议直接用它而不是自己编译 ONNX Runtimeonnxruntime 1.23.1 的 Windows x64 官方发布包是一个解压就能用的 C 推理运行时。很多人会把 ONNX 和 ONNX Runtime 混为一谈ONNX 是模型格式ONNX Runtime 才是真正加载模型、执行算子、管理内存的引擎。这个 zip 解决的是“拿到 .onnx 模型如何在 Windows x64 进程里把推理跑起来”适合两类人一是被 CMake 和头文件缠住的 C 开发者二是内网环境装不了 pip 包、只能用官方二进制的部署人员。它不是安装向导解压后没有 setup.exe。核心是 dll、头文件和导入库相当于把运行时组件交给你由你决定是拷进工程、加 PATH还是用 CMake 链接。接下来按“拆包 → 接入 → 验证 → 排坑”的顺序把边界、参数和容易翻车的地方逐个过一遍。2. 解压后的真实结构onnxruntime.dll、头文件、lib 文件各归各位第一次解开 onnxruntime-win-x64-1.23.1.zip你大概率会看到 include、lib、bin 三个目录外加 LICENSE、README 和 ThirdPartyNotices。第一反应别去翻 README先把 dll 拷贝到工程里试试能不能加载比什么都管用。这个包本质上是一个“绿色”运行时所有组件都集中在解压目录里只要机器上有对应版本的 VC 运行库它就能跑。下面按我常用的排查顺序过一遍。2.1 官方 zip 里典型布局速览路径内容接入时怎么处理bin/onnxruntime.dll核心推理动态库运行时必须能被进程找到拷贝到 exe 旁或加入 PATHinclude/onnxruntime_c_api.hC API 声明C 工程 include 该目录include/onnxruntime_cxx_api.hC API 封装C 工程 include内部会再拉取 C API 声明lib/onnxruntime.lib导入库链接时传给 linker实际调用的还是 bin 里的 dllLICENSE / README许可与说明保留即可商用分发时要带着 LICENSE官方每个 release 版本的目录结构基本稳定但 include 下有少量辅助头文件比如 onnxruntime_utils.h、onnxruntime_float16.h 等。写业务代码时只 include onnxruntime_cxx_api.h 就足够不用逐个关心辅助头文件。lib 目录下这个 onnxruntime.lib 不是完整的静态库它只负责把符号搬运给可执行文件真正运行时还是找 bin/onnxruntime.dll。所以工程里就算 link 成功运行阶段 dll 找不到一样会崩这个问题在第五章会单独讲。2.2 运行时依赖不是解压就能跑缺的是 VC 运行库很多人在这一步以为 zip 是“免安装”结果双击 demo 直接报“VCRUNTIME140.dll 找不到”。这不是 onnxruntime 文件损坏而是 Windows 上没有对应的 VC 运行库。官方二进制使用 MD 动态链接模式依赖 msvcp140.dll、vcruntime140.dll、vcruntime140_1.dll 等。如果机器上装过 Visual C Redistributable 2015-2022 x64这些文件就有没有就去微软官网下载对应版本。还可以用 PowerShell 先看一下 dll 是否能加载$dll Get-Item .\bin\onnxruntime.dll $dll.VersionInfo | Select-Object FileVersion, ProductVersion, FileDescription这段命令读的是 Windows PE 文件里的版本资源。如果能看到 FileVersion 前缀是 1.23.1说明文件本身完整如果报错多数是文件下载不完整或路径不对。版本资源里的 FileVersion 常带内部 build 号只要前缀是 1.23.1 就能认定是目标发行版。2.3 先分清 CPU 版还是 GPU 版别被“win-x64”骗了这个包的名字里没有 gpu也没有 dml所以它是纯 CPU 的 ONNX Runtime。有些项目跑起来性能不符合预期最后发现用的是 CPU provider。如果你要 CUDA 或者 DirectML需要另外找 onnxruntime-gpu-win-x64 或 onnxruntime-directml-win-x64 的对应版本打包结构和接入方式类似但额外依赖 CUDA/cuDNN 或 DirectML.dll。确认当前 dll 支持哪些执行提供程序可以在程序里打印 Ort::GetAvailableProviders()这个最后一张会再演示。日常做法是先用这个 CPU 包把整条推理链路跑通再根据硬件换 GPU 包。这样排错时目标更干净不会一上来就陷入“CUDA 版本对不上”的泥潭。2.4 include、lib、bin 三者的关系与 x64 边界很多从 Java/Python 转过来的同学第一次看到 import library 会以为 lib 里是完整实现。其实 onnxruntime.lib 只记录导出符号的位置真正算力在 dll 里。编译期链接器用 lib 找到符号名运行期 loader 按 dll 的导出表加载函数地址。这意味着你把 dll 挪走exe 就会在启动阶段报“找不到入口点”或“找不到 onnxruntime.dll”。另外要特别记住这个包是 x64 的工程目标平台必须是 x64 而不是 Win32。VS 默认新项目有时候是 x86Debug|x86 下去链接会直接报“无法解析的外部符号”或者运行时报“试图加载格式不正确的程序”。我一般会在 CMake 里显式写set(CMAKE_GENERATOR_PLATFORM x64)避免生成 32 位目标。提示如果想把 dll 打进局域网分发包不要只拷 onnxruntime.dll还要带上 LICENSE。ONNX Runtime 的 MIT 许可要求保留版权声明。3. 在 C 工程里接住 1.23.1CMake 链接与最小推理示例这一章解决的是“怎么把 zip 变成实际能跑的 exe”。我见过太多人卡在第三行代码之前不是头文件找不到就是 lib 和 dll 对不上。这里给出一个我常用的、离线可用的接入方案不依赖 vcpkg也不依赖 NuGet。3.1 为什么不建议在这个场景下用 vcpkg 或 NuGet 包vcpkg 安装 onnxruntime 会牵扯到工具链、版本匹配、编译缓存第一次装可能要等很久。NuGet 的 Microsoft.ML.OnnxRuntime 主要面向 .NET对纯 C 工程来说引入了一堆不必要的东西。而这个官方 zip 本身就是微软为 Windows 原生分发准备的二进制包当你需要锁定 1.23.1 这个精确版本或者在内网离线交付直接解压 zip 是最可控的路线。3.2 CMakeLists.txt 最小配置假设解压后的目录叫onnxruntime-win-x64-1.23.1并且放在工程的third_party下面。CMake 可以这样写cmake_minimum_required(VERSION 3.18) project(ort_demo CXX) set(CMAKE_CXX_STANDARD 17) set(ORT_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/third_party/onnxruntime-win-x64-1.23.1) include_directories(${ORT_ROOT}/include) link_directories(${ORT_ROOT}/lib) add_executable(demo main.cpp) target_link_libraries(demo PRIVATE onnxruntime) # 运行前把 dll 拷到 exe 旁边避免“找不到 onnxruntime.dll” add_custom_command(TARGET demo POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different ${ORT_ROOT}/bin/onnxruntime.dll $TARGET_FILE_DIR:demo)这里link_directories不加也可以改成在target_link_libraries里写完整路径更稳target_link_libraries(demo PRIVATE ${ORT_ROOT}/lib/onnxruntime.lib)两种方式都行关键是 lib 路径和 include 路径指向同一个 1.23.1 解压目录。我习惯把 dll 通过 POST_BUILD 自动拷贝这样每次重新编译后 exe 旁边都会有最新的 dll不会出现“本机能跑换台机器就崩”的玄学问题。3.3 第一个推理代码Ort::Session 读取模型并输出张量下面这个例子假设你有一个model.onnx输入是 shape 为[1, 784]的 float 张量。重点看 session 创建和 run 的调用方式#include onnxruntime_cxx_api.h #include vector #include iostream int main() { Ort::Env env(ORT_LOGGING_LEVEL_WARNING, ort-demo); Ort::SessionOptions opts; opts.SetIntraOpNumThreads(2); opts.SetGraphOptimizationLevel(ORT_ENABLE_ALL); Ort::Session session(env, Lmodel.onnx, opts); Ort::AllocatorWithDefaultOptions allocator; auto input_name session.GetInputNameAllocated(0, allocator); auto output_name session.GetOutputNameAllocated(0, allocator); const char* input_names[] { input_name.get() }; const char* output_names[] { output_name.get() }; std::vectorint64_t input_shape { 1, 784 }; std::vectorfloat input_data(1 * 784, 0.5f); std::vectorOrt::Value input_tensors; input_tensors.push_back(Ort::Value::CreateTensorfloat( allocator, input_data.data(), input_data.size(), input_shape.data(), input_shape.size())); auto output_tensor session.Run(Ort::RunOptions{nullptr}, input_names, input_tensors.data(), 1, output_names, 1); auto output_info output_tensor[0].GetTensorTypeAndShapeInfo(); auto output_shape output_info.GetShape(); std::cout output dims: output_shape.size() std::endl; }逻辑不复杂先创建 Env 和 SessionOptions再创建 Session然后通过 session 拿到输入输出名字最后组装输入张量并执行 Run。注意CreateTensorfloat是浅拷贝视图它不复制数据只是把input_data的指针交给 ORT所以input_data的生命周期必须覆盖session.Run调用。我在项目里见过把 input_data 定义在 lambda 里、运行完就析构的情况输出结果直接乱掉这是典型的“指针悬空”血泪经验。3.4 参数说明线程数、图优化级别与 RunOptionsSessionOptions 里这几个参数最值得调参数取值影响SetIntraOpNumThreads2 / 4 / 0控制单次推理内部算子并行线程数0 表示用默认值SetGraphOptimizationLevelORT_ENABLE_ALL / ORT_ENABLE_BASIC / ORT_DISABLE_ALL图优化等级生产环境一般用 ORT_ENABLE_ALLSetInterOpNumThreads1 / 2控制多个节点之间的并行度简单模型设 1 更好Ort::RunOptions{nullptr}传空指针表示默认 Run 参数。它其实还能设置自定义 terminate 标志、内存分配等日常推理用默认值就够。如果模型对实时性要求高我一般会固定SetIntraOpNumThreads(2)然后用 benchmark 脚本测延迟不盲目堆线程。线程数设太高小模型反而会因为线程切换变慢这个坑做服务端推理时特别容易遇到。4. Python 侧不想装 wheel用 ctypes 调 DLL 并对比两条路线看到这里你可能会问Python 不是有pip install onnxruntime1.23.1吗为什么还要碰这个 zip答案是内网部署。很多生产环境不允许直接从网上下载 wheel但允许拷贝官方二进制压缩包。这一章就演示如何用 Python 侧直接加载这个 zip 里的 dll至少能把版本串读出来确认二进制能跑。4.1 为什么会有“pip 没网但手头只有 zip”的场景内网隔离、离线交付、堡垒机审核这些场景下 pip install 会卡在“找不到包”。手头只有这个 zip 时Python 侧也有办法用 ctypes 加载 dll走 C API。ONNX Runtime 的 dll 导出最底层入口OrtGetApiBase()这个函数返回一个OrtApiBase结构体结构体里有版本字符串函数和获取 API 表的函数。我们不需要调用完整推理功能只要验证 dll 能加载、能得到 1.23.1 版本串就说明部署环境没问题。4.2 ctypes 加载 onnxruntime.dll 并读出版本串代码可以直接跑前提是本机已经装了 VC 运行库import ctypes dll ctypes.CDLL(rD:\libs\onnxruntime-win-x64-1.23.1\bin\onnxruntime.dll) class OrtApiBase(ctypes.Structure): _fields_ [ (GetVersionString, ctypes.CFUNCTYPE(ctypes.c_char_p, ctypes.c_void_p)), (GetApi, ctypes.CFUNCTYPE(ctypes.c_void_p, ctypes.c_uint32)), ] dll.OrtGetApiBase.restype ctypes.POINTER(OrtApiBase) api_base_ptr dll.OrtGetApiBase() version_ptr api_base_ptr.contents.GetVersionString( ctypes.cast(api_base_ptr, ctypes.c_void_p) ) print(version_ptr.decode())运行后如果打印1.23.1或类似前缀说明 dll 被成功加载且底层 API 入口可用。这里最关键的是OrtApiBase的结构定义第一个字段必须是GetVersionString第二个是GetApi因为 C API 暴露的就是这个内存布局。一旦顺序错了读出来的就是乱码或野指针直接崩溃。4.3 两条路线对比路线优点缺点zip ctypes不依赖 pip离线可用二进制可单独分发要手动维护 C API 结构体开发效率低pip 安装 onnxruntime wheel开箱即用有完整 numpy 绑定和 Python 异常内网无镜像时难安装版本冲突管理麻烦如果你的内网其实有 PyPI 镜像我仍然建议pip install onnxruntime1.23.1。ctypes 这条路适合“临时验证环境”和“只读版本号”的场景真正写业务代码还是 wheel 省心。4.4 什么时候必须用 zip需要把 ONNX Runtime 和 C 业务代码打进同一个交付包时zip 是必须的。因为 wheel 里面是单独的 dll还要从 site-packages 里抠出来反倒不如直接分发官方 zip 干净。还有一种场景是动态库名冲突系统里已经有另一个版本的 onnxruntime.dll用 wheel 时会因为 PATH 顺序加载到旧版本。这时候把 zip 里的 dll 和 exe 放同一目录Windows 会优先加载可执行文件目录下的 dll避免“装对了版本却用的是旧库”的隐性 bug。5. 避坑与常见问题Windows x64 上部署 1.23.1 的五个真实翻车点这一章写的都是实际项目里反复出现的问题。每条我都按“现象 → 原因 → 解决”记录方便你直接对照。5.1 翻车点一exe 启动就报“找不到 onnxruntime.dll”现象编译链接都成功Start debugging后立刻弹窗提示找不到 onnxruntime.dll。原因链接器只用了 lib 导入库运行期进程没去解压目录找 dll。Windows 的 DLL 搜索顺序依次是 exe 所在目录、系统目录、PATH 目录你如果没把 dll 放进去loader 自然找不到。解决把 bin/onnxruntime.dll 拷贝到 exe 输出目录或者在系统 PATH 中加入解压目录的 bin。我推荐用第三章里的 POST_BUILD 自动拷贝避免每次手动复制漏掉。5.2 翻车点二提示缺少 VCRUNTIME140.dll / msvcp140.dll现象exe 已经抱着 dll 跑了但换一台干净的 Windows Server 就报缺 VCRUNTIME140.dll。原因目标机器没装 Visual C Redistributable。ONNX Runtime 官方二进制依赖 VC 运行库这不是 ORT 自己能打包解决的问题。解决在交付说明里明确要求先安装 VC 2015-2022 x64 运行库。也可以在部署脚本里检测Get-Item C:\Windows\System32\vcruntime140.dll不存在就先安装。5.3 翻车点三拿到的是 CPU 包却指望它跑 GPU现象程序能跑但打开任务管理器发现 GPU 占用为 0推理耗时很高。原因onnxruntime-win-x64-1.23.1.zip是 CPU 版。名字里的 win-x64 只说明平台不代表包含 CUDA 或 DirectML 执行提供程序。解决先打印Ort::GetAvailableProviders()如果列表里只有 CPUExecutionProvider就老老实实换 GPU 包。需要 CUDA 就找对应 CUDA/cuDNN 版本的 gpu 包需要通用加速就找 directml 包。5.4 翻车点四模型 opset 太新或带自定义算子session 加载失败现象代码编译没问题但Ort::Session构造函数抛异常日志显示“unsupported opset”或“kernel not found”。原因模型导出时用了比当前 ORT 支持的 ONNX opset 更高的版本或者模型里带了 Pytorch 导出时的自定义算子。1.23.1 支持较新的官方 opset但自定义算子必须注册对应的 Custom Op。解决先用 Python 检查模型 opsetonnx.load(model.onnx).opset_import再用合适的 onnx 版本重新导出。如果是自定义算子要么在 C 里注册实现要么把相关逻辑转成标准算子。5.5 翻车点五调用 ORT_API 时崩溃根因是 ABI 不匹配现象程序起来后调用 session.Run 偶尔崩溃或输出随机张量Debug 模式下断点位置没有规律。原因最常见的是编译器/运行库版本不一致比如用老版本 MSVC 编译的 exe 链接新版本 ORT或者 C 异常处理模式没对齐。ONNX Runtime 官方二进制是用较新 MSVC 编译的你工程如果用了过旧工具集就会踩 ABI 兼容问题。解决把工程工具集升级到与 VC 2015-2022 Redistributable 对应的版本至少用 VS2019 或 VS2022 重新编译。另一个不常见但要记住的是不要把 onnxruntime.dll 和自己的 dll 混在同一个静态链接边界上尽量保持 exe 直接链接 ORT不要让中间层传递 Ort::Value。6. 让 1.23.1 证明自己版本串验证与 EP 列表检查的小技巧拿到一个新解压的 ONNX Runtime不要马上去写推理代码先花三分钟验证“这个 dll 确实是 1.23.1 且支持我要的 provider”。我每次接入新版本都会强制走一遍这台机器的双检查。6.1 PowerShell 快速读版本资源(Get-Item .\bin\onnxruntime.dll).VersionInfo | Format-List FileVersion, ProductVersion文件版本号前缀如果是 1.23.1说明二进制就是预期版本。这个检查也能发现下载损坏如果版本资源读不出来多半是 zip 没下完整。6.2 C 打印版本串与可用 provider#include onnxruntime_cxx_api.h #include iostream int main() { Ort::Env env(ORT_LOGGING_LEVEL_WARNING, verify); auto providers Ort::GetAvailableProviders(); for (const auto p : providers) { std::cout Provider: p std::endl; } }这段代码会在控制台输出类似CPUExecutionProvider的列表。如果连CPUExecutionProvider都没有说明 dll 没加载成功问题在 PATH 或 VC 运行库如果 provider 列表里有CUDAExecutionProvider但这个 zip 包名没有 gpu那你看的肯定是别的目录。从那以后我每次拿到新的 onnxruntime 发行包都会强制走一遍版本串 provider 列表检查确认 dll 能加载才继续写业务代码。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑