Savant Explained: Pipeline Element Groups

Ivan Kud
Inside In-Sight
Published in
3 min readJul 28, 2023

--

Savant 0.2.5 introduces a new pipeline syntax structure — Element Group (EG). The purpose of an EG is to specify a group of elements conditionally loaded during the pipeline initialization based on a specified expression. E.g., imagine that your pipeline can use YOLOV8 or PeopleNet for people detection, and you want to specify the environment variable DETECTOR, determining which model will be loaded.

Consider visiting our GitHub, and don’t forget to subscribe to our Twitter to receive updates on Savant. Also, we have Discord, where we help users to onboard.

In previous versions of Savant, a developer had two strategies to deal with that:

  1. have a separate pipeline for every flavor;
  2. load both models and implement conditional processing in runtime.

Both approaches have cons and thus influenced the creation of the new syntax. The main disadvantage of the first one is that you need to maintain multiple pipeline files with duplications which is error-prone and inefficient. The second utilizes more GPU RAM and CPU power than required, thus inefficient.

Element Group Syntax

The syntax for element groups efficiently solves the above-mentioned problems. You can take a look at the syntax in action in the traffic_meter sample on GitHub:

pipeline:

elements:
# regular pyfunc unit definition
- element: pyfunc
module: samples.traffic_meter.line_crossing
class_name: ConditionalDetectorSkip
kwargs:
config_path: ${oc.env:PROJECT_PATH}/samples/traffic_meter/line_config.yml

# variant group: peoplenet detector
# groups are included in the pipeline.elements alongside regular units or other groups
- group:
# enabled if env var DETECTOR==peoplenet
init_condition:
expr: ${oc.env:DETECTOR}
value: peoplenet
elements:
# below follows detector unit definition as usual
- element: nvinfer@detector
name: peoplenet
# ... hidden for clarity

# variant group: yolov8m detector
# groups are included in the pipeline.elements alongside regular units or other groups
- group:
# enabled if env var DETECTOR==yolov8m
init_condition:
expr: ${oc.env:DETECTOR}
value: yolov8m
elements:
# below follows detector unit definition as usual
- element: nvinfer@detector
name: yolov8m
# ... hidden for clarity

# regular nvtracker definition
- element: nvtracker
properties:
ll-lib-file: /opt/nvidia/deepstream/deepstream/lib/libnvds_nvmultiobjecttracker.so
ll-config-file: ${oc.env:PROJECT_PATH}/samples/traffic_meter/config_tracker_NvDCF_perf.yml
tracker-width: 960 # 640 # must be a multiple of 32
tracker-height: 544 # 384
display-tracking-id: 0

# regular pyfunc unit definition
- element: pyfunc
module: samples.traffic_meter.line_crossing
class_name: LineCrossing
kwargs:
config_path: ${oc.env:PROJECT_PATH}/samples/traffic_meter/line_config.yml
stale_track_del_period: 5000
target_obj_label: ${parameters.detected_object.label}
send_stats: True

The first element and the last two in the pipeline are common. In the middle, you may find two groups: the first one includes a single element and initializes when the DETECTOR environment variable is set to peoplenet , the second is when it is set to yolov8m .

The init_condition element of a group is checked only upon the pipeline boot and thus defines a static configuration.

Where To Use

There are different cases where to use element group:

  1. implementing various flavors which activate different models based on camera placement conditions, like indoor, outdoor, higher, lower, bird-eye, fisheye, etc.
  2. disabling certain parts of pipelines based on camera placement, like disabling car-plate recognition if camera placement doesn’t allow doing that.
  3. multiple pipelines defined in a single manifest: you can switch between different pipelines based on the environment variables.

--

--