最近在项目里做模型落地,手里是一个 TensorFlow 训练好的图像分类模型,导出来的文件是 pb 模型。服务端的推理逻辑得用 C++ 写,一开始想直接用 TensorFlow C++ 库,但编译配置、依赖、ABI 适配折腾得头大。后来换成了 OpenCV 的 DNN 模块,一个 readNetFromTensorFlow 就把模型读进来了,推理代码加起来不到一百行。从模型导出到 C++ 跑通整个流程,一共花了两天,这篇就把过程中的原理、代码、参数和踩过的坑完整整理一遍,给同样要在 C++ 环境里加载 TensorFlow pb 模型的朋友一个可直接抄的作业。
1. 整体方案:为什么用 OpenCV DNN 而不是 TensorFlow C++
1.1 部署场景的现实选择
先交代一下场景:底层服务是纯 C++ 写的,输入是一批图片,需要把 TensorFlow 训练出来的分类模型结果返回给上层。关于 C++ 调用 TensorFlow 模型的方案,网上能搜到很多,但真正落地的时候每个方案都有各自的脾气。TensorFlow C++ API 能力完整,但需要自己编译静态库或动态库,链接、依赖、protobuf 版本冲突这些问题在一台没有完整构建链路的服务器上会非常痛苦。PyTorch 的 LibTorch 部署体验好一些,但模型是 TensorFlow 训练的,还得先做权重迁移,中间转换的坑比直接推理还多。
所以最后选了 OpenCV。一方面 OpenCV 在 C++ 项目里几乎是标配,很多图像服务本来就会依赖它;另一方面 OpenCV 从 3.4 开始加入了 DNN 模块,官方文档里很明确支持加载 TensorFlow 的 pb 模型。整个调用链路就是 readNetFromTensorFlow 加 setInput 加 forward,API 简洁,依赖干净,一个 opencv_world 库就能解决问题。当然这个方案有边界:OpenCV 的 DNN 后端偏重推理,适合常见的 CNN 分类、检测、分割网络,如果是 Transformer 这类结构复杂、算子新颖的大模型,兼容性就会差一些,这种情况建议直接考虑 ONNX Runtime 或 TensorRT。工具从来都是匹配场景,关键是把场景判断清楚。
1.2 PB 文件到底是什么,为什么 OpenCV 能读
刚才说 OpenCV 能读 pb 模型,但这里的“pb 模型”是有前提的。TensorFlow 训练时保存的模型有很多种形态:checkpoint、SavedModel、frozen graph(冻结图)。OpenCV 的 readNetFromTensorFlow 只认冻结后的 GraphDef 文件,也就是把训练变量全部固化成常量的 protobuf 序列化文件。这个文件里包含两部分:计算图和权重。GraphDef 里每个节点是一个算子,比如 MatMul、Conv2D、BiasAdd、ReLU,节点之间的连线决定数据流向;变量节点被 freeze_graph 工具转换后变成 Const 节点,这样模型就变成了一个自包含的文件,不再依赖 checkpoint 文件里的权重表。
这里要特别提醒:如果你手里只有一个 TensorFlow 2.x 的 SavedModel 目录,或者只有 .ckpt 训练检查点,OpenCV 是直接读不了的,必须先把模型转换成冻结 pb。转换的原理也不复杂,就是把所有变量赋值后变成常量,顺便把 BatchNorm 这类训练时特有、推理时可能折叠的层处理掉。冻结后的文件可以理解成一张“图纸 + 所有零件拧死”的状态,OpenCV 只要按图执行算子就行。算子是否支持是另一个话题,后面问题排查章节会单独讲。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备:版本搭配是踩坑重灾区
2.1 可复现的版本组合
先说结论,我最后稳定运行的环境是这样一套,直接照这个搭能避开大部分无谓的版本冲突:
| 组件 | 版本 | 说明 |
|---|---|---|
| OpenCV | 4.8.0 | 预编译版,自带 DNN 模块 |
| Visual Studio | 2022 | v143 工具集,C++17 |
| TensorFlow | 2.10 | 仅用于导出 pb,推理侧不依赖 |
| 操作系统 | Windows 10 / Ubuntu 20.04 | 两边都实际跑过 |
如果从零开始,建议 OpenCV 直接用 4.5 以上的版本,越新越好。原因很简单:OpenCV 的 DNN 模块对 TensorFlow 算子的支持是持续增长的,例如 LeakyReLU、Mish 这类激活函数,老版本经常报 “Unsupported layer type”,新版本会好很多。如果你有选择权,直接上当前稳定版 OpenCV 4.8 或 4.9,别在 3.x 上浪费时间。
TensorFlow 侧,训练可以用 1.15 或 2.x。我用 2.10 训练模型,导出时打开 compat 模式生成冻结 pb,效果和 TF 1.x 导出的完全一致。有一点需要注意,TensorFlow 2.11 之后 Windows 官方包默认不再支持 GPU,但这不影响我们只做导出,导出逻辑纯 CPU 就能跑。
2.2 预编译包和 GPU 推理的边界
官网下载
