Skip to content

Commit 4e55681

Browse files
committed
move parsers back to ssd
1 parent 703cd88 commit 4e55681

File tree

3 files changed

+135
-143
lines changed

3 files changed

+135
-143
lines changed

model_api/python/model_api/models/result_types/__init__.py

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,7 @@
55

66
from .anomaly import AnomalyResult
77
from .classification import ClassificationResult, Label
8-
from .detection import (
9-
BoxesLabelsParser,
10-
DetectionResult,
11-
MultipleOutputParser,
12-
SingleOutputParser,
13-
)
8+
from .detection import DetectionResult
149
from .keypoint import DetectedKeypoints
1510
from .segmentation import (
1611
Contour,
@@ -22,13 +17,10 @@
2217

2318
__all__ = [
2419
"AnomalyResult",
25-
"BoxesLabelsParser",
2620
"ClassificationResult",
2721
"Contour",
2822
"DetectionResult",
2923
"DetectedKeypoints",
30-
"MultipleOutputParser",
31-
"SingleOutputParser",
3224
"Label",
3325
"ImageResultWithSoftPrediction",
3426
"InstanceSegmentationResult",

model_api/python/model_api/models/result_types/detection.py

Lines changed: 0 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,6 @@
1010
from .utils import array_shape_to_str
1111

1212

13-
def find_layer_by_name(name, layers):
14-
suitable_layers = [layer_name for layer_name in layers if name in layer_name]
15-
if not suitable_layers:
16-
msg = f'Suitable layer for "{name}" output is not found'
17-
raise ValueError(msg)
18-
19-
if len(suitable_layers) > 1:
20-
msg = f'More than 1 layer matched to "{name}" output'
21-
raise ValueError(msg)
22-
23-
return suitable_layers[0]
24-
25-
2613
class DetectionResult:
2714
"""Result for detection model.
2815
@@ -142,123 +129,3 @@ def feature_vector(self, value):
142129
msg = "Feature vector must be numpy array."
143130
raise ValueError(msg)
144131
self._feature_vector = value
145-
146-
147-
class SingleOutputParser:
148-
def __init__(self, all_outputs):
149-
if len(all_outputs) != 1:
150-
msg = "Network must have only one output."
151-
raise ValueError(msg)
152-
self.output_name, output_data = next(iter(all_outputs.items()))
153-
last_dim = output_data.shape[-1]
154-
if last_dim != 7:
155-
msg = f"The last dimension of the output blob must be equal to 7, got {last_dim} instead."
156-
raise ValueError(msg)
157-
158-
def __call__(self, outputs) -> DetectionResult:
159-
"""Parse model outputs.
160-
161-
Args:
162-
outputs (dict): Model outputs wrapped in dict.
163-
164-
Returns:
165-
DetectionResult: Parsed model outputs.
166-
"""
167-
bboxes = []
168-
scores = []
169-
labels = []
170-
for _, label, score, xmin, ymin, xmax, ymax in outputs[self.output_name][0][0]:
171-
bboxes.append((xmin, ymin, xmax, ymax))
172-
scores.append(score)
173-
labels.append(label)
174-
bboxes = np.array(bboxes)
175-
scores = np.array(scores)
176-
labels = np.array(labels).astype(np.int32)
177-
return DetectionResult(
178-
bboxes=bboxes,
179-
labels=labels,
180-
scores=scores,
181-
)
182-
183-
184-
class MultipleOutputParser:
185-
def __init__(
186-
self,
187-
layers,
188-
bboxes_layer="bboxes",
189-
scores_layer="scores",
190-
labels_layer="labels",
191-
):
192-
self.labels_layer = find_layer_by_name(labels_layer, layers)
193-
self.scores_layer = find_layer_by_name(scores_layer, layers)
194-
self.bboxes_layer = find_layer_by_name(bboxes_layer, layers)
195-
196-
def __call__(self, outputs) -> DetectionResult:
197-
"""Parse model outputs.
198-
199-
Args:
200-
outputs (dict): Model outputs wrapped in dict.
201-
202-
Returns:
203-
DetectionResult: Parsed model outputs.
204-
"""
205-
bboxes = np.array(outputs[self.bboxes_layer][0])
206-
scores = np.array(outputs[self.scores_layer][0])
207-
labels = np.array(outputs[self.labels_layer][0])
208-
return DetectionResult(bboxes, scores, labels)
209-
210-
211-
class BoxesLabelsParser:
212-
def __init__(self, layers, input_size, labels_layer="labels", default_label=0):
213-
try:
214-
self.labels_layer = find_layer_by_name(labels_layer, layers)
215-
except ValueError:
216-
self.labels_layer = None
217-
self.default_label = default_label
218-
219-
self.bboxes_layer = self.find_layer_bboxes_output(layers)
220-
self.input_size = input_size
221-
222-
@staticmethod
223-
def find_layer_bboxes_output(layers):
224-
filter_outputs = [
225-
name
226-
for name, data in layers.items()
227-
if (len(data.shape) == 2 or len(data.shape) == 3) and data.shape[-1] == 5
228-
]
229-
if not filter_outputs:
230-
msg = "Suitable output with bounding boxes is not found"
231-
raise ValueError(msg)
232-
if len(filter_outputs) > 1:
233-
msg = "More than 1 candidate for output with bounding boxes."
234-
raise ValueError(msg)
235-
return filter_outputs[0]
236-
237-
def __call__(self, outputs) -> DetectionResult:
238-
"""Parse model outputs.
239-
240-
Note: Bounding boxes layer from outputs are expected to be in format [xmin, ymin, xmax, ymax, score].
241-
242-
Args:
243-
outputs (dict): Model outputs wrapped in dict.
244-
245-
Returns:
246-
DetectionResult: Parsed model outputs.
247-
"""
248-
bboxes = outputs[self.bboxes_layer]
249-
bboxes = bboxes.squeeze(0)
250-
scores = bboxes[:, 4]
251-
bboxes = bboxes[:, :4]
252-
bboxes[:, 0::2] /= self.input_size[0]
253-
bboxes[:, 1::2] /= self.input_size[1]
254-
if self.labels_layer:
255-
labels = outputs[self.labels_layer]
256-
else:
257-
labels = np.full(len(bboxes), self.default_label, dtype=bboxes.dtype)
258-
labels = labels.squeeze(0)
259-
260-
return DetectionResult(
261-
bboxes=bboxes,
262-
labels=labels,
263-
scores=scores,
264-
)

model_api/python/model_api/models/ssd.py

Lines changed: 134 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,146 @@
66
import numpy as np
77

88
from .detection_model import DetectionModel
9-
from .result_types import BoxesLabelsParser, DetectionResult, MultipleOutputParser, SingleOutputParser
9+
from .result_types import DetectionResult
1010

1111
BBOX_AREA_THRESHOLD = 1.0
1212
SALIENCY_MAP_NAME = "saliency_map"
1313
FEATURE_VECTOR_NAME = "feature_vector"
1414

1515

16+
def find_layer_by_name(name, layers):
17+
suitable_layers = [layer_name for layer_name in layers if name in layer_name]
18+
if not suitable_layers:
19+
msg = f'Suitable layer for "{name}" output is not found'
20+
raise ValueError(msg)
21+
22+
if len(suitable_layers) > 1:
23+
msg = f'More than 1 layer matched to "{name}" output'
24+
raise ValueError(msg)
25+
26+
return suitable_layers[0]
27+
28+
29+
class SingleOutputParser:
30+
def __init__(self, all_outputs):
31+
if len(all_outputs) != 1:
32+
msg = "Network must have only one output."
33+
raise ValueError(msg)
34+
self.output_name, output_data = next(iter(all_outputs.items()))
35+
last_dim = output_data.shape[-1]
36+
if last_dim != 7:
37+
msg = f"The last dimension of the output blob must be equal to 7, got {last_dim} instead."
38+
raise ValueError(msg)
39+
40+
def __call__(self, outputs) -> DetectionResult:
41+
"""Parse model outputs.
42+
43+
Args:
44+
outputs (dict): Model outputs wrapped in dict.
45+
46+
Returns:
47+
DetectionResult: Parsed model outputs.
48+
"""
49+
bboxes = []
50+
scores = []
51+
labels = []
52+
for _, label, score, xmin, ymin, xmax, ymax in outputs[self.output_name][0][0]:
53+
bboxes.append((xmin, ymin, xmax, ymax))
54+
scores.append(score)
55+
labels.append(label)
56+
bboxes = np.array(bboxes)
57+
scores = np.array(scores)
58+
labels = np.array(labels).astype(np.int32)
59+
return DetectionResult(
60+
bboxes=bboxes,
61+
labels=labels,
62+
scores=scores,
63+
)
64+
65+
66+
class MultipleOutputParser:
67+
def __init__(
68+
self,
69+
layers,
70+
bboxes_layer="bboxes",
71+
scores_layer="scores",
72+
labels_layer="labels",
73+
):
74+
self.labels_layer = find_layer_by_name(labels_layer, layers)
75+
self.scores_layer = find_layer_by_name(scores_layer, layers)
76+
self.bboxes_layer = find_layer_by_name(bboxes_layer, layers)
77+
78+
def __call__(self, outputs) -> DetectionResult:
79+
"""Parse model outputs.
80+
81+
Args:
82+
outputs (dict): Model outputs wrapped in dict.
83+
84+
Returns:
85+
DetectionResult: Parsed model outputs.
86+
"""
87+
bboxes = np.array(outputs[self.bboxes_layer][0])
88+
scores = np.array(outputs[self.scores_layer][0])
89+
labels = np.array(outputs[self.labels_layer][0])
90+
return DetectionResult(bboxes, scores, labels)
91+
92+
93+
class BoxesLabelsParser:
94+
def __init__(self, layers, input_size, labels_layer="labels", default_label=0):
95+
try:
96+
self.labels_layer = find_layer_by_name(labels_layer, layers)
97+
except ValueError:
98+
self.labels_layer = None
99+
self.default_label = default_label
100+
101+
self.bboxes_layer = self.find_layer_bboxes_output(layers)
102+
self.input_size = input_size
103+
104+
@staticmethod
105+
def find_layer_bboxes_output(layers):
106+
filter_outputs = [
107+
name
108+
for name, data in layers.items()
109+
if (len(data.shape) == 2 or len(data.shape) == 3) and data.shape[-1] == 5
110+
]
111+
if not filter_outputs:
112+
msg = "Suitable output with bounding boxes is not found"
113+
raise ValueError(msg)
114+
if len(filter_outputs) > 1:
115+
msg = "More than 1 candidate for output with bounding boxes."
116+
raise ValueError(msg)
117+
return filter_outputs[0]
118+
119+
def __call__(self, outputs) -> DetectionResult:
120+
"""Parse model outputs.
121+
122+
Note: Bounding boxes layer from outputs are expected to be in format [xmin, ymin, xmax, ymax, score].
123+
124+
Args:
125+
outputs (dict): Model outputs wrapped in dict.
126+
127+
Returns:
128+
DetectionResult: Parsed model outputs.
129+
"""
130+
bboxes = outputs[self.bboxes_layer]
131+
bboxes = bboxes.squeeze(0)
132+
scores = bboxes[:, 4]
133+
bboxes = bboxes[:, :4]
134+
bboxes[:, 0::2] /= self.input_size[0]
135+
bboxes[:, 1::2] /= self.input_size[1]
136+
if self.labels_layer:
137+
labels = outputs[self.labels_layer]
138+
else:
139+
labels = np.full(len(bboxes), self.default_label, dtype=bboxes.dtype)
140+
labels = labels.squeeze(0)
141+
142+
return DetectionResult(
143+
bboxes=bboxes,
144+
labels=labels,
145+
scores=scores,
146+
)
147+
148+
16149
class SSD(DetectionModel):
17150
__model__ = "SSD"
18151

0 commit comments

Comments
 (0)