- 人工智能
- 深度学习
- 计算机视觉
- NLP
- 语音
【免费下载链接】models
Officially maintained, supported by PaddlePaddle, including CV, NLP, Speech, Rec, TS, big models and so on.
导读
本文以 Paddle Serving 的 C++ 服务化部署为对象,讲解如何在飞桨训推一体全流程(TIPC)框架下,为任意飞桨模型开发「部署模型转换 + C++ 服务部署」的一键自动化测试。读者将掌握serving_infer_cpp.txt配置文件的字段语义、test_serving_infer_cpp.sh的解析执行原理,以及从数据准备、环境搭建、脚本组织到配置验证的完整开发与核验流程,可直接迁移到自己的模型仓库。
Paddle Serving 是飞桨官方推荐的服务化推理框架,长期目标是为人工智能落地的"最后一公里"提供专业、可靠且易用的在线服务。本文档主要关注 Linux GPU/CPU 环境下模型的C++ 服务化部署功能测试,具体测试点如下:
- 模型转换:部署模型转换流程跑通(Paddle 静态图模型 → Serving 部署模型);
- 模型部署:C++ 服务端部署与服务端/客户端交互流程跑通。
为了一键跑通上述所有功能,TIPC 提供了「训推一体全流程」功能自动化测试工具,它包含3 个脚本文件和 1 个配置文件:
| 文件 | 作用 | 是否需要修改 |
|---|---|---|
test_serving_infer_cpp.sh | 测试部署模型转换和 C++ 服务部署预测的脚本,会解析serving_infer_cpp.txt得到具体执行命令 | 无需修改 |
prepare.sh | 准备测试所需的数据或预训练模型 | 无需修改(按模型定制数据下载) |
common_func.sh | 提供配置文件解析、状态检查等通用函数 | 无需修改 |
serving_infer_cpp.txt | 配置文件,其内容会被test_serving_infer_cpp.sh解析为具体的执行命令字段 | 按模型修改 |
在 mobilenetv3_prod/Step6/test_tipc 目录下可以看到这套工具的真实实现:test_serving_infer_cpp.sh、prepare.sh、common_func.sh三个脚本与configs/mobilenet_v3_small/serving_infer_cpp.txt配置文件,是本文讲解的最佳参照物。
命令与配置文件解析
客户端启动命令的拆解
Paddle Serving 的 C++ 服务客户端启动命令一般由 Python 程序编写,可以拆解为 2 个部分:
python run_script例如对于通过 argparse 传参的场景:
python:替换为具体的 Python 解释器,如python3.7;run_script:替换为实际的客户端脚本,如resnet50_client.py。
即python3.7 resnet50_client.py。TIPC 测试脚本正是按照"解释器 + 脚本路径"两个字段的组合方式来拼接客户端命令的。
配置文件与运行命令的映射
完整的serving_infer_cpp.txt配置文件共有 16 行(原文档描述为 13 行,仓库实际文件为 16 行,其中包含 2 行注释分隔行),包含 3 个方面的内容:
- Serving 部署模型转换:第 4~9 行(
trans_model及其 5 个转换参数); - Serving 启动部署服务:第 10~14 行(服务端启动参数);
- Serving 启动客户端:第 15~16 行(客户端脚本与 prototxt 路径)。
具体内容见 serving_infer_cpp.txt,以 mobilenet_v3_small 为例的完整文件如下:
===========================serving_params=========================== model_name:mobilenet_v3_small python:python3.7 trans_model:-m paddle_serving_client.convert --dirname:./inference/mobilenet_v3_small_infer/ --model_filename:inference.pdmodel --params_filename:inference.pdiparams --serving_server:./deploy/serving_cpp/serving_server/ --serving_client:./deploy/serving_cpp/serving_client/ serving_dir:./deploy/serving_cpp --model:serving_server --op:GeneralClasOp --port:9997 --gpu_id:"0"|null cpp_client:serving_client.py proto_path:deploy/serving_cpp/preprocess/serving_client_conf.prototxt配置文件中主要有以下 3 种类型的字段:
key:value形式:该行可以被解析为key:value格式,需要根据实际含义修改该行内容;======xxxxx=====形式:注释信息,无需修改;##形式:段落分隔符,没有实际意义,无需修改。
从 test_serving_infer_cpp.sh 的源码可以看到,脚本通过awk 'NR==1, NR==18{print}' $FILENAME读取配置文件的前 18 行,再按行索引依次解析(lines[1]~lines[15]对应上面的 16 行有效配置),因此配置文件的行顺序不可随意调整。
模型转换配置参数
在配置文件中,可以通过下面的方式配置模型转换所需的超参数,如 Paddle 模型路径、部署模型路径等。下表给出了常用配置及其需要修改的内容:
| 行号 | 参考内容 | 含义 | key 是否需要修改 | value 是否需要修改 | 修改内容 |
|---|---|---|---|---|---|
| 2 | model_name:mobilenet_v3_small | 模型名字 | 否 | 是 | value 修改为自己的模型名字 |
| 3 | python:python3.7 | python 环境 | 否 | 是 | value 修改为自己的 python 环境 |
| 4 | trans_model:-m paddle_serving_client.convert | 模型转换模块入口 | 否 | 否 | 使用内置转换模块,无需修改 |
| 5 | --dirname:./inference/mobilenet_v3_small_infer/ | Paddle inference 模型保存路径 | 否 | 是 | value 修改为自己 Inference 模型的路径 |
| 6 | --model_filename:inference.pdmodel | pdmodel 文件名 | 否 | 是 | value 修改为 pdmodel 文件名 |
| 7 | --params_filename:inference.pdiparams | pdiparams 文件名 | 否 | 是 | value 修改为 pdiparams 文件名 |
| 8 | --serving_server:./deploy/serving_cpp/serving_server/ | 转换出的部署模型(服务端)目录 | 否 | 是 | value 修改为部署模型保存路径 |
| 9 | --serving_client:./deploy/serving_cpp/serving_client/ | 转换出的服务模型(客户端)目录 | 否 | 是 | value 修改为服务模型保存路径 |
以模型转换命令为例,总共包含 5 个超参数,解析后拼接出的完整命令为:
python3.7 -m paddle_serving_client.convert --dirname=./inference/resnet50_infer/ --model_filename=inference.pdmodel --params_filename=inference.pdiparams --serving_server=./deploy/serving_cpp/serving_server/ --serving_client=./deploy/serving_cpp/serving_client/其中:
- 推理模型路径
--dirname=./inference/resnet50_infer/,对应修改第 5 行; - pdmodel 文件名
--model_filename=inference.pdmodel,对应修改第 6 行; - 其他参数以此类推(第 7、8、9 行)。
paddle_serving_client.convert是paddle_serving_clientwheel 包内置的转换函数,无需修改。转换完成后会在本地生成serving_server和serving_client两个文件夹,后续服务端部署主要使用serving_server中的模型。
C++ 服务端部署配置参数
C++ 服务的服务端使用命令行启动,解析后拼接出的命令形如:
python3.7 -m paddle_serving_server.serve --model ./deploy/serving_cpp/serving_server/ --op GeneralClasOp --port 9997 --gpu_id "0"服务端启动配置参数如下:
| 行号 | 参考内容 | 含义 | key 是否需要修改 | value 是否需要修改 | 修改内容 |
|---|---|---|---|---|---|
| 10 | serving_dir:./deploy/serving_cpp | serving 服务执行路径 | 否 | 是 | value 修改为实际路径 |
| 11 | --model:serving_server | 部署模型名称 | 否 | 是 | value 修改为实际部署模型名称 |
| 12 | --op:GeneralClasOp | 自定义 OP 名称 | 否 | 是 | value 修改为自定义模型的 OP 名称 |
| 13 | --port:9997 | 端口号 | 否 | 是 | value 修改为实际使用的端口号 |
| 14 | --gpu_id:"0"\|null | 是否使用 GPU | 否 | 否 | 默认在 "0" 号 GPU 卡和 CPU 卡上运行,以\|分隔多卡 |
其中第 14 行的"0"|null是典型的 TIPC 多值字段:以|作为分隔符,"0"表示在 0 号 GPU 上启动服务端,null表示在 CPU 上启动服务端。test_serving_infer_cpp.sh中通过for gpu_id in ${gpu_value[*]}遍历该字段,为每个取值分别启动一次服务端 + 客户端测试,并将日志分别写入cpp_server_gpu.log/cpp_client_gpu.log或cpp_server_cpu.log/cpp_client_cpu.log。
客户端配置参数
C++ 服务的客户端采用 Python 语言编写,解析后拼接出的命令为:
python3.7 serving_client.py客户端配置参数如下:
| 行号 | 参考内容 | 含义 | key 是否需要修改 | value 是否需要修改 | 修改内容 |
|---|---|---|---|---|---|
| 15 | cpp_client:serving_client.py | 客户端服务执行路径 | 否 | 是 | value 修改为实际路径 |
| 16 | proto_path:deploy/serving_cpp/preprocess/serving_client_conf.prototxt | 准备好的 prototxt 路径 | 否 | 是 | value 修改为实际的 prototxt 文件路径 |
proto_path指向的serving_client_conf.prototxt是客户端与服务端通信的协议描述文件。由于客户端输入的是原始图像,可能与推理时需要的输入数据类型不同,建议将输入数据类型统一修改成 string 类型。仓库中的示例文件 serving_client_conf.prototxt 内容如下:
feed_var { name: "input" alias_name: "input" is_lod_tensor: false feed_type: 20 shape: 1 } fetch_var { name: "softmax_1.tmp_0" alias_name: "softmax_1.tmp_0" is_lod_tensor: false fetch_type: 1 shape: 1000 }其中feed_type: 20即表示 string 类型的输入数据,shape: 1表示单样本输入。TIPC 测试时会在模型转换完成后执行cp ${proto_path} ${serving_client_value}(见test_serving_infer_cpp.sh第 59 行),用该文件覆盖自动生成的serving_client/serving_client_conf.prototxt,以保证客户端发送 base64 图像数据时协议一致。
C++ 服务化部署功能测试开发
服务化部署功能测试开发主要分为以下 6 个步骤:
- 准备待测试的命令;
- 准备数据与环境;
- 准备开发所需脚本;
- 填写配置文件;
- 验证配置正确性;
- 撰写说明文档。
其中设置了 2 个核验点:启动服务端成功与启动客户端成功。下面详细介绍开发过程。
准备待测试的命令
【基本内容】
准备模型转换、模型推理的命令,后续会将这些命令按照上文第 2 节所述内容,映射到配置文件中。
【实战】
MobileNetV3 的 Serving 模型转换、服务部署运行命令如下所示:
# 模型转换 python3.7 -m paddle_serving_client.convert \ --dirname=./inference/mobilenet_v3_small_infer/ \ --model_filename=inference.pdmodel \ --params_filename=inference.pdiparams \ --serving_server=./deploy/serving_cpp/serving_server/ \ --serving_client=./deploy/serving_cpp/serving_client/ # 服务端部署 python3.7 -m paddle_serving_server.serve --model ./deploy/serving_cpp/serving_server/ --op GeneralClasOp --port 9997 --gpu_id "0" # 客户端访问 python3.7 serving_client.py这三条命令分别对应配置文件中的模型转换段(第 4~9 行)、服务端启动段(第 10~14 行)和客户端启动段(第 15~16 行)。mobilenet_v3_small 的完整参考配置见 serving_infer_cpp.txt。
准备数据与环境
【基本内容】
数据集:为方便快速验证训练/评估/推理过程,需要准备一个小数据集(训练集和验证集各 8~16 张图像即可,压缩后数据大小建议在
20M以内),放在lite_data文件夹下。相关文档可以参考论文复现赛指南 3.2 章节。环境:安装好 PaddlePaddle 和 PaddleServing 即可进行服务化部署测试开发。项目仅支持 Python3.6/3.7/3.8/3.9,接下来所有与 Python/Pip 相关的操作都需要选择正确的 Python 版本。
为了将模型预处理放在 C++ 端,需要自行开发自定义 op 并重新编译 PaddleServing,参考如下步骤将自定义 op 放在 Serving repo 目录下:
cp deploy/serving_cpp/preprocess/general_clas_op.* {Serving_repo_path}/core/general-server/op cp deploy/serving_cpp/preprocess/preprocess_op.* {Serving_repo_path}/core/predictor/tools/pp_shitu_tools仓库中这两组文件的真实实现位于 deploy/serving_cpp/preprocess 目录:
- general_clas_op.cpp / general_clas_op.h:自定义 OP,继承
OpWithChannel<GeneralBlob>,在其inference()方法中完成 base64 解码、BGR2RGB 转换、Resize(短边 256)、CenterCrop(224×224)、Normalize(mean 为[0.485, 0.456, 0.406],scale 为1/0.229, 1/0.224, 1/0.225)、Permute 转 CHW,再调用InferManager::instance().infer()执行推理; - preprocess_op.cpp / preprocess_op.h:复用的工具类函数(
ResizeImg、Normalize、Permute、CenterCropImg等)。
上述预处理参数与训练时完全一致,这正是保证服务化部署结果与 Paddle Inference 推理结果一致的关键。
完成代码开发后,参考 Serving 编译文档重新编译 Serving,并设置SERVING_BIN环境变量。仓库提供了针对registry.baidubce.com/paddlepaddle/paddle:latest-dev-cuda10.1-cudnn7-gcc82镜像的一键编译脚本 build_server.sh,其中完成了 Go 依赖安装、OpenCV 库下载、Serving 源码 clone、自定义 OP 拷贝(L49-L50处替换自定义 OP 的文件名)以及cmake + make编译流程,使用其他镜像需手动修改 CUDA 和 TensorRT 相关 path。
【注意事项】
为方便管理,建议在上传至 github 前,首先将lite_data文件夹压缩为 tar 包,直接上传 tar 包即可,在测试训练评估与推理过程时,可以首先对数据进行解压。
- 压缩命令:
tar -zcf lite_data.tar lite_data - 解压命令:
tar -xf lite_data.tar
准备开发所需脚本
【基本内容】
在 repo 中新建test_tipc目录,将文件 common_func.sh、prepare.sh 和 test_serving_infer_cpp.sh 分别拷贝到test_tipc目录中。
【注意事项】
上述 3 个脚本文件无需改动,在实际使用时,直接修改配置文件即可。
从源码看这三个脚本的职责分工:
- common_func.sh 提供
func_parser_key(以:分割取 key)、func_parser_value(以:分割取 value)、func_set_params(拼接key=value,null或空值返回空串)和status_check(根据退出码输出Run successfully with command - ...或Run failed with command - ...); - prepare.sh 的
serving_infer分支负责解压lite_data.tar、下载并解压mobilenet_v3_small_infer.tar到./inference目录,同时执行unset https_proxy/unset http_proxy避免代理影响访问; - test_serving_infer_cpp.sh 负责解析配置并依次执行「模型转换 → 服务端启动 → 客户端访问」三个阶段,每个阶段均通过
status_check记录成功/失败状态,并将日志写入test_tipc/output/${model_name}/${MODE}目录。
填写配置文件
【基本内容】
在 repo 的test_tipc/目录中新建configs/model_name,将文件 serving_infer_cpp.txt 拷贝到该目录中,其中model_name需要修改为您自己的模型名称。
【实战】
配置文件的含义解析可以参考上文「配置文件与运行命令的映射」部分。mobilenet_v3_small 的测试开发配置文件可以参考 serving_infer_cpp.txt,需要修改的核心字段汇总如下:
- 第 2 行
model_name:改为自己的模型名(同时决定日志目录名); - 第 3 行
python:改为实际使用的 Python 解释器; - 第 5~9 行:分别改为自己的 inference 模型目录、
pdmodel文件名、pdiparams文件名、serving_server/serving_client输出目录; - 第 10~13 行:改为实际的 serving 执行路径、部署模型名、自定义 OP 名、端口号;
- 第 15~16 行:改为实际的客户端脚本路径与 prototxt 路径。
验证配置正确性
【基本内容】
基于修改完的配置,运行:
bash test_tipc/prepare.sh ${your_params_file} serving_infer bash test_tipc/test_serving_infer_cpp.sh ${your_params_file} serving_infer其中第一个参数${your_params_file}为配置文件的路径,第二个参数serving_infer为测试模式,prepare.sh会据此进入serving_infer分支完成数据与模型准备。
【注意事项】
如果运行失败,会输出具体的报错命令,可以根据输出的报错命令排查配置文件的问题并修改,示例报错如下所示:
Run failed with command - python3.7 serving_client.py > ../../log/mobilenet_v3_small/serving_infer/server_infer_batchsize_1.log 2>&1 !【实战】
以 mobilenet_v3_small 的Linux GPU/CPU 服务化部署测试为例,命令如下所示:
bash test_tipc/prepare.sh test_tipc/configs/mobilenet_v3_small/serving_infer_cpp.txt serving_inferbash test_tipc/test_serving_infer_cpp.sh test_tipc/configs/mobilenet_v3_small/serving_infer_cpp.txt serving_infer输出结果如下,表示命令运行成功:
Run successfully with command - python3.7 serving_client.py > ../../log/mobilenet_v3_small/serving_infer/server_infer_batchsize_1.log 2>&1 !测试通过时,在test_tipc/output/mobilenet_v3_small/serving_infer/目录下会生成cpp_server_gpu.log、cpp_client_gpu.log(GPU 模式)以及cpp_server_cpu.log、cpp_client_cpu.log(CPU 模式)等日志文件,可用于进一步核对服务端启动与客户端预测的输出。
从 test_serving_infer_cpp.sh 源码可以确认完整执行链路:
- 模型转换(第 48~64 行):拼接
python3.7 -m paddle_serving_client.convert ...命令并执行,随后cp ${proto_path} ${serving_client_value}用自定义 prototxt 覆盖客户端配置,再cd ${serving_dir_value}进入部署目录,最后取消代理设置; - 启动服务端(第 66~88 行):遍历
gpu_id字段,对 GPU/CPU 分别以python -m paddle_serving_server.serve --model serving_server --op GeneralClasOp --port 9997 [--gpu_id "0"]形式启动,日志重定向到cpp_server_*.log,status_check记录状态后sleep 5s等待服务就绪; - 启动客户端(第 76~94 行):执行
python ${cpp_client_value} > cpp_client_*.log 2>&1并检查状态,结束后ps ux | grep -i ${port_value} | awk '{print $2}' | xargs kill -s 9清理占用端口 9997 的服务进程,避免影响后续测试轮次。
客户端脚本 serving_client.py 展示了完整的数据处理逻辑:通过cv2_to_base64将图像字节编码为 base64 字符串,preprocess返回{"input": image}作为 feed 字典、["softmax_1.tmp_0"]作为 fetch 列表(key 与serving_client_conf.prototxt中feed_var/fetch_var的 name 字段一一对应),postprocess从fetch_map["softmax_1.tmp_0"]中取出概率向量,取最大值得到class_id与prob并返回。当客户端成功访问服务端时,会输出形如{'class_id': 8, 'prob': 0.909...}的预测结果(见 serving_client_result.png 运行截图),与基于 Paddle Inference 的推理结果一致。
【核验】
基于修改后的配置文件,测试通过,全部命令成功。
撰写说明文档
【基本内容】
撰写 TIPC 功能总览和测试流程说明文档,分别为:
- TIPC 功能总览文档:
test_tipc/README.md; - C++ 服务化部署测试说明文档:
test_tipc/docs/test_serving_infer_cpp.md。
2 个文档模板可以直接拷贝到自己的 repo 中,根据自己的模型进行修改。功能总览文档可参考 mobilenetv3_prod/Step6/test_tipc/README.md,其中以表格形式汇总了各功能的打通情况(基础训练预测、更多训练方式、更多部署方式、Slim 训练部署、更多训练环境),并在「开始测试」一节按功能列出对应的测试文档入口。
【实战】
mobilenet_v3_small 中test_tipc目录结构如下所示(tutorials/mobilenetv3_prod/Step6/test_tipc 为仓库中的真实示例):
test_tipc |--configs # 配置目录 | |--model_name # 您的模型名称 | |--serving_infer_cpp.txt # C++ 服务化部署测试配置文件 |--docs # 文档目录 | |--test_serving_infer_cpp.md # C++ 服务化部署测试说明文档 |----README.md # TIPC说明文档 |----test_serving_infer_cpp.sh # C++ 服务化部署解析脚本,无需改动 |----common_func.sh # TIPC基础训练推理测试常用函数,无需改动【核验】
基于test_serving_infer_cpp.md文档,跑通C++服务化部署功能测试流程。
服务化部署全链路可视化
为了直观理解"测试开发"所覆盖的部署目标,可以参考 Paddle Serving C++ 服务化部署的真实运行效果。当服务端启动成功时,终端会输出推理引擎初始化(插入PADDLE_INFER标签的推理引擎工厂)与 IR 分析优化流程日志(ir_graph_build_pass、ir_analysis_pass、memory_optimize_pass、ir_graph_to_program_pass等):
当客户端成功访问服务端后,会输出模型预测的分类结果:
这两张运行截图是核验点「启动服务端」「启动客户端」的直观判据:客户端输出与基于 Paddle Inference 的推理结果一致,即表明服务化部署测试整体跑通。
FAQ
如果访问不成功,可能是设置了代理影响导致的,可以用下面命令取消代理设置:
unset http_proxy unset https_proxy需要注意的是,这条处理同样内置于测试链路中:prepare.sh的serving_infer分支和test_serving_infer_cpp.sh的模型转换阶段都会执行unset https_proxy/unset http_proxy,以保证数据下载与服务访问不受代理干扰。
小结
本文完整梳理了基于 TIPC 的 Linux GPU/CPU C++ 服务化部署测试开发流程:从命令准备、数据与环境准备、脚本组织、配置文件填写,到一键验证与文档撰写,并深入剖析了 serving_infer_cpp.txt 的字段语义与 test_serving_infer_cpp.sh 的执行原理。开发者只需将待测模型的转换命令与部署命令映射到配置文件中,即可复用这套"无需改动脚本、只改配置"的自动化测试方案,将任何飞桨模型的 C++ 服务化部署能力纳入一键可验证的工程化体系。
- 人工智能
- 深度学习
- 计算机视觉
- NLP
- 语音
【免费下载链接】models
Officially maintained, supported by PaddlePaddle, including CV, NLP, Speech, Rec, TS, big models and so on.
相关推荐
Paddle Serving C++ 服务化部署实战:Linux GPU/CPU 环境下的功能开发与 TIPC 测试规范
Paddle Serving C++ 服务化部署实战:Linux GPU/CPU 环境下的功能开发与 TIPC 测试规范 本技术指南以 PaddlePaddle
人工智能深度学习计算机视觉NLP语音飞桨 Paddle Serving 服务化部署开发全流程指南:Linux GPU/CPU 下的功能开发与 TIPC 自动化测试
飞桨 Paddle Serving 服务化部署开发全流程指南:Linux GPU/CPU 下的功能开发与 TIPC 自动化测试 Paddle Serving 是
人工智能深度学习计算机视觉NLP语音Paddle Serving 服务化部署测试开发实战指南:Linux GPU/CPU 环境下的 TIPC 测试体系搭建
Paddle Serving 服务化部署测试开发实战指南:Linux GPU/CPU 环境下的 TIPC 测试体系搭建 本文是 PaddlePaddle 模型仓
人工智能深度学习计算机视觉NLP语音
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考