Skip to content

Latest commit

 

History

History
214 lines (161 loc) · 9.04 KB

Pipeline_Optimize_CN.md

File metadata and controls

214 lines (161 loc) · 9.04 KB

Python Pipeline 优化指南

通常,服务的性能优化是基于耗时分析,首先要掌握服务运行的各阶段耗时信息,从中找到耗时最长的性能瓶颈再做针对性优化。对于模型推理服务化不仅要关注耗时,由于 GPU 芯片昂贵,更要关注服务吞吐,从而提升 GPU 利用率实现降本增效。因此,模型推理服务化可总结为:

  • 优化响应时长
  • 优化服务吞吐

经过分析和调优后,各个阶段实现整体服务的性能最优。

优化响应时长

首先,优化响应时长的主要思路首先要掌握各阶段耗时,并分析出性能瓶颈或者耗时占比较高的阶段,再针对性能瓶颈做专项优化。

Paddle Serving 提供2种耗时分析工具,Pipeline Trace ToolPipeline Profile Tool。2个工具的特点如下:

  • Pipeline Trace Tool : 统计服务端所有进程各个阶段的平均耗时,包括每个 OpChannel,用于定量分析。
  • Pipeline Profile Tool : 是可视化 Trace View 工具,生成多进程并发效果图,用定性和定量分析执行和并发效果。

一.耗时分析

1.Pipeline Trace Tool

Pipeline Trace Tool 统计每个 OpChannel 中各阶段的处理耗时,

开启方法在配置文件 config.ymldag 区段内添加 tracer 字段,框架会每隔 interval_s 时间生成 Trace 信息。

dag:
    #op资源类型, True, 为线程模型;False,为进程模型
    is_thread_op: True

    #tracer, 跟踪框架吞吐,每个OP和channel的工作情况。无tracer时不生成数据
    tracer:
        #每次trace的时间间隔,单位秒/s
        interval_s: 10

生成的 Trace 信息保存在 ./PipelineServingLogs/pipeline.tracer 日志中。如下图所示

==================== TRACER ======================
 Op(uci):
         in[8473.507333333333 ms]:          # 等待前置 Channel 中数据放入 Op 的耗时,如长时间无请求,此值会变大
         prep[0.6753333333333333 ms]         # 推理前处理 preprocess 阶段耗时 
         midp[26.476333333333333 ms]         # 推理 process 阶段耗时
         postp[1.8616666666666666 ms]        # 推理后处理 postprocess 阶段耗时
         out[1.3236666666666668 ms]          # 后处理结果放入后置 channel 耗时
         idle[0.9965882097324374]            # 框架自循环耗时,间隔 1 ms,如此值很大说明系统负载高,调度变慢
 DAGExecutor:
         Query count[30]                     # interval_s 间隔时间内请求数量 
         QPS[27.35 q/s]                      # interval_s 间隔时间内服务 QPS 
         Succ[1.0]                           # interval_s 间隔时间内请求成功率 
         Error req[]                         # 异常请求信息
         Latency:                
                 ave[36.55233333333334 ms]   # 平均延时
                 .50[8.702 ms]               # 50分位延时
                 .60[8.702 ms]               # 60分位延时
                 .70[92.346 ms]              # 70分位延时
                 .80[92.346 ms]              # 70分位延时
                 .90[92.346 ms]              # 90分位延时
                 .95[92.346 ms]              # 95分位延时
                 .99[92.346 ms]              # 99分位延时
 Channel (server worker num[1]):
         chl0(In: ['@DAGExecutor'], Out: ['uci']) size[0/0]  # 框架 RequestOp 与 uci Op 之间 Channel 中堆积请求数。此值较大,说明下游 uci Op 消费能力不足。
         chl1(In: ['uci'], Out: ['@DAGExecutor']) size[0/0]  # uci Op 与 框架 ResponseOp 之间 Channel 中堆积的请求数。此值较大,说明下游 ReponseOp 消费能力不足。
 ==================== TRACER ======================

2.Pipeline Profile Tool

dag:
    #op资源类型, True, 为线程模型;False,为进程模型
    is_thread_op: True
    
    #使用性能分析, 默认为 False,imeline性能数据,对性能有一定影响
    use_profile: True,

开启后,Server 端在预测的过程中会将对应的日志信息打印到标准输出,为了更直观地展现各阶段的耗时,因此服务启动要使用如下命令:

python3.7 web_service.py > profile.txt 2>&1

服务接收请求后,输出 Profile 信息到 profile.txt 文件中。再粘贴如下代码到 trace.py, 使用框架提供 Analyst 模块对日志文件做进一步的分析处理。

from paddle_serving_server.pipeline import Analyst
import json
import sys

if __name__ == "__main__":
    log_filename = "profile.txt"
    trace_filename = "trace"
    analyst = Analyst(log_filename)
    analyst.save_trace(trace_filename)

运行命令,脚本将日志中的时间打点信息转换成 json 格式保存到 trace 文件。

python3.7 trace.py

trace 文件可以通过 chrome 浏览器的 tracing 功能进行可视化。

打开 chrome 浏览器,在地址栏输入 chrome://tracing/ ,跳转至 tracing 页面,点击 load 按钮,打开保存的 trace 文件,即可将预测服务的各阶段时间信息可视化。

通过图示中并发请求的处理流程可观测到推理阶段的流水线状态,以及多个请求在推理阶段的间隔信息,进行优化。

二.降低响应时长优化思路

根据 Pipeline Trace Tool 输出结果在不同阶段耗时长的问题,常见场景的优化方法如下:

  • Op 推理阶段(midp) 耗时长:
    • 增加 Op 并发度
    • 开启 auto-batching (前提是多个请求的 shape 一致)
    • 若批量数据中某条数据的 shape 很大,padding 很大导致推理很慢,可参考 OCR 示例中 mini-batch 方法。
    • 开启 TensorRT/MKL-DNN 优化
    • 开启低精度推理
  • Op 前处理阶段(prep) 或 后处理阶段耗时长:
    • 增加 OP 并发度
    • 优化前后处理逻辑
  • in/out 耗时长(channel 堆积>5)
    • 检查 channel 传递的数据大小,可能为传输的数据大导致延迟大。
    • 优化传入数据,不传递数据或压缩后再传入
    • 增加 Op 并发度
    • 减少上游 Op 并发度

根据 Pipeline Profile Tool 输出结果优化流水行并发的效果

  • 增加 Op 并发度,或调整不同 Op 的并发度
  • 开启 auto-batching

此外,还有一些优化思路,如将 CPU 处理较慢的过程转换到 GPU 上处理等,客户端与服务端传输较大数据时,可使用共享内存方式传递内存或显存地址等。

优化服务吞吐

一.分析吞吐瓶颈

服务的吞吐量受到多种多因素条件制约,如 Op 处理时长、传输数据耗时、并发数和 DAG 图结构等,可以将这些因素进一步拆解,当传输数据不是极端庞大的时候,最重要因素是流水线中最慢 Op 的处理时长和并发数

Op 处理时长:
op_cost = process(pre + mid + post) 

服务吞吐量:
service_throughput = 1 / 最慢 op_cost * 并发数

服务平响:
service_avg_cost = ∑op_concurrency 【关键路径】

批量预测平均耗时:
avg_batch_cost = (N * pre + mid + post) / N 

二.优化思路

优化吞吐的主要方法是 增大 Op 并发数自动批量CPU 与 GPU 处理分离

1.增加 Op 并发**

调整 Op 的并发数量通过设置 is_thread_op: False 进程类型 Op 和 uci Op 的 concurrency 字段

dag:
    #op资源类型, True, 为线程模型;False,为进程模型
    is_thread_op: False
op:
    uci:
        #并发数,is_thread_op=True时,为线程并发;否则为进程并发
        concurrency: 10

Op 的进程数量不是越大越好,受到机器 CPU 核数、内存和显存大小的限制,推荐设置 Op 的并发数不超过系统 CPU 核数。

2.动态批量

动态批量是增加吞吐的有一种方法,开启方式可参考Python Pipeline 核心功能

3.CPU 与 GPU 处理分离

CV 模型中,对图片或视频的前后处理成为主要瓶颈时,可考虑此方案,即将前后处理过程独立成一个 Op 并独立设置并发度。

将 CPU 前后处理和 GPU 推理过程比例调整到服务最佳配比。以 OCR 为例,原有流水线设计为 RequestOp -> DetOp -> RecOp -> ResponseOp

根据耗时分析,DetOpRecOp 的前处理耗时很长,因此,将2个模型前处理分离成独立 Op,最新的流水线设计为:

RequestOp -> PreDetOp -> DetOp -> PreRecOp -> RecOp -> ResponseOp,并调大 PreDetOpPreRecOp的并发度,从而获得 20% 的性能提升。

由于增加了2次数据传递,单条请求的处理延时会增加。