- 人工智能
- 计算机视觉
- 预训练
【免费下载链接】PaddleSeg
Easy-to-use image segmentation library with awesome pre-trained model zoo, supporting wide-range of practical tasks in Semantic Segmentation, Interactive Segmentation, Panoptic Segmentation, Image Matting, 3D Segmentation, etc.
导读
本文完整讲解如何在 Windows 10 上使用 Paddle Inference 的 C++ 接口部署 PaddleSeg 语义分割模型,覆盖环境准备(Visual Studio、CUDA/CUDNN/TensorRT、Paddle 预测库、OpenCV)、预测模型与测试图片准备、CMake 工程生成与 Visual Studio 编译、以及 GPU/CPU 推理执行的完整流程。读完本文,你将能够把 PaddleSeg 训练导出的推理模型编译为本地test_seg.exe可执行程序,并理解deploy/cpp目录下 C++ 示例(test_seg.cc)从读取deploy.yaml、图像预处理到推理后处理的完整调用链,为后续接入自己的业务工程打下基础。
1. 部署方案概述
PaddleSeg 仓库在 deploy/cpp 目录下提供了基于 Paddle Inference C++ 接口的部署示例,主要包含三个步骤:
- 准备环境:安装 Visual Studio 2019、CUDA/CUDNN/TensorRT(GPU 场景)、CMake、Paddle Inference C++ 预测库、OpenCV;
- 准备模型和图片:下载或导出预测模型(
model.pdmodel/model.pdiparams/deploy.yaml等),并准备一张测试图片; - 编译、执行:用 CMake 生成 Visual Studio 工程,编译出可执行文件并运行推理。
飞桨针对不同场景提供了多种预测引擎(Paddle Inference、Paddle Lite、Paddle Serving、Paddle.js 等),C++ 服务端部署使用 Paddle Inference 是其中最直接的一种。本文档中的全部示例以工作目录D:\projects演示。
2. 准备环境
2.1 准备基础环境
模型部署的基础环境要求如下:
- Visual Studio 2019:需根据 Paddle Inference C++ 预测库编译所使用的 VS 版本选择对应版本(Visual Studio 各版本间存在二进制兼容性约束,2015/2017/2019 的 C++ 运行库二进制兼容);
- CUDA / CUDNN / TensorRT:仅在使用 GPU 版本的预测库时需要;
- CMake 3.0+:用于生成 VS 工程文件。
2.2 准备 CUDA/CUDNN/TensorRT 环境
模型部署环境与所需库的对应关系如下表:
| 部署环境 | 需要准备的库 |
|---|---|
| CPU | 无 |
| GPU | CUDA / CUDNN |
| GPU_TRT | CUDA / CUDNN / TensorRT |
使用 GPU 推理的用户需要准备 CUDA 和 CUDNN,仅使用 CPU 推理的用户可跳过本节:
- CUDA:按 NVIDIA 官方安装指南完成安装。CUDA 默认安装路径为
C:\Program Files\NVIDIA GPU Computing Toolkit,需将C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\Vx.y\bin加入环境变量(Vx.y中的x.y为 CUDA 版本号)。 - CUDNN:将 cudnn 解压目录中
bin、include、lib三个文件夹内的文件,分别复制到C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\Vx.y下同名文件夹中。 - TensorRT(可选):若需在 CUDA 下使用 TensorRT 加速推理,还需安装 TensorRT,并把安装目录
lib文件夹下的.dll文件复制到C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\Vx.y\bin。
本文档以CUDA=11.6、CUDNN=8.4.1.5、TensorRT=8.4.1.5的组合为例进行介绍。
2.3 准备 Paddle Inference C++ 预测库
Paddle Inference C++ 预测库针对不同的 CPU 和 CUDA 版本提供了不同的预编译版本,应根据自身环境在 Paddle Inference 官方下载页选择合适的预编译库(Windows 平台)。若预编译库不满足需求,也可以自行源码编译预测库。本文不再展开预测库的编译细节,直接使用预编译库。
假设预测库解压至D:\projects\paddle_inference,其目录结构如下:
D:\projects\paddle_inference ├── paddle ├── third_party ├── CMakeCache.txt └── version.txt其中paddle目录存放头文件与paddle_inference.lib等链接库,third_party目录存放预测库依赖的第三方库(如 protobuf、glog、gflags、xxhash、cryptopp、onnxruntime、paddle2onnx 以及 MKL/OpenBLAS 等),这些路径会在编译阶段由 CMake 自动引用。
2.4 安装 OpenCV
本示例使用 OpenCV 读取图片,因此需要安装 OpenCV;其他项目中可视需要决定是否安装。安装步骤:
- 从 OpenCV 官网下载适用于 Windows 平台的4.6.0版本(
opencv-4.6.0-vc14_vc15安装程序); - 运行下载的可执行文件,将 OpenCV 解压至指定目录,例如
D:\projects\opencv; - 配置环境变量(若在编译命令中使用全局绝对路径,也可不设置环境变量):
我的电脑→属性→高级系统设置→环境变量;- 在系统变量中找到
Path(如不存在则自行创建),双击编辑; - 新建一条,填入 OpenCV 的
bin路径并保存,例如D:\projects\opencv\build\x64\vc15\bin。
3. 准备模型和图片
3.1 获取预测模型
本文示例使用 PaddleSeg 提供的 PP-LiteSeg 预测模型(pp_liteseg_infer_model.tar.gz),下载后解压即可用于测试。预测模型的文件格式如下:
pp_liteseg_infer_model ├── deploy.yaml # 部署相关的配置文件,主要说明数据预处理方式等信息 ├── model.pdmodel # 预测模型的拓扑结构文件 ├── model.pdiparams # 预测模型的权重文件 └── model.pdiparams.info # 参数额外信息,一般无需关注如果需要测试其他模型,可参考 模型导出文档 自行导出预测模型。导出命令位于 PaddleSeg 仓库根目录下执行:
python tools/export.py \ --config configs/pp_liteseg/pp_liteseg_stdc1_cityscapes_1024x512_scale0.5_160k.yml \ --model_path model.pdparams \ --save_dir output/inference_model导出脚本的关键参数如下:
| 参数 | 用途 | 是否必需 | 默认值 | |-|-|-|-| | config | 配置文件路径 | 是 | - | | model_path | 训练好的权重路径 | 否 | - | | save_dir | 预测模型保存目录 | 否 |output/inference_model| | input_shape | 指定推理模型输入形状(N*C*H*W),如--input_shape 1 3 1024 1024;若不指定则为[-1, 3, -1, -1],预测时图像尺寸固定则应显式设置 | 否 | None | | output_op | 追加到推理模型末尾的算子,可选argmax、softmax、none;默认输出每个像素的类别标签(N*H*W),加softmax则输出各类别概率 | 否 |argmax|
导出成功后,output/inference_model目录下即生成deploy.yaml、model.pdmodel、model.pdiparams、model.pdiparams.info四个文件,与上文目录结构一致。
3.2 认识 deploy.yaml:C++ 端如何解析预处理配置
与 Python 端部署不同,C++ 示例不会加载 PaddleSeg 的 transforms 配置,而是直接从模型目录的deploy.yaml中读取数据预处理方式。查看 test_seg.cc 中的load_yaml函数可以看到解析逻辑:
- 读取
Deploy.model与Deploy.params字段,得到模型文件名和权重文件名; - 遍历
Deploy.transforms列表,识别Normalize变换(开启归一化)与Resize变换(读取target_size得到resize_width与resize_height)。
对应地,read_process_image 实现图像预处理:先用cv::imread读图并BGR2RGB转换通道顺序;若配置了Resize则cv::resize到目标尺寸;若配置了Normalize则将像素值缩放到[0,1](除以 255)再执行(x - 0.5) / 0.5的标准化。也就是说,C++ 端与 Python 端推理会保持一致的预处理行为。
3.3 用 Netron 检查输入输出,确认输出数据类型
model.pdmodel可通过 Netron 打开进行模型可视化,点击输入节点即可查看推理模型的输入/输出个数及数据类型(如int32_t、int64_t、float等)。这一点很重要:默认代码假设模型输出为int32_t的类别标签。如果模型的输出数据类型不是int32_t(例如导出的模型带了softmax输出概率),执行默认代码会报错,此时需要手动修改 test_seg.cc 中的如下代码,将其改为对应的输出数据类型:
std::vector<int32_t> out_data(out_num);3.4 准备测试图片
下载一张 cityscapes 验证集中的图片(cityscapes_demo.png)到本地,用于后续推理测试。
4. 编译
4.1 工程整体目录结构
完成上述准备后,D:\projects下应包含:
D:\projects ├── opencv ├── paddle_inference └── PaddleSeg即把 PaddleSeg 仓库克隆到D:\projects\PaddleSeg,与opencv、paddle_inference平级。
4.2 使用 CMake 生成项目文件
编译参数说明如下,其中带*表示仅在使用 GPU 版本预测库时指定,带#表示仅在使用 TensorRT 时指定:
| 参数名 | 含义 |
|---|---|
| *WITH_GPU | 是否使用 GPU,默认为 OFF |
| *CUDA_LIB | CUDA 的库路径 |
| *USE_TENSORRT | 是否使用 TensorRT,默认为 OFF |
| #TENSORRT_DLL | TensorRT 的.dll文件存放路径 |
| WITH_MKL | 是否使用 MKL,默认为 ON(使用 MKL);设为 OFF 表示使用 OpenBLAS |
| CMAKE_BUILD_TYPE | 指定编译时使用 Release 或 Debug |
| PADDLE_LIB_NAME | Paddle 预测库名称 |
| OPENCV_DIR | OpenCV 的安装路径 |
| PADDLE_LIB | Paddle 预测库的安装路径 |
| DEMO_NAME | 可执行文件名 |
首先进入cpp目录:
cd D:\projects\PaddleSeg\deploy\cpp创建build文件夹并进入:
mkdir build cd build执行编译命令的通用格式如下(注意:若路径中包含空格,需用引号括起来):
cmake .. -G "Visual Studio 16 2019" -A x64 -T host=x64 -DUSE_TENSORRT=ON -DWITH_GPU=ON -DWITH_MKL=ON -DCMAKE_BUILD_TYPE=Release -DPADDLE_LIB_NAME=paddle_inference -DCUDA_LIB=path_to_cuda_lib -DOPENCV_DIR=path_to_opencv -DPADDLE_LIB=path_to_paddle_dir -DTENSORRT_DLL=path_to_tensorrt_.dll -DDEMO_NAME=test_seg按部署场景分四种典型命令:
GPU 推理(不使用 TensorRT):
cmake .. -G "Visual Studio 16 2019" -A x64 -T host=x64 -DUSE_TENSORRT=OFF -DWITH_GPU=ON -DWITH_MKL=ON -DCMAKE_BUILD_TYPE=Release -DPADDLE_LIB_NAME=paddle_inference -DCUDA_LIB="C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.6\lib\x64" -DOPENCV_DIR=D:\projects\opencv -DPADDLE_LIB=D:\projects\paddle_inference -DDEMO_NAME=test_segGPU 推理(使用 TensorRT 加速):
cmake .. -G "Visual Studio 16 2019" -A x64 -T host=x64 -DUSE_TENSORRT=ON -DWITH_GPU=ON -DWITH_MKL=ON -DCMAKE_BUILD_TYPE=Release -DPADDLE_LIB_NAME=paddle_inference -DCUDA_LIB="C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.6\lib\x64" -DOPENCV_DIR=D:\projects\opencv -DPADDLE_LIB=D:\projects\paddle_inference -DTENSORRT_DLL="C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.6\bin" -DDEMO_NAME=test_segCPU 推理(MKL):
cmake .. -G "Visual Studio 16 2019" -A x64 -T host=x64 -DWITH_GPU=OFF -DWITH_MKL=ON -DCMAKE_BUILD_TYPE=Release -DPADDLE_LIB_NAME=paddle_inference -DOPENCV_DIR=D:\projects\opencv -DPADDLE_LIB=D:\projects\paddle_inference -DDEMO_NAME=test_segCPU 推理(OpenBLAS):
cmake .. -G "Visual Studio 16 2019" -A x64 -T host=x64 -DWITH_GPU=OFF -DWITH_MKL=OFF -DCMAKE_BUILD_TYPE=Release -DPADDLE_LIB_NAME=paddle_inference -DOPENCV_DIR=D:\projects\opencv -DPADDLE_LIB=D:\projects\paddle_inference -DDEMO_NAME=test_seg4.3 源码视角:CMake 生成工程时发生了什么
从 deploy/cpp/CMakeLists.txt 可以看到 Windows 分支的几个关键行为,理解它们有助于排查编译问题:
- 自动编译 yaml-cpp:Windows 下通过 cmake/yaml-cpp.cmake 引入
ExternalProject_Add,在构建阶段自动下载并编译静态版yaml-cpp(链接库输出到build/ext/yaml-cpp/lib),因此示例代码中的deploy.yaml解析依赖无需手动安装; - 依赖库自动链接:
PADDLE_LIB/third_party/install/下的 protobuf、glog、gflags、xxhash、cryptopp、onnxruntime、paddle2onnx 头文件与库目录均被自动加入编译与链接搜索路径,WITH_MKL决定链接mklml还是openblas; - POST_BUILD 自动拷贝 dll:编译完成后,CMake 会把推理运行所需的
mklml.dll、libiomp5md.dll、mkldnn.dll、onnxruntime.dll、paddle2onnx.dll、paddle_inference.dll以及 TensorRT 的nvinfer.dll、nvinfer_plugin.dll自动复制到可执行文件目录和Release目录(见 CMakeLists.txt 的add_custom_command),这正是后面Release目录中*.dll的来源; - 运行时库统一为静态 CRT:Windows 分支默认启用
MSVC_STATIC_CRT,将/MD替换为/MT,避免与预测库的运行时库冲突。
4.4 使用 Visual Studio 编译
用 Visual Studio 2019 打开生成的cpp\build\cpp_inference_demo.sln,将编译模式设置为Release,点击生成→生成解决方案,编译完成后在cpp\build\Release目录内生成test_seg.exe。
5. 执行推理
5.1 准备 Release 目录
进入build\Release目录,将准备好的模型和图片放到test_seg.exe同级目录,最终目录结构如下:
Release ├──test_seg.exe # 可执行文件 ├──cityscapes_demo.png # 测试图片 ├──pp_liteseg_infer_model # 推理用到的模型 ├── deploy.yaml # 部署相关的配置文件,主要说明数据预处理方式等信息 ├── model.pdmodel # 预测模型的拓扑结构文件 ├── model.pdiparams # 预测模型的权重文件 └── model.pdiparams.info # 参数额外信息,一般无需关注 ├──*.dll # dll 文件(由 CMake POST_BUILD 自动拷贝)5.2 可执行文件的命令行参数
test_seg.cc 使用 gflags 定义了全部运行时参数,推理时可按需组合:
| 参数 | 类型 | 默认值 | 含义 |
|---|---|---|---|
--model_dir | string | "" | 推理模型目录(必须包含deploy.yaml与模型文件),为空时程序直接报错退出 |
--img_path | string | "" | 测试图片路径 |
--devices | string | GPU | 使用 GPU 或 CPU 设备 |
--use_trt | bool | false | GPU 下是否启用 TensorRT |
--trt_precision | string | fp32 | TensorRT 精度,支持fp32、fp16、int8 |
--use_trt_dynamic_shape | bool | false | GPU + TensorRT 下是否启用动态 shape |
--dynamic_shape_path | string | "" | 若指定,则从该路径读取 TRT 动态 shape 配置 |
--use_mkldnn | bool | false | CPU 下是否启用 MKLDNN |
--save_dir | string | "" | 输出图片目录(当前示例固定输出为out_img.jpg) |
5.3 运行推理
GPU 推理:
test_seg.exe --model_dir=./pp_liteseg_infer_model --img_path=./cityscapes_demo.png --devices=GPUCPU 推理:
test_seg.exe --model_dir=./pp_liteseg_infer_model --img_path=./cityscapes_demo.png --devices=CPU预测结果保存为out_img.jpg。该图片对预测的灰度标签图做了直方图均衡化(cv::equalizeHist),便于可视化观察分割轮廓,而不是对标签着色后的原图。
5.4 推理流程源码解读
结合 test_seg.cc 的main函数,整个执行链路可以拆解为五个阶段:
- 解析参数并校验:
google::ParseCommandLineFlags解析命令行,model_dir为空则LOG(FATAL)终止; - 加载部署配置:读取
model_dir/deploy.yaml得到模型文件名、权重文件名以及预处理配置; - 图像预处理:读图 →
BGR2RGB→ 按deploy.yaml决定是否Resize与Normalize→ 通过hwc_img_2_chw_data将 HWC 布局的cv::Mat转为 CHW 布局的float数组(test_seg.cc 用cv::extractChannel逐通道抽取实现); - 创建 Predictor 并推理:
create_predictor(test_seg.cc)根据devices构造paddle_infer::Config:CPU 分支可EnableMKLDNN()并设置 5 线程;GPU 分支调用EnableUseGpu(100, 0)(显存 100MB、设备 0),开启 TensorRT 时按trt_precision选择kFloat32/kHalf/kInt8,并可通过SetTRTDynamicShapeInfo传入内置的 min/max/opt 输入 shape({1,3,112,112}/{1,3,1024,2048}/{1,3,512,1024})或从dynamic_shape_path读取调优配置;随后设置输入 tensor 形状{1, chs, rows, cols}、CopyFromCpu拷入数据并Run(); - 读取输出并保存:
GetOutputHandle获取输出,将输出元素总数out_num拷贝到std::vector<int32_t>,转为uint8_t后按H*W组织成单通道灰度图,经直方图均衡化后cv::imwrite保存为out_img.jpg。
6. 常见问题与排查思路
- 模型输出类型不是 int32_t 导致报错:用 Netron 查看输出节点数据类型,按 3.3 修改
std::vector<int32_t> out_data(out_num);为对应类型; - 路径包含空格:CMake 命令与运行参数中的路径均需使用引号括起;
- 运行缺 dll:确认使用 CMake 生成的工程完成一次完整构建(POST_BUILD 步骤会自动拷贝 dll),或将缺失的 dll 手动复制到
Release目录; - TensorRT 相关报错:确认
TENSORRT_DLL指向包含nvinfer.dll、nvinfer_plugin.dll的目录,且 TensorRT 主版本与预测库匹配; - 动态 shape 需求:当输入尺寸不固定时,在 GPU + TensorRT 场景启用
--use_trt_dynamic_shape,可配合--dynamic_shape_path传入调优后的动态 shape 配置;固定尺寸场景则建议在导出模型时通过--input_shape固定输入形状。
至此,你已经完成了从环境搭建、模型准备、工程编译到 GPU/CPU 推理的完整 Windows C++ 部署闭环,可将该流程迁移到自定义模型与业务代码中。
- 人工智能
- 计算机视觉
- 预训练
【免费下载链接】PaddleSeg
Easy-to-use image segmentation library with awesome pre-trained model zoo, supporting wide-range of practical tasks in Semantic Segmentation, Interactive Segmentation, Panoptic Segmentation, Image Matting, 3D Segmentation, etc.
相关推荐
PaddleSeg 基于 FastDeploy 的 CPU/GPU Python 部署实战:语义分割模型从环境搭建到 Paddle-TensorRT 加速
PaddleSeg 基于 FastDeploy 的 CPU/GPU Python 部署实战:语义分割模型从环境搭建到 Paddle TensorRT 加速 本文
人工智能计算机视觉预训练PaddleSeg 分割模型在 Linux 上的 C++ 部署实战:Paddle Inference 环境搭建、编译运行与 TensorRT 加速全指南
PaddleSeg 分割模型在 Linux 上的 C++ 部署实战:Paddle Inference 环境搭建、编译运行与 TensorRT 加速全指南 本指南
人工智能计算机视觉预训练PaddleSeg LaneSeg 车道线分割模型 C++ 部署实战:基于 Paddle Inference 的编译、推理与后处理全流程
PaddleSeg LaneSeg 车道线分割模型 C++ 部署实战:基于 Paddle Inference 的编译、推理与后处理全流程 车道线检测是智能驾驶与
人工智能计算机视觉预训练
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考