Skip to content

Commit c5893b1

Browse files
authored
Update accuracy checker for OpenVINO converted models (#3995)
* Auto detect RCNN network outputs * Add handling of custom ouput order for some ssd models * Document new 'custom ouput order' parameter for ssd adapter * Add autoconvertion of output with NHWC to NCHW layout for yolo adapter * Add ouput_layout param to yolo_v3 adapter
1 parent 668e0b0 commit c5893b1

File tree

4 files changed

+47
-3
lines changed

4 files changed

+47
-3
lines changed

tools/accuracy_checker/accuracy_checker/adapters/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ AccuracyChecker supports following set of adapters:
6868
* `outputs` - the list of output layers names.
6969
* `raw_output` - enabling additional preprocessing for raw YOLO output format (default `False`).
7070
* `output_format` - setting output layer format - boxes first (`BHW`)(default, also default for generated IRs), boxes last (`HWB`). Applicable only if network output not 3D (4D with batch) tensor.
71+
* `output_layout` - setting output layout - channel first (`NCHW`)(default), channel last (`NHWC`).
7172
* `cells` - sets grid size for each layer, according `outputs` filed. Works only with `do_reshape=True` or when output tensor dimensions not equal 3.
7273
* `do_reshape` - forces reshape output tensor to [B,Cy,Cx] or [Cy,Cx,B] format, depending on `output_format` value ([B,Cy,Cx] by default). You may need to specify `cells` value.
7374
* `transpose` - transpose output tensor to specified format (optional).
@@ -107,6 +108,7 @@ AccuracyChecker supports following set of adapters:
107108
* `vocabulary_file` - file with recognition symbols for decoding.
108109
* `remove_duplicates` - allow removing of duplicated symbols (Optional, default value - `True`).
109110
* `ssd` - converting output of SSD model to `DetectionPrediction` representation.
111+
* `custom_output_order` - Use custom output data order: bbox, score, label (Optional, default `False`).
110112
* `ssd_mxnet` - converting output of SSD-based models from MXNet framework to `DetectionPrediction` representation.
111113
* `pytorch_ssd_decoder` - converts output of SSD model from PyTorch without embedded decoder.
112114
* `scores_out` - name of output layer with bounding boxes scores.

tools/accuracy_checker/accuracy_checker/adapters/mask_rcnn.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,14 +84,14 @@ def is_box_outputs(config, box_outputs):
8484
for elem in box_outputs:
8585
if not config.get(elem):
8686
return False
87-
8887
return True
8988

9089
box_outputs = ['classes_out', 'scores_out', 'boxes_out']
9190
if is_detection_out(self.launcher_config) and is_box_outputs(self.launcher_config, box_outputs):
9291
raise ConfigError('only detection output or [{}] should be provided'.format(', '.join(box_outputs)))
9392

9493
self.raw_masks_out = self.get_value_from_config('raw_masks_out')
94+
self.outputs_verified = False
9595

9696
if is_detection_out(self.launcher_config):
9797
self.detection_out = self.get_value_from_config('detection_out')
@@ -106,12 +106,28 @@ def is_box_outputs(config, box_outputs):
106106
if not is_box_outputs(self.launcher_config, box_outputs):
107107
raise ConfigError('all related outputs should be specified: {}'.format(', '.join(box_outputs)))
108108
self.realisation = self._process_tf_obj_detection_api_outputs
109+
self.outputs_verified = False
109110
return
110111

111112
self.realisation = self._process_pytorch_outputs
112-
self.outputs_verified = False
113+
114+
def assign_matching_outputs_names(self, outputs):
115+
def _get_matching_output(name):
116+
return [output for output in outputs if name in output][0]
117+
118+
self.num_detections_out = _get_matching_output('num_detections')
119+
self.boxes_out = _get_matching_output('boxes')
120+
self.raw_masks_out = _get_matching_output('masks')
121+
self.scores_out = _get_matching_output('scores')
122+
self.classes_out = _get_matching_output('classes')
113123

114124
def select_output_blob(self, outputs):
125+
# handle case where config has detection_out and raw_masks_out but model has different outputs
126+
if hasattr(self, 'detection_out') and len(outputs) == 5:
127+
self.assign_matching_outputs_names(outputs)
128+
self.realisation = self._process_tf_obj_detection_api_outputs
129+
self.outputs_verified = True
130+
return
115131
if self.raw_masks_out:
116132
self.raw_masks_out = self.check_output_name(self.raw_masks_out, outputs)
117133
if hasattr(self, 'detection_out'):

tools/accuracy_checker/accuracy_checker/adapters/ssd.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,19 @@ class SSDAdapter(Adapter):
3333
__provider__ = 'ssd'
3434
prediction_types = (DetectionPrediction, )
3535

36+
@classmethod
37+
def parameters(cls):
38+
parameters = super().parameters()
39+
parameters.update({
40+
'custom_output_order': BoolField(
41+
optional=True, default=False,
42+
description='Use custom output data order: bbox, score, label')
43+
})
44+
return parameters
45+
3646
def configure(self):
3747
super().configure()
48+
self.custom_output_order = self.get_value_from_config('custom_output_order')
3849
self.outputs_verified = False
3950

4051
def select_output_blob(self, outputs):
@@ -62,7 +73,12 @@ def process(self, raw, identifiers, frame_meta):
6273
prediction_mask = np.where(prediction_batch[:, 0] == batch_index)
6374
detections = prediction_batch[prediction_mask]
6475
detections = detections[:, 1::]
65-
result.append(DetectionPrediction(identifier, *zip(*detections)))
76+
if self.custom_output_order:
77+
y_mins, x_mins, y_maxs, x_maxs, scores, labels = detections.T
78+
else:
79+
labels, scores, x_mins, y_mins, x_maxs, y_maxs = detections.T
80+
81+
result.append(DetectionPrediction(identifier, labels, scores, x_mins, y_mins, x_maxs, y_maxs))
6682

6783
return result
6884

tools/accuracy_checker/accuracy_checker/adapters/yolo.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ def process(self, raw, identifiers, frame_meta):
273273
predictions = predictions[self.output_blob]
274274
out_precision = frame_meta[0].get('output_precision', {})
275275
out_layout = frame_meta[0].get('output_layout', {})
276+
276277
if self.output_blob in out_precision and predictions.dtype != out_precision[self.output_blob]:
277278
predictions = predictions.view(out_precision[self.output_blob])
278279
if self.output_blob in out_layout and out_layout[self.output_blob] == 'NHWC':
@@ -370,6 +371,10 @@ def parameters(cls):
370371
choices=['BHW', 'HWB'], optional=True,
371372
description="Set output layer format", default='BHW',
372373
),
374+
'output_layout': StringField(
375+
choices=['NCHW', 'NHWC'], optional=True, default='NCHW',
376+
description="Set output layout format"
377+
),
373378
'multiple_labels': BoolField(
374379
optional=True, default=False,
375380
description="Allow multiple labels for detection objects"
@@ -420,6 +425,7 @@ def configure(self):
420425

421426
self.raw_output = self.get_value_from_config('raw_output')
422427
self.output_format = self.get_value_from_config('output_format')
428+
self.output_layout = self.get_value_from_config('output_layout')
423429
if self.raw_output:
424430
self.processor = YoloOutputProcessor(coord_correct=lambda x: 1.0 / (1.0 + np.exp(-x)),
425431
conf_correct=lambda x: 1.0 / (1.0 + np.exp(-x)),
@@ -517,6 +523,10 @@ def prepare_predictions(self, batch, raw_outputs, out_precision, out_layout):
517523
if blob in out_layout and out_layout[blob] == 'NHWC':
518524
shape = out_blob.shape
519525
out_blob = np.transpose(out_blob, (0, 3, 1, 2)).reshape(shape)
526+
elif self.output_layout == 'NHWC' and len(out_blob.shape) == 4:
527+
# layout is NHWC turn it to NCHW
528+
out_blob = np.transpose(out_blob, (0, 3, 1, 2))
529+
520530
if batch == 1 and out_blob.shape[0] != batch:
521531
out_blob = np.expand_dims(out_blob, 0)
522532

0 commit comments

Comments
 (0)