Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make timer available from Pipeline #1075

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/deepsparse/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ def __init__(
self.engine = self._initialize_engine()

self._batch_size = self._batch_size or 1
self._timer = Timer()

self.log(
identifier=f"{SystemGroups.INFERENCE_DETAILS}/num_cores_total",
Expand Down Expand Up @@ -319,6 +320,8 @@ def __call__(self, *args, **kwargs) -> BaseModel:
category=MetricCategories.SYSTEM,
)

self._timer = timer

return pipeline_outputs

@staticmethod
Expand Down Expand Up @@ -704,6 +707,13 @@ def engine_type(self) -> str:
"""
return self._engine_type

@property
def timer(self) -> Timer:
"""
:return: reference to timer used for latest inference
"""
return self._timer

def to_config(self) -> "PipelineConfig":
"""
:return: PipelineConfig that can be used to reload this object
Expand Down
48 changes: 35 additions & 13 deletions src/deepsparse/utils/annotate.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@
import os
import shutil
import time
from collections import deque
from copy import copy
from pathlib import Path
from typing import Any, Callable, Iterable, Iterator, List, Optional, Tuple, Union

import numpy

from deepsparse.timing import InferencePhases
from sparsezoo.utils import create_dirs


Expand All @@ -42,6 +44,23 @@
__all__ = ["get_image_loader_and_saver", "get_annotations_save_dir", "annotate"]


class AverageFPS:
def __init__(self, num_samples=20):
self.frame_times = deque(maxlen=num_samples)

def measure(self, duration):
self.frame_times.append(duration)

def calculate(self):
if len(self.frame_times) > 1:
return numpy.average(self.frame_times)
else:
return 0.0


afps = AverageFPS()


def get_image_loader_and_saver(
path: str,
save_dir: str,
Expand All @@ -61,6 +80,19 @@ def get_image_loader_and_saver(
image_batch, video, or web-cam based on path given, and a boolean value
that is True is the returned objects load videos
"""
# webcam
if path.isnumeric():
loader = WebcamLoader(int(path), image_shape)
saver = (
VideoSaver(save_dir, 30, loader.original_frame_size, None)
if not no_save
else None
)
return loader, saver, True

if no_save:
print("no_save ignored since not using webcam")

# video
if path.endswith(".mp4"):
loader = VideoLoader(path, image_shape)
Expand All @@ -71,15 +103,7 @@ def get_image_loader_and_saver(
target_fps,
)
return loader, saver, True
# webcam
if path.isnumeric():
loader = WebcamLoader(int(path), image_shape)
saver = (
VideoSaver(save_dir, 30, loader.original_frame_size, None)
if not no_save
else None
)
return loader, saver, True

# image file(s)
return ImageLoader(path, image_shape), ImageSaver(save_dir), False

Expand Down Expand Up @@ -364,13 +388,11 @@ def annotate(
if isinstance(original_image, str):
original_image = cv2.imread(image)

if target_fps is None and calc_fps:
start = time.perf_counter()

pipeline_output = pipeline(images=[image])

if target_fps is None and calc_fps:
target_fps = 1 / (time.perf_counter() - start)
afps.measure(1 / pipeline._timer.time_delta(InferencePhases.ENGINE_FORWARD))
target_fps = afps.calculate()

result = annotation_func(
image=original_image,
Expand Down
5 changes: 4 additions & 1 deletion src/deepsparse/yolo/annotate.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,8 +219,11 @@ def main(
)

if is_webcam:
cv2.namedWindow("annotated", cv2.WINDOW_NORMAL)
cv2.imshow("annotated", annotated_image)
cv2.waitKey(1)
ch = cv2.waitKey(1)
if ch == 27 or ch == ord("q") or ch == ord("Q"):
break

# save
if saver:
Expand Down
61 changes: 52 additions & 9 deletions src/deepsparse/yolo/utils/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -410,12 +410,12 @@ def modify_yolo_onnx_input_shape(
f"at {model_path} with the new input shape"
)
save_onnx(model, model_path)
return model_path
return model_path, None
else:
_LOGGER.info(
"Saving the ONNX model with the " "new input shape to a temporary file"
)
return save_onnx_to_temp_files(model, with_external_data=not inplace)
return save_onnx_to_temp_files(model, with_external_data=not inplace), None


def get_tensor_dim_shape(tensor: onnx.TensorProto, dim: int) -> int:
Expand Down Expand Up @@ -461,9 +461,11 @@ def annotate_image(

img_res = numpy.copy(image)

num_ppl = 0
for idx in range(len(boxes)):
label = labels[idx]
if scores[idx] > score_threshold:
num_ppl += 1 if label == "person" else 0
annotation_text = f"{label}: {scores[idx]:.0%}"

# bounding box points
Expand Down Expand Up @@ -509,13 +511,22 @@ def annotate_image(
)

if images_per_sec is not None:
img_res = _plot_fps(
img_res=img_res,
images_per_sec=images_per_sec,
x=20,
y=30,
font_scale=0.9,
thickness=2,
# img_res = _plot_fps(
# img_res=img_res,
# images_per_sec=images_per_sec,
# x=20,
# y=30,
# font_scale=0.9,
# thickness=2,
# )
img_res = _draw_text(
img_res,
f"FPS: {images_per_sec:0.1f} | People Count: {num_ppl} | YOLOv8 on DeepSparse",
pos=(10, 10),
font_scale=0.7,
text_color=(204, 85, 17),
text_color_bg=(255, 255, 255),
font_thickness=2,
)
return img_res

Expand Down Expand Up @@ -557,3 +568,35 @@ def _plot_fps(
cv2.LINE_AA,
)
return img_res


def _draw_text(
img: numpy.ndarray,
text: str,
font=cv2.FONT_HERSHEY_SIMPLEX,
pos=(0, 0),
font_scale=1,
font_thickness=2,
text_color=(0, 255, 0),
text_color_bg=(0, 0, 0),
):

offset = (5, 5)
x, y = pos
text_size, _ = cv2.getTextSize(text, font, font_scale, font_thickness)
text_w, text_h = text_size
rec_start = tuple(x - y for x, y in zip(pos, offset))
rec_end = tuple(x + y for x, y in zip((x + text_w, y + text_h), offset))
cv2.rectangle(img, rec_start, rec_end, text_color_bg, -1)
cv2.putText(
img,
text,
(x, int(y + text_h + font_scale - 1)),
font,
font_scale,
text_color,
font_thickness,
cv2.LINE_AA,
)

return text_size
5 changes: 4 additions & 1 deletion src/deepsparse/yolov8/annotate.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,8 +230,11 @@ def main(
)

if is_webcam:
cv2.namedWindow("annotated", cv2.WINDOW_NORMAL)
cv2.imshow("annotated", annotated_image)
cv2.waitKey(1)
ch = cv2.waitKey(1)
if ch == 27 or ch == ord("q") or ch == ord("Q"):
break

# save
if saver:
Expand Down