|
|
|
@ -6,15 +6,44 @@
|
|
|
|
# pylint: disable=exec-used
|
|
|
|
# pylint: disable=exec-used
|
|
|
|
|
|
|
|
|
|
|
|
import cv2
|
|
|
|
import cv2
|
|
|
|
|
|
|
|
import logging as log
|
|
|
|
import numpy as np
|
|
|
|
import numpy as np
|
|
|
|
import os
|
|
|
|
|
|
|
|
import os.path as osp
|
|
|
|
import os.path as osp
|
|
|
|
import platform
|
|
|
|
import shutil
|
|
|
|
|
|
|
|
|
|
|
|
from openvino.inference_engine import IENetwork, IEPlugin
|
|
|
|
from openvino.inference_engine import IECore
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
from datumaro.components.cli_plugin import CliPlugin
|
|
|
|
from datumaro.components.launcher import Launcher
|
|
|
|
from datumaro.components.launcher import Launcher
|
|
|
|
from datumaro.util.os_util import check_instruction_set
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class OpenVinoImporter(CliPlugin):
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
|
|
|
def build_cmdline_parser(cls, **kwargs):
|
|
|
|
|
|
|
|
parser = super().build_cmdline_parser(**kwargs)
|
|
|
|
|
|
|
|
parser.add_argument('-d', '--description', required=True,
|
|
|
|
|
|
|
|
help="Path to the model description file (.xml)")
|
|
|
|
|
|
|
|
parser.add_argument('-w', '--weights', required=True,
|
|
|
|
|
|
|
|
help="Path to the model weights file (.bin)")
|
|
|
|
|
|
|
|
parser.add_argument('-i', '--interpreter', required=True,
|
|
|
|
|
|
|
|
help="Path to the network output interprter script (.py)")
|
|
|
|
|
|
|
|
parser.add_argument('--device', default='CPU',
|
|
|
|
|
|
|
|
help="Target device (default: %(default)s)")
|
|
|
|
|
|
|
|
return parser
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
|
|
|
|
def copy_model(model_dir, model):
|
|
|
|
|
|
|
|
shutil.copy(model['description'],
|
|
|
|
|
|
|
|
osp.join(model_dir, osp.basename(model['description'])))
|
|
|
|
|
|
|
|
model['description'] = osp.basename(model['description'])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
shutil.copy(model['weights'],
|
|
|
|
|
|
|
|
osp.join(model_dir, osp.basename(model['weights'])))
|
|
|
|
|
|
|
|
model['weights'] = osp.basename(model['weights'])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
shutil.copy(model['interpreter'],
|
|
|
|
|
|
|
|
osp.join(model_dir, osp.basename(model['interpreter'])))
|
|
|
|
|
|
|
|
model['interpreter'] = osp.basename(model['interpreter'])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class InterpreterScript:
|
|
|
|
class InterpreterScript:
|
|
|
|
@ -25,12 +54,15 @@ class InterpreterScript:
|
|
|
|
context = {}
|
|
|
|
context = {}
|
|
|
|
exec(script, context, context)
|
|
|
|
exec(script, context, context)
|
|
|
|
|
|
|
|
|
|
|
|
process_outputs = context['process_outputs']
|
|
|
|
process_outputs = context.get('process_outputs')
|
|
|
|
assert callable(process_outputs)
|
|
|
|
if not callable(process_outputs):
|
|
|
|
|
|
|
|
raise Exception("Can't find 'process_outputs' function in "
|
|
|
|
|
|
|
|
"the interpreter script")
|
|
|
|
self.__dict__['process_outputs'] = process_outputs
|
|
|
|
self.__dict__['process_outputs'] = process_outputs
|
|
|
|
|
|
|
|
|
|
|
|
get_categories = context.get('get_categories')
|
|
|
|
get_categories = context.get('get_categories')
|
|
|
|
assert callable(get_categories) or get_categories is None
|
|
|
|
assert get_categories is None or callable(get_categories)
|
|
|
|
|
|
|
|
if get_categories:
|
|
|
|
self.__dict__['get_categories'] = get_categories
|
|
|
|
self.__dict__['get_categories'] = get_categories
|
|
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
@staticmethod
|
|
|
|
@ -39,41 +71,16 @@ class InterpreterScript:
|
|
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
@staticmethod
|
|
|
|
def process_outputs(inputs, outputs):
|
|
|
|
def process_outputs(inputs, outputs):
|
|
|
|
return []
|
|
|
|
raise NotImplementedError(
|
|
|
|
|
|
|
|
"Function should be implemented in the interpreter script")
|
|
|
|
|
|
|
|
|
|
|
|
class OpenVinoLauncher(Launcher):
|
|
|
|
|
|
|
|
_DEFAULT_IE_PLUGINS_PATH = "/opt/intel/openvino_2019.1.144/deployment_tools/inference_engine/lib/intel64"
|
|
|
|
|
|
|
|
_IE_PLUGINS_PATH = os.getenv("IE_PLUGINS_PATH", _DEFAULT_IE_PLUGINS_PATH)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
class OpenVinoLauncher(Launcher):
|
|
|
|
def make_plugin(device='cpu', plugins_path=_IE_PLUGINS_PATH):
|
|
|
|
cli_plugin = OpenVinoImporter
|
|
|
|
if plugins_path is None or not osp.isdir(plugins_path):
|
|
|
|
|
|
|
|
raise Exception('Inference engine plugins directory "%s" not found' % \
|
|
|
|
|
|
|
|
(plugins_path))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
plugin = IEPlugin(device='CPU', plugin_dirs=[plugins_path])
|
|
|
|
|
|
|
|
if (check_instruction_set('avx2')):
|
|
|
|
|
|
|
|
plugin.add_cpu_extension(os.path.join(plugins_path,
|
|
|
|
|
|
|
|
'libcpu_extension_avx2.so'))
|
|
|
|
|
|
|
|
elif (check_instruction_set('sse4')):
|
|
|
|
|
|
|
|
plugin.add_cpu_extension(os.path.join(plugins_path,
|
|
|
|
|
|
|
|
'libcpu_extension_sse4.so'))
|
|
|
|
|
|
|
|
elif platform.system() == 'Darwin':
|
|
|
|
|
|
|
|
plugin.add_cpu_extension(os.path.join(plugins_path,
|
|
|
|
|
|
|
|
'libcpu_extension.dylib'))
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
raise Exception('Inference engine requires support of avx2 or sse4')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return plugin
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
|
|
|
|
def make_network(model, weights):
|
|
|
|
|
|
|
|
return IENetwork.from_ir(model=model, weights=weights)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, description, weights, interpretation_script,
|
|
|
|
def __init__(self, description, weights, interpreter,
|
|
|
|
plugins_path=None, model_dir=None, **kwargs):
|
|
|
|
plugins_path=None, device=None, model_dir=None):
|
|
|
|
if model_dir is None:
|
|
|
|
model_dir = model_dir or ''
|
|
|
|
model_dir = ''
|
|
|
|
|
|
|
|
if not osp.isfile(description):
|
|
|
|
if not osp.isfile(description):
|
|
|
|
description = osp.join(model_dir, description)
|
|
|
|
description = osp.join(model_dir, description)
|
|
|
|
if not osp.isfile(description):
|
|
|
|
if not osp.isfile(description):
|
|
|
|
@ -86,34 +93,37 @@ class OpenVinoLauncher(Launcher):
|
|
|
|
raise Exception('Failed to open model weights file "%s"' % \
|
|
|
|
raise Exception('Failed to open model weights file "%s"' % \
|
|
|
|
(weights))
|
|
|
|
(weights))
|
|
|
|
|
|
|
|
|
|
|
|
if not osp.isfile(interpretation_script):
|
|
|
|
if not osp.isfile(interpreter):
|
|
|
|
interpretation_script = \
|
|
|
|
interpreter = osp.join(model_dir, interpreter)
|
|
|
|
osp.join(model_dir, interpretation_script)
|
|
|
|
if not osp.isfile(interpreter):
|
|
|
|
if not osp.isfile(interpretation_script):
|
|
|
|
raise Exception('Failed to open model interpreter script file "%s"' % \
|
|
|
|
raise Exception('Failed to open model interpretation script file "%s"' % \
|
|
|
|
(interpreter))
|
|
|
|
(interpretation_script))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self._interpreter_script = InterpreterScript(interpretation_script)
|
|
|
|
self._interpreter = InterpreterScript(interpreter)
|
|
|
|
|
|
|
|
|
|
|
|
if plugins_path is None:
|
|
|
|
self._device = device or 'CPU'
|
|
|
|
plugins_path = OpenVinoLauncher._IE_PLUGINS_PATH
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
plugin = OpenVinoLauncher.make_plugin(plugins_path=plugins_path)
|
|
|
|
self._ie = IECore()
|
|
|
|
network = OpenVinoLauncher.make_network(description, weights)
|
|
|
|
if hasattr(self._ie, 'read_network'):
|
|
|
|
self._network = network
|
|
|
|
self._network = self._ie.read_network(description, weights)
|
|
|
|
self._plugin = plugin
|
|
|
|
else: # backward compatibility
|
|
|
|
|
|
|
|
from openvino.inference_engine import IENetwork
|
|
|
|
|
|
|
|
self._network = IENetwork.from_ir(description, weights)
|
|
|
|
|
|
|
|
self._check_model_support(self._network, self._device)
|
|
|
|
self._load_executable_net()
|
|
|
|
self._load_executable_net()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _check_model_support(self, net, device):
|
|
|
|
|
|
|
|
supported_layers = set(self._ie.query_network(net, device))
|
|
|
|
|
|
|
|
not_supported_layers = set(net.layers) - supported_layers
|
|
|
|
|
|
|
|
if len(not_supported_layers) != 0:
|
|
|
|
|
|
|
|
log.error("The following layers are not supported " \
|
|
|
|
|
|
|
|
"by the plugin for device '%s': %s." % \
|
|
|
|
|
|
|
|
(device, ', '.join(not_supported_layers)))
|
|
|
|
|
|
|
|
raise NotImplementedError(
|
|
|
|
|
|
|
|
"Some layers are not supported on the device")
|
|
|
|
|
|
|
|
|
|
|
|
def _load_executable_net(self, batch_size=1):
|
|
|
|
def _load_executable_net(self, batch_size=1):
|
|
|
|
network = self._network
|
|
|
|
network = self._network
|
|
|
|
plugin = self._plugin
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
supported_layers = plugin.get_supported_layers(network)
|
|
|
|
|
|
|
|
not_supported_layers = [l for l in network.layers.keys() if l not in supported_layers]
|
|
|
|
|
|
|
|
if len(not_supported_layers) != 0:
|
|
|
|
|
|
|
|
raise Exception('Following layers are not supported by the plugin'
|
|
|
|
|
|
|
|
' for the specified device {}:\n {}'. format( \
|
|
|
|
|
|
|
|
plugin.device, ", ".join(not_supported_layers)))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
iter_inputs = iter(network.inputs)
|
|
|
|
iter_inputs = iter(network.inputs)
|
|
|
|
self._input_blob_name = next(iter_inputs)
|
|
|
|
self._input_blob_name = next(iter_inputs)
|
|
|
|
@ -131,14 +141,14 @@ class OpenVinoLauncher(Launcher):
|
|
|
|
network.reshape({self._input_blob_name: self._input_layout})
|
|
|
|
network.reshape({self._input_blob_name: self._input_layout})
|
|
|
|
self._batch_size = batch_size
|
|
|
|
self._batch_size = batch_size
|
|
|
|
|
|
|
|
|
|
|
|
self._net = plugin.load(network=network, num_requests=1)
|
|
|
|
self._net = self._ie.load_network(network=network, num_requests=1,
|
|
|
|
|
|
|
|
device_name=self._device)
|
|
|
|
|
|
|
|
|
|
|
|
def infer(self, inputs):
|
|
|
|
def infer(self, inputs):
|
|
|
|
assert len(inputs.shape) == 4, \
|
|
|
|
assert len(inputs.shape) == 4, \
|
|
|
|
"Expected an input image in (N, H, W, C) format, got %s" % \
|
|
|
|
"Expected an input image in (N, H, W, C) format, got %s" % \
|
|
|
|
(inputs.shape)
|
|
|
|
(inputs.shape)
|
|
|
|
assert inputs.shape[3] == 3, \
|
|
|
|
assert inputs.shape[3] == 3, "Expected BGR input, got %s" % inputs.shape
|
|
|
|
"Expected BGR input"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
n, c, h, w = self._input_layout
|
|
|
|
n, c, h, w = self._input_layout
|
|
|
|
if inputs.shape[1:3] != (h, w):
|
|
|
|
if inputs.shape[1:3] != (h, w):
|
|
|
|
@ -170,11 +180,11 @@ class OpenVinoLauncher(Launcher):
|
|
|
|
results = self.process_outputs(inputs, outputs)
|
|
|
|
results = self.process_outputs(inputs, outputs)
|
|
|
|
return results
|
|
|
|
return results
|
|
|
|
|
|
|
|
|
|
|
|
def get_categories(self):
|
|
|
|
def categories(self):
|
|
|
|
return self._interpreter_script.get_categories()
|
|
|
|
return self._interpreter.get_categories()
|
|
|
|
|
|
|
|
|
|
|
|
def process_outputs(self, inputs, outputs):
|
|
|
|
def process_outputs(self, inputs, outputs):
|
|
|
|
return self._interpreter_script.process_outputs(inputs, outputs)
|
|
|
|
return self._interpreter.process_outputs(inputs, outputs)
|
|
|
|
|
|
|
|
|
|
|
|
def preferred_input_size(self):
|
|
|
|
def preferred_input_size(self):
|
|
|
|
_, _, h, w = self._input_layout
|
|
|
|
_, _, h, w = self._input_layout
|
|
|
|
|