pytorch-cpp-inference
使用 LibTorch C++ API 将 PyTorch 模型部署为生产级 HTTP 推理服务,无
加载项目详情…
本应用为开源项目,仅供学习研究,请遵守其开源协议。
使用 LibTorch C++ API 将 PyTorch 模型部署为生产级 HTTP 推理服务,无
加载项目详情…
本应用为开源项目,仅供学习研究,请遵守其开源协议。
小张花了两周训练了一个 ResNet18 图像分类模型,在 Python 里效果很好——准确率 92%,推理速度也满意。但当产品经理说要集成到现有的 C++ 后台系统里时,他愣住了:现有系统是纯 C++ 写的,不可能为了一个 AI 模块引入 Python 运行时,那样既笨重又带来额外的依赖噩梦。
小张的困境并非个例。Python 在 AI 研究领域无可匹敌,但生产环境中有大量遗留系统、嵌入式设备和高性能服务器都基于 C++ 构建。如何让训练好的 PyTorch 模型无缝接入这些环境?pytorch-cpp-inference 项目给出了答案:使用 PyTorch 官方 C++ API(LibTorch),将 Python 训练的模型以 TorchScript 格式导出,然后在 C++ 环境中直接加载运行。
pytorch-cpp-inference 是一个围绕 LibTorch C++ API 构建的演示型项目,聚焦于一个核心场景:如何将 Python 训练好的 CNN 模型(以 ResNet18 为例)部署为 C++ HTTP 推理服务。项目代码量不大(14 次提交),但覆盖了从模型导出、图像预处理、C++ 推理引擎到 REST API 服务的完整链路。
作者 Wizaron 的设计思路非常清晰:将整个流程分为两个阶段:Python 端负责模型定义、训练和导出;C++ 端负责模型加载和推理服务。两者通过 PyTorch 官方推荐的 TorchScript 中间格式桥接。TorchScript 是 PyTorch 的一个子集,可以被 JIT 编译和序列化,使得模型不再依赖 Python 解释器。
这种"Python 训练、C++ 推理"的分离架构有明显的工程价值:AI 研究团队可以继续在 Python 生态中快速迭代模型,而运维团队则可以在不引入 Python 依赖的情况下,将模型嵌入任何 C++ 应用——无论是高性能服务器、边缘设备,还是嵌入式系统。
import torchvision
model = torchvision.models.resnet18(pretrained=True)
model.eval()
example = torch.rand(1, 3, 224, 224)
traced_script_module = torch.jit.trace(model, example)
traced_script_module.save("resnet_model_cpu.pth")
这段导出代码做了三件事:创建 ResNet18 预训练模型、切换为评估模式、用 torch.jit.trace 追踪前向传播并生成 TorchScript 模块。导出的 .pth 文件是一个序列化包,包含模型结构、权重参数和追踪得到的计算图,不包含任何 Python 依赖。
// 读取 TorchScript 模型
torch::jit::script::Module model = torch::jit::load(model_path);
// 图像预处理:OpenCV 读取 + 缩放 + 标准化
cv::Mat image = cv::imread(image_path);
image = preprocess(image, 224, 224, mean, std);
// 前向传播(CPU/GPU)
std::vector<float> probs = forward({image}, model, usegpu);
关键在于 torch::jit::script::Module 这个类型——它对应 Python 端的 torch.jit.ScriptModule,API 设计高度对称。C++ 端通过 torch::jit::load() 加载序列化文件,即可获得完整的模型对象,直接调用前向传播。
项目在 utils/torchutils.cc 中实现了 OpenCV 到 LibTorch 张量的转换链路:读取 JPEG 图像 → OpenCV 解码 → 缩放至 224×224 → 归一化(ImageNet 统计量:mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])→ 转换为 CHW 格式张量 → 输入模型。整个流程硬编码了 ImageNet 预处理的固定参数,这也是演示项目的局限性之一:它是为 ImageNet 风格的 RGB 图像分类场景量身定制的。
项目最有价值的功能是提供了一个基于 Crow 的 HTTP 推理服务。Crow 是一个 header-only 的 C++ HTTP 框架,类似 Python 的 Flask,但完全用 C++ 实现,零外部依赖——非常适合嵌入到已有的 C++ 项目中。
服务监听在 8181 端口,暴露一个 /predict 接口:
CROW_ROUTE(app, "/predict").methods("POST"_method)([...](const crow::request& req){
auto args = crow::json::load(req.body);
std::string base64_image = args["image"].s();
// base64 解码 → OpenCV 图像 → 推理 → 返回 JSON
result["Prediction"] = pred;
result["Confidence"] = prob;
result["Status"] = "OK";
return crow::response(result);
});
客户端通过 POST 请求以 JSON 格式发送 base64 编码的图像,服务器解码后执行推理并返回分类结果和置信度。项目提供了 test_api.py 测试脚本,演示了完整的请求流程。
项目在 docker/ 目录下提供了两个 Dockerfile,分别针对不同硬件环境:
torch==1.3.1+cpu 和 torchvision==0.4.2+cpu。适用于没有 NVIDIA GPU 的服务器环境,依赖最轻量。nvidia/cuda:10.0-cudnn7-devel-ubuntu16.04,通过 pip 安装 CUDA 版 PyTorch,可利用 NVIDIA GPU 加速推理。适合有 GPU 基础设施的生产环境。两者的构建流程一致:
docker build -t pytorch-cpp-inference .
docker run -v <repo-dir>:<target-dir> -p 8181:8181 -it pytorch-cpp-inference
项目没有提供 docker-compose.yml,但 Dockerfile 中已内置了 libtorch 的下载和配置逻辑,构建过程全自动。需要注意的是:LibTorch 库文件较大(CPU 版约 500MB,CUDA 版更大),镜像构建时间较长。
| 层次 | 技术选型 | 作用 |
|---|---|
| 模型序列化 | TorchScript (torch.jit.trace) | Python ↔ C++ 桥接 |
| 推理引擎 | LibTorch C++ API (torch::jit) | 模型加载与前向推理 |
| 图像处理 | OpenCV 4.x | 图像解码、缩放、归一化 |
| HTTP 服务 | Crow (header-only) | REST API (/predict) |
| 构建系统 | CMake 3.0+ | C++ 编译链接 |
| 容器化 | Docker (CPU + CUDA 10) | 环境隔离 |
| 主语言 | C++11 | 核心推理代码 |
| 示例语言 | Python 3 + C++ | 模型导出脚本 |
| 示例模型 | torchvision ResNet18 | 演示用预训练模型 |
项目采用分层模块化设计:utils/torchutils.cc 和 utils/opencvutils.cc 封装底层工具函数;infer.cc 实现核心推理逻辑;main.cc 提供命令行入口;server/main.cc 提供 HTTP 服务入口。模块边界清晰,便于在真实项目中复用。
1. PyTorch 版本过旧:项目基于 PyTorch 1.3.1 开发,发布于 2019 年底,距今已超过 5 年。PyTorch 官方已明确表示 LibTorch C++ API 将逐步被废弃,未来迁移路径是 AOTInductor(PyTorch 2.x 的 C++ 部署方案)。在生产环境中选择此方案需评估未来迁移成本。
2. 仅支持图像分类:预处理逻辑(224×224、ImageNet 归一化参数)硬编码在代码中,无法直接迁移到目标检测、语义分割、NLP 等其他任务。每换一种任务,都需要重新实现预处理和后处理逻辑。
3. REST API 无安全防护:HTTP 服务没有任何认证、限流或 HTTPS 配置,直接暴露在公网存在安全风险。生产环境使用需要自行在前面加一层 Nginx 认证或 API 网关。
4. 缺乏自动化测试:项目中没有单元测试、集成测试或性能基准测试。对于需要长期维护的生产项目,这是较大的工程隐患。
pytorch-cpp-inference 项目折射出一个持续多年的行业趋势:AI 模型的生产化部署。Python 是 AI 研究的皇后,但生产系统的皇后是 C++(或 Rust、Go 等系统语言)。PyTorch 官方在 LibTorch 上的投入,正是为了解决这个"研究与生产之间的语言鸿沟"。
随着 PyTorch 2.x 引入 AOTInductor,桥接机制已经进化到"任意 PyTorch 模型 → 编译后的 .so 文件 → C++ 直接 dlopen 加载"的阶段,不再依赖 TorchScript 的追踪机制。但 pytorch-cpp-inference 作为 LibTorch + TorchScript 模式的经典案例,对于理解 PyTorch 生产化部署的演进历程仍有参考价值。
如果你需要在 C++ 环境中运行 PyTorch 模型,这个项目提供了清晰的起点;如果你在构建新的生产系统,建议直接采用 PyTorch 2.x 的 AOTInductor 方案以获得更好的长期支持。