CANN/triton-ge-backend性能调优方法论
性能调优方法论【免费下载链接】triton-inference-server-ge-backendge-backend基于triton inference server框架实现对接NPU生态快速实现传统CV\NLP等模型的服务化。项目地址: https://gitcode.com/cann/triton-inference-server-ge-backend模型优化有一套通用的流程本文档首先介绍一下通用的优化手段然后再以cnclip模型为例为大家提供模型接入、运行、优化整体过程。优化步骤总结1. 开启小batch自动合并模式triton server 支持在高吞吐模式下在用户设置的间隙时间内若存在多个小batch请求将其合并为大batch从而提高NPU利用率。以cnclip模型的image过程为例在config.pbtxt中配置动态batch参数dynamic_batching { max_queue_delay_microseconds: 10000 # 等待合并的最大延迟微秒可调整 preferred_batch_size: [4, 8] # 优先合并成这些batch_size可选 }注此模式只支持0轴为bs动态轴其余轴固定的情况该参数含义如下在10ms内若多个request可以合并为 4,8 大小的batch则将其合并后计算。若所有请求均为1bs则当达到4bs时将会执行不会到达8bs所以要根据请求情况进行调整若经过测试在8bs时吞吐最好则建议preferred_batch_size 仅保留 8。若请求均为随机则根据请求顺序进行拼接达到 4,8 bs的请求会被合并从而加快计算。在理想情况下比如我们用8个并发每个请求1bs则如果8个并发恰好在10ms内请求到server则会被合并成一个8bs的推理任务推理完成后再拆分分别响应。这样做的前提是处理8个1bs推理任务要比1个8bs的任务耗时长才有收益。所以在填写之前用户需要自行测试亲和batch进行填写。因8个请求在理想情况下合并为1个推理任务一张NPU建议stream不大于8那么在最理想的情况下8个stream可以处理8*8个请求也就是64个并发任务。我们将config中的count等信息做如下修改instance_group [{ count: 64 } ] parameters: [ { key: device_ids, value: {string_value: 2} } ] parameters: [ { key: device_exec_blocks, value: {string_value: 8} } ]默认情况下count如果填写64在卡上会开相应的stream显然64条stream没必要可以通过 device_exec_blocks 参数进行限制每张卡上支持的流水数量使其为 8。 在1张卡的情况下我们限制server最多支持64个请求并发在NPU侧因配置了动态合并参数当吞吐率高的情况下会合并成刚好8个stram可以处理。此时达到最优吞吐。测试数据在不开启小batch动态合并时用1bs1并发测试Request concurrency: 1 Client: Request count: 3445 Throughput: 191.355 infer/sec Avg latency: 5224 usec (standard deviation 306 usec) p50 latency: 5220 usec p90 latency: 5393 usec p95 latency: 5677 usec p99 latency: 6408 usec Avg HTTP time: 5218 usec (send/recv 110 usec response wait 5108 usec) Server: Request count: 0 Inferences/Second vs. Client Average Batch Latency Concurrency: 1, throughput: 191.355 infer/sec, latency 5224 usec因动态图每一节点tiling计算在CPU侧在机选完成后才能发送至NPU执行所以在单流1bs下性能较差。在开启小batch合并且用1bs64并发测试Request concurrency: 64 Client: Request count: 23940 Throughput: 1329.13 infer/sec Avg latency: 48084 usec (standard deviation 13285 usec) p50 latency: 47319 usec p90 latency: 49055 usec p95 latency: 49707 usec p99 latency: 51560 usec Avg HTTP time: 48075 usec (send/recv 319 usec response wait 47756 usec) Server: Request count: 0 Inferences/Second vs. Client Average Batch Latency Concurrency: 64, throughput: 1329.13 infer/sec, latency 48084 usec可以看到性能提升明显 通过profiling分析可以看出在64条请求并发情况下NPU使用率有明显提升空泡减少明显。该优化也可叠加锁核方式提高p99指标。注意此方法虽吞吐效果明显但在整体考虑资源时需要合理规划。此方法是通过CPU换NPU性能目前仅测试单张卡就使用了64核若考虑一台服务器有8张卡如果均使用此种方式性能肯定无法达到8*单张吞吐。所以需要用户综合考虑使用场景调整并发度。1.1 使用分档模式当请求中可以确定bs 最大亲和bs 时如上示例中 max_batch_size max [2, 4, 8] , 我们可以尝试通过分档将不同bs大小生成静态图从而支持图下沉方式推理进一步提高吞吐。比如 preferred_batch_size: [2, 4, 8] 那在理想情况下 请求会被合并成 2,4,8 bs 进行推理但在某些时段由于请求数量少无法拼接为2,4,8 时就会有可能形成1,3,5,6,7 bs 长度的请求。所以在配置分档时要确保分档能覆盖所有bs。开启方式可通过config.pbtxt 或者 命令行参数生效如上例子模型有1个输入shape信息为image:[-1,3,224,224]则配置示例为parameters: [ { key: graph.ge.inputShape, value: {string_value: image:-1,3,224,224} } ] parameters: [ { key: graph.ge.dynamicDims, value: {string_value: 1;2;3;4;5;6;7;8} } ] parameters: [ { key: graph.ge.dynamicNodeType, value: {string_value: 1} } ]或者通过在命令行后添加参数进行使能--backend-confignpu_ge,graph.ge.inputShapeimage:-1,3,224,224 \ --backend-confignpu_ge,graph.ge.dynamicDims1;2;3;4;5;6;7;8 \ --backend-confignpu_ge,graph.ge.dynamicNodeType1若input为多个可参考 Ascend Graph构图接口 options参数说明 进行详细配置。注dynamicDims 数量过多会导致模型编译过程变长。1.2 尝试锁核在小batch场景下小模型每条流使用完整核会有较大的启动开销也就是通过控制使用较小核数量可以通过降低启动开销来进一步提高吞吐率。使能方法支持config.pbtxt以及命令行参数parameters: [ { key: ge.aicoreNum, value: {string_value: 12|10} } ]或--backend-confignpu_ge,ge.aicoreNum12|10其中 12|10 代表 每条流使用12个cube核10个vector核。不同产品型号昇腾AI处理器包含的最大AICore-CubeCore与AICore-VectorCore的数量可从${INSTALL_DIR}/arch-linux/data/platform_config/xxx.ini文件查看。具体值填写多少需根据模型本身整体运行占用CV核情况进行调整过大、过小均会影响吞吐可以通过调整后进行性能测试来逐步逼近最优值。详细说明可参考 Ascend Graph构图接口 options参数说明 进行详细配置。2. 动态图转静态图当推理场景不存在动态batch场景则可考虑使用静态图进行推理。(若bs始终为1可考虑使用小batch合并进行优化效果要比直接使用该章节吞吐率好)。onnx模型在编译完成后默认使用动态图模式此模式下因input中可能存在动态shape所以无法在编译阶段完全计算出每个节点所需显存资源需要根据真实的input进行动态计算计算显存大小过程在CPU侧所以很可能出现CPU侧导致的HostBound为了使性能达到最优如果我们的input可以改为静态shape则可以使其在编译阶段直接计算出每个节点所需显存资源执行过程可以下沉至NPU中此时执行过程中CPU不再参与运算从而达到NPU的利用率最大化。静态图GE支持分档场景以及全静态场景2.1 分档场景若input中非bs轴存在动态轴且具体shape为固定档位比如cnclip模型image shape[1,3,-1,1], 后两个轴取值只有 224,224 或 336,336 则可通过分档方式将执行图转为静态图。parameters: [ { key: graph.ge.inputShape, value: {string_value: image:1,3,-1,-1} } ] parameters: [ { key: graph.ge.dynamicDims, value: {string_value: 224,224;336,336} } ] parameters: [ { key: graph.ge.dynamicNodeType, value: {string_value: 1} } ]或者通过在命令行后添加参数进行使能--backend-confignpu_ge,graph.ge.inputShapeimage:1,3,-1,-1 \ --backend-confignpu_ge,graph.ge.dynamicDims224,224;336,336 \ --backend-confignpu_ge,graph.ge.dynamicNodeType1详细说明可参考 Ascend Graph构图接口 options参数说明 进行详细配置。2.2 全静态场景非动态分档场景指模型输入shape均为标量。 通过config添加配置parameters: { key: static_model value: {string_value: 1} }或通过启动参数配置--backend-confignpu_ge,static_model1即可使能静态图。具体使用哪种请自行选择。具体是否生效需要采集Profiling查看是否所有节点均为static。采集工具请参考 Profiling 工具使用3. 模型优化动态图转静态图Netron 查看是否有无需计算的节点转静态图后某些节点可能导致静态图回到动态图定位手段就是采集Profiling以CN_CLIP模型为例当用原始的model直接开启静态图模式后通过分析Profiling结果结合Netron是否整图可以下沉哪些节点可以删除。如上一节中的删除Mod节点目的是让全图下沉。在转静态图后某些模型可能存在大片节点变成了固定值但编译器无法自动优化需要我们去做分析一部分可以通过人工编辑onnx图也可以通过辅助工具来实现在实践过程中我们发现onnxsim可以将一些固定节点向下合并可以消除如Mod等输入都是固定的节点从而优化模型。CN_CLIP通过onnxsim工具的优化结果如下可以看出CN_CLIP经过优化后把Mod等固定的计算节点进行了优化比原始图少了好多节点。注MindStudio和Netron工具安装与使用方法见附录。3. 多流并行锁核当用户在 config中用户设置 instance_group.count 的值1 时无论动态图模式或者静态图模式采用多流并行方式执行。 建议 count值不要过大会影响单个推理稳定性造成p99变大。推荐不要超过8。 当采用动态图模式时CPU侧需要动态计算每一个节点输入的shape无法实现最大吞吐所以如果在动态图模式下通过调整count无法达到吞吐指标可以尝试转静态图后观察吞吐情况。目前GE图模式实现了锁核能力也就是可以限制某一个Stream只使用其中一部分Vector核一部分Cube核这样剩下的资源可以让其他Stream使用算子在启动core的过程中使用的core越多消耗越大而对于小模型特别是小shape场景用整个核其实存在资源浪费情况如果能合理切分让多条流同时使用CV核反而要比只让一个Stream使用效果要好。常用锁核参数C|V有“12|10”、“7|10”等这些参数都是经验值也可以根据实际模型测试找到最佳锁核值。本框架锁核功能可通过如下命令参数开启--backend-confignpu_ge,ge.aicoreNum12|10注芯片型号不同对应的CV核数也不一样。CV核数不能大于本芯片的CV核数具体芯片CV核数请参考 Ascend Graph构图接口 options参数说明。4. 自动融合自动融合在某些场景下会有性能收益使用方法也比较简单通过环境变量即可激活目前已包含在CANN版本中。正式环境变量使用样例功能控制export AUTOFUSE_FLAGS--enable_autofusetrue;--autofuse_disable_passreduce,concat,slice;--autofuse_enable_passtranspose;--autofuse_att_algorithmxxDFX控制export AUTOFUSE_DFX_FLAGS--att_accuracy_level1;--att_profilingtrue;--autofuse_enable_dump_orign_graphtrue具体如何使用请参考AutoFuse自动融合5. 尝试使用float16推理若使用onnx转om进行推理时默认atc会使用float16进行优化。当前框架为保证精度默认使用图原始精度(origin)进行推理若使用float16进行推理可显著提高推理性能使能float16后要系统性测试精度是否达标若精度满足要求则可保留。 使能方法支持config.pbtxt以及命令行参数parameters: [ { key: session.ge.exec.precision_mode_v2, value: {string_value: fp16} } ]或--backend-confignpu_ge,session.ge.exec.precision_mode_v2fp16详细说明可参考 Ascend Graph构图接口 options参数说明 进行详细配置。6. ENSEMBLE在执行模型推理的过程会出现预处理后的数据量大于原始数据量增加数据耗时甚至导致传输 Bound进而影响端到端吞吐率。 Triton Inference Server原生支持python backend和Ensemble能力这样可以将多个不同模型后端可以不同串联起来形成一条推理流水线。通过将模型的前后处理封装成python model可以降低传输数据量避免传输Bound情况的出现。其改造如下所示详细使用可参考下方优化案例。7. 融合PASS在所有优化手段都使用后如果性能仍不达标就需要具体分析耗时长算子、或者看哪些算子能融合这个代价就比较高需要打开具体的模型图分析哪些算子执行过程可以做融合通过编写融合算子以及融合Pass替换GE图中某些节点从而优化整网性能此类方法一般在性能要求比较高的模型中进行或者因当前NPU存在短板比如对int64支持不佳等场景下需要手工写新的算子进行全局替换进行优化。注相关文档可参考昇腾官方文档自定义pass开发.优化案例性能优化可参考 CN_CLIP模型优化示例【免费下载链接】triton-inference-server-ge-backendge-backend基于triton inference server框架实现对接NPU生态快速实现传统CV\NLP等模型的服务化。项目地址: https://gitcode.com/cann/triton-inference-server-ge-backend创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2599062.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!