昇腾学院 | Atlas性能调优之流程编排

举报
xiongoal 发表于 2020/03/25 01:49:07 2020/03/25
【摘要】 在上一篇《Atlas性能调优之瓶颈分析》中,主要阐述在性能出现瓶颈,业务无法增加时,通过哪些工具和方法,统计和观测性能数据,确定瓶颈点,从而方便进一步进行优化。 本文将详细描述使用Matrix框架的时候如何进行流程编排,搭建高性能应用。基本概念MatrixMatrix运行于操作系统之上,业务应用之下。屏蔽操作系统差异,为应用提供统一的标准化接口。Matrix具有多节点调度能力和多进程管理,...

在上一篇《Atlas性能调优之瓶颈分析》中,主要阐述在性能出现瓶颈,业务无法增加时,通过哪些工具和方法,统计和观测性能数据,确定瓶颈点,从而方便进一步进行优化。  

本文将详细描述使用Matrix框架的时候如何进行流程编排,搭建高性能应用。


基本概念

Matrix

Matrix运行于操作系统之上,业务应用之下。屏蔽操作系统差异,为应用提供统一的标准化接口。Matrix具有多节点调度能力和多进程管理,可以根据配置文件完成业务流程的建立和运行,以及相关的统计信息汇总等。

                                                                                                                                         ----《Matrix API 参考》

这里详细解释下,Matrix开发框架不仅仅是一套API,不是扔几个硬件的调用接口给你就完事了。它是一个开发框架,他抽象出Graph、Engine的概念,在支撑多种硬件形态的同时,帮助你完成了复杂的C++多线程调用和业务逻辑解耦。理解这套框架,有助于快速、高效的开发应用。

Graph & Engine

Matrix框架的Graph是由不同的Engine串联而成,开发者规划好各个Engine的业务逻辑,再将其串成一个Graph即可。

以下面官方Sample HelloDavinci 的Graph配置文件graph.config为例,里面定义了3个Engine,分别是SrcEngineHelloDavinciDstEngine。又定义了两个connects将这几个Engine串联起来,根据Connects的src_engine_id和target_engine_id,我们可以知道数据是从SrcEngineHelloDavinci,再到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工作方式

graph.png

调用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结构

单模型图片推理

spacer.gifjpegd_infer.PNG

以一个简单的单模型图片推理为例,SrcEngine读取图片数据,传送到Device侧的JpegdEngine,该Engine可设置线程数为3,这个Engine里面,调用Dvpp接口,完成对图片的解码,获取yuv数据,再调用vpc接口,对解码完的图片进行缩放抠图,获取模型要求输入大小的图片,传入InferEngine进行模型推理,这里注意,绝大部分模型都是使用rgb或者bgr进行训练的,因此,在模型转换的时候,设置好AIPP,自动将输入的yuv转成rgb,JpegdEngine出来的yuv数据就可以直接用于模型推理。推理完成后,将模型输出解析后传到Host的DstEngine

图像识别

我们来看一个复杂的案例,图像识别 FaceRecognition 的graph。

face.PNG

首先,Host侧起了12个StreamPullerEngine用于RTSP拉流,然后将获取到的数据推送到对应Device侧VdecEngine里面,我们上面讲过,每路视频拉流解码都用一个Engine来封装,让Matrix框架提你管理线程,能让你解码代码更简单,更易维护。

视频解码完成后,将数据分布发送给StreamDataOutputEngineFaceDetectionEngine

FaceDetectionEngine里面跑了一个yolov3-tiny模型,用于目标检测,将检测完成的数据再分发给对应路数的SORTEngine,该Engine用于图像跟踪,会计算检测到的图像的特征向量,和已有图像数据进行比对。如果是已知图像,数据直接发送给MergeEngine,未知的话,发给engine_id为555的DistributionEngine,该Engine会根据传入数据的batch大小(1,4,8)进行分发,发送给FaceLandmarkEngine

FaceLandmarkEngine对获取到的图像图片进行分析,计算特征点后进行图像校正,校正后的数据再由DistributionEngine进行分发给FaceFeatureEngine,计算512维的特征值。计算完成后,根据视频id,发给对应的MergeEngineMergeEngine完成原始解码数据和推理数据的同步后,发送给StreamDataOutputEngine

StreamDataOutputEngine使用opencv,在原图上将计算出的图像框画上,12路视频最终会整合成一个1080p的视频,再推流给RTSP服务器。




本文简单介绍了下Matrix框架Graph的概念和Engine的合并拆分思路,大家在构建自己的应用时,一定要灵活应用。



【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。