NVIDIA Deepstream SDK是一个通用的Steaming分析框架,可以让你从各个传感器中构建你自己的应用。它实际上是一个建立在GStreamer之上的SDK,GStreamer是一个开源的多媒体分析框架。NVIDIA将Deepstream作为SDK,旨在加速流视频分析所需的完整堆栈。它是一个模块化的SDK,允许开发人员为智能视频分析(IVA)构建一个高效的管道。您在这里看到的是一个典型的IVA管道,由Deepstream插件构建,它支持插件使用的底层硬件、管道的每个功能,并利用硬件体系结构移动数据,而无需任何内存拷贝。
DeepStream 以 GStreamer 插件的形式提供构建块,可用于构建高效的视频分析管道。有超过 20 个插件为各种任务进行了硬件加速。
- 流数据可以通过 RTSP 通过网络或来自本地文件系统或直接来自摄像机。使用 CPU 捕获流。一旦帧进入内存,它们就会被发送到使用 NVDEC 加速器进行解码。用于解码的插件称为Gst-nvvideo4linux2。
- 解码后,有一个可选的图像预处理步骤,可以在推理之前对输入图像进行预处理。预处理可以是图像去扭曲或色彩空间转换。Gst-nvdewarper插件可以对鱼眼或 360 度相机的图像进行反扭曲。gst-nvvideoconvert插件可以对帧进行颜色格式转换。这些插件使用 GPU 或 VIC(视觉图像合成器)。
- 下一步是批处理帧以获得最佳推理性能。批处理是使用Gst-nvstreammux插件完成的。
- 对帧进行批处理后,将其发送以进行推理。推理可以使用 NVIDIA 的推理加速器运行时 TensorRT 完成,也可以使用 Triton 推理服务器在 TensorFlow 或PyTorch等本机框架中完成。本机 TensorRT 推理是使用Gst-nvinfer插件执行的,使用 Triton 的推理是使用Gst-nvinferserver插件完成的。推理可以为 Jetson AGX Xavier 和 Xavier NX 使用 GPU 或 DLA(深度学习加速器)。
- 在推理之后,下一步可能涉及跟踪对象。SDK 中有几个内置的参考跟踪器,从高性能到高精度。使用Gst-nvtracker插件执行对象跟踪。
- 为了创建可视化工件,例如边界框、分割掩码、标签,有一个名为Gst-nvdsosd的可视化插件。
- 最后,为了输出结果,DeepStream 提供了各种选项:使用屏幕上的边界框渲染输出、将输出保存到本地磁盘、通过 RTSP 流式传输或仅将元数据发送到云端。为了将元数据发送到云端,DeepStream 使用Gst-nvmsgconv和Gst-nvmsgbroker插件。Gst-nvmsgconv将元数据转换为模式有效负载,Gst-nvmsgbroker建立与云的连接并发送遥测数据。有几种内置的代理协议,例如 Kafka、MQTT、AMQP 和 Azure IoT。可以创建自定义代理适配器。
deepstream部署的方式与openvino差不多,它也提供了镜像,但需要前置条件,需要安装nvidia-docker,安装参考:docker学习笔记(9):nvidia-docker安装、部署与使用 下面从宿主机与docker两种方式介绍:
输入以下命令以安装必备软件包:
$ sudo apt install \
libssl1.1 \
libgstreamer1.0-0 \
gstreamer1.0-tools \
gstreamer1.0-plugins-good \
gstreamer1.0-plugins-bad \
gstreamer1.0-plugins-ugly \
gstreamer1.0-libav \
libgstrtspserver-1.0-0 \
libjansson4 \
libyaml-cpp-dev
然后安装 librdkafka(为消息代理启用 Kafka 协议适配器,不知道是否是可选参数,但应该没有额外标示,还是需要安装的):
"""1. 从 GitHub克隆librdkafka存储库:"""
$ git clone https://github.com/edenhill/librdkafka.git
"""2. 配置和构建库:"""
$ cd librdkafka
# $ git reset --hard 7101c2310341ab3f4675fc565f64f0967e135a6a # 可选可不选,我安装并没有进行回退,没有啥问题,而且kafka主要存在deepstream-test5的例程
./configure
$ make
$ sudo make install
"""将生成的库复制到deepstream目录:"""
$ sudo mkdir -p /opt/nvidia/deepstream/deepstream-6.1/lib
$ sudo cp /usr/local/lib/librdkafka* /opt/nvidia/deepstream/deepstream-6.1/lib
安装完必要依赖后,可以直接从官网中下载Deepstream SDK包:https://developer.nvidia.com/deepstream-getting-started
方便定义过程说明阿亮完全不同过程定义的部分结果说明,当前是
$ sudo tar -xvf deepstream_sdk_v6.1.0_jetson.tbz2 -C /
$ cd /opt/nvidia/deepstream/deepstream-6.1
$ sudo ./install.sh
$ sudo ldconfig
这里如果装了nvidia-docker的话,直接一句命令就能省略上述所有步骤,直接从nvidia仓库中拉取相关版本的镜像,如下表:
Container |
Container 拉取命令 |
---|---|
base docker (仅包含运行时库和GStreamer插件。可以用作为DeepStream应用程序构建自定义Docker的基础) |
|
devel docker (包含整个SDK以及用于构建DeepStream应用程序和graph composer的开发环境) |
|
Triton推理服务器docker与Triton推理服务器和依赖项一起安装,以及用于构建DeepStream应用程序的开发环境 |
|
安装了DeepStream-test5-app并删除了所有其他参考应用程序的DeepStream IoT docker |
|
DeepStream samples docker (包含运行时库、GStreamer插件、参考应用程序和样本流、模型和配置) |
|
如果还需要其它非6.1版本,可以在nvidia仓库中寻找,地址为:https://catalog.ngc.nvidia.com/orgs/nvidia/containers/deepstream/tags
关于启动命令与nvidia普通镜像一样,可以看链接说明,这里就不再叙述。以上环境皆为Cpp环境,也是python需要的前置环境,这里可以直接使用源码进行测试。
deepstream-sdk中一般就自带c语言的deepstream-app全部测试源码,所以不需要另外安装,另外,这里如果想验证前面环境是否安装正确,可以输入如下命令进行查看,deepstream-app命令一般sdk的安装过程中已经将预编译过的可执行文件映射到了bin目录,所以可以全局使用:
$ deepstream-app --version-all
如果没有问题的话,会输出相关依赖的版本:
deepstream-app version 6.1.0
DeepStreamSDK 6.1.0
CUDA Driver Version: 11.6
CUDA Runtime Version: 11.6
TensorRT Version: 8.2
cuDNN Version: 8.4
libNVWarp360 Version: 2.0.1d3
这里如果跟我一样选择的是deepstream镜像,进入容器后,初始目录为/opt/nvidia/deepstream/deepstream-6.1
,当前目录除了脚本与一些说明文档外,有四个文件夹,分别为bin(预编译的可执行文件目录)
,lib(依赖地址)
,samples(配置文件与测试资源(视频)等地址)
,sources(deepstream sdk开源的源码所在目录)
,所以进入sources目录。
这里的文件夹叙述部分参考英伟达DeepStream学习笔记2——deepstream_sdk文件夹解析:
sources目录结构为:
|-- SONYCAudioClassifier(TTS/ASR 索尼模型?没太关注过)
|-- apps(deepstream-app的测试代码)
|-- gst-plugins(gstreamer插件部分源码)
|-- includes(各种头文件)
|-- libs(依赖库)
|-- objectDetector_FasterRCNN(faster rcnn目标检测器)
|-- objectDetector_SSD(SSD目标检测器)
|-- objectDetector_Yolo(yolo目标检测器)
|-- tools(日志工具)
`-- tracker_DeepSORT(tracker跟踪代码)
这里面tracker_DeepSORT
、SONYCAudioClassifier
是deepstream 6.1新加入的适配源码包,虽然目前我还没用上,所以这里只提一下。deepstream主要的源码都在apps/sample_apps
中,目录结构为:
sample_apps
├── deepstream-app
├ 端到端示例演示了4级联神经网络(1个一级检测器和3个二级分类器)的多相机流,并显示平铺输出。
├── deepstream-dewarper-test
├ 演示单个或多个360度摄像机流的扭曲功能。从CSV文件读取相机校准参数,
├ 并在显示屏上渲染过道和斑点表面。
├── deepstream-gst-metadata-test
├ 演示如何在DeepStream管道中的Gst-nvstreammux插件之前设置元数据,
├ 以及如何在Gst-nvstreammux之后访问元数据。
├── deepstream-image-decode-test
├ 建立在deepstream-test3上,以演示图像解码而不是视频。本示例使用自定义解码箱,
├ 因此可以将MJPEG编解码器用作输入。
├── deepstream-infer-tensor-meta-test
├ 演示如何将nvinfer张量输出作为元数据传递和访问。
├── deepstream-nvof-test
├ 演示单个或多个流的光流功能。本示例使用两个GStreamer插件(Gst-nvof和Gst-nvofvisual)。
├ Gst-nvof元素生成MV(运动矢量)数据并将其作为用户元数据附加。Gst-nvofvisual元素使用
├ 预定义的色轮矩阵可视化MV数据。
├── deepstream-perf-demo
├ 对目录中的所有流顺序执行单通道级联推理和对象跟踪。
├── deepstream-segmentation-test
├ 演示使用语义或工业神经网络对多流视频或图像进行分割,并将输出呈现到显示器。
├── deepstream-test1
├ 有关如何对单个H.264流使用DeepStream元素的简单示例:filesrc→decode解码→nvstreammux→nvinfer
├ (主检测器)→nvosd→renderer渲染器。
├── deepstream-test2
├ 简单的应用程序,建立在test1之上,显示额外的属性,如跟踪和二级分类属性。
├── deepstream-test3
├ 基于deepstream-test1(简单测试应用程序1)构建,以演示如何:
├ •在管道中使用多个来源
├ •使用uridecodebin接受任何类型的输入(例如RTSP /文件),任何GStreamer支持的容器格式以及任何编解码器
├ •配置Gst-nvstreammux生成一批帧并推断出这些帧以提高资源利用率
├ •提取流元数据,其中包含有关批处理缓冲区中的帧的有用信息
├── deepstream-test4
├ 基于deepstream-test1 构建单个H.264流:filesrc,decode,nvstreammux,nvinfer,nvosd, renderer演示如何:
├ •在管道中使用Gst-nvmsgconv和Gst-nvmsgbroker插件
├ •创建NVDS_META_EVENT_MSG类型的元数据并将其附加到缓冲区
├ •将 NVDS_META_EVENT_MSG用于不同类型的对象,例如车辆和人
├ •实现元数据通过extMsg字段扩展的“复制”和“免费”功能
├── deepstream-test5
├ 建立在deepstream-app之上。展示:
├ •在管道中将Gst-nvmsgconv和Gst-nvmsgbroker插件用于多流
├ •如何从配置文件中将Gst-nvmsgbroker插件配置为接收器插件(适用于KAFKA,Azure等)
├ •如何处理来自RTSP服务器或摄像机的RTCP发送者报告,以及如何将Gst Buffer PTS转换为UTC时间戳。
├ 欲了解更多详情,请参阅该RTCP发送者报告回调函数test5_rtcp_sender_report_callback注册和使用的 deepstream_test5_app_main.c。
├ 使用rtpmanager元素的“ handle-sync”信号进行GStreamer回调注册的过程记录在apps-common /src / deepstream_source_bin.c中。
├──deepstream-user-metadata-test
├ 演示如何向DeepStream的任何组件中添加自定义或用户特定的元数据。测试代码将一个填充有用户
├ 数据的16字节数组附加到所选组件。数据在另一个组件中检索。
这里更详细的说明可以参考官方对此目录文件的介绍:C/C++ Sample Apps Source Details . 我们进入deepstream-test1文件夹,这里需要区分一个东西,我因为是docker启动,本身宿主机使用的是服务器,是没有桌面的,所以也没有x11,docker也挂载不进来,这里要将"nveglglessink"
改为fakesink
,原因是nveglglessink
插件会将结果显示在显示器上,如果不希望结果显示,可以使用fakesink
插件。(PS:这个问题刚开始我不知道,还在想为什么程序能跑,但就是跑几帧就断,然后去nvidia官网提了两个issue。。。只能说,文档没看仔细),改动为:
如果有桌面或者不用修改的,可以直接修改Makefile,加入当前cuda版本号进行重新编译:
make没有问题后,可以选择sdk中samples下面的h264文件测试:
./deepstream-test1-app /opt/nvidia/deepstream/deepstream-6.1/samples/streams/sample_720p.h264
输出日志为:
Using file: /opt/nvidia/deepstream/deepstream-6.1/samples/streams/sample_720p.h264
0:00:01.632841348 278 0x5623c35c4390 INFO nvinfer gstnvinfer.cpp:646:gst_nvinfer_logger:<primary-nvinference-engine> NvDsInferContext[UID 1]: Info from NvDsInferContextImpl::deserializeEngineAndBackend() <nvdsinfer_context_impl.cpp:1900> [UID = 1]: deserialized trt engine from :/opt/nvidia/deepstream/deepstream-6.1/samples/models/Primary_Detector/resnet10.caffemodel_b1_gpu0_int8.engine
INFO: ../nvdsinfer/nvdsinfer_model_builder.cpp:610 [Implicit Engine Info]: layers num: 3
0 INPUT kFLOAT input_1 3x368x640
1 OUTPUT kFLOAT conv2d_bbox 16x23x40
2 OUTPUT kFLOAT conv2d_cov/Sigmoid 4x23x40
0:00:01.660045168 278 0x5623c35c4390 INFO nvinfer gstnvinfer.cpp:646:gst_nvinfer_logger:<primary-nvinference-engine> NvDsInferContext[UID 1]: Info from NvDsInferContextImpl::generateBackendContext() <nvdsinfer_context_impl.cpp:2003> [UID = 1]: Use deserialized engine model: /opt/nvidia/deepstream/deepstream-6.1/samples/models/Primary_Detector/resnet10.caffemodel_b1_gpu0_int8.engine
0:00:01.663054273 278 0x5623c35c4390 INFO nvinfer gstnvinfer_impl.cpp:328:notifyLoadModelStatus:<primary-nvinference-engine> [UID 1]: Load new model:dstest1_pgie_config.txt sucessfully
Running...
Frame Number = 0 Number of objects = 13 Vehicle Count = 9 Person Count = 4
Frame Number = 1 Number of objects = 11 Vehicle Count = 8 Person Count = 3
Frame Number = 2 Number of objects = 11 Vehicle Count = 7 Person Count = 4
。。。。。。
上述作为c语言的环境,也是python的一些前置环境,如果没有安装相应的依赖库,python编译是通不过的。如下图所示,官方并没有说是重新做了一套python的相关接口,而是通过pyBindings进行映射。python通过pybindings访问deepstream的C库,pybindings使用的第三方库是pybind11。
DeepStream Python 应用程序使用Gst-Python API 操作来构建管道并使用探测函数访问管道中各个点的数据。数据类型都在本机 C 中,需要通过PyBindings或 NumPy的填充层才能从 Python 应用程序访问它们。张量数据是推理后出来的原始张量输出。如果您尝试检测对象,则需要通过解析和聚类算法对该张量数据进行后处理,以在检测到的对象周围创建边界框。要开始使用 Python,请参阅本指南中的Python 示例应用源详细信息和 DeepStream Python API 指南中的“DeepStream Python”。
所以这里我们主要安装的环境为DeepStream python bindings。
官方的dockerfile并没有针对python环境再出一个相应的版本,所以不管是宿主机还是镜像,都需要一步步部署,首先安装依赖:
$ apt install python3-gi python3-dev python3-gst-1.0 python-gi-dev git python-dev \
python3 python3-pip python3.8-dev cmake g++ build-essential libglib2.0-dev \
libglib2.0-dev-bin libgstreamer1.0-dev libtool m4 autoconf automake libgirepository1.0-dev libcairo2-dev
然后进入到deepstream sdk中的sources源代码路径下,拉下来python的编译源码:
$ cd <DeepStream 6.1 ROOT>/sources/
$ git clone https://github.com/NVIDIA-AI-IOT/deepstream_python_apps
$ cd deepstream_python_apps/
$ git submodule update --init
确保我们添加 gst-python git 服务器现在使用的新证书:
sudo apt-get install -y apt-transport-https ca-certificates -y
sudo update-ca-certificates
构建并安装 gst-python:
cd 3rdparty/gst-python/
./autogen.sh
make
sudo make install
没有问题的情况下,就能进行cmake了。Python bindings 是使用 CMake 编译的。它的主要参数为:
变量 | 默认值 | 目的 | 可用值 |
---|---|---|---|
DS_VERSION | 6.1 | 用于确定默认的 deepstream 库路径 | 应与您计算机上安装的 deepstream 版本匹配 |
PYTHON_MAJOR_VERSION | 3 | 用于设置用于绑定的 python 版本 | 3 |
PYTHON_MINOR_VERSION | 8 | 用于设置用于绑定的 python 版本 | 6、8 |
PIP_PLATFORM | linux_x86_64 | 用于选择目标架构来编译绑定 | linux_x86_64, linux_aarch64 |
DS_PATH | /opt/nvidia/deepstream/deepstream-${DS_VERSION} | deepstream 库可用的路径 | 应该与现有的 deepstream 库文件夹匹配 |
因为我现在的路径与默认值路径基本一致,宿主机与容器也是在x86下面,所使用的deepstream版本为6.1,所以可以选择快速构建,或者加个指定版本:
$ cd deepstream_python_apps/bindings
$ mkdir build
$ cd build
$ cmake ..
$ make
# cmake -DPYTHON_MAJOR_VERSION=3 -DPYTHON_MINOR_VERSION=8
编译完成后,没问题会在当前build路径下面,产生pyds.so
与 pyds-1.1.3-py3-none-linux_x86_64.whl
。然后使用python下载离线包:
pip3 install ./pyds-1.1.3-py3-none*.whl
至此,python环境安装完成。
这里同样环境需要更改一下,如果没有桌面的话,需要将sink的配置改为fakesink:
$ cd deepstream_python_apps/apps/deepstream-test1
$ python3 deepstream_test_1.py /opt/nvidia/deepstream/deepstream-6.1/samples/streams/sample_720p.h264
Creating Pipeline
Creating Source
Creating H264Parser
Creating Decoder
Creating EGLSink
Playing file /opt/nvidia/deepstream/deepstream-6.1/samples/streams/sample_720p.h264
Adding elements to Pipeline
Linking elements in the Pipeline
Starting pipeline
0:00:00.243918936 350 0x33ebac0 WARN nvinfer gstnvinfer.cpp:643:gst_nvinfer_logger:<primary-inference> NvDsInferContext[UID 1]: Warning from NvDsInferContextImpl::initialize() <nvdsinfer_context_impl.cpp:1161> [UID = 1]: Warning, OpenCV has been deprecated. Using NMS for clustering instead of cv::groupRectangles with topK = 20 and NMS Threshold = 0.5
0:00:01.751623788 350 0x33ebac0 INFO nvinfer gstnvinfer.cpp:646:gst_nvinfer_logger:<primary-inference> NvDsInferContext[UID 1]: Info from NvDsInferContextImpl::deserializeEngineAndBackend() <nvdsinfer_context_impl.cpp:1900> [UID = 1]: deserialized trt engine from :/opt/nvidia/deepstream/deepstream-6.1/samples/models/Primary_Detector/resnet10.caffemodel_b1_gpu0_fp16.engine
INFO: ../nvdsinfer/nvdsinfer_model_builder.cpp:610 [Implicit Engine Info]: layers num: 3
0 INPUT kFLOAT input_1 3x368x640
1 OUTPUT kFLOAT conv2d_bbox 16x23x40
2 OUTPUT kFLOAT conv2d_cov/Sigmoid 4x23x40
0:00:01.825552519 350 0x33ebac0 INFO nvinfer gstnvinfer.cpp:646:gst_nvinfer_logger:<primary-inference> NvDsInferContext[UID 1]: Info from NvDsInferContextImpl::generateBackendContext() <nvdsinfer_context_impl.cpp:2003> [UID = 1]: Use deserialized engine model: /opt/nvidia/deepstream/deepstream-6.1/samples/models/Primary_Detector/resnet10.caffemodel_b1_gpu0_fp16.engine
0:00:01.826814569 350 0x33ebac0 INFO nvinfer gstnvinfer_impl.cpp:328:notifyLoadModelStatus:<primary-inference> [UID 1]: Load new model:dstest1_pgie_config.txt sucessfully
Frame Number=0 Number of Objects=10 Vehicle_count=6 Person_count=4
Frame Number=1 Number of Objects=11 Vehicle_count=7 Person_count=4
Frame Number=2 Number of Objects=11 Vehicle_count=7 Person_count=4
Frame Number=3 Number of Objects=11 Vehicle_count=7 Person_count=4
......