We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
infer result passed from openvino launcher to interpreter is not appropriate.
I tried model run using openvino's mobileenet-v2-pytorch model.
(using mobilenet-v2-pytorch.xml, mobilenet-v2-pytorch.bin)

`datum model run -p proj -m model-0`

However, only the name of the layer (ex. 'prob' string) comes into the input parameters(outputs) of the interpreter. Please check the return result of OpenvinoLauncher.infer

`results = self._net.infer(inputs)` line 178, openvino_launcher.py
Debugging results are normal up to the code above, but it seems that only the name of the result layer is returned when returning and passing to interpreter.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `datumaro/plugins/openvino_launcher.py`
Content:
```
1 
2 # Copyright (C) 2019-2020 Intel Corporation
3 #
4 # SPDX-License-Identifier: MIT
5 
6 # pylint: disable=exec-used
7 
8 import cv2
9 import logging as log
10 import numpy as np
11 import os.path as osp
12 import shutil
13 
14 from openvino.inference_engine import IECore
15 
16 from datumaro.components.cli_plugin import CliPlugin
17 from datumaro.components.launcher import Launcher
18 
19 
20 class _OpenvinoImporter(CliPlugin):
21     @staticmethod
22     def _parse_output_layers(s):
23         return [s.strip() for s in s.split(',')]
24 
25     @classmethod
26     def build_cmdline_parser(cls, **kwargs):
27         parser = super().build_cmdline_parser(**kwargs)
28         parser.add_argument('-d', '--description', required=True,
29             help="Path to the model description file (.xml)")
30         parser.add_argument('-w', '--weights', required=True,
31             help="Path to the model weights file (.bin)")
32         parser.add_argument('-i', '--interpreter', required=True,
33             help="Path to the network output interprter script (.py)")
34         parser.add_argument('--device', default='CPU',
35             help="Target device (default: %(default)s)")
36         parser.add_argument('--output-layers', type=cls._parse_output_layers,
37             help="A comma-separated list of extra output layers")
38         return parser
39 
40     @staticmethod
41     def copy_model(model_dir, model):
42         shutil.copy(model['description'],
43             osp.join(model_dir, osp.basename(model['description'])))
44         model['description'] = osp.basename(model['description'])
45 
46         shutil.copy(model['weights'],
47             osp.join(model_dir, osp.basename(model['weights'])))
48         model['weights'] = osp.basename(model['weights'])
49 
50         shutil.copy(model['interpreter'],
51             osp.join(model_dir, osp.basename(model['interpreter'])))
52         model['interpreter'] = osp.basename(model['interpreter'])
53 
54 
55 class InterpreterScript:
56     def __init__(self, path):
57         with open(path, 'r') as f:
58             script = f.read()
59 
60         context = {}
61         exec(script, context, context)
62 
63         process_outputs = context.get('process_outputs')
64         if not callable(process_outputs):
65             raise Exception("Can't find 'process_outputs' function in "
66                 "the interpreter script")
67         self.__dict__['process_outputs'] = process_outputs
68 
69         get_categories = context.get('get_categories')
70         assert get_categories is None or callable(get_categories)
71         if get_categories:
72             self.__dict__['get_categories'] = get_categories
73 
74     @staticmethod
75     def get_categories():
76         return None
77 
78     @staticmethod
79     def process_outputs(inputs, outputs):
80         raise NotImplementedError(
81             "Function should be implemented in the interpreter script")
82 
83 
84 class OpenvinoLauncher(Launcher):
85     cli_plugin = _OpenvinoImporter
86 
87     def __init__(self, description, weights, interpreter,
88             device=None, model_dir=None, output_layers=None):
89         if not model_dir:
90             model_dir = ''
91         if not osp.isfile(description):
92             description = osp.join(model_dir, description)
93         if not osp.isfile(description):
94             raise Exception('Failed to open model description file "%s"' % \
95                 (description))
96 
97         if not osp.isfile(weights):
98             weights = osp.join(model_dir, weights)
99         if not osp.isfile(weights):
100             raise Exception('Failed to open model weights file "%s"' % \
101                 (weights))
102 
103         if not osp.isfile(interpreter):
104             interpreter = osp.join(model_dir, interpreter)
105         if not osp.isfile(interpreter):
106             raise Exception('Failed to open model interpreter script file "%s"' % \
107                 (interpreter))
108 
109         self._interpreter = InterpreterScript(interpreter)
110 
111         self._device = device or 'CPU'
112         self._output_blobs = output_layers
113 
114         self._ie = IECore()
115         self._network = self._ie.read_network(description, weights)
116         self._check_model_support(self._network, self._device)
117         self._load_executable_net()
118 
119     def _check_model_support(self, net, device):
120         not_supported_layers = set(name
121             for name, dev in self._ie.query_network(net, device).items()
122             if not dev)
123         if len(not_supported_layers) != 0:
124             log.error("The following layers are not supported " \
125                 "by the plugin for device '%s': %s." % \
126                 (device, ', '.join(not_supported_layers)))
127             raise NotImplementedError(
128                 "Some layers are not supported on the device")
129 
130     def _load_executable_net(self, batch_size=1):
131         network = self._network
132 
133         if self._output_blobs:
134             network.add_outputs(self._output_blobs)
135 
136         iter_inputs = iter(network.input_info)
137         self._input_blob = next(iter_inputs)
138 
139         # NOTE: handling for the inclusion of `image_info` in OpenVino2019
140         self._require_image_info = 'image_info' in network.input_info
141         if self._input_blob == 'image_info':
142             self._input_blob = next(iter_inputs)
143 
144         self._input_layout = network.input_info[self._input_blob].input_data.shape
145         self._input_layout[0] = batch_size
146         network.reshape({self._input_blob: self._input_layout})
147         self._batch_size = batch_size
148 
149         self._net = self._ie.load_network(network=network, num_requests=1,
150             device_name=self._device)
151 
152     def infer(self, inputs):
153         assert len(inputs.shape) == 4, \
154             "Expected an input image in (N, H, W, C) format, got %s" % \
155             (inputs.shape, )
156 
157         if inputs.shape[3] == 1: # A batch of single-channel images
158             inputs = np.repeat(inputs, 3, axis=3)
159 
160         assert inputs.shape[3] == 3, \
161             "Expected BGR input, got %s" % (inputs.shape, )
162 
163         n, c, h, w = self._input_layout
164         if inputs.shape[1:3] != (h, w):
165             resized_inputs = np.empty((n, h, w, c), dtype=inputs.dtype)
166             for inp, resized_input in zip(inputs, resized_inputs):
167                 cv2.resize(inp, (w, h), resized_input)
168             inputs = resized_inputs
169         inputs = inputs.transpose((0, 3, 1, 2)) # NHWC to NCHW
170         inputs = {self._input_blob: inputs}
171         if self._require_image_info:
172             info = np.zeros([1, 3])
173             info[0, 0] = h
174             info[0, 1] = w
175             info[0, 2] = 1.0 # scale
176             inputs['image_info'] = info
177 
178         results = self._net.infer(inputs)
179         if len(results) == 1:
180             return next(iter(results))
181         else:
182             return results
183 
184     def launch(self, inputs):
185         batch_size = len(inputs)
186         if self._batch_size < batch_size:
187             self._load_executable_net(batch_size)
188 
189         outputs = self.infer(inputs)
190         results = self.process_outputs(inputs, outputs)
191         return results
192 
193     def categories(self):
194         return self._interpreter.get_categories()
195 
196     def process_outputs(self, inputs, outputs):
197         return self._interpreter.process_outputs(inputs, outputs)
198 
199
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/datumaro/plugins/openvino_launcher.py b/datumaro/plugins/openvino_launcher.py
--- a/datumaro/plugins/openvino_launcher.py
+++ b/datumaro/plugins/openvino_launcher.py
@@ -177,7 +177,7 @@
 
         results = self._net.infer(inputs)
         if len(results) == 1:
-            return next(iter(results))
+            return next(iter(results.values()))
         else:
             return results

{"golden_diff": "diff --git a/datumaro/plugins/openvino_launcher.py b/datumaro/plugins/openvino_launcher.py\n--- a/datumaro/plugins/openvino_launcher.py\n+++ b/datumaro/plugins/openvino_launcher.py\n@@ -177,7 +177,7 @@\n \n         results = self._net.infer(inputs)\n         if len(results) == 1:\n-            return next(iter(results))\n+            return next(iter(results.values()))\n         else:\n             return results\n", "issue": "infer result passed from openvino launcher to interpreter is not appropriate.\nI tried model run using openvino's mobileenet-v2-pytorch model.\r\n(using mobilenet-v2-pytorch.xml, mobilenet-v2-pytorch.bin)\r\n\r\n`datum model run -p proj -m model-0`\r\n\r\nHowever, only the name of the layer (ex. 'prob' string) comes into the input parameters(outputs) of the interpreter. Please check the return result of OpenvinoLauncher.infer\r\n\r\n`results = self._net.infer(inputs)` line 178, openvino_launcher.py\r\nDebugging results are normal up to the code above, but it seems that only the name of the result layer is returned when returning and passing to interpreter.\n", "before_files": [{"content": "\n# Copyright (C) 2019-2020 Intel Corporation\n#\n# SPDX-License-Identifier: MIT\n\n# pylint: disable=exec-used\n\nimport cv2\nimport logging as log\nimport numpy as np\nimport os.path as osp\nimport shutil\n\nfrom openvino.inference_engine import IECore\n\nfrom datumaro.components.cli_plugin import CliPlugin\nfrom datumaro.components.launcher import Launcher\n\n\nclass _OpenvinoImporter(CliPlugin):\n    @staticmethod\n    def _parse_output_layers(s):\n        return [s.strip() for s in s.split(',')]\n\n    @classmethod\n    def build_cmdline_parser(cls, **kwargs):\n        parser = super().build_cmdline_parser(**kwargs)\n        parser.add_argument('-d', '--description', required=True,\n            help=\"Path to the model description file (.xml)\")\n        parser.add_argument('-w', '--weights', required=True,\n            help=\"Path to the model weights file (.bin)\")\n        parser.add_argument('-i', '--interpreter', required=True,\n            help=\"Path to the network output interprter script (.py)\")\n        parser.add_argument('--device', default='CPU',\n            help=\"Target device (default: %(default)s)\")\n        parser.add_argument('--output-layers', type=cls._parse_output_layers,\n            help=\"A comma-separated list of extra output layers\")\n        return parser\n\n    @staticmethod\n    def copy_model(model_dir, model):\n        shutil.copy(model['description'],\n            osp.join(model_dir, osp.basename(model['description'])))\n        model['description'] = osp.basename(model['description'])\n\n        shutil.copy(model['weights'],\n            osp.join(model_dir, osp.basename(model['weights'])))\n        model['weights'] = osp.basename(model['weights'])\n\n        shutil.copy(model['interpreter'],\n            osp.join(model_dir, osp.basename(model['interpreter'])))\n        model['interpreter'] = osp.basename(model['interpreter'])\n\n\nclass InterpreterScript:\n    def __init__(self, path):\n        with open(path, 'r') as f:\n            script = f.read()\n\n        context = {}\n        exec(script, context, context)\n\n        process_outputs = context.get('process_outputs')\n        if not callable(process_outputs):\n            raise Exception(\"Can't find 'process_outputs' function in \"\n                \"the interpreter script\")\n        self.__dict__['process_outputs'] = process_outputs\n\n        get_categories = context.get('get_categories')\n        assert get_categories is None or callable(get_categories)\n        if get_categories:\n            self.__dict__['get_categories'] = get_categories\n\n    @staticmethod\n    def get_categories():\n        return None\n\n    @staticmethod\n    def process_outputs(inputs, outputs):\n        raise NotImplementedError(\n            \"Function should be implemented in the interpreter script\")\n\n\nclass OpenvinoLauncher(Launcher):\n    cli_plugin = _OpenvinoImporter\n\n    def __init__(self, description, weights, interpreter,\n            device=None, model_dir=None, output_layers=None):\n        if not model_dir:\n            model_dir = ''\n        if not osp.isfile(description):\n            description = osp.join(model_dir, description)\n        if not osp.isfile(description):\n            raise Exception('Failed to open model description file \"%s\"' % \\\n                (description))\n\n        if not osp.isfile(weights):\n            weights = osp.join(model_dir, weights)\n        if not osp.isfile(weights):\n            raise Exception('Failed to open model weights file \"%s\"' % \\\n                (weights))\n\n        if not osp.isfile(interpreter):\n            interpreter = osp.join(model_dir, interpreter)\n        if not osp.isfile(interpreter):\n            raise Exception('Failed to open model interpreter script file \"%s\"' % \\\n                (interpreter))\n\n        self._interpreter = InterpreterScript(interpreter)\n\n        self._device = device or 'CPU'\n        self._output_blobs = output_layers\n\n        self._ie = IECore()\n        self._network = self._ie.read_network(description, weights)\n        self._check_model_support(self._network, self._device)\n        self._load_executable_net()\n\n    def _check_model_support(self, net, device):\n        not_supported_layers = set(name\n            for name, dev in self._ie.query_network(net, device).items()\n            if not dev)\n        if len(not_supported_layers) != 0:\n            log.error(\"The following layers are not supported \" \\\n                \"by the plugin for device '%s': %s.\" % \\\n                (device, ', '.join(not_supported_layers)))\n            raise NotImplementedError(\n                \"Some layers are not supported on the device\")\n\n    def _load_executable_net(self, batch_size=1):\n        network = self._network\n\n        if self._output_blobs:\n            network.add_outputs(self._output_blobs)\n\n        iter_inputs = iter(network.input_info)\n        self._input_blob = next(iter_inputs)\n\n        # NOTE: handling for the inclusion of `image_info` in OpenVino2019\n        self._require_image_info = 'image_info' in network.input_info\n        if self._input_blob == 'image_info':\n            self._input_blob = next(iter_inputs)\n\n        self._input_layout = network.input_info[self._input_blob].input_data.shape\n        self._input_layout[0] = batch_size\n        network.reshape({self._input_blob: self._input_layout})\n        self._batch_size = batch_size\n\n        self._net = self._ie.load_network(network=network, num_requests=1,\n            device_name=self._device)\n\n    def infer(self, inputs):\n        assert len(inputs.shape) == 4, \\\n            \"Expected an input image in (N, H, W, C) format, got %s\" % \\\n            (inputs.shape, )\n\n        if inputs.shape[3] == 1: # A batch of single-channel images\n            inputs = np.repeat(inputs, 3, axis=3)\n\n        assert inputs.shape[3] == 3, \\\n            \"Expected BGR input, got %s\" % (inputs.shape, )\n\n        n, c, h, w = self._input_layout\n        if inputs.shape[1:3] != (h, w):\n            resized_inputs = np.empty((n, h, w, c), dtype=inputs.dtype)\n            for inp, resized_input in zip(inputs, resized_inputs):\n                cv2.resize(inp, (w, h), resized_input)\n            inputs = resized_inputs\n        inputs = inputs.transpose((0, 3, 1, 2)) # NHWC to NCHW\n        inputs = {self._input_blob: inputs}\n        if self._require_image_info:\n            info = np.zeros([1, 3])\n            info[0, 0] = h\n            info[0, 1] = w\n            info[0, 2] = 1.0 # scale\n            inputs['image_info'] = info\n\n        results = self._net.infer(inputs)\n        if len(results) == 1:\n            return next(iter(results))\n        else:\n            return results\n\n    def launch(self, inputs):\n        batch_size = len(inputs)\n        if self._batch_size < batch_size:\n            self._load_executable_net(batch_size)\n\n        outputs = self.infer(inputs)\n        results = self.process_outputs(inputs, outputs)\n        return results\n\n    def categories(self):\n        return self._interpreter.get_categories()\n\n    def process_outputs(self, inputs, outputs):\n        return self._interpreter.process_outputs(inputs, outputs)\n\n", "path": "datumaro/plugins/openvino_launcher.py"}], "after_files": [{"content": "\n# Copyright (C) 2019-2020 Intel Corporation\n#\n# SPDX-License-Identifier: MIT\n\n# pylint: disable=exec-used\n\nimport cv2\nimport logging as log\nimport numpy as np\nimport os.path as osp\nimport shutil\n\nfrom openvino.inference_engine import IECore\n\nfrom datumaro.components.cli_plugin import CliPlugin\nfrom datumaro.components.launcher import Launcher\n\n\nclass _OpenvinoImporter(CliPlugin):\n    @staticmethod\n    def _parse_output_layers(s):\n        return [s.strip() for s in s.split(',')]\n\n    @classmethod\n    def build_cmdline_parser(cls, **kwargs):\n        parser = super().build_cmdline_parser(**kwargs)\n        parser.add_argument('-d', '--description', required=True,\n            help=\"Path to the model description file (.xml)\")\n        parser.add_argument('-w', '--weights', required=True,\n            help=\"Path to the model weights file (.bin)\")\n        parser.add_argument('-i', '--interpreter', required=True,\n            help=\"Path to the network output interprter script (.py)\")\n        parser.add_argument('--device', default='CPU',\n            help=\"Target device (default: %(default)s)\")\n        parser.add_argument('--output-layers', type=cls._parse_output_layers,\n            help=\"A comma-separated list of extra output layers\")\n        return parser\n\n    @staticmethod\n    def copy_model(model_dir, model):\n        shutil.copy(model['description'],\n            osp.join(model_dir, osp.basename(model['description'])))\n        model['description'] = osp.basename(model['description'])\n\n        shutil.copy(model['weights'],\n            osp.join(model_dir, osp.basename(model['weights'])))\n        model['weights'] = osp.basename(model['weights'])\n\n        shutil.copy(model['interpreter'],\n            osp.join(model_dir, osp.basename(model['interpreter'])))\n        model['interpreter'] = osp.basename(model['interpreter'])\n\n\nclass InterpreterScript:\n    def __init__(self, path):\n        with open(path, 'r') as f:\n            script = f.read()\n\n        context = {}\n        exec(script, context, context)\n\n        process_outputs = context.get('process_outputs')\n        if not callable(process_outputs):\n            raise Exception(\"Can't find 'process_outputs' function in \"\n                \"the interpreter script\")\n        self.__dict__['process_outputs'] = process_outputs\n\n        get_categories = context.get('get_categories')\n        assert get_categories is None or callable(get_categories)\n        if get_categories:\n            self.__dict__['get_categories'] = get_categories\n\n    @staticmethod\n    def get_categories():\n        return None\n\n    @staticmethod\n    def process_outputs(inputs, outputs):\n        raise NotImplementedError(\n            \"Function should be implemented in the interpreter script\")\n\n\nclass OpenvinoLauncher(Launcher):\n    cli_plugin = _OpenvinoImporter\n\n    def __init__(self, description, weights, interpreter,\n            device=None, model_dir=None, output_layers=None):\n        if not model_dir:\n            model_dir = ''\n        if not osp.isfile(description):\n            description = osp.join(model_dir, description)\n        if not osp.isfile(description):\n            raise Exception('Failed to open model description file \"%s\"' % \\\n                (description))\n\n        if not osp.isfile(weights):\n            weights = osp.join(model_dir, weights)\n        if not osp.isfile(weights):\n            raise Exception('Failed to open model weights file \"%s\"' % \\\n                (weights))\n\n        if not osp.isfile(interpreter):\n            interpreter = osp.join(model_dir, interpreter)\n        if not osp.isfile(interpreter):\n            raise Exception('Failed to open model interpreter script file \"%s\"' % \\\n                (interpreter))\n\n        self._interpreter = InterpreterScript(interpreter)\n\n        self._device = device or 'CPU'\n        self._output_blobs = output_layers\n\n        self._ie = IECore()\n        self._network = self._ie.read_network(description, weights)\n        self._check_model_support(self._network, self._device)\n        self._load_executable_net()\n\n    def _check_model_support(self, net, device):\n        not_supported_layers = set(name\n            for name, dev in self._ie.query_network(net, device).items()\n            if not dev)\n        if len(not_supported_layers) != 0:\n            log.error(\"The following layers are not supported \" \\\n                \"by the plugin for device '%s': %s.\" % \\\n                (device, ', '.join(not_supported_layers)))\n            raise NotImplementedError(\n                \"Some layers are not supported on the device\")\n\n    def _load_executable_net(self, batch_size=1):\n        network = self._network\n\n        if self._output_blobs:\n            network.add_outputs(self._output_blobs)\n\n        iter_inputs = iter(network.input_info)\n        self._input_blob = next(iter_inputs)\n\n        # NOTE: handling for the inclusion of `image_info` in OpenVino2019\n        self._require_image_info = 'image_info' in network.input_info\n        if self._input_blob == 'image_info':\n            self._input_blob = next(iter_inputs)\n\n        self._input_layout = network.input_info[self._input_blob].input_data.shape\n        self._input_layout[0] = batch_size\n        network.reshape({self._input_blob: self._input_layout})\n        self._batch_size = batch_size\n\n        self._net = self._ie.load_network(network=network, num_requests=1,\n            device_name=self._device)\n\n    def infer(self, inputs):\n        assert len(inputs.shape) == 4, \\\n            \"Expected an input image in (N, H, W, C) format, got %s\" % \\\n            (inputs.shape, )\n\n        if inputs.shape[3] == 1: # A batch of single-channel images\n            inputs = np.repeat(inputs, 3, axis=3)\n\n        assert inputs.shape[3] == 3, \\\n            \"Expected BGR input, got %s\" % (inputs.shape, )\n\n        n, c, h, w = self._input_layout\n        if inputs.shape[1:3] != (h, w):\n            resized_inputs = np.empty((n, h, w, c), dtype=inputs.dtype)\n            for inp, resized_input in zip(inputs, resized_inputs):\n                cv2.resize(inp, (w, h), resized_input)\n            inputs = resized_inputs\n        inputs = inputs.transpose((0, 3, 1, 2)) # NHWC to NCHW\n        inputs = {self._input_blob: inputs}\n        if self._require_image_info:\n            info = np.zeros([1, 3])\n            info[0, 0] = h\n            info[0, 1] = w\n            info[0, 2] = 1.0 # scale\n            inputs['image_info'] = info\n\n        results = self._net.infer(inputs)\n        if len(results) == 1:\n            return next(iter(results.values()))\n        else:\n            return results\n\n    def launch(self, inputs):\n        batch_size = len(inputs)\n        if self._batch_size < batch_size:\n            self._load_executable_net(batch_size)\n\n        outputs = self.infer(inputs)\n        results = self.process_outputs(inputs, outputs)\n        return results\n\n    def categories(self):\n        return self._interpreter.get_categories()\n\n    def process_outputs(self, inputs, outputs):\n        return self._interpreter.process_outputs(inputs, outputs)\n\n", "path": "datumaro/plugins/openvino_launcher.py"}]}