-
-
Save mfoglio/5dca2c6cc82fc17c71742d6d3c3aaf92 to your computer and use it in GitHub Desktop.
Yolo V3 slow fps
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Build | |
docker build . -t deepstream-custom-slow | |
# Run | |
# Add your RTSP video url on line 64 of pipeline.py . You can also try to use a local file. | |
# You can also change number_of_streams if you want to increase/decrease the number of replicated streams. | |
docker run \ | |
-it \ | |
--rm \ | |
--net=host \ | |
--runtime nvidia \ | |
-e DISPLAY=$DISPLAY \ | |
-v /tmp/.X11-unix/:/tmp/.X11-unix \ | |
--cap-add=SYS_PTRACE \ | |
--security-opt seccomp=unconfined \ | |
--device /dev/video0 \ | |
--privileged \ | |
--expose 8554 \ | |
deepstream-custom-slow | |
# Kill | |
docker kill $(docker ps -a -q --filter ancestor=deepstream-custom-slow) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
################################################################################ | |
# Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved. | |
# | |
# Permission is hereby granted, free of charge, to any person obtaining a | |
# copy of this software and associated documentation files (the "Software"), | |
# to deal in the Software without restriction, including without limitation | |
# the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
# and/or sell copies of the Software, and to permit persons to whom the | |
# Software is furnished to do so, subject to the following conditions: | |
# | |
# The above copyright notice and this permission notice shall be included in | |
# all copies or substantial portions of the Software. | |
# | |
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
# DEALINGS IN THE SOFTWARE. | |
################################################################################ | |
# Following properties are mandatory when engine files are not specified: | |
# int8-calib-file(Only in INT8), model-file-format | |
# Caffemodel mandatory properties: model-file, proto-file, output-blob-names | |
# UFF: uff-file, input-dims, uff-input-blob-name, output-blob-names | |
# ONNX: onnx-file | |
# | |
# Mandatory properties for detectors: | |
# num-detected-classes | |
# | |
# Optional properties for detectors: | |
# cluster-mode(Default=Group Rectangles), interval(Primary mode only, Default=0) | |
# custom-lib-path | |
# parse-bbox-func-name | |
# | |
# Mandatory properties for classifiers: | |
# classifier-threshold, is-classifier | |
# | |
# Optional properties for classifiers: | |
# classifier-async-mode(Secondary mode only, Default=false) | |
# | |
# Optional properties in secondary mode: | |
# operate-on-gie-id(Default=0), operate-on-class-ids(Defaults to all classes), | |
# input-object-min-width, input-object-min-height, input-object-max-width, | |
# input-object-max-height | |
# | |
# Following properties are always recommended: | |
# batch-size(Default=1) | |
# | |
# Other optional properties: | |
# net-scale-factor(Default=1), network-mode(Default=0 i.e FP32), | |
# model-color-format(Default=0 i.e. RGB) model-engine-file, labelfile-path, | |
# mean-file, gie-unique-id(Default=0), offsets, process-mode (Default=1 i.e. primary), | |
# custom-lib-path, network-mode(Default=0 i.e FP32) | |
# | |
# The values in the config file are overridden by values set through GObject | |
# properties. | |
[property] | |
gpu-id=0 | |
net-scale-factor=0.0039215697906911373 | |
#batch-size=54 | |
#0=RGB, 1=BGR | |
model-color-format=0 | |
custom-network-config=/src/models/yoloV3/yolov3.cfg | |
model-file=/src/models/yoloV3/yolov3.weights | |
#model-engine-file=yolov3_b1_gpu0_int8.engine | |
labelfile-path=/src/labels.txt | |
int8-calib-file=/src/models/yoloV3/yolov3-calibration.table.trt7.0 | |
## 0=FP32, 1=INT8, 2=FP16 mode | |
network-mode=1 | |
num-detected-classes=80 | |
gie-unique-id=1 | |
network-type=0 | |
is-classifier=0 | |
## 1=DBSCAN, 2=NMS, 3= DBSCAN+NMS Hybrid, 4 = None(No clustering) | |
cluster-mode=2 | |
maintain-aspect-ratio=1 | |
parse-bbox-func-name=NvDsInferParseCustomYoloV3 | |
custom-lib-path=/src/models/yoloV3/nvdsinfer_custom_impl_Yolo/libnvdsinfer_custom_impl_Yolo.so | |
engine-create-func-name=NvDsInferYoloCudaEngineGet | |
#scaling-filter=0 | |
#scaling-compute-hw=0 | |
[class-attrs-all] | |
nms-iou-threshold=0.3 | |
threshold=0.7 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
FROM nvcr.io/nvidia/deepstream:6.0-triton | |
ENV GIT_SSL_NO_VERIFY=1 | |
RUN sh docker_python_setup.sh | |
RUN update-alternatives --set python3 /usr/bin/python3.8 | |
RUN apt install --fix-broken -y | |
RUN apt -y install python3-gi python3-gst-1.0 python-gi-dev git python3 python3-pip cmake g++ build-essential \ | |
libglib2.0-dev python3-dev python3.8-dev libglib2.0-dev-bin python-gi-dev libtool m4 autoconf automake | |
RUN cd /opt/nvidia/deepstream/deepstream-6.0/sources/apps && \ | |
git clone https://github.com/NVIDIA-AI-IOT/deepstream_python_apps.git | |
RUN cd /opt/nvidia/deepstream/deepstream-6.0/sources/apps/deepstream_python_apps && \ | |
git submodule update --init | |
RUN cd /opt/nvidia/deepstream/deepstream-6.0/sources/apps/deepstream_python_apps/3rdparty/gst-python/ && \ | |
./autogen.sh && \ | |
make && \ | |
make install | |
RUN pip3 install --upgrade pip | |
RUN cd /opt/nvidia/deepstream/deepstream-6.0/sources/apps/deepstream_python_apps/bindings && \ | |
mkdir build && \ | |
cd build && \ | |
cmake -DPYTHON_MAJOR_VERSION=3 -DPYTHON_MINOR_VERSION=8 -DPIP_PLATFORM=linux_x86_64 -DDS_PATH=/opt/nvidia/deepstream/deepstream-6.0 .. && \ | |
make && \ | |
pip3 install pyds-1.1.0-py3-none-linux_x86_64.whl | |
RUN cd /opt/nvidia/deepstream/deepstream-6.0/sources/apps/deepstream_python_apps && \ | |
mv apps/* ./ | |
RUN pip3 install --upgrade pip | |
RUN pip3 install numpy opencv-python | |
# RTSP | |
RUN apt update && \ | |
apt install -y python3-gi python3-dev python3-gst-1.0 | |
RUN apt update && \ | |
apt install -y libgstrtspserver-1.0-0 gstreamer1.0-rtsp && \ | |
apt install -y libgirepository1.0-dev && \ | |
apt-get install -y gobject-introspection gir1.2-gst-rtsp-server-1.0 | |
# DEVELOPMENT TOOLS | |
RUN apt install -y ipython3 graphviz | |
# Yolo V3 | |
ADD ./setup.sh /src/setup.sh | |
RUN sh /src/setup.sh | |
## Copying Project. | |
ADD ./ /src | |
WORKDIR /src | |
## Disable previous entrypoint. | |
ENTRYPOINT [] | |
## Run Project. | |
CMD ["python3", "pipeline.py"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
person | |
bicycle | |
car | |
motorbike | |
aeroplane | |
bus | |
train | |
truck | |
boat | |
traffic light | |
fire hydrant | |
stop sign | |
parking meter | |
bench | |
bird | |
cat | |
dog | |
horse | |
sheep | |
cow | |
elephant | |
bear | |
zebra | |
giraffe | |
backpack | |
umbrella | |
handbag | |
tie | |
suitcase | |
frisbee | |
skis | |
snowboard | |
sports ball | |
kite | |
baseball bat | |
baseball glove | |
skateboard | |
surfboard | |
tennis racket | |
bottle | |
wine glass | |
cup | |
fork | |
knife | |
spoon | |
bowl | |
banana | |
apple | |
sandwich | |
orange | |
broccoli | |
carrot | |
hot dog | |
pizza | |
donut | |
cake | |
chair | |
sofa | |
pottedplant | |
bed | |
diningtable | |
toilet | |
tvmonitor | |
laptop | |
mouse | |
remote | |
keyboard | |
cell phone | |
microwave | |
oven | |
toaster | |
sink | |
refrigerator | |
book | |
clock | |
vase | |
scissors | |
teddy bear | |
hair drier |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sys | |
sys.path.append("../") | |
import pyds | |
import gi | |
gi.require_version("Gst", "1.0") | |
gi.require_version("GstRtspServer", "1.0") | |
from gi.repository import GObject, Gst, GstRtspServer | |
from collections import defaultdict | |
import multiprocessing | |
import threading | |
import time | |
# Counter to count FPS | |
class Counter: | |
lock = threading.Lock() | |
count = defaultdict(int) | |
started = multiprocessing.Value("d", time.time()) | |
@classmethod | |
def print_fps_and_reset(cls): | |
with cls.lock: | |
# Compute fps | |
tot_fps = round(sum(cls.count.values()) / (time.time() - cls.started.value), 2) | |
avg_fps = round(tot_fps / 54) if cls.count else 0 | |
streams_up = len(cls.count) | |
# Reset | |
cls.count = defaultdict(int) | |
cls.started.value = time.time() | |
print(f"TOT FPS {tot_fps} AVG FPS {avg_fps} STREAMS UP {streams_up}") | |
# Start monitoring process to print FPS | |
def monitor(Counter): | |
while True: | |
Counter.print_fps_and_reset() | |
time.sleep(5) | |
monitoring_thread = threading.Thread(target=monitor, daemon=True, args=(Counter,)) | |
monitoring_thread.start() | |
# Bus call copied from official examples | |
def bus_call(bus, message, loop): | |
t = message.type | |
if t == Gst.MessageType.EOS: | |
sys.stdout.write("End-of-stream\n") | |
loop.quit() | |
elif t==Gst.MessageType.WARNING: | |
err, debug = message.parse_warning() | |
sys.stderr.write("Warning: %s: %s\n" % (err, debug)) | |
elif t == Gst.MessageType.ERROR: | |
err, debug = message.parse_error() | |
sys.stderr.write("Error: %s: %s\n" % (err, debug)) | |
loop.quit() | |
return True | |
# Manager for the Deepstream pipeline | |
class PipelineManager: | |
def __init__(self): | |
# Load cameras configuration | |
url = "" # INSERT HERE YOUR RTSP VIDEO STREAM URL | |
number_of_streams = 54 # CHANGE THIS TO TRY WITH A DIFFERENT NUMBER OF STREAMS | |
self.fps_streams = dict() | |
for index in range(number_of_streams): | |
self.fps_streams["stream{0}".format(index)] = url | |
number_sources = len(self.fps_streams) | |
print(f"Number of streams {number_sources}") | |
# Standard GStreamer initialization | |
GObject.threads_init() | |
Gst.init(None) | |
# Create Pipeline element that will form a connection of other elements | |
print("Creating Pipeline \n") | |
pipeline = Gst.Pipeline() | |
if not pipeline: | |
sys.stderr.write(" Unable to create Pipeline \n") | |
# Create nvstreammux instance to form batches from one or more sources. | |
print("Creating nvstreammux \n") | |
streammux = Gst.ElementFactory.make("nvstreammux", "Stream-muxer") | |
if not streammux: | |
sys.stderr.write(" Unable to create NvStreamMux \n") | |
pipeline.add(streammux) | |
for index in range(number_of_streams): | |
# sourcebin (source pad) -> (sinkpad) streammux -> | |
# Source bin | |
print("Creating source_bin ", index, " \n ") | |
source_bin = self.create_source_bin(index, url) | |
if not source_bin: | |
sys.stderr.write("Unable to create source bin \n") | |
pipeline.add(source_bin) | |
# Sink pad | |
padname = "sink_%u" % index | |
sinkpad = streammux.get_request_pad(padname) | |
if not sinkpad: | |
sys.stderr.write("Unable to create sink pad bin \n") | |
# Source pad | |
srcpad = source_bin.get_static_pad("src") | |
if not srcpad: | |
sys.stderr.write("Unable to create src pad bin \n") | |
srcpad.link(sinkpad) | |
# Primary GPU Inference Engine (pgie) | |
print("Creating Pgie \n ") | |
pgie = Gst.ElementFactory.make("nvinfer", "primary-inference") | |
if not pgie: | |
sys.stderr.write(" Unable to create pgie \n") | |
# Fakesink | |
sink = Gst.ElementFactory.make("fakesink", "fakesink") | |
batch_size = number_sources | |
streammux.set_property("width", 1920) | |
streammux.set_property("height", 1080) | |
streammux.set_property("batch-size", batch_size) | |
streammux.set_property("batched-push-timeout", 4000000) | |
streammux.set_property("live-source", 1) | |
pgie.set_property("config-file-path", "/src/config_infer_primary_yoloV3.txt") | |
pgie.set_property("batch-size", batch_size) | |
pipeline.add(pgie) | |
pipeline.add(sink) | |
streammux.link(pgie) | |
pgie.link(sink) | |
# create an event loop and feed gstreamer bus messages to it | |
loop = GObject.MainLoop() | |
bus = pipeline.get_bus() | |
bus.add_signal_watch() | |
bus.connect("message", bus_call, loop) | |
# Probe to get metadata | |
tiler_src_pad = pgie.get_static_pad("src") | |
if not tiler_src_pad: | |
sys.stderr.write(" Unable to get src pad \n") | |
else: | |
tiler_src_pad.add_probe(Gst.PadProbeType.BUFFER, self.tiler_src_pad_buffer_probe, 0) | |
# Start play back and listen to events | |
print("Starting pipeline \n") | |
pipeline.set_state(Gst.State.PLAYING) | |
try: | |
loop.run() | |
except BaseException: | |
pass | |
except Exception as e: | |
print("Exception", str(e)) | |
# cleanup | |
pipeline.set_state(Gst.State.NULL) | |
def tiler_src_pad_buffer_probe(self, pad, info, u_data): | |
gst_buffer = info.get_buffer() | |
if not gst_buffer: | |
print("Unable to get GstBuffer ") | |
return | |
# Retrieve batch metadata from the gst_buffer | |
# Note that pyds.gst_buffer_get_nvds_batch_meta() expects the | |
# C address of gst_buffer as input, which is obtained with hash(gst_buffer) | |
batch_meta = pyds.gst_buffer_get_nvds_batch_meta(hash(gst_buffer)) | |
l_frame = batch_meta.frame_meta_list | |
while l_frame is not None: | |
try: | |
# Note that l_frame.data needs a cast to pyds.NvDsFrameMeta | |
# The casting is done by pyds.NvDsFrameMeta.cast() | |
# The casting also keeps ownership of the underlying memory | |
# in the C code, so the Python garbage collector will leave | |
# it alone. | |
frame_meta = pyds.NvDsFrameMeta.cast(l_frame.data) | |
except StopIteration: | |
break | |
# Update FPS counter | |
with Counter.lock: | |
Counter.count[frame_meta.pad_index] += 1 | |
l_obj = frame_meta.obj_meta_list | |
while l_obj is not None: | |
try: | |
# Casting l_obj.data to pyds.NvDsObjectMeta | |
obj_meta = pyds.NvDsObjectMeta.cast(l_obj.data) | |
except StopIteration: | |
break | |
# do what you want with obj_meta | |
try: | |
l_obj = l_obj.next | |
except StopIteration: | |
break | |
try: | |
l_frame = l_frame.next | |
except StopIteration: | |
break | |
return Gst.PadProbeReturn.OK | |
def cb_newpad(self, decodebin, decoder_src_pad, data): | |
print("In cb_newpad\n") | |
caps = decoder_src_pad.get_current_caps() | |
gststruct = caps.get_structure(0) | |
gstname = gststruct.get_name() | |
source_bin = data | |
features = caps.get_features(0) | |
# Need to check if the pad created by the decodebin is for video and not | |
# audio. | |
print("gstname=", gstname) | |
if gstname.find("video") != -1: | |
# Link the decodebin pad only if decodebin has picked nvidia | |
# decoder plugin nvdec_*. We do this by checking if the pad caps contain | |
# NVMM memory features. | |
print("features=", features) | |
if features.contains("memory:NVMM"): | |
# Get the source bin ghost pad | |
bin_ghost_pad = source_bin.get_static_pad("src") | |
if not bin_ghost_pad.set_target(decoder_src_pad): | |
sys.stderr.write( | |
"Failed to link decoder src pad to source bin ghost pad\n" | |
) | |
else: | |
sys.stderr.write( | |
" Error: Decodebin did not pick nvidia decoder plugin.\n") | |
def decodebin_child_added(self, child_proxy, Object, name, user_data): | |
print("Decodebin child added:", name, "\n") | |
if name.find("decodebin") != -1: | |
Object.connect("child-added", self.decodebin_child_added, user_data) | |
def create_source_bin(self, id, uri): | |
print("Creating source bin") | |
# Create a source GstBin to abstract this bin's content from the rest of the | |
# pipeline | |
bin_name = "source-bin-%02d" % id | |
print(bin_name) | |
nbin = Gst.Bin.new(bin_name) | |
if not nbin: | |
sys.stderr.write(" Unable to create source bin \n") | |
# Source element for reading from the uri. | |
# We will use decodebin and let it figure out the container format of the | |
# stream and the codec and plug the appropriate demux and decode plugins. | |
uri_decode_bin = Gst.ElementFactory.make("uridecodebin", "uri-decode-bin") | |
if not uri_decode_bin: | |
sys.stderr.write(" Unable to create uri decode bin \n") | |
# We set the input uri to the source element | |
uri_decode_bin.set_property("uri", uri) | |
# Connect to the "pad-added" signal of the decodebin which generates a | |
# callback once a new pad for raw data has been created by the decodebin | |
uri_decode_bin.connect("pad-added", self.cb_newpad, nbin) | |
uri_decode_bin.connect("child-added", self.decodebin_child_added, nbin) | |
# We need to create a ghost pad for the source bin which will act as a proxy | |
# for the video decoder src pad. The ghost pad will not have a target right | |
# now. Once the decode bin creates the video decoder and generates the | |
# cb_newpad callback, we will set the ghost pad target to the video decoder | |
# src pad. | |
Gst.Bin.add(nbin, uri_decode_bin) | |
bin_pad = nbin.add_pad( | |
Gst.GhostPad.new_no_target( | |
"src", Gst.PadDirection.SRC)) | |
if not bin_pad: | |
sys.stderr.write(" Failed to add ghost pad in source bin \n") | |
return None | |
return nbin | |
if __name__ == "__main__": | |
PipelineManager() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
mkdir -p /src/models/yoloV3 | |
cd /src/models/yoloV3 | |
# Download data | |
wget https://raw.githubusercontent.com/pjreddie/darknet/master/cfg/yolov3.cfg | |
wget https://pjreddie.com/media/files/yolov3.weights | |
# Copy calibration from sample | |
cp /opt/nvidia/deepstream/deepstream-6.0/sources/objectDetector_Yolo/yolov3-calibration.table.trt7.0 /src/models/yoloV3 | |
# Build plugin | |
cd /opt/nvidia/deepstream/deepstream-6.0/sources/objectDetector_Yolo/ | |
# wget https://forums.developer.nvidia.com/uploads/short-url/oezjVVUIuYdfJ8BdTJWNmIBVawl.patch -O DS6.0GA_objectDetector_Yolo_perf_regression.patch | |
#patch -t -p1 < DS6.0GA_objectDetector_Yolo_perf_regression.patch | |
CUDA_VER=11.4 make -C nvdsinfer_custom_impl_Yolo | |
mkdir /src/models/yoloV3/nvdsinfer_custom_impl_Yolo | |
cp /opt/nvidia/deepstream/deepstream-6.0/sources/objectDetector_Yolo/nvdsinfer_custom_impl_Yolo/libnvdsinfer_custom_impl_Yolo.so /src/models/yoloV3/nvdsinfer_custom_impl_Yolo |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment