edgefirst-validator 4.2.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- deepview/modelpack/utils/argmax.py +16 -0
- edgefirst/validator/__init__.py +1 -0
- edgefirst/validator/__main__.py +375 -0
- edgefirst/validator/datasets/__init__.py +118 -0
- edgefirst/validator/datasets/cache.py +296 -0
- edgefirst/validator/datasets/core.py +250 -0
- edgefirst/validator/datasets/darknet.py +446 -0
- edgefirst/validator/datasets/database.py +1067 -0
- edgefirst/validator/datasets/instance/__init__.py +4 -0
- edgefirst/validator/datasets/instance/core.py +222 -0
- edgefirst/validator/datasets/instance/detection.py +145 -0
- edgefirst/validator/datasets/instance/multitask.py +80 -0
- edgefirst/validator/datasets/instance/segmentation.py +120 -0
- edgefirst/validator/datasets/utils/fetch.py +682 -0
- edgefirst/validator/datasets/utils/readers.py +425 -0
- edgefirst/validator/datasets/utils/transformations.py +1695 -0
- edgefirst/validator/evaluators/__init__.py +17 -0
- edgefirst/validator/evaluators/callbacks/__init__.py +3 -0
- edgefirst/validator/evaluators/callbacks/core.py +192 -0
- edgefirst/validator/evaluators/callbacks/plots.py +900 -0
- edgefirst/validator/evaluators/callbacks/studio.py +234 -0
- edgefirst/validator/evaluators/core.py +257 -0
- edgefirst/validator/evaluators/detection.py +749 -0
- edgefirst/validator/evaluators/multitask.py +270 -0
- edgefirst/validator/evaluators/parameters/__init__.py +53 -0
- edgefirst/validator/evaluators/parameters/core.py +554 -0
- edgefirst/validator/evaluators/parameters/dataset.py +239 -0
- edgefirst/validator/evaluators/parameters/model.py +338 -0
- edgefirst/validator/evaluators/parameters/validation.py +528 -0
- edgefirst/validator/evaluators/segmentation.py +729 -0
- edgefirst/validator/evaluators/utils/__init__.py +3 -0
- edgefirst/validator/evaluators/utils/classify.py +292 -0
- edgefirst/validator/evaluators/utils/match.py +262 -0
- edgefirst/validator/evaluators/utils/timer.py +132 -0
- edgefirst/validator/metrics/__init__.py +9 -0
- edgefirst/validator/metrics/data/__init__.py +7 -0
- edgefirst/validator/metrics/data/label.py +668 -0
- edgefirst/validator/metrics/data/metrics.py +759 -0
- edgefirst/validator/metrics/data/plots.py +476 -0
- edgefirst/validator/metrics/data/stats.py +507 -0
- edgefirst/validator/metrics/detection.py +595 -0
- edgefirst/validator/metrics/segmentation.py +173 -0
- edgefirst/validator/metrics/utils/math.py +717 -0
- edgefirst/validator/publishers/__init__.py +3 -0
- edgefirst/validator/publishers/console.py +147 -0
- edgefirst/validator/publishers/studio.py +128 -0
- edgefirst/validator/publishers/tensorboard.py +119 -0
- edgefirst/validator/publishers/utils/logger.py +111 -0
- edgefirst/validator/publishers/utils/table.py +403 -0
- edgefirst/validator/runners/__init__.py +8 -0
- edgefirst/validator/runners/core.py +727 -0
- edgefirst/validator/runners/deepviewrt.py +177 -0
- edgefirst/validator/runners/hailo.py +263 -0
- edgefirst/validator/runners/keras.py +150 -0
- edgefirst/validator/runners/kinara.py +265 -0
- edgefirst/validator/runners/offline.py +228 -0
- edgefirst/validator/runners/onnx.py +241 -0
- edgefirst/validator/runners/processing/decode.py +320 -0
- edgefirst/validator/runners/processing/dvapi.py +4192 -0
- edgefirst/validator/runners/processing/nms.py +637 -0
- edgefirst/validator/runners/processing/outputs.py +507 -0
- edgefirst/validator/runners/tensorrt.py +321 -0
- edgefirst/validator/runners/tflite.py +221 -0
- edgefirst/validator/validate.py +843 -0
- edgefirst/validator/visualize/__init__.py +3 -0
- edgefirst/validator/visualize/detection.py +623 -0
- edgefirst/validator/visualize/segmentation.py +281 -0
- edgefirst/validator/visualize/utils/plots.py +635 -0
- edgefirst_validator-4.2.1.dist-info/METADATA +111 -0
- edgefirst_validator-4.2.1.dist-info/RECORD +73 -0
- edgefirst_validator-4.2.1.dist-info/WHEEL +5 -0
- edgefirst_validator-4.2.1.dist-info/entry_points.txt +2 -0
- edgefirst_validator-4.2.1.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import time
|
|
5
|
+
import threading
|
|
6
|
+
from typing import TYPE_CHECKING, Any
|
|
7
|
+
|
|
8
|
+
import numpy as np
|
|
9
|
+
|
|
10
|
+
from edgefirst.validator.runners.processing.decode import dequantize_kinara
|
|
11
|
+
from edgefirst.validator.runners.core import Runner
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from edgefirst.validator.evaluators import ModelParameters, TimerContext
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class KinaraRunner(Runner):
|
|
18
|
+
"""
|
|
19
|
+
Loads and runs Kinara models for inference.
|
|
20
|
+
|
|
21
|
+
Parameters
|
|
22
|
+
----------
|
|
23
|
+
model: Any
|
|
24
|
+
This is typically the path to the model (.dvm)
|
|
25
|
+
or the loaded Kinara model.
|
|
26
|
+
parameters: ModelParameters
|
|
27
|
+
These are the model parameters set from the command line.
|
|
28
|
+
metadata: dict
|
|
29
|
+
The model metadata which contains information for decoding
|
|
30
|
+
the model outputs.
|
|
31
|
+
timer: TimerContext
|
|
32
|
+
A timer object for handling validation timings for the model.
|
|
33
|
+
socket_path : str, optional
|
|
34
|
+
Path to the UNIX socket for DVSession.
|
|
35
|
+
|
|
36
|
+
Raises
|
|
37
|
+
------
|
|
38
|
+
ImportError
|
|
39
|
+
Missing Kinara library.
|
|
40
|
+
FileNotFoundError
|
|
41
|
+
Raised if the path to the model does not exist.
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
def __init__(
|
|
45
|
+
self,
|
|
46
|
+
model: Any,
|
|
47
|
+
parameters: ModelParameters,
|
|
48
|
+
metadata: dict,
|
|
49
|
+
timer: TimerContext,
|
|
50
|
+
socket_path: str = "/var/run/ara2.sock"
|
|
51
|
+
):
|
|
52
|
+
super(KinaraRunner, self).__init__(model, parameters, timer)
|
|
53
|
+
|
|
54
|
+
self.socket_path = socket_path
|
|
55
|
+
self.conn = None
|
|
56
|
+
self.endpoints = None
|
|
57
|
+
self.loaded_model = None
|
|
58
|
+
self._lock = threading.Lock()
|
|
59
|
+
self.start()
|
|
60
|
+
|
|
61
|
+
if isinstance(model, str):
|
|
62
|
+
if not os.path.exists(model):
|
|
63
|
+
raise FileNotFoundError(
|
|
64
|
+
"The model '{}' does not exist.".format(model))
|
|
65
|
+
self.load_model(model)
|
|
66
|
+
|
|
67
|
+
self.input_param = self.model.input_param[0]
|
|
68
|
+
self.preprocess_param = self.input_param.preprocess_param
|
|
69
|
+
self.parameters.common.input_quantization = (
|
|
70
|
+
self.preprocess_param.qn, self.preprocess_param.offset)
|
|
71
|
+
|
|
72
|
+
outputs = []
|
|
73
|
+
for output_param in self.model.output_param:
|
|
74
|
+
bpp = output_param.bpp
|
|
75
|
+
dtype = np.int8
|
|
76
|
+
if bpp == 1:
|
|
77
|
+
dtype = (np.int8 if output_param.postprocess_param.is_signed
|
|
78
|
+
else np.uint8)
|
|
79
|
+
elif bpp == 2:
|
|
80
|
+
dtype = (np.int16 if output_param.postprocess_param.is_signed
|
|
81
|
+
else np.uint16)
|
|
82
|
+
elif bpp == 4:
|
|
83
|
+
dtype = (np.int32 if output_param.postprocess_param.is_signed
|
|
84
|
+
else np.uint32)
|
|
85
|
+
|
|
86
|
+
outputs.append(
|
|
87
|
+
{
|
|
88
|
+
"shape": np.array([1, output_param.nch,
|
|
89
|
+
output_param.height]),
|
|
90
|
+
"quantization": [output_param.postprocess_param.qn,
|
|
91
|
+
output_param.postprocess_param.offset],
|
|
92
|
+
"channels_first": False,
|
|
93
|
+
"dtype": dtype
|
|
94
|
+
}
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
self.init_decoder(metadata=metadata, outputs=outputs)
|
|
98
|
+
if self.parameters.warmup > 0:
|
|
99
|
+
self.warmup()
|
|
100
|
+
|
|
101
|
+
def start(self):
|
|
102
|
+
"""
|
|
103
|
+
Start DVSession and fetch available endpoints.
|
|
104
|
+
|
|
105
|
+
Raises
|
|
106
|
+
------
|
|
107
|
+
RuntimeError
|
|
108
|
+
If session creation or endpoint retrieval fails.
|
|
109
|
+
"""
|
|
110
|
+
from edgefirst.validator.runners.processing.dvapi import DVSession
|
|
111
|
+
|
|
112
|
+
ret, self.conn = DVSession.create_via_unix_socket(self.socket_path)
|
|
113
|
+
if ret != 0:
|
|
114
|
+
raise RuntimeError("Failed to create DVSession")
|
|
115
|
+
ret, self.endpoints = self.conn.get_endpoint_list()
|
|
116
|
+
if ret != 0:
|
|
117
|
+
raise RuntimeError("Failed to get endpoints")
|
|
118
|
+
|
|
119
|
+
def load_model(self, model_path: str):
|
|
120
|
+
"""
|
|
121
|
+
Load model from file into DVM endpoint.
|
|
122
|
+
|
|
123
|
+
Parameters
|
|
124
|
+
----------
|
|
125
|
+
model_path : str
|
|
126
|
+
Path to the model file to load.
|
|
127
|
+
|
|
128
|
+
Raises
|
|
129
|
+
------
|
|
130
|
+
RuntimeError
|
|
131
|
+
If model loading fails.
|
|
132
|
+
"""
|
|
133
|
+
with self._lock:
|
|
134
|
+
ret, self.model = self.conn.load_model_from_file(
|
|
135
|
+
endpoint=self.endpoints[0], model_path=model_path)
|
|
136
|
+
if ret != 0:
|
|
137
|
+
raise RuntimeError("Failed to load model")
|
|
138
|
+
|
|
139
|
+
def infer(self, input_tensor, timeout: int = 50000):
|
|
140
|
+
"""
|
|
141
|
+
Run synchronous inference on input tensor.
|
|
142
|
+
|
|
143
|
+
Parameters
|
|
144
|
+
----------
|
|
145
|
+
image : DVTensor
|
|
146
|
+
Input tensor for inference.
|
|
147
|
+
timeout : int, optional
|
|
148
|
+
Timeout in milliseconds for inference.
|
|
149
|
+
|
|
150
|
+
Returns
|
|
151
|
+
-------
|
|
152
|
+
List[DVTensor]
|
|
153
|
+
Inference response outputs from the model.
|
|
154
|
+
|
|
155
|
+
Raises
|
|
156
|
+
------
|
|
157
|
+
RuntimeError
|
|
158
|
+
If inference execution fails.
|
|
159
|
+
"""
|
|
160
|
+
# thread-safe single-call wrapper
|
|
161
|
+
with self._lock:
|
|
162
|
+
ret, response = self.model.infer_sync(
|
|
163
|
+
[input_tensor], timeout=timeout, endpoint=self.endpoints[0])
|
|
164
|
+
if ret != 0:
|
|
165
|
+
raise RuntimeError("Inference failed")
|
|
166
|
+
return response
|
|
167
|
+
|
|
168
|
+
def run_single_instance(self, image: np.ndarray) -> Any:
|
|
169
|
+
"""
|
|
170
|
+
Run Kinara inference on a single image and record the timings.
|
|
171
|
+
|
|
172
|
+
Parameters
|
|
173
|
+
----------
|
|
174
|
+
image: np.ndarray
|
|
175
|
+
The input image after being preprocessed.
|
|
176
|
+
Typically this is an RGB image array.
|
|
177
|
+
|
|
178
|
+
Returns
|
|
179
|
+
-------
|
|
180
|
+
Any
|
|
181
|
+
This could either return detection outputs after NMS.
|
|
182
|
+
np.ndarray
|
|
183
|
+
The prediction bounding boxes.. [[box1], [box2], ...].
|
|
184
|
+
np.ndarray
|
|
185
|
+
The prediction labels.. [cl1, cl2, ...].
|
|
186
|
+
np.ndarray
|
|
187
|
+
The prediction confidence scores.. [score, score, ...]
|
|
188
|
+
normalized between 0 and 1.
|
|
189
|
+
This could also return segmentation masks.
|
|
190
|
+
np.ndarray
|
|
191
|
+
"""
|
|
192
|
+
from edgefirst.validator.runners.processing.dvapi import DVTensor
|
|
193
|
+
|
|
194
|
+
start = time.perf_counter()
|
|
195
|
+
input_tensor = DVTensor(image.flatten(), self.input_param)
|
|
196
|
+
elapsed = time.perf_counter() - start
|
|
197
|
+
# Converting the tensor as part of the preprocess time.
|
|
198
|
+
self.timer.add_time("input", elapsed * 1e3) # Convert to ms.
|
|
199
|
+
|
|
200
|
+
# Inference
|
|
201
|
+
with self.timer.time("inference"):
|
|
202
|
+
response = self.infer(input_tensor)
|
|
203
|
+
|
|
204
|
+
start = time.perf_counter()
|
|
205
|
+
output = dequantize_kinara(
|
|
206
|
+
response.get_output_tensors(),
|
|
207
|
+
method=self.parameters.nms)
|
|
208
|
+
|
|
209
|
+
outputs = []
|
|
210
|
+
for meta in self.outputs.metadata["outputs"]:
|
|
211
|
+
outputs.append(
|
|
212
|
+
output[meta["index"]].reshape(meta["shape"])
|
|
213
|
+
)
|
|
214
|
+
elapsed = time.perf_counter() - start
|
|
215
|
+
|
|
216
|
+
# Postprocessing
|
|
217
|
+
outputs = self.postprocessing(outputs)
|
|
218
|
+
|
|
219
|
+
# Fetching the tensor as part of the postprocess time.
|
|
220
|
+
self.timer.add_time("output", elapsed * 1e3) # Convert to ms.
|
|
221
|
+
|
|
222
|
+
return outputs
|
|
223
|
+
|
|
224
|
+
def stop(self):
|
|
225
|
+
"""
|
|
226
|
+
Close DVSession connection gracefully.
|
|
227
|
+
Attempts to close the session and suppresses any exceptions.
|
|
228
|
+
"""
|
|
229
|
+
try:
|
|
230
|
+
self.conn.close()
|
|
231
|
+
except Exception:
|
|
232
|
+
try:
|
|
233
|
+
self.conn.__exit__(None, None, None)
|
|
234
|
+
except Exception:
|
|
235
|
+
pass
|
|
236
|
+
|
|
237
|
+
def get_input_type(self):
|
|
238
|
+
"""
|
|
239
|
+
This returns the input type of the model. Kinara models
|
|
240
|
+
are always quantized in either INT8 or UINT8 datatypes.
|
|
241
|
+
|
|
242
|
+
Returns
|
|
243
|
+
-------
|
|
244
|
+
np.dtype
|
|
245
|
+
The input type of the model.
|
|
246
|
+
"""
|
|
247
|
+
if self.preprocess_param.is_signed:
|
|
248
|
+
return np.int8
|
|
249
|
+
return np.uint8
|
|
250
|
+
|
|
251
|
+
def get_input_shape(self):
|
|
252
|
+
"""
|
|
253
|
+
This fetches the model input shape. Kinara models are
|
|
254
|
+
always channels first.
|
|
255
|
+
|
|
256
|
+
Returns
|
|
257
|
+
-------
|
|
258
|
+
np.ndarray
|
|
259
|
+
The model input shape (batch size, channels, height, width).
|
|
260
|
+
"""
|
|
261
|
+
input_shape = (self.input_param.batch_size,
|
|
262
|
+
self.input_param.nch,
|
|
263
|
+
self.input_param.height,
|
|
264
|
+
self.input_param.width)
|
|
265
|
+
return input_shape
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import json
|
|
5
|
+
import warnings
|
|
6
|
+
from typing import TYPE_CHECKING, Any
|
|
7
|
+
|
|
8
|
+
import numpy as np
|
|
9
|
+
|
|
10
|
+
from edgefirst.validator.datasets.utils.transformations import (xcycwh2xyxy,
|
|
11
|
+
xywh2xyxy)
|
|
12
|
+
from edgefirst.validator.datasets.utils.fetch import get_shape
|
|
13
|
+
from edgefirst.validator.runners.core import Runner
|
|
14
|
+
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
from edgefirst.validator.evaluators import ModelParameters, TimerContext
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class OfflineRunner(Runner):
|
|
20
|
+
"""
|
|
21
|
+
This class reads model detection annotations stored in text files
|
|
22
|
+
that are in YOLO format. For more information on the YOLO format visit:
|
|
23
|
+
https://support.deepviewml.com/hc/en-us/articles/10869801702029
|
|
24
|
+
|
|
25
|
+
*Note: These text files should also include the model prediction scores
|
|
26
|
+
which adds to the YOLO format: [cls score xc yc width height]*
|
|
27
|
+
|
|
28
|
+
Use Case: PT models are ran using https://github.com/ultralytics/yolov5
|
|
29
|
+
repository. These model predictions will be stored in TXT files that
|
|
30
|
+
are in YOLO format. This class will read the text files to be validated.
|
|
31
|
+
|
|
32
|
+
Parameters
|
|
33
|
+
----------
|
|
34
|
+
annotation_source: str
|
|
35
|
+
This is the path to the model prediction annotations
|
|
36
|
+
stored in text files with YOLO format annotations.
|
|
37
|
+
[cls score xc yc width height].
|
|
38
|
+
parameters: ModelParameters
|
|
39
|
+
These are the model parameters set from the command line.
|
|
40
|
+
annotation_extension: str
|
|
41
|
+
This represents the extension of the files that store
|
|
42
|
+
the prediction annotations. Only text files is supported
|
|
43
|
+
at the moment.
|
|
44
|
+
timer: TimerContext
|
|
45
|
+
A timer object for handling validation timings for the model.
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
def __init__(
|
|
49
|
+
self,
|
|
50
|
+
annotation_source: str,
|
|
51
|
+
parameters: ModelParameters,
|
|
52
|
+
timer: TimerContext,
|
|
53
|
+
annotation_extension='txt'
|
|
54
|
+
):
|
|
55
|
+
super(OfflineRunner, self).__init__(
|
|
56
|
+
annotation_source, parameters, timer=timer)
|
|
57
|
+
|
|
58
|
+
self.annotation_extension = annotation_extension
|
|
59
|
+
if self.parameters.box_format not in ['xcycwh', 'xywh', 'xyxy']:
|
|
60
|
+
raise ValueError(
|
|
61
|
+
f"Unknown annotation format provided {self.parameters.box_format}.")
|
|
62
|
+
|
|
63
|
+
self.transformer = None
|
|
64
|
+
if self.parameters.box_format == 'xcycwh':
|
|
65
|
+
self.transformer = xcycwh2xyxy
|
|
66
|
+
elif self.parameters.box_format == 'xywh':
|
|
67
|
+
self.transformer = xywh2xyxy
|
|
68
|
+
else:
|
|
69
|
+
self.transformer = None
|
|
70
|
+
|
|
71
|
+
self.parameters.common.with_boxes = True
|
|
72
|
+
self.parameters.common.with_masks = False
|
|
73
|
+
|
|
74
|
+
self.__timings = {
|
|
75
|
+
'min_read_time': 0,
|
|
76
|
+
'max_read_time': 0,
|
|
77
|
+
'min_load_time': 0,
|
|
78
|
+
'max_load_time': 0,
|
|
79
|
+
'min_backbone_time': 0,
|
|
80
|
+
'max_backbone_time': 0,
|
|
81
|
+
'min_decode_time': 0,
|
|
82
|
+
'max_decode_time': 0,
|
|
83
|
+
'min_box_time': 0,
|
|
84
|
+
'max_box_time': 0,
|
|
85
|
+
'avg_read_time': 0,
|
|
86
|
+
'avg_load_time': 0,
|
|
87
|
+
'avg_backbone_time': 0,
|
|
88
|
+
'avg_decode_time': 0,
|
|
89
|
+
'avg_box_time': 0,
|
|
90
|
+
}
|
|
91
|
+
timings_path = os.path.join(annotation_source, "timings.json")
|
|
92
|
+
if os.path.exists(timings_path):
|
|
93
|
+
timings = {}
|
|
94
|
+
with open(timings_path) as file:
|
|
95
|
+
timings: dict = json.load(file)
|
|
96
|
+
self.parameters.engine = timings.get("engine", "cpu")
|
|
97
|
+
self.parameters.max_detections = timings.get("max_boxes", None)
|
|
98
|
+
self.parameters.iou_threshold = timings.get("iou", None)
|
|
99
|
+
self.parameters.score_threshold = timings.get("threshold", None)
|
|
100
|
+
self.parameters.common.shape = timings.get(
|
|
101
|
+
"shape", (1, 640, 640, 3))
|
|
102
|
+
self.parameters.common.dtype = timings.get("dtype", "float32")
|
|
103
|
+
self.parameters.warmup = None
|
|
104
|
+
self.__timings = timings.get("timings", {})
|
|
105
|
+
else:
|
|
106
|
+
# OFfline validation is not concerned with these parameters.
|
|
107
|
+
self.parameters.engine = "cpu"
|
|
108
|
+
self.parameters.nms = None
|
|
109
|
+
self.parameters.max_detections = None
|
|
110
|
+
self.parameters.iou_threshold = None
|
|
111
|
+
self.parameters.score_threshold = None
|
|
112
|
+
self.parameters.warmup = None
|
|
113
|
+
self.parameters.common.shape = (1, 640, 640, 3)
|
|
114
|
+
self.parameters.common.dtype = "float32"
|
|
115
|
+
timer.to_dict = self.get_timings
|
|
116
|
+
|
|
117
|
+
height, width = get_shape(self.parameters.common.shape)
|
|
118
|
+
try:
|
|
119
|
+
import edgefirst_python # type: ignore
|
|
120
|
+
self.parameters.common.input_dst = edgefirst_python.TensorImage(
|
|
121
|
+
width, height, edgefirst_python.FourCC.RGBA
|
|
122
|
+
)
|
|
123
|
+
except ImportError:
|
|
124
|
+
if self.parameters.common.backend == "hal":
|
|
125
|
+
raise ImportError(
|
|
126
|
+
"EdgeFirst HAL is needed to create a TensorImage destination."
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
def run_single_instance(self, image: str) -> Any:
|
|
130
|
+
"""
|
|
131
|
+
This method reads one prediction annotation file based on the
|
|
132
|
+
image name and returns the bounding boxes and labels.
|
|
133
|
+
|
|
134
|
+
Parameters
|
|
135
|
+
----------
|
|
136
|
+
image: str
|
|
137
|
+
The path to the image. This is used to match the
|
|
138
|
+
annotation to be read.
|
|
139
|
+
|
|
140
|
+
Returns
|
|
141
|
+
-------
|
|
142
|
+
Any:
|
|
143
|
+
This could either return detection outputs after NMS.
|
|
144
|
+
np.ndarray
|
|
145
|
+
The prediction bounding boxes.. [[box1], [box2], ...].
|
|
146
|
+
np.ndarray
|
|
147
|
+
The prediction labels.. [cl1, cl2, ...].
|
|
148
|
+
np.ndarray
|
|
149
|
+
The prediction confidence scores.. [score, score, ...]
|
|
150
|
+
normalized between 0 and 1.
|
|
151
|
+
This could also return segmentation masks.
|
|
152
|
+
np.ndarray
|
|
153
|
+
"""
|
|
154
|
+
annotation_path = os.path.join(self.model, "{}.{}".format(
|
|
155
|
+
os.path.splitext(os.path.basename(image))[0],
|
|
156
|
+
self.annotation_extension
|
|
157
|
+
))
|
|
158
|
+
|
|
159
|
+
try:
|
|
160
|
+
with warnings.catch_warnings():
|
|
161
|
+
warnings.simplefilter("ignore")
|
|
162
|
+
annotation = np.genfromtxt(annotation_path)
|
|
163
|
+
except FileNotFoundError:
|
|
164
|
+
return np.array([], dtype=np.float32), \
|
|
165
|
+
np.array([], dtype=np.int32), np.array([], dtype=np.float32)
|
|
166
|
+
|
|
167
|
+
if len(annotation):
|
|
168
|
+
annotation = annotation.reshape(-1, 6)
|
|
169
|
+
boxes = annotation[:, 2:6]
|
|
170
|
+
boxes = self.transformer(boxes) if self.transformer else boxes
|
|
171
|
+
else:
|
|
172
|
+
return np.array([], dtype=np.float32), \
|
|
173
|
+
np.array([], dtype=np.int32), np.array([], dtype=np.float32)
|
|
174
|
+
|
|
175
|
+
scores = annotation[:, 1:2].flatten().astype(np.float32)
|
|
176
|
+
labels = annotation[:, 0:1].flatten().astype(
|
|
177
|
+
np.int32) + self.parameters.label_offset
|
|
178
|
+
|
|
179
|
+
return boxes, labels, scores
|
|
180
|
+
|
|
181
|
+
def get_timings(self) -> dict:
|
|
182
|
+
"""
|
|
183
|
+
Returns a summary of all the timings:
|
|
184
|
+
(mean, avg, max) of (load, inference, box).
|
|
185
|
+
|
|
186
|
+
Returns
|
|
187
|
+
-------
|
|
188
|
+
dict
|
|
189
|
+
The timings in milliseconds.
|
|
190
|
+
|
|
191
|
+
.. code-block:: python
|
|
192
|
+
|
|
193
|
+
{
|
|
194
|
+
'min_read_time': minimum time to read the input,
|
|
195
|
+
'max_read_time': maximum time to read the input,
|
|
196
|
+
'min_load_time': minimum time to preprocess the input,
|
|
197
|
+
'max_load_time': maximum time to preprocess the input,
|
|
198
|
+
'min_backbone_time': minimum time to run the model,
|
|
199
|
+
'max_backbone_time': maximum time to run the model,
|
|
200
|
+
'min_decode_time': minimum time to decode the outputs,
|
|
201
|
+
'max_decode_time': maximum time to decode the outputs,
|
|
202
|
+
'min_box_time': minimum time to process the outputs,
|
|
203
|
+
'max_box_time': maximum time to process the outputs,
|
|
204
|
+
'avg_read_time': average time to read the input,
|
|
205
|
+
'avg_load_time': average time to preprocess the input,
|
|
206
|
+
'avg_backbone_time': average time to run the model,
|
|
207
|
+
'avg_decode_time': average time to decode the outputs,
|
|
208
|
+
'avg_box_time': average time to process the outputs,
|
|
209
|
+
}
|
|
210
|
+
"""
|
|
211
|
+
# Convert timings to ms.
|
|
212
|
+
return {
|
|
213
|
+
'min_read_time': self.__timings.get("min_read_time", 0) * 1e3,
|
|
214
|
+
'max_read_time': self.__timings.get("max_read_time", 0) * 1e3,
|
|
215
|
+
'min_load_time': self.__timings.get("min_load_time", 0) * 1e3,
|
|
216
|
+
'max_load_time': self.__timings.get("max_load_time", 0) * 1e3,
|
|
217
|
+
'min_backbone_time': self.__timings.get("min_backbone_time", 0) * 1e3,
|
|
218
|
+
'max_backbone_time': self.__timings.get("max_backbone_time", 0) * 1e3,
|
|
219
|
+
'min_decode_time': self.__timings.get("min_decode_time", 0) * 1e3,
|
|
220
|
+
'max_decode_time': self.__timings.get("max_decode_time", 0) * 1e3,
|
|
221
|
+
'min_box_time': self.__timings.get("min_box_time", 0) * 1e3,
|
|
222
|
+
'max_box_time': self.__timings.get("max_box_time", 0) * 1e3,
|
|
223
|
+
'avg_read_time': self.__timings.get("avg_read_time", 0) * 1e3,
|
|
224
|
+
'avg_load_time': self.__timings.get("avg_load_time", 0) * 1e3,
|
|
225
|
+
'avg_backbone_time': self.__timings.get("avg_backbone_time", 0) * 1e3,
|
|
226
|
+
'avg_decode_time': self.__timings.get("avg_decode_time", 0) * 1e3,
|
|
227
|
+
'avg_box_time': self.__timings.get("avg_box_time", 0) * 1e3,
|
|
228
|
+
}
|