|
12 | 12 | from typing import TYPE_CHECKING |
13 | 13 |
|
14 | 14 | import numpy as np |
15 | | -from openvino import Model, Type |
16 | | -from openvino import opset10 as opset |
17 | | -from openvino.preprocess import PrePostProcessor |
18 | 15 |
|
19 | 16 | from model_api.models.image_model import ImageModel |
20 | 17 | from model_api.models.parameters import ParameterRegistry |
21 | 18 | from model_api.models.result import ClassificationResult, Label |
22 | | -from model_api.models.utils import softmax |
| 19 | +from model_api.models.utils import is_softmaxed, softmax, top_k |
23 | 20 |
|
24 | 21 | if TYPE_CHECKING: |
25 | 22 | from model_api.adapters.inference_adapter import InferenceAdapter |
@@ -95,27 +92,8 @@ def _setup_multilabel(self) -> None: |
95 | 92 |
|
96 | 93 | def _setup_single_label(self) -> None: |
97 | 94 | """Configure model for single-label classification with TopK.""" |
98 | | - try: |
99 | | - addOrFindSoftmaxAndTopkOutputs( |
100 | | - self.inference_adapter, |
101 | | - self.params.topk, |
102 | | - self.params.output_raw_scores, |
103 | | - ) |
104 | | - self.embedded_topk = True |
105 | | - self.out_layer_names = ["indices", "scores"] |
106 | | - if self.params.output_raw_scores: |
107 | | - self.out_layer_names.append(self.raw_scores_name) |
108 | | - except (RuntimeError, AttributeError): |
109 | | - # exception means we have a non-ov model |
110 | | - # with already inserted softmax and topk |
111 | | - if self.params.embedded_processing and len(self.outputs) >= 2: |
112 | | - self.embedded_topk = True |
113 | | - self.out_layer_names = ["indices", "scores"] |
114 | | - self.raw_scores_name = _raw_scores_name |
115 | | - else: # likely a non-ov model |
116 | | - self.embedded_topk = False |
117 | | - self.out_layer_names = _get_non_xai_names(self.outputs.keys()) |
118 | | - self.raw_scores_name = self.out_layer_names[0] |
| 95 | + self.out_layer_names = _get_non_xai_names(self.outputs.keys()) |
| 96 | + self.raw_scores_name = self.out_layer_names[0] |
119 | 97 |
|
120 | 98 | self.embedded_processing = True |
121 | 99 |
|
@@ -228,10 +206,9 @@ def get_all_probs(self, logits: np.ndarray) -> np.ndarray: |
228 | 206 | if cls_heads_info["num_multilabel_classes"]: |
229 | 207 | logits_begin = cls_heads_info["num_single_label_classes"] |
230 | 208 | probs[logits_begin:] = sigmoid_numpy(logits[logits_begin:]) |
231 | | - elif self.embedded_topk: |
232 | | - probs = logits.reshape(-1) |
233 | 209 | else: |
234 | | - probs = softmax(logits.reshape(-1)) |
| 210 | + logits_flattened = logits.reshape(-1) |
| 211 | + probs = logits_flattened if is_softmaxed(logits_flattened, axis=0) else softmax(logits_flattened) |
235 | 212 | return probs |
236 | 213 |
|
237 | 214 | def get_hierarchical_predictions(self, logits: np.ndarray) -> list[Label]: |
@@ -277,68 +254,18 @@ def get_multilabel_predictions(self, logits: np.ndarray) -> list[Label]: |
277 | 254 | return list(starmap(Label, zip(indices, labels, scores))) |
278 | 255 |
|
279 | 256 | def get_multiclass_predictions(self, outputs: dict) -> list[Label]: |
| 257 | + axis = 1 |
| 258 | + logits = outputs[self.out_layer_names[0]] |
| 259 | + if not is_softmaxed(logits, axis=axis): |
| 260 | + logits = softmax(logits, axis=axis) |
| 261 | + top_k_result = top_k(logits, self.params.topk, axis=axis) |
| 262 | + scores = top_k_result.values[0] # noqa: PD011 # silencing false positive - it's not pandas code |
| 263 | + indices = top_k_result.indices[0] |
| 264 | + |
280 | 265 | labels_list = self.params.labels |
281 | | - if self.embedded_topk: |
282 | | - indicesTensor = outputs[self.out_layer_names[0]][0] |
283 | | - scoresTensor = outputs[self.out_layer_names[1]][0] |
284 | | - labels = [labels_list[i] if labels_list else "" for i in indicesTensor] |
285 | | - else: |
286 | | - scoresTensor = softmax(outputs[self.out_layer_names[0]][0]) |
287 | | - indicesTensor = [int(np.argmax(scoresTensor))] |
288 | | - labels = [labels_list[i] if labels_list else "" for i in indicesTensor] |
289 | | - return list(starmap(Label, zip(indicesTensor, labels, scoresTensor))) |
290 | | - |
291 | | - |
292 | | -def addOrFindSoftmaxAndTopkOutputs(inference_adapter: InferenceAdapter, topk: int, output_raw_scores: bool) -> None: |
293 | | - softmaxNode = None |
294 | | - for i in range(len(inference_adapter.model.outputs)): |
295 | | - output_node = inference_adapter.model.get_output_op(i).input(0).get_source_output().get_node() |
296 | | - if output_node.get_type_name() == "Softmax": |
297 | | - softmaxNode = output_node |
298 | | - elif output_node.get_type_name() == "TopK": |
299 | | - return |
300 | | - |
301 | | - if softmaxNode is None: |
302 | | - logitsNode = inference_adapter.model.get_output_op(0).input(0).get_source_output().get_node() |
303 | | - softmaxNode = opset.softmax(logitsNode.output(0), 1) |
304 | | - k = opset.constant(topk, np.int32) |
305 | | - topkNode = opset.topk(softmaxNode, k, 1, "max", "value") |
306 | | - |
307 | | - indices = topkNode.output(0) |
308 | | - scores = topkNode.output(1) |
309 | | - results_descr = [indices, scores] |
310 | | - if output_raw_scores: |
311 | | - raw_scores = softmaxNode.output(0) |
312 | | - results_descr.append(raw_scores) |
313 | | - for output in inference_adapter.model.outputs: |
314 | | - if _saliency_map_name in output.get_names() or _feature_vector_name in output.get_names(): |
315 | | - results_descr.append(output) |
316 | | - |
317 | | - source_rt_info = inference_adapter.get_model().get_rt_info() |
318 | | - inference_adapter.model = Model( |
319 | | - results_descr, |
320 | | - inference_adapter.model.get_parameters(), |
321 | | - "classification", |
322 | | - ) |
323 | | - |
324 | | - if "model_info" in source_rt_info: |
325 | | - source_rt_info = source_rt_info["model_info"] |
326 | | - for k in source_rt_info: |
327 | | - inference_adapter.model.set_rt_info(source_rt_info[k], ["model_info", k]) |
328 | | - |
329 | | - # manually set output tensors name for created topK node |
330 | | - inference_adapter.model.outputs[0].tensor.set_names({"scores"}) |
331 | | - inference_adapter.model.outputs[1].tensor.set_names({"indices"}) |
332 | | - if output_raw_scores: |
333 | | - inference_adapter.model.outputs[2].tensor.set_names({_raw_scores_name}) |
334 | | - |
335 | | - # set output precisions |
336 | | - ppp = PrePostProcessor(inference_adapter.model) |
337 | | - ppp.output("indices").tensor().set_element_type(Type.i32) |
338 | | - ppp.output("scores").tensor().set_element_type(Type.f32) |
339 | | - if output_raw_scores: |
340 | | - ppp.output(_raw_scores_name).tensor().set_element_type(Type.f32) |
341 | | - inference_adapter.model = ppp.build() |
| 266 | + labels = [labels_list[i] if labels_list else "" for i in indices] |
| 267 | + |
| 268 | + return list(starmap(Label, zip(indices, labels, scores))) |
342 | 269 |
|
343 | 270 |
|
344 | 271 | def sigmoid_numpy(x: np.ndarray) -> np.ndarray: |
|
0 commit comments