Deepstream
- Why do we need it?
- What is Deepstream?
- Basics
- Increase Inference Throughput
- Example Apps
- INT8 Mode
- Config Files
- DLA
- Usage of
deepstream-appvia ssh - Docker
- Troubleshooting
Note: If you want to use Deepstream via ssh, see section "Usage via ssh".
Why do we need it?
- Nvidia's Deepstream SDK is the Nvidia recommended way of implementing a detection pipeline on Jetson AGX
- since Nvidia is also the company which designs the AGX, the Deepstream approach is very likely the most efficient and robust way of implementing the detection our Team can get
- from this comment:
- "a significant portion of time has been spent on image preprocessing, postprocessing and display"
- "if you use C++ to parallelize/pipeline preprocessing, inferencing and postprocessing, you could speed up the whole video pipeline quite a bit [...]"
- "One good way to achieve that is to use NVIDIA DeepStream SDK"
What is Deepstream?
Deepstream "automates" setting up the model pipeline properly and efficiently using so called config files. It "automates" in the sense that it aims to minimize the coding effort to set up a Deep Learning model pipeline.
The Deepstream documentation often leaves open some questions. However, in general, it's a pretty good starting point.
There is a huge amount of configuration options in Deepstream 6 and at the time of writing the framework is still growing. Please, read the Deepstream documentation for usage instructions.
You can find some of the common errors and their fixes in the respective sections of the Team Galaxis traffic sign documentation.
Basics
| command | description |
|---|---|
deepstream-app -h | Show help options |
deepstream-app --help-all | Show all help options |
deepstream-app --help-gst | Show GStreamer Options |
deepstream-app -v | Print DeepStreamSDK version |
deepstream-app --version-all | Print DeepStreamSDK and dependencies version (e.g. CUDA version, TensorRT version, etc.) |
Increase Inference Throughput
- see tips in Deepstream doc
- Set the
interval=0parameter under[property]in the inference config file to a higher value. E.g.interval=1means that Deepstream will infer every other frame (orinterval=2for every third frame) and use a tracker to predict the location of the object. This can effectively double the throughput!
Example Apps
YOLO (sources/objectDetector_Yolo)
Custom Library nvdsinfer_custom_impl_Yolo
| file | description |
|---|---|
nvdsinfer_custom_impl_Yolo/nvdsinfer_yolo_engine.cpp | Implementation of 'NvDsInferCreateModelParser'/IModelParser for nvdsinfer to parse custom models. Alternatively, also contains implementation of 'NvDsInferYoloCudaEngineGet' for nvdsinfer to directly create cuda engine. To use the 'NvDsInferYoloCudaEngineGet' interface, enable the macro USE_CUDA_ENGINE_GET_API in nvdsinfer_yolo_engine.cpp |
nvdsinfer_custom_impl_Yolo/nvdsparsebbox_Yolo.cpp | Output layer parsing function for detected objects for the Yolo model. |
nvdsinfer_custom_impl_Yolo/yoloPlugins.h | Declaration of YoloLayerV3 and YoloLayerV3PluginCreator. |
nvdsinfer_custom_impl_Yolo/yoloPlugins.cpp | Implementation of YoloLayerV3 and YoloLayerV3PluginCreator. |
nvdsinfer_custom_impl_Yolo/kernels.cu | Implementation of cuda kernels for |
nvdsinfer_custom_impl_Yolo/trt_utils.h | Utilities to setup tensorRT networks |
nvdsinfer_custom_impl_Yolo/trt_utils.cpp | Implementation of Utilities to setup tensorRT networks |
nvdsinfer_custom_impl_Yolo/yolo.h | Interface to create Yolo Cuda-Engine |
nvdsinfer_custom_impl_Yolo/yolo.cpp | Implementation to create Yolo Cuda-Engine |
Compile nvdsinfer_custom_impl_Yolo
- Important: Do not copy
nvdsinfer_custom_impl_Yolo/to some other directory! Otherwisemakewill fail. - on AGX:
sudo chmod a+rwx /opt/nvidia/deepstream/deepstream-6.0/sources/objectDetector_Yolo/sudo chmod a+rwx /opt/nvidia/deepstream/deepstream-6.0/sources/objectDetector_Yolo/nvdsinfer_custom_impl_Yolo/export CUDA_VER=10.2make -C nvdsinfer_custom_impl_Yolo/(first setNUM_CLASSES_YOLOinnvdsinfer_custom_impl_Yolo/nvdsparsebbox_Yolo.cpp)- Important: Do not copy
nvdsinfer_custom_impl_Yolo/to some other directory! Otherwisemakewill fail.
- Important: Do not copy
yolov2
- to run on DLA use
network-mode=2(i.e. FP16 mode) in configuration group[property]- Nvidia does not provide an INT8 calibration table file for YOLOv2 in Deepstream 6.0.1, so in order to use INT8 mode on DLA a calibration table must be generated first (see TensorRT doc)
yolov4 and yolov7
Apps from deepstream_python_apps (sources/apps/sample_apps)
Troubleshooting
Error 1:
Makefile:25: *** "CUDA_VER is not set". Stop.
- instead of
sudo make, runmake
INT8 Mode
- "Calibration must be performed using images representative of those which will be used at runtime." (from TensorRT doc)
- This means that the provided INT8 calibration table in Deepstream 6.0.1 does not work for our trained traffic sign detection networks! We have to generate our own INT8 calibration tables using images of our real test track! (Better: Don't use INT8 mode.)
Config Files
- see configuration groups
- see Best practices
DLA
# check, if a DLA is active:
cat /sys/devices/platform/host1x/15880000.nvdla0/power/runtime_status #DLA0
cat /sys/devices/platform/host1x/158c0000.nvdla1/power/runtime_status #DLA1
Usage of deepstream-app via ssh
Deepstream does not support x11 forwarding via ssh, so you must save all outputs to files! This can be done in the following way:
- auf host:
xhost + - auf AGX:
export DISPLAY=:0- oder
export DISPLAY=:1(je nach dem, was klappt) - liegt daran, dass x11 forwarding nicht von Deepstream supported wird (May 2022) [komischerweise obwohl Gstreamer x11 forwarding supported]
- d.h. man muss die DISPLAY Variable der AGX bash shell auf den lokalen AGX Monitor setzen (i.e.
export DISPLAY=:0)
- d.h. man muss die DISPLAY Variable der AGX bash shell auf den lokalen AGX Monitor setzen (i.e.
- oder
- Then in the Deepstream config file (e.g.
deepstream_app_config_yoloV3.txt) in the[sink0]configuration group set the output to a file (see configuration groups). Example:
[sink0]
enable=1
type=3
#1=mp4 2=mkv
container=1
#1=h264 2=h265
codec=1
sync=0
#iframeinterval=10
bitrate=2000000
output-file=traffic_sign_detections.mp4
source-id=0
Recording mp4 files
It may be useful to record .mp4 files for later use, while you have enough light.
You can record an .mp4 file from command line by running
gst-launch-1.0 v4l2src device="/dev/video2" num-buffers=3000 ! 'video/x-raw, framerate=60/1' ! videoconvert ! x264enc ! mp4mux ! filesink location=traffic_signs_3000frames.mp4
which records 3000 frames at 60 fps, i.e. the output .mp4 duration will be 50 seconds.
Important: The above command will output an .mp4 file in yuv422p pixel format. However, Deepstream config files will only take yuv420p formatted input files. Run ffmpeg -i file.mp4 -vf format=yuv420p file_yuv420p.mp4 to convert files from yuv422p to yuv420p.
- actually, you can record
yuv420p(akaI420in the Gstreamer framework) directly, but I have not yet figured out the rightgst-launch-1.0pipeline for this ... - if you need to change framerates, you can do this by running
ffmpeg -i <input> -filter:v fps=30 <output>
Note: If you stream .mp4 files via ssh, the output will lag significantly. So, always download .mp4 files using scp and play them locally on your computer!
Note: You can get some metadata about an .mp4 file (i.e. duration, fps, encoding, ... etc.) by running e.g. ffmpeg -i traffic_signs_1000frames.mp4.
Docker
xhost +vor dem docker Start!- im docker start script: mounte die richtige Kamera (z.B. via
docker run --device=/dev/video4)
Troubleshooting
Check Camera Device
l /dev/video*v4l2-ctl --list-devices- always use the right camera device number in your apps!
Display the webcam feed
You can display the webcam feed of device=/dev/video2 from command line by running
# using mpv
mpv /dev/video2
# using vlc
vlc v4l2:///dev/video2
# using Gstreamer
gst-launch-1.0 v4l2src device=/dev/video2 name=cam_src ! videoconvert ! videoscale ! video/x-raw,format=RGB ! queue ! videoconvert ! ximagesink name=img_origin
Clear Cache
- Always do this first!
rm .cache/gstreamer-1.0/registry.aarch64.bin- Note:
.cache/is in folder/root/
- Note:
Errors
Error 1
# no output at all
- If
gst-inspect-1.0andgst-launch-1.0both do not give any output, at all, reboot Ubuntu.
Error 2
[NvMediaParserParse:357] Video parser parse failed: 0Stream format not found, dropping the frame
- Problem: The input video source's format is not supported by Deepstream.
- Fix: Convert the video file to one of Deepstream's supported formats first.
- e.g. yuv422 (the Realsense default format) is not supported in Deepstream pipelines
Error 3
** INFO: <bus_callback:180>: Pipeline running
ERROR from src_elem: Internal data stream error.
Debug info: gstbasesrc.c(3055): gst_base_src_loop (): /GstPipeline:pipeline/GstBin:multi_src_bin/GstBin:src_sub_bin0/GstV4l2Src:src_elem:
streaming stopped, reason not-negotiated (-4)
** INFO: <bus_callback:160>: incorrect camera parameters provided, please provide supported resolution and frame rate
** INFO: <bus_callback:217>: Received EOS. Exiting ...
Quitting
App run failed
- problem: here the line
** INFO: <bus_callback:160>: incorrect camera parameters provided, please provide supported resolution and frame rateindicates that the camera resolution settings specified indeepstream_app_config_yoloV4.txtunder[source0]are probably not supported by the camera. - solution:
- run
v4l2-ctl -d /dev/video2 --list-formats-extto check supported formats and resolutions - choose one of the supported formats and in
deepstream_app_config_yoloV4change[source0]camera-width=424camera-height=240camera-fps-n=60
- run
Error 4
ERROR: ../nvdsinfer/nvdsinfer_model_builder.cpp:1523 Deserialize engine failed because file path: /opt/nvidia/deepstream/deepstream-5.1/sources/objectDetector_Yolo/yolov3_b1_gpu0_int8.engine open error
- Possible Problem 1: a wrong
.enginefile name was specified- solution:
- In
config_infer_primary_yoloV3.txtchangemodel-engine-file=yolov3_b1_gpu0_int8.enginetomodel-engine-file=model_b1_gpu0_int8.engine. - The right name of the
.enginefile can be determined by generating a new.enginefile by runningdeepstream-app -c deepstream_app_config_yoloV3.txtand then checking which.enginefile was created. - Deepstream usually generates
model_b1_gpu0_int8.enginefor YoloV3. Thus,yolov3_b1_gpu0_int8.enginewon't work.
- In
- solution:
- Possible Problem 2: the specified
.enginefile does not exist- solution: create an
.enginefile (Deepstream does this automatically)
- solution: create an
- Note: This
ERRORis usually not a problem. It indicates that the.enginefile is missing. Deepstream automatically generates a new.enginefile after displaying thisERROR.
Error 5
No EGL Display
nvbufsurftransform: could not get EGL display
- solution: wenn login über
ssh: setzeexport DISPLAY=:0oderexport DISPLAY=:1auf dem AGX (s. section "Using Deepstream via ssh")
Error 6
WARNING: Num classes mismatch. Configured:80, detected by network: 4
- solution:
- in
nvdsinfer_custom_impl_Yolo/nvdsparsebbox_Yolo.cppcheck, ifNUM_CLASSES_YOLO = 4is set correctly - In
deepstream_app_config_yoloV3.txtandconfig_infer_primary_yoloV3.txtchecklabelfile-path=. Setting it indeepstream_app_config_yoloV3.txtwill override the value inconfig_infer_primary_yoloV3.txt.
- Therefore, make sure to set it only in one of the two files. Deepstream-app will crash, if the values in both files conflict!
- in
Error 7
ERROR: ../nvdsinfer/nvdsinfer_func_utils.cpp:31 Could not open lib: /opt/nvidia/deepstream/deepstream-6.0/sources/deepstream_yolov4, error string: /opt/nvidia/deepstream/deepstream-6.0/sources/deepstream_yolov4: cannot open shared object file: No such file or directory
0:00:15.658106044 9401 0x3a0bd30 ERROR nvinfer gstnvinfer.cpp:632:gst_nvinfer_logger:<primary-inference1> NvDsInferContext[UID 1]: Error in NvDsInferContextImpl::initialize() <nvdsinfer_context_impl.cpp:1248> [UID = 1]: Could not open custom lib: (null)
0:00:15.658129358 9401 0x3a0bd30 WARN nvinfer gstnvinfer.cpp:841:gst_nvinfer_start:<primary-inference1> error: Failed to create NvDsInferContext instance
0:00:15.658135900 9401 0x3a0bd30 WARN nvinfer gstnvinfer.cpp:841:gst_nvinfer_start:<primary-inference1> error: Config file path: /root/docker_volume/realsense_gstream_ds_ws_scp/src/ros2_deepstream/config_files/dstest2_pgie_config.txt, NvDsInfer Error: NVDSINFER_CUSTOM_LIB_FAILED
[NvMultiObjectTracker] De-initialized
Error: gst-resource-error-quark: Failed to create NvDsInferContext instance (1): gstnvinfer.cpp(841): gst_nvinfer_start (): /GstPipeline:pipeline0/GstNvInfer:primary-inference1:
Config file path: /root/docker_volume/realsense_gstream_ds_ws_scp/src/ros2_deepstream/config_files/dstest2_pgie_config.txt, NvDsInfer Error: NVDSINFER_CUSTOM_LIB_FAILED
- problem: the folder
deepstream_yolov4/is not in/opt/nvidia/deepstream/deepstream-6.0/sources/ - solution:
Error 8
gstnvtracker: Loading low-level lib at /opt/nvidia/deepstream/deepstream/lib/libnvds_mot_klt.so
gstnvtracker: Failed to open low-level lib at /opt/nvidia/deepstream/deepstream/lib/libnvds_mot_klt.so
dlopen error: /opt/nvidia/deepstream/deepstream/lib/libnvds_mot_klt.so: cannot open shared object file: No such file or directory
gstnvtracker: Failed to initilaize low level lib.
gstnvtracker: Loading low-level lib at /opt/nvidia/deepstream/deepstream/lib/libnvds_mot_klt.so
gstnvtracker: Failed to open low-level lib at /opt/nvidia/deepstream/deepstream/lib/libnvds_mot_klt.so
dlopen error: /opt/nvidia/deepstream/deepstream/lib/libnvds_mot_klt.so: cannot open shared object file: No such file or directory
gstnvtracker: Failed to initilaize low level lib.
- output: the camera window opens, but it is completely black and shows nothing
- problem: the multi-object tracker
libnvds_mot_klt.socould not be found - solution:
- in Deepstream 6.0.1
libnvds_mot_klt.sowas renamed tolibnvds_nvmultiobjecttracker.so - for Deepstream 6.0.1: in
path/to/config_files/dstest2_tracker_config.txtset34 ll-lib-file=/opt/nvidia/deepstream/deepstream/lib/libnvds_nvmultiobjecttracker.soinstead of34 ll-lib-file=/opt/nvidia/deepstream/deepstream/lib/libnvds_mot_klt.so
- in Deepstream 6.0.1
Error 9
Error: gst-stream-error-quark: memory type configured and i/p buffer mismatch ip_surf 0 muxer 3 (1): gstnvstreammux.c(619): gst_nvstreammux_chain (): /GstPipeline:pipeline0/GstNvStreamMux:Stream-muxer
- problem: the specified streammux resolution is wrong
- fix: in
single_stream_pkg/single_stream_pkg/single_stream_class.pyset
324 # streammux.set_property('width', 1920)
325 # streammux.set_property('height', 1080)
326 streammux.set_property('width', 640)
327 streammux.set_property('height', 540)
- important: resolution must be set to exactly one of the following values ! Other resolutions will give the above error.
- on phth's machine:
- width: 640 x height: 540
- 424 x 240
- on AGX:
- width: 640 x height: 480
- on phth's machine:
Error 10
NvDsInferCudaEngineGetFromTltModel: Failed to open TLT encoded model file /root/docker_volume/ds_ws/src/ros2_deepstream/config_files/final_model.etlt
ERROR: ../nvdsinfer/nvdsinfer_model_builder.cpp:724 Failed to create network using custom network creation function
ERROR: ../nvdsinfer/nvdsinfer_model_builder.cpp:789 Failed to get cuda engine from custom library API
0:00:15.477449959 11681 0x23cd730 ERROR nvinfer gstnvinfer.cpp:632:gst_nvinfer_logger:<secondary1-nvinference-engine> NvDsInferContext[UID 22]: Error in NvDsInferContextImpl::buildModel() <nvdsinfer_context_impl.cpp:1934> [UID = 22]: build engine file failed
terminate called after throwing an instance of 'nvinfer1::InternalError'
what(): Assertion val > 0 failed.
- problem: there is no model file
final_model.etltin the directorysrc/ros2_deepstream/config_files/ - fix: download the model file
Error 11
ERROR: ../nvdsinfer/nvdsinfer_model_builder.cpp:1484 Deserialize engine failed because file path: /root/docker_volume/ds_ws/src/ros2_deepstream/config_files/final_model.etlt_b32_gpu0_fp16.engine open error
- problem: there is no engine file
final_model.etlt_b32_gpu0_fp16.enginein the directorysrc/ros2_deepstream/config_files/ - fix: download the engine file
Error 12
ERROR: [TRT]: ModelImporter.cpp:726: ERROR: ModelImporter.cpp:527 In function importModel:
[4] Assertion failed: !_importer_ctx.network()->hasImplicitBatchDimension() && "This version of the ONNX parser only supports TensorRT INetworkDefinitions with an explicit batch dimension. P
lease ensure the network was created using the EXPLICIT_BATCH NetworkDefinitionCreationFlag."
ERROR: ../nvdsinfer/nvdsinfer_model_builder.cpp:315 Failed to parse onnx file
ERROR: ../nvdsinfer/nvdsinfer_model_builder.cpp:966 failed to build network since parsing model errors.
- problem: Explicit batch is required when you are dealing with Dynamic shapes, otherwise network will be created using implicit batch dimension.
- fix: Use
force-implicit-batch-dim=0.force-implicit-batch-dim=1means: When a network supports both implicit batch dimension and full dimension, force the implicit batch dimension mode. doc
Note: DeepStream 6.0 uses explicit batch dimension for caffemodels. Some caffemodels use TensorRT plugins/layers which have not been updated for explicit batch dimensions. Add force-implicit-batch-dim=1 in the nvinfer config file for such models to build the models using implicit batch dimension networks. source