edgefirst-validator 4.1.12__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 +336 -0
- edgefirst/validator/datasets/__init__.py +131 -0
- edgefirst/validator/datasets/arrow.py +147 -0
- edgefirst/validator/datasets/cache.py +258 -0
- edgefirst/validator/datasets/core.py +245 -0
- edgefirst/validator/datasets/darknet.py +432 -0
- edgefirst/validator/datasets/database.py +1353 -0
- edgefirst/validator/datasets/instance/__init__.py +8 -0
- edgefirst/validator/datasets/instance/core.py +223 -0
- edgefirst/validator/datasets/instance/detection.py +348 -0
- edgefirst/validator/datasets/instance/fusion.py +22 -0
- edgefirst/validator/datasets/instance/multitask.py +80 -0
- edgefirst/validator/datasets/instance/pose.py +51 -0
- edgefirst/validator/datasets/instance/segmentation.py +120 -0
- edgefirst/validator/datasets/tfrecord.py +243 -0
- edgefirst/validator/datasets/utils/fetch.py +856 -0
- edgefirst/validator/datasets/utils/readers.py +598 -0
- edgefirst/validator/datasets/utils/transformations.py +1878 -0
- edgefirst/validator/evaluators/__init__.py +16 -0
- edgefirst/validator/evaluators/callbacks/__init__.py +3 -0
- edgefirst/validator/evaluators/callbacks/core.py +194 -0
- edgefirst/validator/evaluators/callbacks/plots.py +857 -0
- edgefirst/validator/evaluators/callbacks/studio.py +128 -0
- edgefirst/validator/evaluators/core.py +255 -0
- edgefirst/validator/evaluators/detection.py +795 -0
- edgefirst/validator/evaluators/multitask.py +294 -0
- edgefirst/validator/evaluators/parameters/__init__.py +53 -0
- edgefirst/validator/evaluators/parameters/core.py +443 -0
- edgefirst/validator/evaluators/parameters/dataset.py +176 -0
- edgefirst/validator/evaluators/parameters/model.py +288 -0
- edgefirst/validator/evaluators/parameters/validation.py +529 -0
- edgefirst/validator/evaluators/pose.py +155 -0
- edgefirst/validator/evaluators/segmentation.py +975 -0
- edgefirst/validator/evaluators/utils/__init__.py +2 -0
- edgefirst/validator/evaluators/utils/classify.py +284 -0
- edgefirst/validator/evaluators/utils/match.py +262 -0
- edgefirst/validator/metrics/__init__.py +12 -0
- edgefirst/validator/metrics/data/__init__.py +9 -0
- edgefirst/validator/metrics/data/label.py +727 -0
- edgefirst/validator/metrics/data/metrics.py +753 -0
- edgefirst/validator/metrics/data/plots.py +447 -0
- edgefirst/validator/metrics/data/stats.py +690 -0
- edgefirst/validator/metrics/detection.py +588 -0
- edgefirst/validator/metrics/pose.py +80 -0
- edgefirst/validator/metrics/segmentation.py +171 -0
- edgefirst/validator/metrics/utils/math.py +698 -0
- edgefirst/validator/publishers/__init__.py +3 -0
- edgefirst/validator/publishers/console.py +78 -0
- edgefirst/validator/publishers/studio.py +107 -0
- edgefirst/validator/publishers/tensorboard.py +118 -0
- edgefirst/validator/publishers/utils/logger.py +111 -0
- edgefirst/validator/publishers/utils/table.py +434 -0
- edgefirst/validator/runners/__init__.py +7 -0
- edgefirst/validator/runners/core.py +644 -0
- edgefirst/validator/runners/deepviewrt.py +169 -0
- edgefirst/validator/runners/hailo.py +281 -0
- edgefirst/validator/runners/keras.py +219 -0
- edgefirst/validator/runners/offline.py +228 -0
- edgefirst/validator/runners/onnx.py +332 -0
- edgefirst/validator/runners/processing/decode.py +105 -0
- edgefirst/validator/runners/processing/nms.py +824 -0
- edgefirst/validator/runners/processing/postprocess.py +520 -0
- edgefirst/validator/runners/processing/preprocess.py +134 -0
- edgefirst/validator/runners/tensorrt.py +352 -0
- edgefirst/validator/runners/tflite.py +272 -0
- edgefirst/validator/validate.py +701 -0
- edgefirst/validator/visualize/__init__.py +4 -0
- edgefirst/validator/visualize/detection.py +946 -0
- edgefirst/validator/visualize/pose.py +243 -0
- edgefirst/validator/visualize/segmentation.py +377 -0
- edgefirst/validator/visualize/utils/plots.py +686 -0
- edgefirst_validator-4.1.12.dist-info/METADATA +114 -0
- edgefirst_validator-4.1.12.dist-info/RECORD +78 -0
- edgefirst_validator-4.1.12.dist-info/WHEEL +5 -0
- edgefirst_validator-4.1.12.dist-info/entry_points.txt +2 -0
- edgefirst_validator-4.1.12.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from keras.saving import register_keras_serializable
|
|
2
|
+
import tensorflow as tf
|
|
3
|
+
import keras
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@register_keras_serializable(package="deepview.modelpack.utils")
|
|
7
|
+
class Argmax(keras.layers.Layer):
|
|
8
|
+
def __init__(self, **kwargs):
|
|
9
|
+
super().__init__(**kwargs)
|
|
10
|
+
|
|
11
|
+
def call(self, x):
|
|
12
|
+
return tf.argmax(x, axis=-1, output_type=tf.int32)
|
|
13
|
+
|
|
14
|
+
def get_config(self):
|
|
15
|
+
return super().get_config()
|
|
16
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "4.1.12"
|
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
|
|
3
|
+
from edgefirst.validator import __version__
|
|
4
|
+
from edgefirst.validator.validate import validate
|
|
5
|
+
|
|
6
|
+
try:
|
|
7
|
+
import ctypes
|
|
8
|
+
import inspect
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
import nvidia
|
|
12
|
+
|
|
13
|
+
nvpath = Path(inspect.getfile(nvidia)).parent
|
|
14
|
+
cudnn = nvpath / 'cudnn' / 'lib' / 'libcudnn.so.9'
|
|
15
|
+
if cudnn.exists():
|
|
16
|
+
ctypes.CDLL(cudnn.as_posix(), mode=ctypes.RTLD_GLOBAL)
|
|
17
|
+
except ImportError:
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def main():
|
|
22
|
+
parser = argparse.ArgumentParser(
|
|
23
|
+
description=('EdgeFirst Validator'),
|
|
24
|
+
formatter_class=argparse.RawTextHelpFormatter
|
|
25
|
+
)
|
|
26
|
+
parser.add_argument('-V', '--version',
|
|
27
|
+
help="Print the package version.",
|
|
28
|
+
action='version',
|
|
29
|
+
version=__version__
|
|
30
|
+
)
|
|
31
|
+
parser.add_argument('model',
|
|
32
|
+
help=("The path to the model: \n"
|
|
33
|
+
"- DeepViewRT (.rtm) \n"
|
|
34
|
+
"- TensorFlow or Keras (**/*.pb), (.h5), (.keras) \n"
|
|
35
|
+
"- TFlite (.tflite) \n"
|
|
36
|
+
"- ONNX (.onnx) \n"
|
|
37
|
+
"- Hailo (.hef) \n"
|
|
38
|
+
"- Offline (directory of model annotations)."),
|
|
39
|
+
metavar='model.onnx',
|
|
40
|
+
nargs="?",
|
|
41
|
+
type=str,
|
|
42
|
+
default="yolov5s.onnx"
|
|
43
|
+
)
|
|
44
|
+
parser.add_argument('dataset',
|
|
45
|
+
help=("The absolute or relative path "
|
|
46
|
+
"to the dataset folder or YAML file."),
|
|
47
|
+
metavar='dataset.yaml',
|
|
48
|
+
nargs="?",
|
|
49
|
+
type=str,
|
|
50
|
+
default='samples/coco128.yaml'
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
studio_parser = parser.add_argument_group(
|
|
54
|
+
title="EdgeFirst Studio Parameters",
|
|
55
|
+
description=("Specify the interface parameters "
|
|
56
|
+
"for a direct communication with EdgeFirst Studio.")
|
|
57
|
+
)
|
|
58
|
+
studio_parser.add_argument('--token',
|
|
59
|
+
help="EdgeFirst Studio authentication token.",
|
|
60
|
+
type=str,
|
|
61
|
+
)
|
|
62
|
+
studio_parser.add_argument('--username',
|
|
63
|
+
help="EdgeFirst Studio username.",
|
|
64
|
+
type=str,
|
|
65
|
+
)
|
|
66
|
+
studio_parser.add_argument('--password',
|
|
67
|
+
help="EdgeFirst Studio password.",
|
|
68
|
+
type=str,
|
|
69
|
+
)
|
|
70
|
+
studio_parser.add_argument('--server',
|
|
71
|
+
help="EdgeFirst Studio server.",
|
|
72
|
+
type=str,
|
|
73
|
+
choices=['test', 'stage', 'saas'],
|
|
74
|
+
default='saas'
|
|
75
|
+
)
|
|
76
|
+
studio_parser.add_argument('--session-id',
|
|
77
|
+
help=("Specify the validator session ID "
|
|
78
|
+
"for posting results."),
|
|
79
|
+
type=str,
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
model_parser = parser.add_argument_group(
|
|
83
|
+
title="Model Parameters",
|
|
84
|
+
description="Specify how the model should be run with these parameters."
|
|
85
|
+
)
|
|
86
|
+
parser.add_argument('--config',
|
|
87
|
+
help=("Specify the path to 'edgefirst.yaml' "
|
|
88
|
+
"containing the model metadata. This overrides "
|
|
89
|
+
"the metadata embedded in the model."),
|
|
90
|
+
type=str
|
|
91
|
+
)
|
|
92
|
+
model_parser.add_argument('--model-labels',
|
|
93
|
+
help=("Specify the path to the model labels file "
|
|
94
|
+
"This artifact is a labels.txt file "
|
|
95
|
+
"containing model string labels. This is "
|
|
96
|
+
"used to map model output indices to strings."),
|
|
97
|
+
type=str,
|
|
98
|
+
)
|
|
99
|
+
model_parser.add_argument('-i', '--nms-iou-threshold',
|
|
100
|
+
help="NMS IoU threshold for valid predictions.",
|
|
101
|
+
default=0.70,
|
|
102
|
+
type=float
|
|
103
|
+
)
|
|
104
|
+
model_parser.add_argument('-t', '--nms-score-threshold',
|
|
105
|
+
help="Set the NMS score threshold for valid scores.",
|
|
106
|
+
default=0.001,
|
|
107
|
+
type=float
|
|
108
|
+
)
|
|
109
|
+
model_parser.add_argument('-m', '--max-detections',
|
|
110
|
+
help="Number of maximum detections for NMS.",
|
|
111
|
+
default=300,
|
|
112
|
+
type=int
|
|
113
|
+
)
|
|
114
|
+
model_parser.add_argument('-e', '--engine',
|
|
115
|
+
help=("Inference Engine. Options include 'cpu', 'gpu', "
|
|
116
|
+
"or a path the NPU delegate '/usr/lib/libvx_delegate.so'."),
|
|
117
|
+
default='npu',
|
|
118
|
+
type=str
|
|
119
|
+
)
|
|
120
|
+
model_parser.add_argument('-s', '--nms',
|
|
121
|
+
help="Specify the NMS algorithm. Default to use 'numpy'.",
|
|
122
|
+
choices=['numpy', 'tensorflow', 'torch'],
|
|
123
|
+
default='tensorflow',
|
|
124
|
+
type=str
|
|
125
|
+
)
|
|
126
|
+
model_parser.add_argument('-n', '--norm',
|
|
127
|
+
help=("Normalization method applied to input images.\n "
|
|
128
|
+
"- raw (default, no processing)\n "
|
|
129
|
+
"- unsigned (0...1)\n "
|
|
130
|
+
"- signed (-1...1)\n "
|
|
131
|
+
"- whitening (per-image standardization/whitening)\n "
|
|
132
|
+
"- imagenet (standardization using imagenet)\n "),
|
|
133
|
+
choices=[
|
|
134
|
+
'raw', 'unsigned', 'signed', 'imagenet'],
|
|
135
|
+
default='unsigned',
|
|
136
|
+
type=str
|
|
137
|
+
)
|
|
138
|
+
model_parser.add_argument('-p', '--preprocessing',
|
|
139
|
+
help=("The type of image preprocessing to perform. \n"
|
|
140
|
+
"- letterbox: YOLOv5, YOLOv7 implementation. \n"
|
|
141
|
+
"- pad: Image padding based on YOLOx implementation. \n"
|
|
142
|
+
"- resize: Does not maintain aspect ratio. (default)"),
|
|
143
|
+
choices=['letterbox', 'pad', 'resize'],
|
|
144
|
+
default='letterbox',
|
|
145
|
+
type=str
|
|
146
|
+
)
|
|
147
|
+
model_parser.add_argument('-b', '--box-format',
|
|
148
|
+
help=("box format to reorient the bounding box "
|
|
149
|
+
"coordinates: 'xcycwh', 'xywh', 'xyxy', etc).\n"),
|
|
150
|
+
choices=['yolo', 'coco', 'pascalvoc'],
|
|
151
|
+
default='pascalvoc',
|
|
152
|
+
type=str
|
|
153
|
+
)
|
|
154
|
+
model_parser.add_argument('-w', '--warmup',
|
|
155
|
+
help="The number of model warmup iterations.",
|
|
156
|
+
default=5,
|
|
157
|
+
type=int
|
|
158
|
+
)
|
|
159
|
+
model_parser.add_argument('-l', '--label-offset',
|
|
160
|
+
help="Label offset when mapping index to string representations.",
|
|
161
|
+
default=0,
|
|
162
|
+
type=int
|
|
163
|
+
)
|
|
164
|
+
model_parser.add_argument('--override',
|
|
165
|
+
help=("This parameter is set to True by default "
|
|
166
|
+
"When specified, this will use the model "
|
|
167
|
+
"parameters specified in the model metadata "
|
|
168
|
+
"to validate the model. Otherwise, the "
|
|
169
|
+
"command line parameters can be set."),
|
|
170
|
+
action='store_false')
|
|
171
|
+
|
|
172
|
+
dataset_parser = parser.add_argument_group(
|
|
173
|
+
title="Dataset Parameters",
|
|
174
|
+
description="Specify how the dataset should be read with these parameters."
|
|
175
|
+
)
|
|
176
|
+
dataset_parser.add_argument('--cache',
|
|
177
|
+
help=("Specify the path to the dataset cache. "
|
|
178
|
+
"A dataset cache is an LMDB file."),
|
|
179
|
+
metavar="cache/val.db",
|
|
180
|
+
type=str,
|
|
181
|
+
)
|
|
182
|
+
dataset_parser.add_argument('--dataset-labels',
|
|
183
|
+
help=("Absolute or relative path "
|
|
184
|
+
"to the labels.txt file. \n"
|
|
185
|
+
"This can be stored inside the dataset folder "
|
|
186
|
+
"to avoid having to specify this path. \n"
|
|
187
|
+
"Otherwise, the YAML file can embed the labels. \n"
|
|
188
|
+
"This is used to map dataset indices to strings."),
|
|
189
|
+
type=str
|
|
190
|
+
)
|
|
191
|
+
dataset_parser.add_argument('--suppress-local-reader',
|
|
192
|
+
help=("Specify whether to use deepview-dataset methods "
|
|
193
|
+
"for reading datasets. \n"
|
|
194
|
+
"Otherwise, by default use local validator methods."),
|
|
195
|
+
action='store_false'
|
|
196
|
+
)
|
|
197
|
+
dataset_parser.add_argument('--show-missing-annotations',
|
|
198
|
+
help=("List the images without "
|
|
199
|
+
"annotations on the terminal"),
|
|
200
|
+
action='store_true'
|
|
201
|
+
)
|
|
202
|
+
dataset_parser.add_argument('--absolute-annotations',
|
|
203
|
+
help=("This specifies that the annotations "
|
|
204
|
+
"are not normalized to the image dimensions. "
|
|
205
|
+
"Otherwise, by default the annotations "
|
|
206
|
+
"are normalized."),
|
|
207
|
+
action='store_false'
|
|
208
|
+
)
|
|
209
|
+
dataset_parser.add_argument('--annotation-format',
|
|
210
|
+
help=("Specify the format of the annotations: "
|
|
211
|
+
"'yolo', 'coco', 'pascalvoc'."),
|
|
212
|
+
choices=['yolo', 'coco', 'pascalvoc'],
|
|
213
|
+
default='yolo',
|
|
214
|
+
type=str
|
|
215
|
+
)
|
|
216
|
+
dataset_parser.add_argument('--gt-label-offset',
|
|
217
|
+
help=("The label offset to use for the ground truth "
|
|
218
|
+
"mapping integer labels to string labels. "
|
|
219
|
+
"This is typically set to 1 for segmentation "
|
|
220
|
+
"as datasets include the background class."),
|
|
221
|
+
default=0,
|
|
222
|
+
type=int
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
val_parser = parser.add_argument_group(
|
|
226
|
+
title="Validation Parameters",
|
|
227
|
+
description=("Specify additional validation settings "
|
|
228
|
+
"for metric computations and visualizations.")
|
|
229
|
+
)
|
|
230
|
+
val_parser.add_argument('--validate',
|
|
231
|
+
help="Specify the validation task. By default 'vision'.",
|
|
232
|
+
choices=['vision', 'fusion', 'pose'],
|
|
233
|
+
default='vision',
|
|
234
|
+
type=str
|
|
235
|
+
)
|
|
236
|
+
val_parser.add_argument('--method',
|
|
237
|
+
help=("Specify the validation method to deploy. "
|
|
238
|
+
"The method to reproduce metrics from Ultralytics "
|
|
239
|
+
"or other validator sources such as YOLOv7 or "
|
|
240
|
+
"internal Au-Zone validation methods and metrics."),
|
|
241
|
+
choices=["ultralytics", "yolov7", "edgefirst"],
|
|
242
|
+
default="ultralytics",
|
|
243
|
+
type=str
|
|
244
|
+
)
|
|
245
|
+
val_parser.add_argument('--validation-iou',
|
|
246
|
+
help=("Validation IoU threshold "
|
|
247
|
+
"to consider as true positives. Detections with IoU "
|
|
248
|
+
"lower than this threshold are classified as "
|
|
249
|
+
"localization false positives. This is used in the "
|
|
250
|
+
"edgefirst method of validation."),
|
|
251
|
+
default=0.50,
|
|
252
|
+
type=float
|
|
253
|
+
)
|
|
254
|
+
val_parser.add_argument('--validation-score',
|
|
255
|
+
help=("Validation Score threshold used in the edgefirst "
|
|
256
|
+
"method of validation."),
|
|
257
|
+
default=0.00,
|
|
258
|
+
type=float
|
|
259
|
+
)
|
|
260
|
+
val_parser.add_argument('--metric',
|
|
261
|
+
help=("Specify the metric to use when "
|
|
262
|
+
"matching model predictions to ground truth."),
|
|
263
|
+
choices=['iou', 'centerpoint'],
|
|
264
|
+
default='iou',
|
|
265
|
+
type=str
|
|
266
|
+
)
|
|
267
|
+
val_parser.add_argument('--matching-leniency',
|
|
268
|
+
help=("Distance metric to be considered a valid match "
|
|
269
|
+
"when using the 'centerpoint' metric. "
|
|
270
|
+
"Default is 2 where the distance is no "
|
|
271
|
+
"more than twice the size of the bounding box. \n"),
|
|
272
|
+
default=2,
|
|
273
|
+
type=int
|
|
274
|
+
)
|
|
275
|
+
val_parser.add_argument('--clamp-boxes',
|
|
276
|
+
help=("The value to clamp the minimum width or height "
|
|
277
|
+
"of the bounding boxes of the ground truth and "
|
|
278
|
+
"predictions in pixels."),
|
|
279
|
+
type=int
|
|
280
|
+
)
|
|
281
|
+
val_parser.add_argument('--ignore-boxes',
|
|
282
|
+
help=("Ignore the bounding boxes "
|
|
283
|
+
"of the detections and the ground truth with "
|
|
284
|
+
"height or width less than this value in pixels."),
|
|
285
|
+
type=int
|
|
286
|
+
)
|
|
287
|
+
val_parser.add_argument('--display',
|
|
288
|
+
help=("How many images to display into tensorboard "
|
|
289
|
+
"or to save in disk. By default it is (-1) all "
|
|
290
|
+
"the images are saved. but any integer can be passed."),
|
|
291
|
+
default=-1,
|
|
292
|
+
type=int
|
|
293
|
+
)
|
|
294
|
+
val_parser.add_argument('--suppress-plots',
|
|
295
|
+
help=("Specify to exclude the plots data in the "
|
|
296
|
+
"JSON summary and/or save the plots as images if "
|
|
297
|
+
"visualize or tensorboard parameter is set."),
|
|
298
|
+
action="store_false"
|
|
299
|
+
)
|
|
300
|
+
val_parser.add_argument('--visualize',
|
|
301
|
+
help=("Path to store visualizations "
|
|
302
|
+
"(images with bounding boxes "
|
|
303
|
+
"or segmentation masks) in disk."),
|
|
304
|
+
default=None,
|
|
305
|
+
type=str
|
|
306
|
+
)
|
|
307
|
+
val_parser.add_argument('--tensorboard',
|
|
308
|
+
help=("Path to store *.tfevents files in disk"
|
|
309
|
+
"needed for Tensorboard."),
|
|
310
|
+
default=None,
|
|
311
|
+
type=str
|
|
312
|
+
)
|
|
313
|
+
val_parser.add_argument('--json-out',
|
|
314
|
+
help=("Path to save the validation "
|
|
315
|
+
"JSON files in disk."),
|
|
316
|
+
default=None,
|
|
317
|
+
type=str
|
|
318
|
+
)
|
|
319
|
+
val_parser.add_argument('--include-background',
|
|
320
|
+
help=("This is used for segmentation. "
|
|
321
|
+
"This allows evaluation of the "
|
|
322
|
+
"background class as part of validation."),
|
|
323
|
+
action="store_true"
|
|
324
|
+
)
|
|
325
|
+
val_parser.add_argument('--exclude-symbols',
|
|
326
|
+
help=("Specify whether to exclude symbols when "
|
|
327
|
+
"logging messages on the terminal."),
|
|
328
|
+
action="store_false"
|
|
329
|
+
)
|
|
330
|
+
args = parser.parse_args()
|
|
331
|
+
|
|
332
|
+
validate(args)
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
if __name__ == '__main__':
|
|
336
|
+
main()
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
from edgefirst.validator.datasets.instance import (Instance, DetectionInstance,
|
|
4
|
+
RadarDetectionInstance,
|
|
5
|
+
SegmentationInstance,
|
|
6
|
+
Detection3DInstance,
|
|
7
|
+
MultitaskInstance,
|
|
8
|
+
FusionInstance,
|
|
9
|
+
PoseInstance)
|
|
10
|
+
from edgefirst.validator.datasets.core import Dataset, BaseDataset
|
|
11
|
+
from edgefirst.validator.datasets.tfrecord import TFRecordDataset
|
|
12
|
+
from edgefirst.validator.datasets.darknet import DarkNetDataset
|
|
13
|
+
from edgefirst.validator.datasets.arrow import ArrowDataset
|
|
14
|
+
from edgefirst.validator.datasets.database import (Database, EdgeFirstDatabase,
|
|
15
|
+
DarknetDatabase, LMDBDatabase)
|
|
16
|
+
from edgefirst.validator.datasets.cache import StudioCache
|
|
17
|
+
|
|
18
|
+
from edgefirst.validator.datasets.utils.fetch import download_and_extract
|
|
19
|
+
from edgefirst.validator.publishers.utils.logger import logger
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def instantiate_dataset(
|
|
23
|
+
info_dataset: dict,
|
|
24
|
+
parameters,
|
|
25
|
+
) -> Dataset:
|
|
26
|
+
"""
|
|
27
|
+
This function instantiates either darknet or tfrecord
|
|
28
|
+
format dataset objects.
|
|
29
|
+
|
|
30
|
+
Parameters
|
|
31
|
+
----------
|
|
32
|
+
info_dataset: dict
|
|
33
|
+
If the dataset is Darknet, this contains information such as:
|
|
34
|
+
|
|
35
|
+
.. code-block:: python
|
|
36
|
+
|
|
37
|
+
{
|
|
38
|
+
"classes": [list of unique labels],
|
|
39
|
+
"type": "darknet",
|
|
40
|
+
"validation":
|
|
41
|
+
{
|
|
42
|
+
"images: 'path to the images',
|
|
43
|
+
"annotations": 'path to the annotations'
|
|
44
|
+
},
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
*Note: the classes are optional and the path to the images
|
|
48
|
+
and annotations can be the same.*
|
|
49
|
+
|
|
50
|
+
If the dataset is tfrecord, this contains information such as:
|
|
51
|
+
|
|
52
|
+
.. code-block:: python
|
|
53
|
+
|
|
54
|
+
{
|
|
55
|
+
"classes": [list of unique labels],
|
|
56
|
+
"validation": {
|
|
57
|
+
"path": path to the *.tfrecord files.
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
parameters: DatasetParameters
|
|
61
|
+
A container for the dataset parameters set from the command line.
|
|
62
|
+
|
|
63
|
+
Returns
|
|
64
|
+
-------
|
|
65
|
+
Dataset
|
|
66
|
+
This object is returned depending on the type of the dataset provided.
|
|
67
|
+
|
|
68
|
+
Raises
|
|
69
|
+
------
|
|
70
|
+
InvalidDatasetSourceException
|
|
71
|
+
Raised if the path to the images or annotations is None.
|
|
72
|
+
DatasetNotFoundException
|
|
73
|
+
Raised if the provided path to the images or
|
|
74
|
+
annotations does not exist.
|
|
75
|
+
ValueError
|
|
76
|
+
Raised if the provided path to the images or
|
|
77
|
+
annotations is not a string.
|
|
78
|
+
EmptyDatasetException
|
|
79
|
+
Raised if the provided path to the images or
|
|
80
|
+
text files does not contain any image files or
|
|
81
|
+
text files respectively.
|
|
82
|
+
"""
|
|
83
|
+
if isinstance(info_dataset, dict):
|
|
84
|
+
if "download" in info_dataset.keys():
|
|
85
|
+
url = info_dataset.get("download")
|
|
86
|
+
download_path = os.path.join(os.getcwd(),
|
|
87
|
+
f"samples/{os.path.basename(url)}")
|
|
88
|
+
if not os.path.exists(download_path):
|
|
89
|
+
download_and_extract(url=url, download_path=download_path)
|
|
90
|
+
|
|
91
|
+
try:
|
|
92
|
+
ds_format = info_dataset.get('type')
|
|
93
|
+
if ds_format is None:
|
|
94
|
+
ds_format = info_dataset.get("dataset").get("format")
|
|
95
|
+
except AttributeError:
|
|
96
|
+
logger("Dataset was not properly read. Ensure the dataset " +
|
|
97
|
+
"structure follows images/validate and labels/validate.",
|
|
98
|
+
code="ERROR")
|
|
99
|
+
if ds_format in [None, "tfrecord"]:
|
|
100
|
+
return TFRecordDataset(
|
|
101
|
+
source=parameters.dataset_path,
|
|
102
|
+
parameters=parameters,
|
|
103
|
+
info_dataset=info_dataset,
|
|
104
|
+
)
|
|
105
|
+
elif ds_format == "darknet":
|
|
106
|
+
return DarkNetDataset(
|
|
107
|
+
source=parameters.dataset_path,
|
|
108
|
+
parameters=parameters,
|
|
109
|
+
info_dataset=info_dataset,
|
|
110
|
+
)
|
|
111
|
+
elif ds_format == "arrow":
|
|
112
|
+
return ArrowDataset(
|
|
113
|
+
source=parameters.dataset_path,
|
|
114
|
+
parameters=parameters,
|
|
115
|
+
info_dataset=info_dataset,
|
|
116
|
+
)
|
|
117
|
+
elif ds_format == "lmdb":
|
|
118
|
+
return LMDBDatabase(
|
|
119
|
+
source=parameters.dataset_path,
|
|
120
|
+
parameters=parameters
|
|
121
|
+
)
|
|
122
|
+
elif ds_format == "edgefirst":
|
|
123
|
+
return EdgeFirstDatabase(
|
|
124
|
+
source=parameters.dataset_path,
|
|
125
|
+
parameters=parameters,
|
|
126
|
+
)
|
|
127
|
+
else:
|
|
128
|
+
return BaseDataset(
|
|
129
|
+
source=parameters.dataset_path,
|
|
130
|
+
iterator=info_dataset
|
|
131
|
+
)
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Implementations for reading Arrow datasets.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
from typing import TYPE_CHECKING
|
|
9
|
+
|
|
10
|
+
import numpy as np
|
|
11
|
+
|
|
12
|
+
from edgefirst.validator.datasets import Dataset
|
|
13
|
+
from edgefirst.validator.datasets import DetectionInstance
|
|
14
|
+
from edgefirst.validator.publishers.utils.logger import logger
|
|
15
|
+
from edgefirst.validator.datasets.utils.fetch import (classify_dataset,
|
|
16
|
+
validate_dataset_source)
|
|
17
|
+
|
|
18
|
+
if TYPE_CHECKING:
|
|
19
|
+
from edgefirst.validator.evaluators import DatasetParameters
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class ArrowDataset(Dataset):
|
|
23
|
+
"""
|
|
24
|
+
Reads Arrow datasets.
|
|
25
|
+
|
|
26
|
+
Parameters
|
|
27
|
+
----------
|
|
28
|
+
source: str
|
|
29
|
+
The path to the source dataset.
|
|
30
|
+
parameters: DatasetParameters
|
|
31
|
+
This contains dataset parameters set from the command line.
|
|
32
|
+
info_dataset: dict
|
|
33
|
+
Contains information such as:
|
|
34
|
+
|
|
35
|
+
.. code-block:: python
|
|
36
|
+
|
|
37
|
+
{
|
|
38
|
+
"classes": [list of unique labels],
|
|
39
|
+
"validation":
|
|
40
|
+
{
|
|
41
|
+
"images: 'path to the images arrow files',
|
|
42
|
+
"annotations": 'path to the annotations arrow files'
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
*Note: the classes are optional and the path to the images
|
|
47
|
+
and annotations can be the same.*
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
def __init__(
|
|
51
|
+
self,
|
|
52
|
+
source: str,
|
|
53
|
+
parameters: DatasetParameters,
|
|
54
|
+
info_dataset: dict = None,
|
|
55
|
+
):
|
|
56
|
+
super(ArrowDataset, self).__init__(
|
|
57
|
+
source=source,
|
|
58
|
+
parameters=parameters
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
if info_dataset is None:
|
|
62
|
+
info_dataset = classify_dataset(source)
|
|
63
|
+
|
|
64
|
+
try:
|
|
65
|
+
self.image_source = info_dataset.get(
|
|
66
|
+
"dataset").get('validation').get('images')
|
|
67
|
+
self.annotation_source = info_dataset.get(
|
|
68
|
+
"dataset").get('validation').get('annotations')
|
|
69
|
+
except AttributeError:
|
|
70
|
+
self.image_source = validate_dataset_source(
|
|
71
|
+
info_dataset.get('validation').get('images'))
|
|
72
|
+
self.annotation_source = validate_dataset_source(
|
|
73
|
+
info_dataset.get('validation').get('annotations'))
|
|
74
|
+
|
|
75
|
+
try:
|
|
76
|
+
from deepview.datasets.readers import PolarsDetectionReader # type: ignore
|
|
77
|
+
except ImportError:
|
|
78
|
+
logger(
|
|
79
|
+
"Dependency missing: deepview-datasets is needed for polar datasets.",
|
|
80
|
+
code="ERROR")
|
|
81
|
+
self.reader = PolarsDetectionReader(
|
|
82
|
+
inputs=self.image_source,
|
|
83
|
+
annotations=self.annotation_source,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
labels = info_dataset.get('classes', None)
|
|
87
|
+
if labels is not None:
|
|
88
|
+
self.parameters.labels = [str(label) for label in labels]
|
|
89
|
+
else:
|
|
90
|
+
self.parameters.labels = self.reader.classes
|
|
91
|
+
|
|
92
|
+
def build_dataset(self):
|
|
93
|
+
"""
|
|
94
|
+
Allows iteration in the dataset.
|
|
95
|
+
|
|
96
|
+
Returns
|
|
97
|
+
-------
|
|
98
|
+
Iterator
|
|
99
|
+
Contains the images and boxes.
|
|
100
|
+
"""
|
|
101
|
+
return self.reader
|
|
102
|
+
|
|
103
|
+
def read_sample(self, sample: tuple) -> DetectionInstance:
|
|
104
|
+
"""
|
|
105
|
+
Reads one sample from the dataset.
|
|
106
|
+
|
|
107
|
+
Parameters
|
|
108
|
+
----------
|
|
109
|
+
sample: tuple
|
|
110
|
+
This contains the (image, boxes).
|
|
111
|
+
|
|
112
|
+
Returns
|
|
113
|
+
-------
|
|
114
|
+
DetectionInstance
|
|
115
|
+
The ground truth instance objects contains the bounding boxes
|
|
116
|
+
and the labels representing the ground truth of the image.
|
|
117
|
+
"""
|
|
118
|
+
if self.parameters.common.with_boxes:
|
|
119
|
+
image = sample[0].astype(np.uint8)
|
|
120
|
+
height, width, _ = image.shape
|
|
121
|
+
boxes = sample[1]
|
|
122
|
+
|
|
123
|
+
image_path = self.reader.get_instance_id()
|
|
124
|
+
# Add file extension to allow image saving in disk.
|
|
125
|
+
if os.path.splitext(image_path)[-1] == "":
|
|
126
|
+
image_path += ".png"
|
|
127
|
+
|
|
128
|
+
instance = DetectionInstance(image_path)
|
|
129
|
+
instance.height = height
|
|
130
|
+
instance.width = width
|
|
131
|
+
instance.image = image
|
|
132
|
+
|
|
133
|
+
labels = (np.squeeze(boxes[..., 4:5].astype(np.int32), axis=1) +
|
|
134
|
+
self.parameters.label_offset)
|
|
135
|
+
boxes = boxes[..., 0:4]
|
|
136
|
+
|
|
137
|
+
if len(boxes) > 0:
|
|
138
|
+
boxes = self.normalizer(
|
|
139
|
+
boxes, (height, width)) if self.normalizer else boxes
|
|
140
|
+
boxes = self.transformer(boxes) if self.transformer else boxes
|
|
141
|
+
|
|
142
|
+
instance.boxes = boxes
|
|
143
|
+
instance.labels = labels
|
|
144
|
+
return instance
|
|
145
|
+
else:
|
|
146
|
+
raise NotImplementedError(
|
|
147
|
+
"Only 'with_boxes' is currently supported for Arrow datasets.")
|