InsightFace ArcFace-Paddle 基于 PaddleServing 的 Pipeline 在线服务部署实战指南
【免费下载链接】insightfaceState-of-the-art 2D and 3D Face Analysis Project项目地址: https://gitcode.com/GitHub_Trending/in/insightface
导读
本文以 InsightFace 仓库中 recognition/arcface_paddle 子项目为背景,完整讲解如何将 PaddlePaddle 训练并导出的 ArcFace / MobileFace 人脸识别动态图模型,通过 PaddleServing 框架以 Pipeline 模式部署为可对外提供 HTTP / RPC 预测能力的在线服务。读完本文你将掌握:PaddleServing 运行环境(server / client / app)的安装与版本搭配、inference 模型到 serving 模型的转换命令与目录结构、基于web_service.py + config.yml的服务启动与并发调优,以及 HTTP / RPC 两种客户端发送识别请求的完整闭环,并理解预处理、后处理与性能调优背后的源码实现。
1. 背景:为什么选择 PaddleServing 部署 ArcFace
ArcFace-Paddle 是基于 PaddlePaddle 的深度人脸检测与识别工具包,其中人脸识别部分提供了ArcFace与MobileFace两个预训练模型(recognition/arcface_paddle/README.md)。训练完成或直接下载预训练模型后,要落地为可被业务系统高频调用的在线能力,就需要一个成熟的服务化部署框架。PaddleServing 正是 PaddlePaddle 生态中的官方服务化部署方案,关联文档 recognition/arcface_paddle/deploy/pdserving/README.md 指出其核心优势包括:
- 与 Paddle 训练流程无缝衔接:绝大多数 Paddle 模型只需一条命令即可完成部署,无需为 Serving 单独改造网络结构;
- 工业级服务能力:支持模型管理、在线加载、在线 A/B 测试等生产特性;
- 高并发高效通信:客户端与服务端之间支持高并发和高效通信,且支持 C++、Python、Java 等多种语言开发客户端。
本文介绍的 Pipeline 模式是 PaddleServing 的典型用法:它以 DAG(有向无环图)方式组织多个 Op,每个 Op 完成一段独立逻辑(如人脸识别中的预处理、推理、后处理),服务框架自动调度与并发执行。在 ArcFace-Paddle 的部署目录中,这一整套可运行代码均位于 recognition/arcface_paddle/deploy/pdserving。
2. 环境准备
2.1 ArcFace 运行环境
首先需要准备好 ArcFace 的运行环境,参考 recognition/arcface_paddle/README.md 中的安装指引完成 PaddlePaddle 环境搭建。文档特别提示:根据自身环境下载对应的 paddle whl 包,推荐安装 2.2+ 版本。该环境既用于训练 / 导出模型,也用于后续paddle_serving_client.convert模型转换操作。
2.2 PaddleServing 运行环境
PaddleServing 部署需要安装三个组件,文档给出的版本组合如下:
① 安装 serving(用于启动服务端)
pip3 install paddle-serving-server==0.6.3 # for CPU pip3 install paddle-serving-server-gpu==0.6.3 # for GPU # 其他 GPU 环境需先确认环境,再选择执行如下命令 pip3 install paddle-serving-server-gpu==0.6.3.post101 # GPU with CUDA10.1 + TensorRT6 pip3 install paddle-serving-server-gpu==0.6.3.post11 # GPU with CUDA11 + TensorRT7② 安装 client(用于向服务发送请求)
pip3 install paddle-serving-client==0.6.3③ 安装 serving-app(Pipeline 模式依赖的应用层组件)
pip3 install paddle-serving-app==0.6.3注意:
paddle-serving-app是 Pipeline 服务开发(web_service.py、pipeline_http_client.py等)所必需的依赖包。如需安装最新版本 PaddleServing,请参考官方 LATEST_PACKAGES 文档,按 Python 版本选择对应 client 安装包;中文版 README(README_CN.md)中 client 安装写法为paddle_serving_client==0.6.3,与英文版等价。
2.3 环境验证要点
从源码看,pipeline_rpc_client.py 在导入时会先尝试from paddle_serving_server_gpu.pipeline import PipelineClient,失败再回退到from paddle_serving_server.pipeline import PipelineClient,这说明 GPU 版与 CPU 版 serving 包在 API 上是兼容的,安装哪一个取决于你的硬件环境。
3. 模型转换:从 inference 模型到 serving 模型
3.1 获取 ArcFace 推理模型
PaddleServing 部署前,需要把已保存的 inference 模型转换为 Serving 易于部署的模型格式。首先下载 ArcFace 的 inference 模型(此处为 128 维特征、MobileFaceNet 骨干的mobileface_v1.0_infer):
wget -nc -P ./inference https://paddle-model-ecology.bj.bcebos.com/model/insight-face/mobileface_v1.0_infer.tar tar xf inference/mobileface_v1.0_infer.tar --strip-components 1 -C inference3.2 执行转换命令
使用已安装的paddle_serving_client工具将 inference 模型转换为 server / client 两套文件:
python3 -m paddle_serving_client.convert --dirname ./inference/ \ --model_filename inference.pdmodel \ --params_filename inference.pdiparams \ --serving_server ./MobileFaceNet_128_serving/ \ --serving_client ./MobileFaceNet_128_client/参数说明:
| 参数 | 含义 |
|---|---|
--dirname | inference 模型所在目录(上一步下载解压后的./inference/) |
--model_filename | 模型结构文件名(inference.pdmodel) |
--params_filename | 模型参数文件名(inference.pdiparams) |
--serving_server | 转换后服务端模型输出目录 |
--serving_client | 转换后客户端配置输出目录 |
3.3 转换产物结构
转换完成后,当前目录下会多出两个文件夹,格式如下:
MobileFaceNet_128_serving ├── __model__ ├── __params__ ├── serving_server_conf.prototxt └── serving_server_conf.stream.prototxt MobileFaceNet_128_client/ ├── serving_client_conf.prototxt └── serving_client_conf.stream.prototxtserving_server_conf.prototxt记录了模型输入输出的 tensor 名称与 shape,服务端启动时据此完成 feed / fetch 绑定;serving_client_conf.prototxt供客户端对齐请求字段。MobileFaceNet_128_serving正是后续 config.yml 中model_config指向的路径(./MobileFaceNet_128_serving)。
3.4 从训练产物到 inference 模型的完整链路
需要说明的是:上述mobileface_v1.0_infer.tar对应 MobileFaceNet 骨干、128 维特征(MobileFaceNet_128)的预训练推理模型。若你想用自己的训练权重导出 inference 模型,可参考 scripts/export_dynamic.sh 中的tools/export.py调用方式,核心参数包括--backbone、--embedding_size、--checkpoint_dir与--output_dir。
从源码实现(dynamic/export.py)看,导出时会将 checkpoint 权重加载进 backbone,然后通过paddle.jit.save(默认)或paddle.onnx.export(--export_type onnx时)保存,并显式声明输入规格:
paddle.jit.save( backbone, path, input_spec=[ paddle.static.InputSpec( shape=[None, 3, 112, 112], dtype='float32') ])即模型输入为[N, 3, 112, 112]的 float32 图像张量。这也与 pipeline_http_client.py 服务端预处理中把图片cv2.resize到(112, 112)、转(2, 0, 1)通道序并expand_dims加 batch 维的逻辑一一对应。MobileFaceNet_128的网络定义在 dynamic/backbones/mobilefacenet.py(feature_dim=128,最终通过linear1输出 128 维特征并 reshape 为[batch, 128])。
4. Paddle Serving Pipeline 部署
4.1 获取部署代码与目录结构
若尚未下载 insightface 代码,先克隆仓库并进入工作目录:
git clone https://github.com/deepinsight/insightface cd recognition/arcface_paddle/deploy/pdservingpdserving目录包含了启动 Pipeline 服务与发送预测请求的完整代码:
__init__.py config.yml # 启动服务的配置文件 pipeline_http_client.py # web 方式发送 pipeline 预测请求的脚本 pipeline_rpc_client.py # rpc 方式发送 pipeline 预测请求的脚本 web_service.py # 启动 pipeline 服务端的脚本说明:关联文档正文仅提及 4 个文件,而仓库中实际还包含
pipeline_rpc_client.py(RPC 客户端)以及imgs/下的测试图片与运行截图,本文一并覆盖。
4.2 服务端实现解析(web_service.py)
web_service.py 是整个 Pipeline 服务的入口,代码量不长但结构清晰:
from paddle_serving_server.web_service import WebService, Op import numpy as np import cv2 import base64 class ArcFaceOp(Op): def init_op(self): pass def preprocess(self, input_dicts, data_id, log_id): (_, input_dict), = input_dicts.items() data = base64.b64decode(input_dict["image"]) data = np.frombuffer(data, np.uint8) img = cv2.imdecode(data, cv2.IMREAD_COLOR) img = cv2.resize(img, (112, 112)) # normalize to mean 0.5, std 0.5 img = (img - 127.5) * 0.00784313725 # BGR2RGB img = img[:, :, ::-1] img = img.transpose((2, 0, 1)) img = np.expand_dims(img, 0) img = img.astype('float32') return {"x": img.copy()}, False, None, "" def postprocess(self, input_dicts, fetch_dict, log_id): out = fetch_dict["save_infer_model/scale_0.tmp_1"] out_dict = {"out": out} return out_dict, None, "" class ArcFaceService(WebService): def get_pipeline_response(self, read_op): arcface_op = ArcFaceOp(name="ArcFace", input_ops=[read_op]) return arcface_op arcface_service = ArcFaceService(name="ArcFace") arcface_service.prepare_pipeline_config("config.yml") arcface_service.run_service()关键点逐一解读:
- Op 三阶段生命周期:
init_op(初始化)、preprocess(预处理)、postprocess(后处理),这是 PaddleServing Pipeline Op 的标准接口; - 预处理细节:客户端传来的图片是 base64 编码字节流,服务端先
base64.b64decode还原为字节,再np.frombuffer+cv2.imdecode解码为 BGR 图像,然后缩放到112×112(与模型输入规格一致),执行(img - 127.5) * 0.00784313725归一化(等价于 mean=0.5、std=0.5 的标准化),再 BGR→RGB、(H,W,C)→(C,H,W)、expand_dims增加 batch 维、转 float32,最终以键名"x"送入模型; - fetch 输出绑定:
postprocess从fetch_dict中取"save_infer_model/scale_0.tmp_1",该名字正是 config.yml 中fetch_list配置的 alias_name,二者必须保持一致; - DAG 组装:
get_pipeline_response将ArcFaceOp挂在read_op之后,形成"读取请求 → ArcFace 推理"的单节点 DAG; - 启动流程:
prepare_pipeline_config("config.yml")加载并发/端口等配置,run_service()正式拉起服务。
4.3 配置文件详解(config.yml)
config.yml 是服务调优的核心,完整内容及注释如下:
# rpc端口, rpc_port和http_port不允许同时为空。当rpc_port为空且http_port不为空时,会自动将rpc_port设置为http_port+1 rpc_port: 18091 # http端口, rpc_port和http_port不允许同时为空。当rpc_port可用且http_port为空时,不自动生成http_port http_port: 9998 # worker_num, 最大并发数。当build_dag_each_worker=True时, 框架会创建worker_num个进程,每个进程内构建grpcServer和DAG # 当build_dag_each_worker=False时,框架会设置主线程grpc线程池的max_workers=worker_num worker_num: 10 # build_dag_each_worker, False,框架在进程内创建一条DAG;True,框架会每个进程内创建多个独立的DAG build_dag_each_worker: False dag: # op资源类型, True, 为线程模型;False,为进程模型 is_thread_op: False # 重试次数 retry: 10 # 使用性能分析, True,生成Timeline性能数据,对性能有一定影响;False为不使用 use_profile: True tracer: interval_s: 10 op: ArcFace: # 并发数,is_thread_op=True时,为线程并发;否则为进程并发 concurrency: 8 # 当op配置没有server_endpoints时,从local_service_conf读取本地服务配置 local_service_conf: # client类型,包括brpc, grpc和local_predictor。local_predictor不启动Serving服务,进程内预测 client_type: local_predictor # 模型路径 model_config: ./MobileFaceNet_128_serving # Fetch结果列表,以client_config中fetch_var的alias_name为准 fetch_list: ["save_infer_model/scale_0.tmp_1"] # 计算硬件ID,当devices为""或不写时为CPU预测;当devices为"0", "0,1,2"时为GPU预测,表示使用的GPU卡 devices: "0" ir_optim: True参数调优要点:
rpc_port/http_port:服务同时暴露 RPC(18091)与 HTTP(9998)两个端口,且两者不允许同时为空;RPC 客户端(pipeline_rpc_client.py)连127.0.0.1:18091,HTTP 客户端(pipeline_http_client.py)请求http://127.0.0.1:9998/ArcFace/prediction;worker_num:最大并发 worker 数,build_dag_each_worker=False时决定主线程 grpc 线程池的max_workers;dag.is_thread_op:True为线程并发模型,False为进程并发模型,直接影响资源占用与隔离性;op.ArcFace.concurrency:Op 级并发数,是吞吐调优最直接的旋钮(详见 4.5 节);local_service_conf.client_type: local_predictor:这是本部署的精髓——不额外拉起独立 Serving 服务进程,而是在服务进程内直接做本地推理(进程内预测),减少一次网络往返,提升延迟表现;devices: "0":指定使用 GPU 0 进行预测;留空或删除该字段则为 CPU 预测;ir_optim: True:开启 Paddle 计算图 IR 优化,可进一步提升推理效率。
4.4 启动服务与发送请求
① 启动服务
# 启动服务,运行日志保存在 log.txt python3 web_service.py &>log.txt &服务成功启动后,log.txt中会打印类似如下的日志(实际运行截图见 recognition/arcface_paddle/deploy/pdserving/imgs/start_server.png):
PaddleServing 服务启动日志
② 发送 HTTP 预测请求
python3 pipeline_http_client.pypipeline_http_client.py 的实现逻辑是:遍历--image_dir(默认./imgs)下的所有图片,将每张图片读取为字节后 base64 编码,以{"key": ["image"], "value": [image]}的 JSON 结构 POST 到http://127.0.0.1:9998/ArcFace/prediction,并打印服务端返回的 JSON;结束时输出测试图片总数。运行成功后在命令行窗口会打印模型预测结果,示例输出见 recognition/arcface_paddle/deploy/pdserving/imgs/results.png:
ArcFace 识别预测结果输出
③ 可选:RPC 方式发送请求
仓库还提供了 RPC 客户端 pipeline_rpc_client.py,通过PipelineClient().connect(['127.0.0.1:18091'])连接 RPC 端口,再用client.predict(feed_dict={"image": image}, fetch=["res"])发送预测。两种客户端 feed 的键名都是"image",与服务端preprocess中读取的input_dict["image"]严格对应。
4.5 并发调优与性能观测
调整 config.yml 中的并发个数可以获得最大 QPS。关联文档给出的经验法则是:检测和识别的并发数比例一般为 2:1(若同时部署检测 + 识别两段 Op):
det: concurrency: 8 ... rec: concurrency: 4 ...在本仓库的单 Op(仅 ArcFace 识别)场景下,对应的调优写法是:
op: ArcFace: concurrency: 8 ...有需要时也可以同时发送多个服务请求来压测并发能力。预测性能数据会被自动写入PipelineServingLogs/pipeline.tracer文件,无需额外埋点。
关联文档记录的基准测试(在 700 张真实图片上、V100 GPU 上运行)平均 QPS 约为 57,pipeline.tracer中记录的典型输出如下:
2021-11-04 13:38:52,507 Op(ArcFace): 2021-11-04 13:38:52,507 in[135.4579597902098 ms] 2021-11-04 13:38:52,507 prep[0.9921311188811189 ms] 2021-11-04 13:38:52,507 midp[3.9232132867132865 ms] 2021-11-04 13:38:52,507 postp[0.12166258741258741 ms] 2021-11-04 13:38:52,507 out[0.9898286713286714 ms] 2021-11-04 13:38:52,508 idle[0.9643989520087675] 2021-11-04 13:38:52,508 DAGExecutor: 2021-11-04 13:38:52,508 Query count[573] 2021-11-04 13:38:52,508 QPS[57.3 q/s] 2021-11-04 13:38:52,509 Succ[0.9982547993019197] 2021-11-04 13:38:52,509 Error req[394] 2021-11-04 13:38:52,509 Latency: 2021-11-04 13:38:52,509 ave[11.52941186736475 ms] 2021-11-04 13:38:52,509 .50[11.492 ms] 2021-11-04 13:38:52,509 .60[11.658 ms] 2021-11-04 13:38:52,509 .70[11.95 ms] 2021-11-04 13:38:52,509 .80[12.251 ms] 2021-11-04 13:38:52,509 .90[12.736 ms] 2021-11-04 13:38:52,509 .95[13.21 ms] 2021-11-04 13:38:52,509 .99[13.987 ms] 2021-11-04 13:38:52,510 Channel (server worker num[10]): 2021-11-04 13:38:52,510 chl0(In: ['@DAGExecutor'], Out: ['ArcFace']) size[0/0] 2021-11-04 13:38:52,510 chl1(In: ['ArcFace'], Out: ['@DAGExecutor']) size[0/0]如何读懂这份日志:
Op(ArcFace)时间分解:in(输入接收)135.46ms、prep(预处理)约 0.99ms、midp(模型推理)约 3.92ms、postp(后处理)约 0.12ms、out(输出)约 0.99ms。可以看到推理(midp)与输入接收(in)是耗时主体,预处理/后处理开销极小,这与local_predictor进程内推理、预处理仅包含 resize + 归一化的实现相符;DAGExecutor汇总:Query count为累计查询数,QPS为吞吐,Succ为成功率(0.9983),Latency给出平均与各分位延迟(ave 约 11.5ms,P99 约 13.99ms);Channel队列状态:size[0/0]表示当前 DAG 通道无积压,服务处于健康状态。
注意:上述性能数据是文档作者在特定软硬件环境(700 张真实图片、单张 V100 GPU、2021-11-04)下的实测记录,不同机器、不同并发配置、不同图片尺寸下结果会有差异,应作为调优参考而非绝对指标。
5. 常见问题(FAQ)
Q1:发送请求后没有结果返回,或提示输出解码报错。
A1:启动服务和发送请求时不要设置代理。在启动服务前和发送请求前关闭代理即可,关闭命令:
unset https_proxy unset http_proxy该问题在英文版与中文版 README(README.md / README_CN.md)中均有记录。从实践看,代理会干扰本机 HTTP(9998 端口)与 RPC(18091 端口)的本地回环通信,导致请求超时或响应体解析失败。
6. 部署链路全景回顾
至此,一条完整的"训练 → 导出 → 转换 → 服务化 → 请求"链路已经打通:
- 训练:基于 recognition/arcface_paddle 的
tools/train.py训练得到 checkpoint; - 导出:通过 dynamic/export.py(或 scripts/export_dynamic.sh)导出输入为
[N,3,112,112]的 inference 模型;也可以直接使用文档提供的mobileface_v1.0_infer.tar预训练推理模型; - 转换:用
python3 -m paddle_serving_client.convert生成MobileFaceNet_128_serving/与MobileFaceNet_128_client/; - 服务化:
python3 web_service.py读取 config.yml,以local_predictor进程内推理方式在 9998(HTTP)/ 18091(RPC)端口提供 ArcFace 识别能力; - 调用:
pipeline_http_client.py或pipeline_rpc_client.py以 base64 图像发起请求,获得 128 维人脸特征向量(fetch_list中的"save_infer_model/scale_0.tmp_1"),可作为后续人脸比对、检索、聚类等业务的上游输入。
该部署方案与 ArcFace-Paddle 主仓库 README(recognition/arcface_paddle/README.md)中"检测 + 识别"的离线推理流程(tools/test_recognition.py --det --rec)互补:前者面向在线高并发服务,后者面向单机离线分析;如需端到端的人脸检测 + 识别在线服务,可将 BlazeFace 检测模型与本文的 ArcFace 识别 Op 组合进同一条 Pipeline DAG,并按 2:1 的比例配置检测与识别 Op 的并发数。
【免费下载链接】insightfaceState-of-the-art 2D and 3D Face Analysis Project项目地址: https://gitcode.com/GitHub_Trending/in/insightface
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考