前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >NVIDIA Deepstream 笔记(二):如何设计视频分析的框架?

NVIDIA Deepstream 笔记(二):如何设计视频分析的框架?

作者头像
GPUS Lady
发布2019-07-04 15:44:55
6.3K1
发布2019-07-04 15:44:55
举报
文章被收录于专栏:GPUS开发者GPUS开发者

你已经非常清楚什么是Deepstream,它为什么存在以及3.0中的一些新功能和增强功能。我们现在要退后一步,深入了解是什么驱动Deepstream.

这是第二部分

Deepstream是一个建立在GStreamer之上的SDK,GStreamer是一个开源的多媒体分析框架,由几个核心组件组成。最基本层次的是一种叫plugins的概念,作为基于GStreamer的应用的底层。 右上方的图中,你会看到有很多种不同的plugins,每个plugin做它自己特定的事情。例如说,第一个plugin从数据源接受数据,并解码原始数据帧中的像素, 当第一个plugin解码完毕后,数据发送给第二个plugin,第二个plugin可能做例如图像缩放处理,然后再将数据发送给再下一个plugin。 这种最基本的plugin,则是基于GStreamer的应用的基本功能块。再更高的第二个层次上,则存在一种叫bin(功能箱)的东西,在GStreamer和DeepStream里,功能箱里面容纳了一系列刚才说的功能块。 这许多功能块一共工作,完成某种具体的功能,就构成了我们说的功能箱(Bin)。最上层的第三个层次,则实际上是一种总线,一种为基于GStreamer/DeepStream的应用管理数据流动和同步的总线。

因此GStreamer为应用程序和管道之间的通信和数据交换提供了几种机制,因此其中一个本质上是缓冲区,缓冲区在插件之间传递流数据.在管道中,缓冲区将数据从视频文件传递到解码器,到缩放插件,到过滤器插件,然后最终到显示插件。Event可以用于在GStream框架中的多个plugins之间传递信息,也可以用来将你的应用程序的信息,传递给某个plugin。除了对一些用途创建events外,你还可以创建Messages(消息)。通过消息将信息发布到消息总线上的方式,可让你的应用收集到他们。你还可以创建Queries(查询),查询允许你手动地去查询请求信息,而不是刚才那样直接将信息发送给你的应用程序来收集。

初步了解了GStreamer后,我们来看一下deepstream的底层组件,所以在Deepstream里,主要构建块是插件,因为它建立在GStreamer框架上,它提供了一个基于插件的模型。创建了一个基于图形的管道,将这些插件组合到您的应用程序中,通过将这些插件互连在一起,您可以从深度优化的应用程序性能中受益。它允许您利用GPU和CPU上的异构处理,这意味着当您使用提供GPU加速的插件时,如右侧示例所示,该插件将可以访问低层Nvidia优化库, 专为GPU处理而构建,数据可以像管道中一样传递。现在它的作用是隐藏并行化和同步,它不会让你操心它如何做, 对于您来说,您可以专注于构建自定义用例组件,这也意味着它本身就是多线程的,因此通过启用这种多线程方面的异构化, 通过构建管道架构的插件来处理您创建的应用程序,将针对NVIDIA GPU进行优化,还可以在CPU上有效运行。

为什么它能有效运行?这是智能视频分析应用程序中一个非常重要的方面,因为对于许多应用程序,您将需要以实际或接近实时的延迟运行,或者您可能需要提供服务级别协议针对特定结果提供某些延迟,因此有效管理内存至关重要。Deepstream提供了一个您不需要担心的优化数据交流的情况,它在这张幻灯片上展示了DeepStream是如何做的。

处理流水线的最开始,是NVDec解码组件。无论当数据从视频文件中传输过来的时候,还是通过网络摄像头编码协议,NVDec接受到的都是H264编码后的码流数据。NVDec硬件解码器,通过使用cudaMalloc()函数,在显存中分配了多个输出缓冲区,一旦我们在GPU显存中有了多个输出缓冲区后,NVDec硬件解码器就逐帧的解码,解码一帧,就将一帧的数据放入到一个输出缓冲区中。 然后DeepStreamer处理流水线中的下游处理组件,就可以直接共享使用这包含有解码数据的缓冲区了。例如说下游的nvinfer组件,可以用这解码后的数据进行推理;nvtracker组件,则可以用数据进行跟踪,或者你也可以用其他的推理组件。但不管你用什么下游组件,数据被没有并传输复制一遍,只是通过之前说过的GStreamer缓冲区的指针进行共享的。这样直到整个处理流水线上的,最后一道工序上的组件消费完毕该缓冲区中的数据后,缓冲区被标记为空白,重新归还给流水线上的第一步的缓冲区池(pool)中,这样第一步可以继续在解码一帧后,重新使用该缓冲区。所以并没有实际的数据在流水线的多个工序间制,只是DeepSteamer应用在传递指针罢了。

这样,最后构成了一种情形:在一个GPU Context中,并没有进行缓冲区的复制。 以及,如果你要实现一个第三方的,非NV提供的plugin,只要你写代码的时候,遵循DeepStream的这种准则Guideline),那么就是极好的:用上了你的plugin,也会自动用上这种无缓冲区复制的, DeepStream缓冲区管理流程。

如果某个功能块,需要你在CPU context上访问数据,则需要进行一次性的数据传输。 我们必须通过cudaMemcpy()函数完成这个操作。这个图的最后因此和之前我们看过的图稍微有点不同。在本图案例中,完成了nvinfer功能块后,还有一个用来进行某种视频转换的nvvidconv功能块,该功能块里面需要进行一次Device->Host的传输。在完成了一次性的传输后,这个功能块后面,还有一个CPU上的xvimagesink功能块。即使都在CPU上,我们此时依然享有在CPU上传输缓冲区指针的无实际复制的优化,这点和我们在GPU上共享缓冲区时候的机制是一样的。这样只需要最多有一次传输,则无论在CPU和GPU上的多个组件间,均会有数据了。这种数据指针分别在CPU和GPU都有会,即可消除掉(abstract)手工在你的应用程序中,管理存储器的需要了。直接让DeepStream SDK为你做事即可,免除了大量的复制,使得你能在你的智能视频分析应用中,得到实时的处理性能。也就是说,NV将GStreamer修改了,增加了一些NV写好的GPU版本功能块, 同时如果你还需要调用原本的GStreamer的固有的那些CPU上的功能块,NV保证你最多只需要1次传输即可。 等传输到CPU上后,CPU上的多个功能块之间也享受类似在GPU上的时候,那样的优化。

除了刚才讲过的存储管理外,我在看一下DeepStream里的metadata数据结构。

DeepStreamer提供了一种标准化的可扩展的元数据结构,使得在需要的时候,例如你有更多的类别或者其他描述性信息需要的时候,能够方便的扩展它。 DeepStream元数据结构,包括了每帧图像的信息,还包括了部分和本帧相关的检测到的对象的信息。是该结构的最下面,你会看到有一个stream id(不是CUDA的,这里是GStreamer或者说DeepStream的),这有利于在存在多个stream的时候,能狗确定所该元信息结构,和哪个具体的流所关联。 然后这里面的num_rects字段,则是如果我们在做目标检测的时候,能够告诉我们所想知道的,跟踪到的方框的数量,也就是检测到的目标的数量,有对应数量的元数据指针。还有一个叫gie_unique_id的资源,这代表了当你的应用程序里面有多个网络的时候,本元数据结构所关联到的其中之一的某个神经网络的唯一ID。 这样当你需要做不同的事情的时候,从这些不同网络生成的不同元数据结构体的实例,可以被有效的识别开。

在本结构体图的最上方,还有一个叫NvDsObjectParams的字段。对于每个检测到的对象,有如下基本的参数。例如说BBox(就是环绕物体的方框)坐标、标签/类别信息。这些信息在显示识别的目标的时候可能是必须的,例如你在做一个车辆检测,需要有车辆的类型、车辆的颜色类似这些,你也可以定义其他的信息。以及,tracking_id,这是从物体跟踪代码里面得来的唯一的对象标识信息,以及class_id, 则是根据神经网络自己的检测结果所得到的(assigned)类别识别信息。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-06-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 GPUS开发者 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档