本文作者:赛灵思开发者 陆禹帆
前言
如果KV260是你的第一个FPGA的AI加速平台,那么在上手KV260的开发的时候,你可能会遇到很多的困难。尤其是当你尝试阅读Jupyter中的sample代码时,你会发现很多代码都像黑魔法一样都难以理解。
或许你能发现一些关于Gstreamer和VVAS的相关蛛丝马迹,但是Gst是什么,VVAS又是什么,或许到这里你依旧会感到无从下手。
本文主要给大家分享一下对于整个KV260加速应用的软件结构的理解,希望能够帮助到大家。
Gst是什么?
关于Gstreamer的定义,WIKI上是这么说的:
Gstreamer是一个多媒体框架,它可以允许你轻易地创建、编辑与播放多媒体文件,这是通过创建带有很多特殊的多媒体元素的管道来完成的。
这句话颇有听君一席话如听一席话的味道,事实上,我在第一次看完之后反而觉得更晕了,这里我尝试通俗易懂的来解释下到底什么是Gstreamer的命令行。
首先,Gstreamer命令行就是可以通过command line来执行的程序或者叫命令。这些Gst命令可以被当时shell命令在脚本或者终端中被执行,也可以在程序中被当作子程序被调用(KV260的方式)。
这里我们用一个典型的gst命令行作为例子:
gst-launch-1.0 videotestsrc ! videoconvert ! autovideosink
可以看到,这个命令行以gst-launch-1.0开头,后面加上一些感叹号和字符串。这后面的这一串字符串其实就是Gstreamer的管道命令。初看之下,感觉这个命令非常奇怪,但是仔细分析一下你就会发现这些管道命令的格式其实就是 !!…。这里每一个其实就是一个“执行程序”,当gst运行的时候,这些“程序”从前一个程序的接口拿到数据做一些处理,然后传递给后一个数据再做一些处理。在构建gst程序的时候,我们选择多个“程序”,让他们首尾相连,通过“!”隔开,就可以实现复杂的功能了。只需要选择合适的“程序”,组成我们的命令行,gst程序就能完成我们想要的功能。这里面的每一个“执行程序”在Gstreamer中被称为 “元素”(Elements)或者插件,所有“元素”组成的东西被称为管道。
如果你对管道还是不理解的话,其实在linux有一个非常常用的命令:“命令1 | 命令2 |grep 关键字” 。
其中,“|”就是linux管道的意思,grep表示从前一个命令的输出文本中找特定的字符串,对于搜索结果非常有用。如果你能够理解Linux的管道,我相信你也可以很轻松的理解Gstreamer的管道。
这里多提一句,既然这个叫做管道,这些元素其实是具有流水线的性质的,也就是说,当前一帧的图像被送入下一帧之后,当前元素就会开始执行下一帧的元素,因此Gstreamer很适合用来处理实时视频流。
现在让回到我们的例子。在这条Gst管道命令中,
第一个“元素”叫videotestsrc,表示这个一个测试视频源元素,他会生成一个测试视频给后面的“元素”或者叫“插件”来进行下一步的处理。(在实际使用中,我们可能会使用读文件的元素或者是读摄像头的元素)。
第二个“元素”叫videoconvert,这个是一个格式转换的元素,他能够执行RAW视频格式的转换,来让后面的插件能够读取和处理。
第三个“元素”叫autovideosink,这是一个渲染用的元素,主要用来在创建一个窗口播放视频。
此时,我们把三个元素组合起来,管道就变成了一个显示测试视频的程序了。以上就是一个Gstreamer的基本命令行的样例,看起来很像黑魔法(这是Gstreamer官网的比喻),但是其实所有的Gstreamer都是基于这个简单的结构而来的,要实现更多更复杂的功能,我们其实就是加上了更多的“元素”而已。(关于Gst的核心开发还是非常复杂的,这里我们主要就简单的介绍一下)。
在KV260上,AI视频实时处理的应用也是基于这样一个结构实现而来。只不过我们加上了一些能够处理AI的“元素”罢了。如果你仔细观察我们在Jupyter中看到的代码,你就会发现,我们的应用使用的管道和我们上面例子并没有本质上的变化。
另一方面,既然所以的程序已经被抽象成了“元素”,在Jupyter中看不到任何的底层数据的处理也就变得可以理解了。因为所有的“底层逻辑”都已经被包装到“元素”当中了。
从Gst到VVAS
相信到这里,你已经对什么gst什么有了一定的了解。那么我们的重点就是如何使用和构造我们的利用 DPU加速“元素”了。
很显然,Gstreamer作为一个独立的框架不太可能有直接支持DPU的元素,理论上如果我们想要在gstreamer中使用DPU,那么我们需要自己来构造我们自己的元素。
但是,由于Gstreamer的元素插件开发难度特别高,如果我们为每一个AI应用都开发适配一套元素,我们的开发工程量和难度都会直接上天。因此,Xilinx其实为我们提供了一套转接方案也就是Vitis Video Analytics SDK (VVAS)。
VVAS 官方网站:https://xilinx.github.io/VVAS/main/build/html/index.html
VVAS是什么?
抛开官网的marketing用语,用通俗的话来说,VVAS其实就是几个Xilinx做好的GST插件,在这些插件的内部,程序在执行初始化,数据处理等阶段会去调用一个外部的lib.so 库中的固定的接口函数,来执行对应的功能。(类似hook函数)。
由于so文件是可以通过配置文件改变的,我们在开发时候,只需要根据API来实现我们自己的lib文件,就能够在不改变元素的情况下实现不同的功能。(关于逻辑层代码的具体修改,我们今天先略过)。
正因为如此,在KV260中,配置文件就显得非常重要,无论是lib内部的函数初始化,还是插件本身的初始化,都需要依靠配置文件来完成。如果你仔细研究过jupyter中的代码,你就会发现,我们在载入 ivas相关插件的时候,指定了json文件作为我们元素的参数。
其实这就是我们的配置文件,这个配置文件决定了我们使用什么样的函数,采用什么样的初始化方案。(smartcam应用的配置文件被存放在 /opt/xilinx/share/ivas/smartcam 路径下面)。
这里我们打开
/opt/xilinx/share/ivas/smartcam/refinedet/aiinference.json,作为一个例子:
可以看到,我们使用的是一个名叫libivas_xdpuinfer.so的库文件,并且我们可以指定使用的模型名称,和模型类型。而我们具体的AI处理的代码其实就被封装在了这个库文件里面。具体参数的说明可以参考官方文档。
由于libivas_xdpuinfer.so是官方帮我实现了,因此我们可以直接使用这个库文件,不需要自己开发,比如我们要修改我们使用的模型,我们只需要修改对应的参数就可以。当然,如果有需要实现一些Xilinx的库文件中没有支持的函数,包括一些高级功能,我们其实还是需要自己来修改库函数的。
关于修改KV260的模型的具体操作细节,大家可以参考我的视频《KV260上部署YOLO - VVAS的模型部署通用指南》:
https://www.bilibili.com/video/BV1YP4y1G7Bn/
总结
本文主要给大家介绍了一下KV260上的AI应用的基本架构,其实无论是二进制版本还是python版本的样例代码,都是基于这样一个框架来实现的,希望能够帮助到大家。关于VVAS的库文件修改,开发,编译的细节,有机会我再给大家详细介绍。