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.
Files changed (73) hide show
  1. deepview/modelpack/utils/argmax.py +16 -0
  2. edgefirst/validator/__init__.py +1 -0
  3. edgefirst/validator/__main__.py +375 -0
  4. edgefirst/validator/datasets/__init__.py +118 -0
  5. edgefirst/validator/datasets/cache.py +296 -0
  6. edgefirst/validator/datasets/core.py +250 -0
  7. edgefirst/validator/datasets/darknet.py +446 -0
  8. edgefirst/validator/datasets/database.py +1067 -0
  9. edgefirst/validator/datasets/instance/__init__.py +4 -0
  10. edgefirst/validator/datasets/instance/core.py +222 -0
  11. edgefirst/validator/datasets/instance/detection.py +145 -0
  12. edgefirst/validator/datasets/instance/multitask.py +80 -0
  13. edgefirst/validator/datasets/instance/segmentation.py +120 -0
  14. edgefirst/validator/datasets/utils/fetch.py +682 -0
  15. edgefirst/validator/datasets/utils/readers.py +425 -0
  16. edgefirst/validator/datasets/utils/transformations.py +1695 -0
  17. edgefirst/validator/evaluators/__init__.py +17 -0
  18. edgefirst/validator/evaluators/callbacks/__init__.py +3 -0
  19. edgefirst/validator/evaluators/callbacks/core.py +192 -0
  20. edgefirst/validator/evaluators/callbacks/plots.py +900 -0
  21. edgefirst/validator/evaluators/callbacks/studio.py +234 -0
  22. edgefirst/validator/evaluators/core.py +257 -0
  23. edgefirst/validator/evaluators/detection.py +749 -0
  24. edgefirst/validator/evaluators/multitask.py +270 -0
  25. edgefirst/validator/evaluators/parameters/__init__.py +53 -0
  26. edgefirst/validator/evaluators/parameters/core.py +554 -0
  27. edgefirst/validator/evaluators/parameters/dataset.py +239 -0
  28. edgefirst/validator/evaluators/parameters/model.py +338 -0
  29. edgefirst/validator/evaluators/parameters/validation.py +528 -0
  30. edgefirst/validator/evaluators/segmentation.py +729 -0
  31. edgefirst/validator/evaluators/utils/__init__.py +3 -0
  32. edgefirst/validator/evaluators/utils/classify.py +292 -0
  33. edgefirst/validator/evaluators/utils/match.py +262 -0
  34. edgefirst/validator/evaluators/utils/timer.py +132 -0
  35. edgefirst/validator/metrics/__init__.py +9 -0
  36. edgefirst/validator/metrics/data/__init__.py +7 -0
  37. edgefirst/validator/metrics/data/label.py +668 -0
  38. edgefirst/validator/metrics/data/metrics.py +759 -0
  39. edgefirst/validator/metrics/data/plots.py +476 -0
  40. edgefirst/validator/metrics/data/stats.py +507 -0
  41. edgefirst/validator/metrics/detection.py +595 -0
  42. edgefirst/validator/metrics/segmentation.py +173 -0
  43. edgefirst/validator/metrics/utils/math.py +717 -0
  44. edgefirst/validator/publishers/__init__.py +3 -0
  45. edgefirst/validator/publishers/console.py +147 -0
  46. edgefirst/validator/publishers/studio.py +128 -0
  47. edgefirst/validator/publishers/tensorboard.py +119 -0
  48. edgefirst/validator/publishers/utils/logger.py +111 -0
  49. edgefirst/validator/publishers/utils/table.py +403 -0
  50. edgefirst/validator/runners/__init__.py +8 -0
  51. edgefirst/validator/runners/core.py +727 -0
  52. edgefirst/validator/runners/deepviewrt.py +177 -0
  53. edgefirst/validator/runners/hailo.py +263 -0
  54. edgefirst/validator/runners/keras.py +150 -0
  55. edgefirst/validator/runners/kinara.py +265 -0
  56. edgefirst/validator/runners/offline.py +228 -0
  57. edgefirst/validator/runners/onnx.py +241 -0
  58. edgefirst/validator/runners/processing/decode.py +320 -0
  59. edgefirst/validator/runners/processing/dvapi.py +4192 -0
  60. edgefirst/validator/runners/processing/nms.py +637 -0
  61. edgefirst/validator/runners/processing/outputs.py +507 -0
  62. edgefirst/validator/runners/tensorrt.py +321 -0
  63. edgefirst/validator/runners/tflite.py +221 -0
  64. edgefirst/validator/validate.py +843 -0
  65. edgefirst/validator/visualize/__init__.py +3 -0
  66. edgefirst/validator/visualize/detection.py +623 -0
  67. edgefirst/validator/visualize/segmentation.py +281 -0
  68. edgefirst/validator/visualize/utils/plots.py +635 -0
  69. edgefirst_validator-4.2.1.dist-info/METADATA +111 -0
  70. edgefirst_validator-4.2.1.dist-info/RECORD +73 -0
  71. edgefirst_validator-4.2.1.dist-info/WHEEL +5 -0
  72. edgefirst_validator-4.2.1.dist-info/entry_points.txt +2 -0
  73. edgefirst_validator-4.2.1.dist-info/top_level.txt +2 -0
@@ -0,0 +1,554 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, List, Callable
4
+
5
+ import numpy as np
6
+
7
+ from edgefirst.validator.publishers.utils.logger import logger
8
+
9
+ if TYPE_CHECKING:
10
+ from edgefirst_python import TensorImage # type: ignore
11
+
12
+
13
+ class Parameters:
14
+ """
15
+ Parent parameters to contain common parameters between
16
+ the model, dataset, and validation.
17
+
18
+ Parameters
19
+ ----------
20
+ labels_path: str
21
+ The path to the labels.txt file containing unique string labels
22
+ from the model or the dataset.
23
+ labels: list
24
+ A list of unique string labels which is part of the model artifacts
25
+ for converting model output indices into strings.
26
+ label_offset: int
27
+ This is the offset to map the integer labels to string labels.
28
+ box_format: str
29
+ The output bounding box format of the model. Options could be one
30
+ of the following: "xyxy" (PascalVOC), "xywh" (COCO), or "xcycwh" (YOLO).
31
+ """
32
+
33
+ def __init__(
34
+ self,
35
+ labels_path: str = None,
36
+ labels: list = None,
37
+ label_offset: int = 0,
38
+ box_format: str = "xyxy",
39
+
40
+ ):
41
+ self.__labels_path = labels_path
42
+ self.__labels = labels
43
+ self.__label_offset = label_offset
44
+ self.__box_format = box_format.lower()
45
+
46
+ @property
47
+ def labels_path(self) -> str:
48
+ """
49
+ Attribute to access the labels_path.
50
+ This is the path to the labels.txt file. This contains unique string
51
+ labels from either the dataset or the model.
52
+
53
+ Returns
54
+ -------
55
+ str
56
+ The path to the labels.txt file.
57
+ """
58
+ return self.__labels_path
59
+
60
+ @labels_path.setter
61
+ def labels_path(self, path: str):
62
+ """
63
+ Set the path to the labels.txt file.
64
+
65
+ Parameters
66
+ ----------
67
+ path: str
68
+ The path to the labels.txt file.
69
+ """
70
+ self.__labels_path = path
71
+
72
+ @property
73
+ def labels(self) -> List[str]:
74
+ """
75
+ Attribute to access the model labels.
76
+ This is used for mapping the prediction integer indices to strings.
77
+
78
+ Returns
79
+ -------
80
+ List[str]
81
+ The list of unique string labels from the model.
82
+ """
83
+ return self.__labels
84
+
85
+ @labels.setter
86
+ def labels(self, this_labels: List[str]):
87
+ """
88
+ Sets the string labels for mapping the integer indices to
89
+ string representations.
90
+
91
+ Parameters
92
+ ----------
93
+ this_labels: List[str]
94
+ The labels to set.
95
+ """
96
+ self.__labels = this_labels
97
+
98
+ @property
99
+ def label_offset(self) -> int:
100
+ """
101
+ Attribute to access the label offset for the predictions.
102
+ This is used for mapping the prediction integer labels to strings.
103
+
104
+ Returns
105
+ -------
106
+ int
107
+ The label offset to map integer indices to string representations.
108
+ """
109
+ return self.__label_offset
110
+
111
+ @label_offset.setter
112
+ def label_offset(self, this_label_offset: int):
113
+ """
114
+ Sets the label offset for mapping the integer indices to
115
+ string representations.
116
+
117
+ Parameters
118
+ ----------
119
+ this_label_offset: int
120
+ The label_offset to set.
121
+ """
122
+ self.__label_offset = this_label_offset
123
+
124
+ @property
125
+ def box_format(self) -> str:
126
+ """
127
+ Attribute to access the box format.
128
+ The box format can either be: "xyxy", "xywh", "yxyx"
129
+
130
+ Returns
131
+ -------
132
+ str
133
+ The box format type.
134
+ """
135
+ return self.__box_format
136
+
137
+ @box_format.setter
138
+ def box_format(self, this_box_format: str):
139
+ """
140
+ Sets the box format type.
141
+
142
+ Parameters
143
+ ----------
144
+ this_box_format: str
145
+ The box format to set.
146
+ """
147
+ if this_box_format not in ['xcycwh', 'xywh', 'xyxy']:
148
+ raise ValueError(
149
+ f"Unsupported box format provided: {this_box_format}")
150
+ self.__box_format = this_box_format.lower()
151
+
152
+
153
+ class CommonParameters:
154
+ """
155
+ Parameters that are common between all three parameter types
156
+ where each of these parameters should remain consistent across
157
+ the model, dataset, and validation.
158
+
159
+ Parameters
160
+ ----------
161
+ with_boxes: bool
162
+ The condition of whether or not the dataset and the model both provide
163
+ bounding box detections.
164
+ with_masks: bool
165
+ The condition of whether or not the dataset and the model both provide
166
+ segmentation mask detections.
167
+ norm: str
168
+ The type of image normalization to match the model input requirements.
169
+ Options could be one of the following: "raw", "unsigned", "signed",
170
+ "imagenet", or "whitening".
171
+ preprocessing: str
172
+ The type of image preprocessing to apply to the image prior to model
173
+ inference. Options could be one of the following: "letterbox", "pad",
174
+ "resize".
175
+ shape: tuple
176
+ Specify the input shape of the model which is needed to transform
177
+ the input image to the size requirements.
178
+ dtype: str
179
+ The input data type of the model.
180
+ input_quantization: tuple
181
+ The model input quantization as part of the image preprocessing
182
+ for quantizing float32 outputs to integer types.
183
+ backend: str
184
+ The library to use for image loading and image preprocessing.
185
+ """
186
+
187
+ def __init__(
188
+ self,
189
+ with_boxes: bool = False,
190
+ with_masks: bool = False,
191
+ norm: str = "raw",
192
+ preprocessing: str = "letterbox",
193
+ shape: tuple = None,
194
+ dtype: str = "float32",
195
+ input_quantization: tuple = None,
196
+ backend: str = "hal",
197
+ ):
198
+
199
+ self.__with_boxes = with_boxes
200
+ self.__with_masks = with_masks
201
+ self.__norm = norm.lower()
202
+ self.__preprocessing = preprocessing.lower()
203
+ self.__shape = shape
204
+ self.__dtype = dtype
205
+ self.__input_quantization = input_quantization
206
+ self.__semantic = True
207
+ self.__input_tensor = None # NumPy view array for model direct copies.
208
+ self.__input_dst = None # Input TensorImage destination.
209
+ self.__backend = backend.lower()
210
+ # Condition whether to transpose the input image or not.
211
+ self.__transpose = False
212
+
213
+ def check_backend_availability(self):
214
+ """
215
+ Checks the backend availability and falls back on any
216
+ available backends starting from "hal" to "opencv" and then
217
+ to "pillow".
218
+ """
219
+ if self.backend == "hal":
220
+ try:
221
+ import edgefirst_python # type: ignore
222
+ except ImportError:
223
+ try:
224
+ import cv2 # type: ignore
225
+ self.backend = "opencv"
226
+ logger("HAL backend is not available. Falling back to OpenCV.",
227
+ code="WARNING")
228
+ except ImportError:
229
+ self.backend = "pillow"
230
+ logger("HAL and OpenCV backends are not available. "
231
+ "Falling back to Pillow.", code="WARNING")
232
+ elif self.backend == "opencv":
233
+ try:
234
+ import cv2 # type: ignore
235
+ except ImportError:
236
+ self.backend = "pillow"
237
+ logger("OpenCV backend is not available. Falling back to Pillow.",
238
+ code="WARNING")
239
+
240
+ @property
241
+ def with_boxes(self) -> bool:
242
+ """
243
+ Attribute to access with_boxes.
244
+ Specify whether the model or the dataset provides
245
+ bounding box annotations.
246
+
247
+ Returns
248
+ -------
249
+ bool
250
+ Condition for object detection (bounding box) validation.
251
+ """
252
+ return self.__with_boxes
253
+
254
+ @with_boxes.setter
255
+ def with_boxes(self, boxes: bool):
256
+ """
257
+ Specify condition for object detection (bounding box) validation.
258
+
259
+ Parameters
260
+ ----------
261
+ boxes: bool
262
+ The condition to set.
263
+ """
264
+ self.__with_boxes = boxes
265
+
266
+ @property
267
+ def with_masks(self) -> bool:
268
+ """
269
+ Attribute to access with_masks.
270
+ Specify whether the model or the dataset provides
271
+ segmentation annotations.
272
+
273
+ Returns
274
+ -------
275
+ bool
276
+ Condition for segmentation validation.
277
+ """
278
+ return self.__with_masks
279
+
280
+ @with_masks.setter
281
+ def with_masks(self, masks: bool):
282
+ """
283
+ Specify condition for segmentation validation.
284
+
285
+ Parameters
286
+ ----------
287
+ masks: bool
288
+ The condition to set.
289
+ """
290
+ self.__with_masks = masks
291
+
292
+ @property
293
+ def norm(self) -> str:
294
+ """
295
+ Attribute to access the image normalization type.
296
+ Typically quantized models use "raw" and floating point models
297
+ use "unsigned" or "signed".
298
+
299
+ Returns
300
+ -------
301
+ str
302
+ The image normalization type.
303
+ """
304
+ return self.__norm
305
+
306
+ @norm.setter
307
+ def norm(self, this_norm: str):
308
+ """
309
+ Sets the image normalization type.
310
+
311
+ Parameters
312
+ ----------
313
+ this_norm: str
314
+ The image normalization to set.
315
+ """
316
+ self.__norm = this_norm.lower() if this_norm is not None else this_norm
317
+
318
+ @property
319
+ def preprocessing(self) -> str:
320
+ """
321
+ Attribute to access the type of image preprocessing to perform.
322
+ Options can be "letterbox", "pad", or "resize".
323
+
324
+ Returns
325
+ -------
326
+ str
327
+ The type of image preprocessing to perform.
328
+ """
329
+ return self.__preprocessing
330
+
331
+ @preprocessing.setter
332
+ def preprocessing(self, preprocess: str):
333
+ """
334
+ Sets the type of image preprocessing to perform.
335
+
336
+ Parameters
337
+ ----------
338
+ preprocess: str
339
+ The type of image preprocessing to set. Options include
340
+ "letterbox", "pad", or "resize".
341
+ """
342
+ self.__preprocessing = (preprocess.lower() if
343
+ preprocess is not None else preprocess)
344
+
345
+ @property
346
+ def shape(self) -> tuple:
347
+ """
348
+ Attribute to access the model's input shape.
349
+
350
+ Returns
351
+ --------
352
+ tuple
353
+ The input shape of the model.
354
+ """
355
+ return self.__shape
356
+
357
+ @shape.setter
358
+ def shape(self, size: tuple):
359
+ """
360
+ Sets the input shape of the model.
361
+
362
+ Parameters
363
+ ----------
364
+ size: tuple
365
+ The model input shape to set.
366
+ """
367
+ self.__shape = size
368
+
369
+ @property
370
+ def dtype(self) -> np.dtype:
371
+ """
372
+ Attribute to access the model dtype.
373
+ By default this is set to "float32". However, possible
374
+ variations include "float16", "int8", "uint8", etc.
375
+
376
+ Returns
377
+ -------
378
+ np.dtype
379
+ The model datatype
380
+ """
381
+ return self.__dtype
382
+
383
+ @dtype.setter
384
+ def dtype(self, this_dtype: np.dtype):
385
+ """
386
+ Sets the model data type.
387
+
388
+ Parameters
389
+ ----------
390
+ this_dtype: np.dtype
391
+ The model data type to set.
392
+ """
393
+ self.__dtype = this_dtype
394
+
395
+ @property
396
+ def input_quantization(self) -> tuple:
397
+ """
398
+ Attribute to access the model input quantization.
399
+ This is a tuple that contains the (scale, zero_point) values
400
+ needed for quantizating the input to the model.
401
+ """
402
+ return self.__input_quantization
403
+
404
+ @input_quantization.setter
405
+ def input_quantization(self, quantization: tuple):
406
+ """
407
+ Sets the model input quantization.
408
+
409
+ Parameters
410
+ ----------
411
+ quantization: tuple
412
+ The input quantization containing the
413
+ (scale, zero_point) values.
414
+ """
415
+ self.__input_quantization = quantization
416
+
417
+ @property
418
+ def semantic(self) -> bool:
419
+ """
420
+ Attribute to access the semantic condition.
421
+
422
+ Returns
423
+ -------
424
+ bool
425
+ Specify to True if the model is a semantic segmentation
426
+ model as seen in ModelPack. Otherwise False for instance
427
+ segmentation as seen in Ultralytics.
428
+ """
429
+ return self.__semantic
430
+
431
+ @semantic.setter
432
+ def semantic(self, condition: bool):
433
+ """
434
+ Sets the specification if the model being validated
435
+ is semantic segmentation (True) or instance segmentation (False).
436
+
437
+ Parameters
438
+ ----------
439
+ condition: bool
440
+ Specify the semantic condition.
441
+ """
442
+ self.__semantic = condition
443
+
444
+ @property
445
+ def input_tensor(self) -> Callable:
446
+ """
447
+ Attribute to access the input tensor.
448
+
449
+ Returns
450
+ -------
451
+ Callable
452
+ Callable function for retrieving the input view tensor
453
+ from the model for directly copying the input tensor
454
+ into the model such as the case for TFLite.
455
+ """
456
+ return self.__input_tensor
457
+
458
+ @input_tensor.setter
459
+ def input_tensor(self, tensor: Callable):
460
+ """
461
+ Sets the input tensor.
462
+
463
+ Parameters
464
+ ----------
465
+ tensor: Callable
466
+ Callable function for retrieving the input view tensor
467
+ from the model for directly copying the input tensor
468
+ into the model such as the case for TFLite.
469
+ """
470
+ self.__input_tensor = tensor
471
+
472
+ @property
473
+ def input_dst(self) -> TensorImage:
474
+ """
475
+ Attribute to access the input destination.
476
+
477
+ Returns
478
+ -------
479
+ TensorImage
480
+ Optimization to initialize the input destination once
481
+ upon model load. This prevents the redundant creation
482
+ of the input destination at each sample. The input destination
483
+ tensor image will contain all the image transformations.
484
+ """
485
+ return self.__input_dst
486
+
487
+ @input_dst.setter
488
+ def input_dst(self, dst: TensorImage):
489
+ """
490
+ Sets the input destination.
491
+
492
+ Parameters
493
+ ----------
494
+ dst: TensorImage
495
+ Optimization to initialize the input destination once
496
+ upon model load. This prevents the redundant creation
497
+ of the input destination at each sample. The input destination
498
+ tensor image will contain all the image transformations.
499
+ """
500
+ self.__input_dst = dst
501
+
502
+ @property
503
+ def backend(self) -> str:
504
+ """
505
+ Attribute to access the backend.
506
+ This is the library to use for running the image
507
+ loading and input preprocessing.
508
+
509
+ Returns
510
+ -------
511
+ str
512
+ The library to use "hal", "opencv", "pillow".
513
+ """
514
+ return self.__backend
515
+
516
+ @backend.setter
517
+ def backend(self, backend: str):
518
+ """
519
+ Set the library backend to use for input preprocessing.
520
+
521
+ Parameters
522
+ ----------
523
+ backend: str
524
+ The backend library to use for input preprocessing
525
+ from the options "hal", "opencv", "pillow".
526
+ """
527
+ self.__backend = backend
528
+
529
+ @property
530
+ def transpose(self) -> bool:
531
+ """
532
+ Attribute to access the transpose condition.
533
+
534
+ Returns
535
+ -------
536
+ bool
537
+ The condition of whether or not the input
538
+ image is channels first (True) or channels last (False).
539
+ """
540
+ return self.__transpose
541
+
542
+ @transpose.setter
543
+ def transpose(self, transpose: bool):
544
+ """
545
+ Set the condition to transpose the input image.
546
+
547
+ Parameters
548
+ ----------
549
+ transpose: bool
550
+ If True, the input image will be transposed to
551
+ channels first. Otherwise, the image has
552
+ channels last.
553
+ """
554
+ self.__transpose = transpose