昇腾学院 | Atlas性能调优之流程编排
在上一篇《Atlas性能调优之瓶颈分析》中,主要阐述在性能出现瓶颈,业务无法增加时,通过哪些工具和方法,统计和观测性能数据,确定瓶颈点,从而方便进一步进行优化。
本文将详细描述使用Matrix框架的时候如何进行流程编排,搭建高性能应用。
基本概念
Matrix
Matrix运行于操作系统之上,业务应用之下。屏蔽操作系统差异,为应用提供统一的标准化接口。Matrix具有多节点调度能力和多进程管理,可以根据配置文件完成业务流程的建立和运行,以及相关的统计信息汇总等。
----《Matrix API 参考》
这里详细解释下,Matrix开发框架不仅仅是一套API,不是扔几个硬件的调用接口给你就完事了。它是一个开发框架,他抽象出Graph、Engine的概念,在支撑多种硬件形态的同时,帮助你完成了复杂的C++多线程调用和业务逻辑解耦。理解这套框架,有助于快速、高效的开发应用。
Matrix框架的Graph是由不同的Engine串联而成,开发者规划好各个Engine的业务逻辑,再将其串成一个Graph即可。
以下面官方Sample HelloDavinci 的Graph配置文件graph.config
为例,里面定义了3个Engine,分别是SrcEngine
、HelloDavinci
和DstEngine
。又定义了两个connects将这几个Engine串联起来,根据Connects的src_engine_id和target_engine_id,我们可以知道数据是从SrcEngine
到HelloDavinci
,再到DstEngine
。
graphs {
graph_id: 100
priority: 0
engines {
id: 100
engine_name: "SrcEngine"
side: HOST
thread_num: 1
ai_config {
}
}
engines {
id: 200
engine_name: "HelloDavinci"
side: DEVICE
thread_num: 1
so_name: "./libDevice.so"
}
engines {
id: 300
engine_name: "DstEngine"
side: HOST
thread_num: 1
}
connects {
src_engine_id: 100
src_port_id: 0
target_engine_id: 200
target_port_id: 0
}
connects {
src_engine_id: 200
src_port_id: 0
target_engine_id: 300
target_port_id: 0
}
}
调优参数
我们来看下$DDK_HOME/include/inc/proto
文件夹中的graph_config.proto
结构定义文件,可以看到
Graph的可配置项:
graph_id,graph的id,注意不能重复
device_id,graph运行的处理器id
Engine主要可以调优配置的有4个:
side,可设置为HOST或者DEVICE,用于区分该engine的业务运行位置
queue_size,队列长度,默认值200,上一个Engine发送过来的数据,都会存储在这个队列中
thread_num,线程数,默认值1
thread_priority,线程优先级,数字越大该Engine越容易被被调度到
Host与Device
Host侧指的就是服务器侧,Device指的就是昇腾310处理器,每个处理器作为一个PCIE设备挂接在主机上 。
Host与Device数据传输通过HDC驱动进行传输,硬件通道为PCIe通道。
对于小于256k的数据,推荐使用普通接口。
对于大于256k的数据,推荐使用高速传输接口。
Graph工作方式
调用HiAI_Init对处理器初始化后,创建Graph,调用CreateGraph接口,Matrix框架会调用各个Engine的Init函数,这里可以读取配置文件参数、加载模型,从而创建Graph。
调用graph->SendData方法,将数据发送给第一个Engine,业务流开始处理数据。
每个Engine都有一个队列,上个一个Engine发送过来的数据,都会存储在这个队列中,根据设置的Engine线程数,Matrix框架会创建相应的线程,取这个队列中的数据,调用 HIAI_IMPL_ENGINE_PROCESS
函数。
程序需要关闭时,可调用DestroyGraph方法来释放资源。
推荐配置
Graph、处理器、进程
Atlas 200、Atlas 500上面各有一颗昇腾310处理器,Atlas 300上面有4颗。
我们推荐一个处理器对应一个graph,因为模型需要占用大量device侧内存空间,如果单处理器创建多个相同graph,同一个模型会创建多份,占用大量内存。
一个进程可以创建多个graph,可以设置graph的device_id,分别跑在不同的处理器上,但是建议单进程不要跑过多的graph,可能会导致Host-Device通信能力受影响。
Engine的合并与拆分
对于Graph而言,最简单的结构就是Device侧只跑一个Engine,但这样并不能很好利用我们的硬件。
我们从硬件结构开始分析,昇腾310处理器主要包含4个Ctrl Cpu、4个AI Cpu、2个AI Core和1个Dvpp硬解码编码模块,其中Dvpp里面还包含了vdec、jpegd、vpc等不同的硬件编解码模块。
所以说,如果Device只跑一个Engine的话,想提高性能,我们可能需要创建多个线程来对各种硬件资源调度,以求达到最大利用率,这样的开发起来过于复杂、不易解耦。
最好的办法就是根据硬件模块来对Engine进行拆分:
Dvpp编解码
Jpeg图片解码,需要调用jpegd硬件解码模块,可单独成一个Engine,线程数设置为3(经过测试,线程数大于等于3时性能最佳)。
h264、h265视频解码,需要调用vdec硬件解码模块,昇腾310处理器有16路1080p解码能力。由于视频帧相互依赖,如果在一个Engine内,设置成多线程,代码处理起来比较麻烦。建议每路视频解码分成一个VdecEngine,线程数设置为1,这样每个VdecEngine只需要处理自己这路视频的数据即可。
vpc抠图缩放,一般来说,抠图缩放不怎么耗费性能,作为模型推理的预处理,可以放在图片、视频解码Engine里面,若业务比较复杂,比如要一抠多,送到不同模型推理Engine,可抽成单独一个Engine,设置为多线程。
模型推理
这里主要调用AI Cpu和AI Core,建议一个模型一个Engine,这样能并行使用AICore的推理能力。当然,如果几个模型相似,输入相同,也可以多模型共引擎。
调整Engine的thread_priority值可使该Engine得到优先调度。
预处理和后处理
除使用Dvpp接口外,主要使用Ctrl Cpu的资源,建议刚开始开发时,可以和模型推理用同一个Engine,在调优的过程中,对耗时进行统计,如果耗时不长,可不调整,反之,可以考虑拆成先单独Engine,再调整线程数、提高线程优先级、移动至Host侧、代码优化等多种手段。
推荐的graph结构
单模型图片推理
以一个简单的单模型图片推理为例,SrcEngine
读取图片数据,传送到Device侧的JpegdEngine
,该Engine可设置线程数为3,这个Engine里面,调用Dvpp接口,完成对图片的解码,获取yuv数据,再调用vpc接口,对解码完的图片进行缩放抠图,获取模型要求输入大小的图片,传入InferEngine
进行模型推理,这里注意,绝大部分模型都是使用rgb或者bgr进行训练的,因此,在模型转换的时候,设置好AIPP,自动将输入的yuv转成rgb,JpegdEngine
出来的yuv数据就可以直接用于模型推理。推理完成后,将模型输出解析后传到Host的DstEngine
。
图像识别
我们来看一个复杂的案例,图像识别 FaceRecognition 的graph。
首先,Host侧起了12个StreamPullerEngine
用于RTSP拉流,然后将获取到的数据推送到对应Device侧VdecEngine
里面,我们上面讲过,每路视频拉流解码都用一个Engine来封装,让Matrix框架提你管理线程,能让你解码代码更简单,更易维护。
视频解码完成后,将数据分布发送给StreamDataOutputEngine
和FaceDetectionEngine
。
FaceDetectionEngine
里面跑了一个yolov3-tiny
模型,用于目标检测,将检测完成的数据再分发给对应路数的SORTEngine
,该Engine用于图像跟踪,会计算检测到的图像的特征向量,和已有图像数据进行比对。如果是已知图像,数据直接发送给MergeEngine
,未知的话,发给engine_id为555的DistributionEngine
,该Engine会根据传入数据的batch大小(1,4,8)进行分发,发送给FaceLandmarkEngine
。
FaceLandmarkEngine
对获取到的图像图片进行分析,计算特征点后进行图像校正,校正后的数据再由DistributionEngine
进行分发给FaceFeatureEngine
,计算512维的特征值。计算完成后,根据视频id,发给对应的MergeEngine
。MergeEngine
完成原始解码数据和推理数据的同步后,发送给StreamDataOutputEngine
。
StreamDataOutputEngine
使用opencv,在原图上将计算出的图像框画上,12路视频最终会整合成一个1080p的视频,再推流给RTSP服务器。
本文简单介绍了下Matrix框架Graph的概念和Engine的合并拆分思路,大家在构建自己的应用时,一定要灵活应用。
- 点赞
- 收藏
- 关注作者
评论(0)