Skip to content

Commit

Permalink
Update project requirements (#730)
Browse files Browse the repository at this point in the history
* Update project requirements.

* Fix `Argument list too long` in file mime-type parser.

* Support nvinfer topk and layer-device-precision.

* Fix obj-attr link for multi-label.

* Fix wrong nvds to video_frame obj id mapping.
  • Loading branch information
denisvmedyantsev authored Apr 17, 2024
1 parent 523d75b commit d9fd4b4
Show file tree
Hide file tree
Showing 15 changed files with 81 additions and 66 deletions.
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ publish-local: build build-adapters-deepstream build-adapters-gstreamer build-ad
docker tag savant-adapters-gstreamer$(PLATFORM_SUFFIX) ghcr.io/insight-platform/savant-adapters-gstreamer$(PLATFORM_SUFFIX)
docker tag savant-adapters-py$(PLATFORM_SUFFIX) ghcr.io/insight-platform/savant-adapters-py$(PLATFORM_SUFFIX)

publish-local-extra: build-extra
docker tag savant-deepstream$(PLATFORM_SUFFIX)-extra ghcr.io/insight-platform/savant-deepstream$(PLATFORM_SUFFIX)-extra

build:
docker buildx build \
--platform $(PLATFORM) \
Expand Down Expand Up @@ -135,6 +138,7 @@ run-tests:
savant-deepstream$(PLATFORM_SUFFIX)-extra \
-s $(PROJECT_PATH)/tests

# run jupyter inside `jupyter lab --allow-root`
run-dev:
#xhost +local:docker
docker run -it --rm $(RUNTIME) \
Expand Down
1 change: 0 additions & 1 deletion adapters/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
cachetools~=5.3.0
pretty-traceback==2023.1019
# ClientSDK JpegSource, PngSource
python-magic~=0.4.27
33 changes: 11 additions & 22 deletions docker/Dockerfile.deepstream
Original file line number Diff line number Diff line change
Expand Up @@ -140,13 +140,8 @@ RUN wget -qO- \
dpkg -i OpenCV* && \
rm OpenCV*

COPY requirements/base.txt requirements/base.txt
RUN python -m pip install --no-cache-dir -r requirements/base.txt

COPY requirements/ext.txt requirements/ext.txt
RUN python -m pip install --no-cache-dir -r requirements/ext.txt

RUN rm -r requirements
COPY requirements/base.txt requirements.txt
RUN python -m pip install --no-cache-dir -r requirements.txt && rm requirements.txt

COPY --from=savant-boost-builder /libs/savanboost/dist /libs/savanboost/dist
RUN python -m pip install --no-cache-dir /libs/savanboost/dist/*.whl
Expand Down Expand Up @@ -178,7 +173,9 @@ COPY savant/VERSION .
COPY gst_plugins gst_plugins

COPY adapters/gst/gst_plugins adapters/gst/gst_plugins
RUN rm -f adapters/gst/gst_plugins/python/video_files_sink.py
RUN rm -f \
adapters/gst/gst_plugins/python/video_files_sink.py \
adapters/gst/gst_plugins/python/zeromq_sink.py
COPY adapters/gst/sources adapters/gst/sources

COPY scripts/uri-input.py scripts/
Expand Down Expand Up @@ -293,13 +290,9 @@ RUN wget -nv -O ${PYCUDA_WHL} ${PACKAGES_URL}/${PYCUDA_WHL} && \
ARG ORT_VERSION=1.17.1
RUN python -m pip install --no-cache-dir onnx onnxruntime-gpu --extra-index-url https://aiinfra.pkgs.visualstudio.com/PublicPackages/_packaging/onnxruntime-cuda-12/pypi/simple/

# cython, polars, scikit-learn, jupyter
RUN python -m pip install --no-cache-dir \
Cython \
polars[all] \
scikit-learn \
jupyterlab \
pytest
# cython, polars, scikit-learn, jupyter, etc.
COPY requirements/extra.txt requirements.txt
RUN python -m pip install --no-cache-dir -r requirements.txt && rm requirements.txt


# Extra l4t container
Expand Down Expand Up @@ -356,10 +349,6 @@ ARG ORT_WHL="onnxruntime_gpu-1.17.0-cp310-cp310-linux_aarch64.whl"
RUN wget -nv -O ${ORT_WHL} ${ORT_URL} && \
python -m pip install --no-cache-dir onnx ${ORT_WHL}

# cython, polars, scikit-learn, jupyter
RUN python -m pip install --no-cache-dir \
Cython \
polars[all] \
scikit-learn \
jupyterlab \
pytest
# cython, polars, scikit-learn, jupyter, etc.
COPY requirements/extra.txt requirements.txt
RUN python -m pip install --no-cache-dir -r requirements.txt && rm requirements.txt
22 changes: 13 additions & 9 deletions requirements/base.txt
Original file line number Diff line number Diff line change
@@ -1,20 +1,15 @@
numpy~=1.22.4
cupy-cuda12x

numba~=0.57
scipy~=1.10

pyzmq~=22.2.1
cachetools~=5.3.0

splitstream==1.2.6
click~=8.1.6

# yaml config
omegaconf~=2.3
# for omegaconf arithmetic resolver
# omegaconf arithmetic resolver
simpleeval~=0.9.12
# for dynamic pyfunc reloading
# dynamic pyfunc reloading
inotify-simple~=1.3.5

# pretty error output
pretty-traceback==2023.1019

Expand All @@ -24,6 +19,15 @@ boto3~=1.23
tqdm~=4.64

# ClientSDK JpegSource, PngSource
click~=8.1.6
python-magic~=0.4.27

prometheus-client~=0.19.0

# pyds
pyds @ https://github.com/NVIDIA-AI-IOT/deepstream_python_apps/releases/download/v1.1.10/pyds-1.1.10-py3-none-linux_x86_64.whl ; platform_machine=='x86_64'
pyds @ https://github.com/NVIDIA-AI-IOT/deepstream_python_apps/releases/download/v1.1.10/pyds-1.1.10-py3-none-linux_aarch64.whl ; platform_machine=='aarch64'

# ffmpeg-input
ffmpeg-input @ https://github.com/insight-platform/FFmpeg-Input/releases/download/0.1.23/ffmpeg_input-0.1.23-cp310-cp310-manylinux_2_28_x86_64.whl ; platform_machine=='x86_64'
ffmpeg-input @ https://github.com/insight-platform/FFmpeg-Input/releases/download/0.1.23/ffmpeg_input-0.1.23-cp310-cp310-manylinux_2_28_aarch64.whl ; platform_machine=='aarch64'
7 changes: 0 additions & 7 deletions requirements/ext.txt

This file was deleted.

7 changes: 7 additions & 0 deletions requirements/extra.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Cython
polars[all]
scikit-learn
jupyterlab
ipywidgets
matplotlib
pytest
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,12 @@ pipeline:
- element: nvinfer@detector
name: DashCamNet
model:
format: etlt
remote:
url: "https://api.ngc.nvidia.com/v2/models/nvidia/tao/dashcamnet/versions/pruned_v1.0.2/zip"
model_file: resnet18_dashcamnet_pruned.etlt
url: "https://api.ngc.nvidia.com/v2/models/nvidia/tao/dashcamnet/versions/pruned_v1.0.4/zip"
model_file: resnet18_dashcamnet_pruned.onnx
# label_file: labels.txt
precision: int8
int8_calib_file: dashcamnet_int8.txt
int8_calib_file: resnet18_dashcamnet_pruned_int8.txt
batch_size: 1
input:
layer_name: input_1
Expand Down
2 changes: 1 addition & 1 deletion savant/VERSION
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
SAVANT=0.4.0
SAVANT_RS=0.2.19
SAVANT_RS=0.2.22
DEEPSTREAM=6.4
4 changes: 4 additions & 0 deletions savant/converter/yolo.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ def __call__(
confidences = det_scores[:num]
class_ids = det_classes[:num]

# [0..1] -> model.input
bboxes[:, [0, 2]] *= model.input.width
bboxes[:, [1, 3]] *= model.input.height

# (left, top, right, bottom) -> (xc, yc, width, height)
bboxes[:, 2] -= bboxes[:, 0]
bboxes[:, 3] -= bboxes[:, 1]
Expand Down
5 changes: 4 additions & 1 deletion savant/deepstream/nvinfer/file_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,9 @@ class _FieldMap:
_FieldMap('num-detected-classes', 'output.num_detected_classes', int),
_FieldMap('gpu-id', 'gpu_id', int),
_FieldMap('secondary-reinfer-interval', 'interval', int),
_FieldMap(
'layer-device-precision', 'layer_device_precision', lambda v: v.split(';')
),
]

_CLASS_ATTR_MAP = [
Expand All @@ -198,7 +201,7 @@ class _FieldMap:
_FieldMap('detected-min-h', 'min_height', int, 32),
_FieldMap('detected-max-w', 'max_width', int),
_FieldMap('detected-max-h', 'max_height', int),
# FieldMap('topk', 'topk', int),
_FieldMap('topk', 'top_k', int),
]

@staticmethod
Expand Down
9 changes: 6 additions & 3 deletions savant/deepstream/nvinfer/model.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
"""Gst-nvinfer model configuration templates."""

from dataclasses import dataclass
from dataclasses import dataclass, field
from enum import Enum
from typing import List, Optional

from omegaconf import MISSING

from savant.base.model import (
AttributeModel,
ComplexModel,
Expand Down Expand Up @@ -173,6 +171,11 @@ class NvInferModel(Model):
engine_create_func_name: Optional[str] = None
"""Name of the custom TensorRT CudaEngine creation function."""

layer_device_precision: List[str] = field(default_factory=list)
"""Specifies the device type and precision for any layer in the network.
List of items of format ``<layer1-name>:<precision>:<device-type>``.
"""


NVINFER_DEFAULT_OBJECT_SELECTOR = PyFunc(
module='savant.selector.detector',
Expand Down
11 changes: 4 additions & 7 deletions savant/deepstream/nvinfer/processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -374,14 +374,15 @@ def _process_custom_model_output(self, buffer: Gst.Buffer):
# object or complex model with non-empty output
if bbox_tensor.shape[1] == 6: # no angle
selection_type = ObjectSelectionType.REGULAR_BBOX

# xc -> left, yc -> top
bbox_tensor[:, 2] -= bbox_tensor[:, 4] / 2
bbox_tensor[:, 3] -= bbox_tensor[:, 5] / 2

# clip
# width to right, height to bottom
bbox_tensor[:, 4] += bbox_tensor[:, 2]
bbox_tensor[:, 5] += bbox_tensor[:, 3]

# clip
bbox_tensor[:, 2][
bbox_tensor[:, 2] < self._frame_rect[0]
Expand Down Expand Up @@ -487,14 +488,10 @@ def _process_custom_model_output(self, buffer: Gst.Buffer):
)
selected_bboxes.append((int(bbox[7]), _nvds_obj_meta))

# attribute or complex model
if values:
# attribute or complex model
if self._is_complex_model:
values = [
v
for i, v in enumerate(values)
if i in {i for i, _ in selected_bboxes}
]
values = [values[i] for i, _ in selected_bboxes]
else:
selected_bboxes = [(0, nvds_obj_meta)]
values = [values]
Expand Down
7 changes: 5 additions & 2 deletions savant/deepstream/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -811,6 +811,9 @@ def _update_meta_for_single_frame(
frame_pts,
)

def _nvds_obj_id(_obj_meta: pyds.NvDsObjectMeta) -> str:
return f'{_obj_meta.obj_label}#{_obj_meta.object_id}'

# collect frame objects
nvds_object_id_map = {} # nvds_obj_meta.object_id -> video_object.id
parents = {} # video_object.id -> nvds_obj_meta.parent.object_id
Expand Down Expand Up @@ -855,12 +858,12 @@ def _update_meta_for_single_frame(
obj_meta = nvds_obj_meta_output_converter(
nvds_frame_meta, nvds_obj_meta, self._frame_params, video_frame
)
nvds_object_id_map[nvds_obj_meta.object_id] = obj_meta.id
nvds_object_id_map[_nvds_obj_id(nvds_obj_meta)] = obj_meta.id
if (
not nvds_is_empty_object_meta(nvds_obj_meta.parent)
and nvds_obj_meta.parent.obj_label != PRIMARY_OBJECT_KEY
):
parents[obj_meta.id] = nvds_obj_meta.parent.object_id
parents[obj_meta.id] = _nvds_obj_id(nvds_obj_meta.parent)
# add obj attributes
for attr in attributes:
obj_meta.set_attribute(attr)
Expand Down
11 changes: 9 additions & 2 deletions savant/selector/detector.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,12 @@ def __call__(self, bbox_tensor: np.ndarray) -> np.ndarray:
)


@nb.njit('f4[:, :](f4[:, :], f4, f4, u2, u2, u2, u2)', nogil=True, cache=True)
@nb.njit('f4[:, :](f4[:, :], f4, f4, u2, u2, u2, u2, u2)', nogil=True, cache=True)
def default_selector(
bbox_tensor: np.ndarray,
confidence_threshold: float = 0.0,
nms_iou_threshold: float = 0.0,
top_k: int = 0,
min_width: int = 0,
min_height: int = 0,
max_width: int = 0,
Expand All @@ -102,6 +103,7 @@ def default_selector(
:param bbox_tensor: tensor(class_id, confidence, left, top, width, height)
:param confidence_threshold: confidence threshold
:param nms_iou_threshold: nms iou threshold
:param top_k: top k bboxes to keep
:param min_width: minimal bbox width
:param min_height: minimal bbox height
:param max_width: maximum bbox width
Expand Down Expand Up @@ -129,7 +131,8 @@ def default_selector(
selected_bbox_tensor[:, 2:6],
selected_bbox_tensor[:, 1],
nms_iou_threshold,
selected_bbox_tensor.shape[0], # should specify default with numba.njit
# should specify default with numba.njit
top_k if top_k > 0 else selected_bbox_tensor.shape[0],
)
selected_bbox_tensor = selected_bbox_tensor[keep]

Expand All @@ -141,6 +144,7 @@ class BBoxSelector(BaseSelector):
:param confidence_threshold: confidence threshold
:param nms_iou_threshold: nms iou threshold
:param top_k: top k bboxes to keep
:param min_width: minimal bbox width
:param min_height: minimal bbox height
:param max_width: maximum bbox width
Expand All @@ -151,6 +155,7 @@ def __init__(
self,
confidence_threshold: float = 0.5,
nms_iou_threshold: float = 0.5,
top_k: int = 0,
min_width: int = 0,
min_height: int = 0,
max_width: int = 0,
Expand All @@ -160,6 +165,7 @@ def __init__(
super().__init__(**kwargs)
self.confidence_threshold = confidence_threshold
self.nms_iou_threshold = nms_iou_threshold
self.top_k = top_k
self.min_width = min_width
self.min_height = min_height
self.max_width = max_width
Expand All @@ -175,6 +181,7 @@ def __call__(self, bbox_tensor: np.ndarray) -> np.ndarray:
bbox_tensor=bbox_tensor,
confidence_threshold=self.confidence_threshold,
nms_iou_threshold=self.nms_iou_threshold,
top_k=self.top_k,
min_width=self.min_width,
min_height=self.min_height,
max_width=self.max_width,
Expand Down
17 changes: 10 additions & 7 deletions savant/utils/file_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,15 @@ def from_mime_type(mime_type: Optional[str]) -> Optional['FileType']:


def parse_mime_types(files: List[Path]) -> List[Tuple[Path, str]]:
output = subprocess.check_output(
['file', '--no-pad', '--mime-type'] + [str(x) for x in files]
)
mime_types = []
for line in output.decode().strip().split('\n'):
path, mime_type = line.rsplit(': ', 1)
mime_types.append((Path(path), mime_type))

# use chunks to avoid `Argument list too long` error
chunk_size = 1000
for i in range(0, len(files), chunk_size):
chunk = files[i : i + chunk_size]
output = subprocess.check_output(
['file', '--no-pad', '--mime-type'] + [str(x) for x in chunk]
)
for line in output.decode().strip().split('\n'):
path, mime_type = line.rsplit(': ', 1)
mime_types.append((Path(path), mime_type))
return mime_types

0 comments on commit d9fd4b4

Please sign in to comment.