convert_model() in openvino.runtime. (#18080)
* Used pip wheel to build OpenVINO wheel * Added convert_model() to openvino.runtime. * Removed duplication of InputCutInfo, LayoutMap * Switched Model Conversion API tests to convert_model from openvino.runtime. * Small correction. * Format correction. * Small correction. * Removed duplication of moc frontend files. * Small correction. * Removed duplication of cli_parser, offline_transformations. * Code corrections. * Removed code duplications. * Removed code duplications. * Updated codeowners. * Switched layer tests to convert_model(). * Improvements * Small correction. * Caffe parser path fix. * Added python api properly into deb / rpm packages * Moved implementation to ovc tool. * Moved implementation to ovc tool. * Small correction. * Use cmake -E variant from cmake 3.13 * Namespace fixes. * Minor fixes. * Pylint fixes. * Fixed BOM file. * Small corrections. * Minor corrections. * Minor fix. * Error fixes. * Added telemetry requirement. * Improvements to fix CI * Some refactoring * Don't use developer package for scripts projects * Added exception in case when MO is not imported. * Removed exception from init. * Removed changes from cmake. * Added unit ovc tests, fixed minor errors. * Added ovc unit tests to azure. * Corrected imports. * Fixed path to tests. * Added missed files. * Corrected github labels. * Removed benchmark app from dev package. * Small fix. * Small corrections. * Comment fixed. * Removed changes from setup.py * Removed not needed change. * Removed duplicating unit tests. * Removed wrong change. * Removed not needed change. * Apply suggestions from code review Co-authored-by: Roman Kazantsev <roman.kazantsev@intel.com> * Added ovc tool test, corrected imports. * Added legacy TF config test. * Removed not needed files. --------- Co-authored-by: Ilya Lavrenov <ilya.lavrenov@intel.com> Co-authored-by: Roman Kazantsev <roman.kazantsev@intel.com>
This commit is contained in:
parent
a2b7d561e4
commit
5d399faa64
|
|
@ -449,6 +449,10 @@ jobs:
|
|||
python3 -m pytest -s $(INSTALL_TEST_DIR)/mo/unit_tests --junitxml=$(INSTALL_TEST_DIR)/TEST-ModelOptimizer.xml
|
||||
displayName: 'Model Optimizer UT'
|
||||
|
||||
- script: |
|
||||
python3 -m pytest -s $(REPO_DIR)/tools/ovc/unit_tests --junitxml=$(INSTALL_TEST_DIR)/TEST-OpenVinoConversion.xml
|
||||
displayName: 'OpenVino Conversion UT'
|
||||
|
||||
- script: $(RUN_PREFIX) $(INSTALL_TEST_DIR)/ov_cpu_func_tests --gtest_filter=*smoke* --gtest_print_time=1 --gtest_output=xml:$(INSTALL_TEST_DIR)/TEST-ov_cpu_func_tests.xml
|
||||
displayName: 'CPU FuncTests'
|
||||
condition: and(succeeded(), eq(variables['CMAKE_BUILD_SHARED_LIBS'], 'OFF'))
|
||||
|
|
|
|||
|
|
@ -99,6 +99,7 @@
|
|||
/tools/legacy/ @openvinotoolkit/openvino-samples-maintainers
|
||||
/tools/openvino_dev/ @openvinotoolkit/openvino-tools-maintainers @openvinotoolkit/openvino-ie-python-api-maintainers
|
||||
/tools/mo/ @openvinotoolkit/openvino-mo-maintainers
|
||||
/tools/ovc/ @openvinotoolkit/openvino-mo-maintainers
|
||||
/tools/pot/ @openvinotoolkit/openvino-pot-maintainers
|
||||
/thirdparty/open_model_zoo/ @openvinotoolkit/omz-maintainers @openvinotoolkit/openvino-pot-maintainers
|
||||
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@
|
|||
|
||||
'category: MO':
|
||||
- 'tools/mo/**/*'
|
||||
- 'tools/ovc/**/*'
|
||||
|
||||
'category: ONNX FE':
|
||||
- 'src/frontends/onnx/**/*'
|
||||
|
|
|
|||
|
|
@ -1,2 +1,3 @@
|
|||
numpy>=1.16.6
|
||||
singledispatchmethod; python_version<'3.8'
|
||||
openvino-telemetry>=2023.0.0
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@
|
|||
# mypy: ignore-errors
|
||||
|
||||
|
||||
from openvino.tools.mo.moc_frontend.shape_utils import get_static_shape
|
||||
from openvino.tools.mo.utils.versions_checker import get_environment_setup # pylint: disable=no-name-in-module
|
||||
from openvino.tools.mo.utils.error import Error
|
||||
from openvino.tools.ovc.moc_frontend.shape_utils import get_static_shape
|
||||
from openvino.tools.ovc.environment_setup_utils import get_environment_setup # pylint: disable=no-name-in-module
|
||||
from openvino.tools.ovc.error import Error
|
||||
from distutils.version import LooseVersion
|
||||
import logging as log
|
||||
|
||||
|
|
|
|||
|
|
@ -67,6 +67,13 @@ from openvino.runtime.ie_api import tensor_from_file
|
|||
from openvino.runtime.ie_api import compile_model
|
||||
|
||||
|
||||
# Model Conversion API
|
||||
try:
|
||||
from openvino.tools.ovc import convert_model, InputCutInfo, LayoutMap
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
# Extend Node class to support binary operators
|
||||
Node.__add__ = opset11.add
|
||||
Node.__sub__ = opset11.subtract
|
||||
|
|
|
|||
|
|
@ -175,6 +175,18 @@ PY_INSTALL_CFG = {
|
|||
"install_dir": PY_PACKAGES_DIR,
|
||||
"binary_dir": OPENVINO_PYTHON_BINARY_DIR,
|
||||
},
|
||||
"ovc": {
|
||||
"entry_point": {
|
||||
"console_scripts": [
|
||||
"ovc = openvino.tools.ovc.main:main",
|
||||
],
|
||||
},
|
||||
"name": f"pyopenvino_{PYTHON_VERSION}",
|
||||
"prefix": f"{BUILD_BASE}/site-packages",
|
||||
"source_dir": f"{OPENVINO_SOURCE_DIR}/tools/ovc",
|
||||
"install_dir": PY_PACKAGES_DIR,
|
||||
"binary_dir": "ovc",
|
||||
},
|
||||
# "benchmark_app": { # noqa: E731
|
||||
# "entry_point": { # noqa: E731
|
||||
# "console_scripts": [ # noqa: E731
|
||||
|
|
@ -187,18 +199,6 @@ PY_INSTALL_CFG = {
|
|||
# "install_dir": PY_PACKAGES_DIR, # noqa: E731
|
||||
# "binary_dir": "benchmark_app", # noqa: E731
|
||||
# }, # noqa: E731
|
||||
# "model_optimizer": { # noqa: E731
|
||||
# "entry_point": { # noqa: E731
|
||||
# "console_scripts": [ # noqa: E731
|
||||
# "mo = openvino.tools.mo.main:main", # noqa: E731
|
||||
# ], # noqa: E731
|
||||
# }, # noqa: E731
|
||||
# "name": f"pyopenvino_{PYTHON_VERSION}", # noqa: E731
|
||||
# "prefix": f"{BUILD_BASE}/site-packages", # noqa: E731
|
||||
# "source_dir": f"{OPENVINO_SOURCE_DIR}/tools/mo", # noqa: E731
|
||||
# "install_dir": PY_PACKAGES_DIR, # noqa: E731
|
||||
# "binary_dir": "model_optimizer", # noqa: E731
|
||||
# }, # noqa: E731
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -11,8 +11,7 @@ from pathlib import Path
|
|||
import numpy as np
|
||||
from common.constants import test_device, test_precision
|
||||
from common.layer_utils import IEInfer, InferAPI20
|
||||
from common.utils.common_utils import generate_ir
|
||||
from common.utils.parsers import mapping_parser
|
||||
from common.utils.common_utils import generate_ir_python_api
|
||||
|
||||
|
||||
class CommonLayerTest:
|
||||
|
|
@ -60,7 +59,7 @@ class CommonLayerTest:
|
|||
else:
|
||||
mo_params["use_legacy_frontend"] = True
|
||||
|
||||
exit_code, stderr = generate_ir(**mo_params)
|
||||
exit_code, stderr = generate_ir_python_api(**mo_params)
|
||||
|
||||
del os.environ['MO_ENABLED_TRANSFORMS']
|
||||
del os.environ['MO_DISABLED_TRANSFORMS']
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@
|
|||
|
||||
from pathlib import Path
|
||||
|
||||
from openvino.runtime import serialize
|
||||
from openvino.runtime import serialize, convert_model
|
||||
from openvino.tools.mo import convert_model as legacy_convert_model
|
||||
from openvino.test_utils import compare_functions
|
||||
from openvino.tools.mo import convert_model
|
||||
|
||||
from common.utils.common_utils import generate_ir
|
||||
|
||||
|
|
@ -16,7 +16,10 @@ class CommonMOConvertTest:
|
|||
output_dir = kwargs['output_dir']
|
||||
model_name = kwargs['model_name']
|
||||
del kwargs['output_dir']
|
||||
model = convert_model(**kwargs)
|
||||
if 'use_legacy_frontend' in kwargs:
|
||||
model = legacy_convert_model(**kwargs)
|
||||
else:
|
||||
model = convert_model(**kwargs)
|
||||
serialize(model, str(Path(output_dir, model_name + '.xml')))
|
||||
|
||||
def _test(self, temp_dir, test_params, ref_params):
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import logging
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
|
|
@ -46,6 +47,20 @@ def generate_ir(coverage=False, **kwargs):
|
|||
return exit_code, stderr
|
||||
|
||||
|
||||
def generate_ir_python_api(coverage=False, **kwargs):
|
||||
from openvino.runtime import convert_model, serialize
|
||||
from openvino.tools.mo import convert_model as legacy_convert_model
|
||||
|
||||
if "use_legacy_frontend" in kwargs and kwargs['use_legacy_frontend']:
|
||||
ov_model = legacy_convert_model(**kwargs)
|
||||
else:
|
||||
ov_model = convert_model(**kwargs)
|
||||
|
||||
out_dir = kwargs['output_dir'] + os.sep + kwargs['model_name'] + ".xml"
|
||||
serialize(ov_model, out_dir)
|
||||
|
||||
return 0, ""
|
||||
|
||||
def shell(cmd, env=None, cwd=None, out_format="plain"):
|
||||
"""
|
||||
Run command execution in specified environment
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from openvino.tools.mo import convert_model
|
||||
from openvino.runtime import convert_model
|
||||
|
||||
if __name__ == "__main__":
|
||||
convert_model(help=True)
|
||||
|
|
|
|||
|
|
@ -4,8 +4,7 @@
|
|||
import numpy as np
|
||||
import os
|
||||
import pytest
|
||||
from openvino.runtime import Model, Layout, PartialShape, Shape, layout_helpers, Type, Dimension
|
||||
from openvino.tools.mo.convert import InputCutInfo, LayoutMap
|
||||
from openvino.runtime import Model, Layout, PartialShape, Shape, layout_helpers, Type, Dimension, InputCutInfo, LayoutMap
|
||||
|
||||
from common.mo_convert_test_class import CommonMOConvertTest
|
||||
from common.tf_layer_test_class import save_to_pb
|
||||
|
|
|
|||
|
|
@ -9,8 +9,7 @@ import openvino.runtime as ov
|
|||
import pytest
|
||||
import torch
|
||||
import unittest
|
||||
from openvino.runtime import PartialShape, Dimension, Model, Type
|
||||
from openvino.tools.mo import InputCutInfo
|
||||
from openvino.runtime import PartialShape, Dimension, Model, Type, InputCutInfo
|
||||
|
||||
from common.mo_convert_test_class import CommonMOConvertTest
|
||||
|
||||
|
|
@ -747,7 +746,7 @@ def create_pt_model_with_custom_op():
|
|||
|
||||
class ConvertRaises(unittest.TestCase):
|
||||
def test_example_inputs(self):
|
||||
from openvino.tools.mo import convert_model
|
||||
from openvino.runtime import convert_model
|
||||
pytorch_model = create_pt_model_with_custom_op()
|
||||
|
||||
# Check that mo raises error message of wrong argument.
|
||||
|
|
|
|||
|
|
@ -666,7 +666,7 @@ class TFConvertTest(unittest.TestCase):
|
|||
@pytest.mark.precommit
|
||||
def test_tf_function_no_signature(self):
|
||||
import tensorflow as tf
|
||||
from openvino.tools.mo import convert_model
|
||||
from openvino.runtime import convert_model
|
||||
|
||||
@tf.function()
|
||||
def function(x1, x2):
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import os
|
|||
import sys
|
||||
import unittest
|
||||
from openvino.tools.mo import mo
|
||||
from openvino.tools.mo.utils.cli_parser import get_mo_convert_params
|
||||
from openvino.tools.ovc.cli_parser import get_mo_convert_params
|
||||
from pathlib import Path
|
||||
|
||||
from common.utils.common_utils import shell
|
||||
|
|
|
|||
|
|
@ -0,0 +1,89 @@
|
|||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import numpy as np
|
||||
import openvino.runtime as ov
|
||||
from openvino.runtime import PartialShape, Model
|
||||
from openvino.test_utils import compare_functions
|
||||
from openvino.tools.ovc import ovc
|
||||
|
||||
from common.mo_convert_test_class import CommonMOConvertTest
|
||||
from common.tf_layer_test_class import save_to_pb
|
||||
from common.utils.common_utils import shell
|
||||
|
||||
|
||||
def generate_ir_ovc(coverage=False, **kwargs):
|
||||
# Get OVC file directory
|
||||
ovc_path = Path(ovc.__file__).parent
|
||||
|
||||
ovc_runner = ovc_path.joinpath('main.py').as_posix()
|
||||
if coverage:
|
||||
params = [sys.executable, '-m', 'coverage', 'run', '-p', '--source={}'.format(ovc_runner.parent),
|
||||
'--omit=*_test.py', ovc_runner]
|
||||
else:
|
||||
params = [sys.executable, ovc_runner]
|
||||
for key, value in kwargs.items():
|
||||
if key == "batch":
|
||||
params.extend(("-b", str(value)))
|
||||
elif key == "k":
|
||||
params.extend(("-k", str(value)))
|
||||
# for FP32 set explicitly compress_to_fp16=False,
|
||||
# if we omit this argument for FP32, it will be set implicitly to True as the default
|
||||
elif key == 'compress_to_fp16':
|
||||
params.append("--{}={}".format(key, value))
|
||||
elif isinstance(value, bool) and value:
|
||||
params.append("--{}".format(key))
|
||||
elif isinstance(value, bool) and not value:
|
||||
continue
|
||||
elif (isinstance(value, tuple) and value) or (isinstance(value, str)):
|
||||
params.extend(("--{}".format(key), str('"{}"'.format(value))))
|
||||
elif key == "mean_values" and (' ' in value or '(' in value):
|
||||
params.extend(("--{}".format(key), str('"{}"'.format(value))))
|
||||
else:
|
||||
params.extend(("--{}".format(key), str(value)))
|
||||
exit_code, stdout, stderr = shell(params)
|
||||
return exit_code, stderr
|
||||
|
||||
def create_ref_graph():
|
||||
shape = PartialShape([1, 3, 2, 2])
|
||||
param = ov.opset8.parameter(shape, dtype=np.float32)
|
||||
relu = ov.opset8.relu(param)
|
||||
sigm = ov.opset8.sigmoid(relu)
|
||||
|
||||
return Model([sigm], [param], "test")
|
||||
|
||||
class TestOVCTool(CommonMOConvertTest):
|
||||
def create_tf_model(self, tmp_dir):
|
||||
import tensorflow as tf
|
||||
|
||||
tf.compat.v1.reset_default_graph()
|
||||
|
||||
with tf.compat.v1.Session() as sess:
|
||||
inp = tf.compat.v1.placeholder(tf.float32, [1, 3, 2, 2], 'Input')
|
||||
relu = tf.nn.relu(inp, name='Relu')
|
||||
output = tf.nn.sigmoid(relu, name='Sigmoid')
|
||||
tf.compat.v1.global_variables_initializer()
|
||||
tf_net = sess.graph_def
|
||||
|
||||
# save model to .pb and return path to the model
|
||||
return save_to_pb(tf_net, tmp_dir)
|
||||
|
||||
|
||||
def test_ovc_tool(self, ie_device, precision, ir_version, temp_dir, use_new_frontend, use_old_api):
|
||||
from openvino.runtime import Core
|
||||
|
||||
model_path = self.create_tf_model(temp_dir)
|
||||
|
||||
core = Core()
|
||||
|
||||
# tests for MO cli tool
|
||||
exit_code, stderr = generate_ir_ovc(coverage=False, **{"input_model": model_path, "output_dir": temp_dir})
|
||||
assert not exit_code
|
||||
|
||||
ov_model = core.read_model(os.path.join(temp_dir, "model.xml"))
|
||||
flag, msg = compare_functions(ov_model, create_ref_graph(), False)
|
||||
assert flag, msg
|
||||
|
|
@ -139,7 +139,7 @@ class PytorchLayerTest:
|
|||
|
||||
def convert_via_mo(self, model, example_input, trace_model, dynamic_shapes, ov_inputs):
|
||||
import torch
|
||||
from openvino.tools.mo import convert_model
|
||||
from openvino.runtime import convert_model
|
||||
kwargs = {"example_input": example_input if len(
|
||||
example_input) > 1 else example_input[0], "compress_to_fp16": False}
|
||||
with torch.no_grad():
|
||||
|
|
|
|||
|
|
@ -36,10 +36,15 @@ add_subdirectory(mo)
|
|||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/pot/openvino/tools/pot/version.txt.in"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/pot/openvino/tools/pot/version.txt" @ONLY)
|
||||
|
||||
# Benchmark Tool
|
||||
|
||||
if(ENABLE_PYTHON)
|
||||
|
||||
# Benchmark Tool
|
||||
add_subdirectory(benchmark_tool)
|
||||
|
||||
# OpenVino Conversion Tool
|
||||
add_subdirectory(ovc)
|
||||
|
||||
endif()
|
||||
|
||||
# wheel openvino-dev
|
||||
|
|
|
|||
|
|
@ -41,12 +41,10 @@ openvino/tools/mo/back/MatMulNormalizer.py
|
|||
openvino/tools/mo/back/MaxPool.py
|
||||
openvino/tools/mo/back/names_uniqueness_check.py
|
||||
openvino/tools/mo/back/NormalizeToNormalizeL2.py
|
||||
openvino/tools/mo/back/offline_transformations.py
|
||||
openvino/tools/mo/back/op_versioning.py
|
||||
openvino/tools/mo/back/OptimizeTransposeReshapeSequence.py
|
||||
openvino/tools/mo/back/PackBinaryWeights.py
|
||||
openvino/tools/mo/back/pass_separator.py
|
||||
openvino/tools/mo/back/preprocessing.py
|
||||
openvino/tools/mo/back/priorbox_mutation.py
|
||||
openvino/tools/mo/back/ProposalMutation.py
|
||||
openvino/tools/mo/back/ReduceMerge.py
|
||||
|
|
@ -831,16 +829,6 @@ openvino/tools/mo/mo_mxnet.py
|
|||
openvino/tools/mo/mo_onnx.py
|
||||
openvino/tools/mo/mo_paddle.py
|
||||
openvino/tools/mo/mo_tf.py
|
||||
openvino/tools/mo/moc_frontend/__init__.py
|
||||
openvino/tools/mo/moc_frontend/analysis.py
|
||||
openvino/tools/mo/moc_frontend/check_config.py
|
||||
openvino/tools/mo/moc_frontend/extractor.py
|
||||
openvino/tools/mo/moc_frontend/layout_utils.py
|
||||
openvino/tools/mo/moc_frontend/paddle_frontend_utils.py
|
||||
openvino/tools/mo/moc_frontend/pipeline.py
|
||||
openvino/tools/mo/moc_frontend/pytorch_frontend_utils.py
|
||||
openvino/tools/mo/moc_frontend/serialize.py
|
||||
openvino/tools/mo/moc_frontend/shape_utils.py
|
||||
openvino/tools/mo/ops/__init__.py
|
||||
openvino/tools/mo/ops/activation.py
|
||||
openvino/tools/mo/ops/activation_ops.py
|
||||
|
|
@ -1038,7 +1026,6 @@ openvino/tools/mo/utils/find_inputs.py
|
|||
openvino/tools/mo/utils/get_ov_update_message.py
|
||||
openvino/tools/mo/utils/graph.py
|
||||
openvino/tools/mo/utils/guess_framework.py
|
||||
openvino/tools/mo/utils/help.py
|
||||
openvino/tools/mo/utils/ie_version.py
|
||||
openvino/tools/mo/utils/import_extensions.py
|
||||
openvino/tools/mo/utils/ir_engine/__init__.py
|
||||
|
|
@ -1098,12 +1085,10 @@ openvino/tools/mo/utils/shape.py
|
|||
openvino/tools/mo/utils/simple_proto_parser.py
|
||||
openvino/tools/mo/utils/str_to.py
|
||||
openvino/tools/mo/utils/summarize_graph.py
|
||||
openvino/tools/mo/utils/telemetry_params.py
|
||||
openvino/tools/mo/utils/telemetry_stub.py
|
||||
openvino/tools/mo/utils/telemetry_utils.py
|
||||
openvino/tools/mo/utils/tensorboard_util.py
|
||||
openvino/tools/mo/utils/type_utils.py
|
||||
openvino/tools/mo/utils/unsupported_ops.py
|
||||
openvino/tools/mo/utils/utils.py
|
||||
openvino/tools/mo/utils/version.py
|
||||
openvino/tools/mo/utils/versions_checker.py
|
||||
openvino/tools/mo/utils/version.py
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from .convert import convert_model, InputCutInfo, LayoutMap
|
||||
from openvino.tools.mo.convert import convert_model
|
||||
from openvino.tools.ovc import InputCutInfo, LayoutMap # pylint: disable=no-name-in-module,import-error
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ from openvino.tools.mo.back.replacement import BackReplacementPattern
|
|||
from openvino.tools.mo.front.common.partial_infer.utils import mo_array
|
||||
from openvino.tools.mo.graph.graph import Graph
|
||||
from openvino.tools.mo.ops.crop import Crop
|
||||
from openvino.tools.mo.utils.logger import log
|
||||
from openvino.tools.ovc.logger import log # pylint: disable=no-name-in-module,import-error
|
||||
|
||||
|
||||
class CutMemoryInput(BackReplacementPattern):
|
||||
|
|
|
|||
|
|
@ -2,16 +2,13 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
import os
|
||||
import pathlib
|
||||
from collections import namedtuple
|
||||
from typing import Any
|
||||
|
||||
from openvino.runtime import PartialShape, Shape, Layout, Model
|
||||
from openvino.tools.mo.convert_impl import _convert
|
||||
from openvino.tools.mo.utils.cli_parser import get_all_cli_parser
|
||||
from openvino.tools.mo.utils.logger import get_logger_state, restore_logger_state
|
||||
|
||||
InputCutInfo = namedtuple("InputInfo", ["name", "shape", "type", "value"], defaults=[None, None, None, None])
|
||||
LayoutMap = namedtuple("LayoutMap", ["source_layout", "target_layout"], defaults=[None, None])
|
||||
from openvino.tools.ovc import InputCutInfo, LayoutMap # pylint: disable=no-name-in-module,import-error
|
||||
from openvino.tools.ovc.cli_parser import get_all_cli_parser # pylint: disable=no-name-in-module,import-error
|
||||
from openvino.tools.ovc.logger import get_logger_state, restore_logger_state # pylint: disable=no-name-in-module,import-error
|
||||
|
||||
|
||||
def convert_model(
|
||||
|
|
@ -68,8 +65,8 @@ def convert_model(
|
|||
|
||||
# Caffe*-specific parameters:
|
||||
input_proto: [str, pathlib.Path] = None,
|
||||
caffe_parser_path: [str, pathlib.Path] = os.path.join(os.path.dirname(__file__), 'front', 'caffe', 'proto'),
|
||||
k: [str, pathlib.Path] = os.path.join(os.path.dirname(__file__), 'front', 'caffe', 'CustomLayersMapping.xml'),
|
||||
caffe_parser_path: [str, pathlib.Path] = None,
|
||||
k: [str, pathlib.Path] = None,
|
||||
disable_omitting_optional: bool = False,
|
||||
enable_flattening_nested_params: bool = False,
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import sys
|
|||
import traceback
|
||||
from collections import OrderedDict
|
||||
from copy import deepcopy
|
||||
from distutils.version import LooseVersion
|
||||
from pathlib import Path
|
||||
|
||||
try:
|
||||
|
|
@ -19,17 +18,19 @@ except ImportError:
|
|||
import openvino.tools.mo.utils.telemetry_stub as tm
|
||||
|
||||
from openvino.tools.mo.back.SpecialNodesFinalization import RemoveConstOps, CreateConstNodesReplacement, NormalizeTI
|
||||
from openvino.tools.mo.moc_frontend.check_config import legacy_transformations_config_used, \
|
||||
tensorflow_custom_operations_config_update_used, new_extensions_used
|
||||
from openvino.tools.mo.moc_frontend.pipeline import moc_pipeline
|
||||
from openvino.tools.mo.moc_frontend.serialize import moc_emit_ir
|
||||
from openvino.tools.ovc.moc_frontend.check_config import legacy_transformations_config_used, \
|
||||
tensorflow_custom_operations_config_update_used, new_extensions_used # pylint: disable=no-name-in-module,import-error
|
||||
from openvino.tools.ovc.moc_frontend.pipeline import moc_pipeline # pylint: disable=no-name-in-module,import-error
|
||||
from openvino.tools.ovc.moc_frontend.moc_emit_ir import moc_emit_ir # pylint: disable=no-name-in-module,import-error
|
||||
from openvino.tools.mo.graph.graph import Graph
|
||||
from openvino.tools.mo.middle.pattern_match import for_graph_and_each_sub_graph_recursively
|
||||
from openvino.tools.mo.middle.passes.convert_data_type import destination_type_to_np_data_type
|
||||
from openvino.tools.mo.pipeline.common import prepare_emit_ir
|
||||
from openvino.tools.mo.pipeline.unified import unified_pipeline
|
||||
from openvino.tools.mo.utils import import_extensions
|
||||
from openvino.tools.mo.utils.cli_parser import check_available_transforms, \
|
||||
|
||||
# pylint: disable=no-name-in-module,import-error
|
||||
from openvino.tools.ovc.cli_parser import check_available_transforms, \
|
||||
get_advanced_cli_options, get_available_front_ends, get_caffe_cli_options, \
|
||||
get_common_cli_options, get_freeze_placeholder_values, get_kaldi_cli_options, get_layout_values, \
|
||||
get_mean_scale_dictionary, get_mxnet_cli_options, get_onnx_cli_options, \
|
||||
|
|
@ -38,19 +39,20 @@ from openvino.tools.mo.utils.cli_parser import check_available_transforms, \
|
|||
input_shape_to_input_cut_info, freeze_placeholder_to_input_cut_info
|
||||
|
||||
from openvino.tools.mo.utils.error import Error, FrameworkError
|
||||
from openvino.tools.mo.utils.get_ov_update_message import get_ov_update_message, get_ov_api20_message, \
|
||||
get_tf_fe_message, get_try_legacy_fe_message, get_compression_message
|
||||
from openvino.tools.ovc.get_ov_update_message import get_ov_update_message, get_ov_api20_message, \
|
||||
get_tf_fe_message, get_compression_message # pylint: disable=no-name-in-module,import-error
|
||||
from openvino.tools.mo.utils.get_ov_update_message import get_try_legacy_fe_message
|
||||
from openvino.tools.mo.utils.model_analysis import AnalysisResults
|
||||
from openvino.tools.mo.utils.version import VersionChecker
|
||||
from openvino.tools.mo.utils.guess_framework import deduce_legacy_frontend_by_namespace
|
||||
from openvino.tools.mo.utils.logger import init_logger, progress_printer
|
||||
from openvino.tools.ovc.logger import init_logger, progress_printer # pylint: disable=no-name-in-module,import-error
|
||||
from openvino.tools.mo.utils.utils import refer_to_faq_msg, check_values_equal
|
||||
from openvino.tools.mo.utils.telemetry_utils import send_params_info, send_framework_info, send_conversion_result, \
|
||||
get_tid
|
||||
from openvino.tools.mo.moc_frontend.check_config import legacy_extensions_used
|
||||
from openvino.tools.mo.moc_frontend.pytorch_frontend_utils import get_pytorch_decoder, extract_input_info_from_example
|
||||
from openvino.tools.mo.moc_frontend.paddle_frontend_utils import paddle_frontend_converter
|
||||
from openvino.tools.mo.moc_frontend.shape_utils import parse_input_shapes
|
||||
from openvino.tools.ovc.moc_frontend.check_config import legacy_extensions_used # pylint: disable=no-name-in-module,import-error
|
||||
from openvino.tools.ovc.moc_frontend.pytorch_frontend_utils import get_pytorch_decoder, extract_input_info_from_example # pylint: disable=no-name-in-module,import-error
|
||||
from openvino.tools.ovc.moc_frontend.paddle_frontend_utils import paddle_frontend_converter # pylint: disable=no-name-in-module,import-error
|
||||
from openvino.tools.ovc.moc_frontend.shape_utils import parse_input_shapes # pylint: disable=no-name-in-module,import-error
|
||||
|
||||
# pylint: disable=no-name-in-module,import-error
|
||||
from openvino.frontend import FrontEndManager, OpConversionFailure, ProgressReporterExtension, TelemetryExtension
|
||||
|
|
@ -491,7 +493,7 @@ def emit_ir(graph: Graph, argv: argparse.Namespace, non_default_params: dict):
|
|||
return_code = "not executed"
|
||||
if not (argv.framework == 'tf' and argv.tensorflow_custom_operations_config_update):
|
||||
try:
|
||||
from openvino.tools.mo.back.offline_transformations import apply_offline_transformations
|
||||
from openvino.tools.ovc.moc_frontend.offline_transformations import apply_offline_transformations # pylint: disable=no-name-in-module,import-error
|
||||
func = apply_offline_transformations(func, argv)
|
||||
if "compress_to_fp16" in argv and argv.compress_to_fp16:
|
||||
# restore data_type cmd parameter
|
||||
|
|
@ -841,7 +843,7 @@ def _convert(cli_parser: argparse.ArgumentParser, framework, args, python_api_us
|
|||
elif 'example_inputs' in args:
|
||||
raise AssertionError("'example_inputs' argument is not recognized, maybe you meant to provide 'example_input'?")
|
||||
|
||||
decoder = get_pytorch_decoder(args['input_model'], parse_input_shapes(args), example_inputs, args)
|
||||
decoder = get_pytorch_decoder(args['input_model'], parse_input_shapes(args), example_inputs, args)
|
||||
if model_framework == "paddle":
|
||||
example_inputs = None
|
||||
if 'example_input' in args and args['example_input'] is not None:
|
||||
|
|
@ -951,6 +953,6 @@ def _convert(cli_parser: argparse.ArgumentParser, framework, args, python_api_us
|
|||
|
||||
send_conversion_result('fail')
|
||||
if python_api_used:
|
||||
raise e#.with_traceback(None)
|
||||
raise e.with_traceback(None)
|
||||
else:
|
||||
return None, argv
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ from pathlib import Path
|
|||
from openvino.tools.mo.graph.graph import Node
|
||||
from openvino.tools.mo.utils.error import Error, FrameworkError
|
||||
from openvino.tools.mo.utils.utils import refer_to_faq_msg
|
||||
from openvino.tools.mo.utils.versions_checker import get_environment_setup
|
||||
from openvino.tools.ovc.environment_setup_utils import get_environment_setup # pylint: disable=no-name-in-module,import-error
|
||||
|
||||
# do not print INFO and WARNING messages from TensorFlow
|
||||
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import os
|
||||
from openvino.tools.mo.load.loader import Loader
|
||||
from openvino.tools.mo.front.caffe import custom_layers_mapping, loader
|
||||
from openvino.tools.mo.front.caffe.extractor import caffe_type_extractors, caffe_extractor
|
||||
|
|
@ -17,6 +18,8 @@ class CaffeLoader(Loader):
|
|||
|
||||
def load(self, graph: Graph):
|
||||
argv = graph.graph['cmd_params']
|
||||
if argv.caffe_parser_path is None:
|
||||
argv.caffe_parser_path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'front', 'caffe', 'proto')
|
||||
caffe_pb2 = loader.import_caffe_pb2(argv.caffe_parser_path)
|
||||
|
||||
proto, model = loader.load_caffe_proto_model(caffe_pb2, argv.input_proto, argv.input_model)
|
||||
|
|
@ -42,6 +45,8 @@ class CaffeLoader(Loader):
|
|||
graph.graph['original_shapes'] = original_shapes
|
||||
graph.graph['caffe_pb2'] = caffe_pb2
|
||||
|
||||
if argv.k is None:
|
||||
argv.k = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'front', 'caffe', 'CustomLayersMapping.xml')
|
||||
custom_layers_map = custom_layers_mapping.load_layers_xml(argv.k)
|
||||
custom_layers_mapping.update_extractors(
|
||||
caffe_type_extractors,
|
||||
|
|
|
|||
|
|
@ -34,5 +34,5 @@ def main(cli_parser: argparse.ArgumentParser, framework=None):
|
|||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from openvino.tools.mo.utils.cli_parser import get_all_cli_parser
|
||||
from openvino.tools.ovc.cli_parser import get_all_cli_parser # pylint: disable=no-name-in-module,import-error
|
||||
sys.exit(main(get_all_cli_parser(), None))
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
import sys
|
||||
|
||||
from openvino.tools.mo.utils.cli_parser import get_caffe_cli_parser
|
||||
from openvino.tools.ovc.cli_parser import get_caffe_cli_parser # pylint: disable=no-name-in-module,import-error
|
||||
|
||||
if __name__ == "__main__":
|
||||
from openvino.tools.mo.main import main
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
import sys
|
||||
|
||||
from openvino.tools.mo.utils.cli_parser import get_kaldi_cli_parser
|
||||
from openvino.tools.ovc.cli_parser import get_kaldi_cli_parser # pylint: disable=no-name-in-module,import-error
|
||||
|
||||
if __name__ == "__main__":
|
||||
from openvino.tools.mo.main import main
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
import sys
|
||||
|
||||
from openvino.tools.mo.utils.cli_parser import get_mxnet_cli_parser
|
||||
from openvino.tools.ovc.cli_parser import get_mxnet_cli_parser # pylint: disable=no-name-in-module,import-error
|
||||
|
||||
if __name__ == "__main__":
|
||||
from openvino.tools.mo.main import main
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
import sys
|
||||
|
||||
from openvino.tools.mo.utils.cli_parser import get_onnx_cli_parser
|
||||
from openvino.tools.ovc.cli_parser import get_onnx_cli_parser # pylint: disable=no-name-in-module,import-error
|
||||
|
||||
if __name__ == "__main__":
|
||||
from openvino.tools.mo.main import main
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
import sys
|
||||
|
||||
from openvino.tools.mo.utils.cli_parser import get_all_cli_parser
|
||||
from openvino.tools.ovc.cli_parser import get_all_cli_parser # pylint: disable=no-name-in-module,import-error
|
||||
|
||||
from openvino.frontend import FrontEndManager # pylint: disable=no-name-in-module,import-error
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
import sys
|
||||
|
||||
from openvino.tools.mo.utils.cli_parser import get_tf_cli_parser
|
||||
from openvino.tools.ovc.cli_parser import get_tf_cli_parser # pylint: disable=no-name-in-module,import-error
|
||||
|
||||
if __name__ == "__main__":
|
||||
from openvino.tools.mo.main import main
|
||||
|
|
|
|||
|
|
@ -10,88 +10,10 @@ from openvino.tools.mo.graph.graph import Node, Graph
|
|||
from openvino.tools.mo.utils.error import Error
|
||||
from openvino.tools.mo.utils.utils import refer_to_faq_msg
|
||||
|
||||
"""
|
||||
Packed data of custom types are stored in numpy uint8 data type.
|
||||
To distinguish true uint8 and custom data we introduce this class not to store,
|
||||
but to have unique data type in SUPPORTED_DATA_TYPES map
|
||||
"""
|
||||
|
||||
|
||||
class packed_U1(np.generic):
|
||||
pass
|
||||
|
||||
|
||||
class packed_U4(np.generic):
|
||||
pass
|
||||
|
||||
|
||||
class packed_I4(np.generic):
|
||||
pass
|
||||
|
||||
|
||||
SUPPORTED_DATA_TYPES = {
|
||||
'float': (np.float32, 'FP32', 'f32'),
|
||||
'half': (np.float16, 'FP16', 'f16'),
|
||||
'FP32': (np.float32, 'FP32', 'f32'),
|
||||
'FP64': (np.float64, 'FP64', 'f64'),
|
||||
'FP16': (np.float16, 'FP16', 'f16'),
|
||||
'I32': (np.int32, 'I32', 'i32'),
|
||||
'I64': (np.int64, 'I64', 'i64'),
|
||||
'int8': (np.int8, 'I8', 'i8'),
|
||||
'int32': (np.int32, 'I32', 'i32'),
|
||||
'int64': (np.int64, 'I64', 'i64'),
|
||||
'bool': (bool, 'BOOL', 'boolean'),
|
||||
'uint8': (np.uint8, 'U8', 'u8'),
|
||||
'uint32': (np.uint32, 'U32', 'u32'),
|
||||
'uint64': (np.uint64, 'U64', 'u64'),
|
||||
|
||||
# custom types
|
||||
'U1': (packed_U1, 'U1', 'u1'),
|
||||
'int4': (packed_I4, 'I4', 'i4'),
|
||||
'uint4': (packed_U4, 'U4', 'u4'),
|
||||
'I4': (packed_I4, 'I4', 'i4'),
|
||||
'U4': (packed_U4, 'U4', 'u4'),
|
||||
}
|
||||
|
||||
|
||||
def data_type_str_to_np(data_type_str: str):
|
||||
return SUPPORTED_DATA_TYPES[data_type_str][0] if data_type_str in SUPPORTED_DATA_TYPES else None
|
||||
|
||||
|
||||
def data_type_str_to_precision(data_type_str: str):
|
||||
return SUPPORTED_DATA_TYPES[data_type_str][1] if data_type_str in SUPPORTED_DATA_TYPES else None
|
||||
|
||||
|
||||
def data_type_str_to_destination_type(data_type_str: str):
|
||||
return SUPPORTED_DATA_TYPES[data_type_str][2] if data_type_str in SUPPORTED_DATA_TYPES else None
|
||||
|
||||
|
||||
def np_data_type_to_precision(np_data_type):
|
||||
for np_t, precision, _ in SUPPORTED_DATA_TYPES.values():
|
||||
if np_t == np_data_type:
|
||||
return precision
|
||||
raise Error('Data type "{}" is not supported'.format(np_data_type))
|
||||
|
||||
|
||||
def np_data_type_to_destination_type(np_data_type):
|
||||
for np_t, _, destination_type in SUPPORTED_DATA_TYPES.values():
|
||||
if np_t == np_data_type:
|
||||
return destination_type
|
||||
raise Error('Data type "{}" is not supported'.format(np_data_type))
|
||||
|
||||
|
||||
def destination_type_to_np_data_type(dst_type):
|
||||
for np_t, _, destination_type in SUPPORTED_DATA_TYPES.values():
|
||||
if destination_type == dst_type:
|
||||
return np_t
|
||||
raise Error('Destination type "{}" is not supported'.format(dst_type))
|
||||
|
||||
|
||||
def precision_to_destination_type(data_type_str):
|
||||
for _, precision, destination_type in SUPPORTED_DATA_TYPES.values():
|
||||
if precision == data_type_str:
|
||||
return destination_type
|
||||
raise Error('Data type "{}" is not supported'.format(data_type_str))
|
||||
# pylint: disable=no-name-in-module,import-error
|
||||
from openvino.tools.ovc.convert_data_type import packed_U1, packed_U4, packed_I4, SUPPORTED_DATA_TYPES, \
|
||||
data_type_str_to_np, data_type_str_to_precision, data_type_str_to_destination_type, np_data_type_to_precision, \
|
||||
np_data_type_to_destination_type, destination_type_to_np_data_type, precision_to_destination_type
|
||||
|
||||
|
||||
def convert_blob(blob: np.ndarray, dst_type: type):
|
||||
|
|
|
|||
|
|
@ -12,8 +12,7 @@ from openvino.tools.mo.graph.graph import Graph
|
|||
from openvino.tools.mo.middle.passes.eliminate import shape_inference
|
||||
from openvino.tools.mo.middle.pattern_match import for_graph_and_each_sub_graph_recursively
|
||||
from openvino.tools.mo.utils.error import Error, InternalError, FrameworkError
|
||||
from openvino.tools.mo.utils.logger import progress_bar
|
||||
from openvino.tools.mo.utils.utils import refer_to_faq_msg
|
||||
from openvino.tools.ovc.logger import progress_bar # pylint: disable=no-name-in-module,import-error
|
||||
|
||||
_registered_classes_dict = {}
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,49 +1,4 @@
|
|||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import re
|
||||
|
||||
|
||||
class BasicError(Exception):
|
||||
""" Base class for all exceptions in Model Optimizer
|
||||
|
||||
It operates like Exception but when it is converted to str,
|
||||
it formats string as args[0].format(*args[1:]), where
|
||||
args are arguments provided when an exception instance is
|
||||
created.
|
||||
"""
|
||||
|
||||
def __str__(self):
|
||||
if len(self.args) <= 1:
|
||||
return Exception.__str__(self)
|
||||
return self.args[0].format(*self.args[1:]) # pylint: disable=unsubscriptable-object
|
||||
|
||||
|
||||
class FrameworkError(BasicError):
|
||||
""" User-friendly error: raised when the error on the framework side. """
|
||||
pass
|
||||
|
||||
|
||||
class Error(BasicError):
|
||||
""" User-friendly error: raised when the error on the user side. """
|
||||
pass
|
||||
|
||||
|
||||
class InternalError(BasicError):
|
||||
""" Not user-friendly error: user cannot fix it and it points to the bug inside MO. """
|
||||
pass
|
||||
|
||||
|
||||
def classify_error_type(e):
|
||||
patterns = [
|
||||
# Example: No module named 'openvino._offline_transformations.offline_transformations_api'
|
||||
r"No module named \'\S+\'",
|
||||
# Example: cannot import name 'IECore' from 'openvino.inference_engine' (unknown location)
|
||||
r"cannot import name \'\S+\'",
|
||||
]
|
||||
error_message = str(e)
|
||||
for pattern in patterns:
|
||||
m = re.search(pattern, error_message)
|
||||
if m:
|
||||
return m.group(0)
|
||||
return "undefined"
|
||||
from openvino.tools.ovc.error import Error, InternalError, FrameworkError, classify_error_type # pylint: disable=no-name-in-module,import-error
|
||||
|
|
|
|||
|
|
@ -1,48 +1,6 @@
|
|||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import datetime
|
||||
|
||||
msg_fmt = 'Check for a new version of Intel(R) Distribution of OpenVINO(TM) toolkit here {0} ' \
|
||||
'or on https://github.com/openvinotoolkit/openvino'
|
||||
|
||||
|
||||
def get_ov_update_message():
|
||||
expected_update_date = datetime.date(year=2023, month=12, day=1)
|
||||
current_date = datetime.date.today()
|
||||
|
||||
link = 'https://software.intel.com/content/www/us/en/develop/tools/openvino-toolkit/download.html?cid=other&source=prod&campid=ww_2023_bu_IOTG_OpenVINO-2023-0&content=upg_all&medium=organic'
|
||||
|
||||
return msg_fmt.format(link) if current_date >= expected_update_date else None
|
||||
|
||||
|
||||
def get_ov_api20_message():
|
||||
link = "https://docs.openvino.ai/2023.0/openvino_2_0_transition_guide.html"
|
||||
message = '[ INFO ] The model was converted to IR v11, the latest model format that corresponds to the source DL framework ' \
|
||||
'input/output format. While IR v11 is backwards compatible with OpenVINO Inference Engine API v1.0, ' \
|
||||
'please use API v2.0 (as of 2022.1) to take advantage of the latest improvements in IR v11.\n' \
|
||||
'Find more information about API v2.0 and IR v11 at {}'.format(link)
|
||||
|
||||
return message
|
||||
|
||||
|
||||
def get_tf_fe_message():
|
||||
link = "https://docs.openvino.ai/2023.0/openvino_docs_MO_DG_TensorFlow_Frontend.html"
|
||||
message = '[ INFO ] IR generated by new TensorFlow Frontend is compatible only with API v2.0. Please make sure to use API v2.0.\n' \
|
||||
'Find more information about new TensorFlow Frontend at {}'.format(link)
|
||||
|
||||
return message
|
||||
|
||||
|
||||
def get_compression_message():
|
||||
link = "https://docs.openvino.ai/2023.0/openvino_docs_MO_DG_FP16_Compression.html"
|
||||
message = '[ INFO ] Generated IR will be compressed to FP16. ' \
|
||||
'If you get lower accuracy, please consider disabling compression ' \
|
||||
'by removing argument --compress_to_fp16 or set it to false --compress_to_fp16=False.\n' \
|
||||
'Find more information about compression to FP16 at {}'.format(link)
|
||||
return message
|
||||
|
||||
|
||||
def get_try_legacy_fe_message():
|
||||
message = '[ INFO ] You can also try to use legacy TensorFlow Frontend by using argument --use_legacy_frontend.\n'
|
||||
return message
|
||||
|
|
|
|||
|
|
@ -1,160 +1,6 @@
|
|||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import importlib.util
|
||||
import logging as log
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from argparse import Namespace
|
||||
from copy import copy
|
||||
|
||||
# WA for abseil bug that affects logging while importing TF starting 1.14 version
|
||||
# Link to original issue: https://github.com/abseil/abseil-py/issues/99
|
||||
if importlib.util.find_spec('absl') is not None:
|
||||
import absl.logging
|
||||
|
||||
log.root.removeHandler(absl.logging._absl_handler)
|
||||
|
||||
handler_num = 0
|
||||
|
||||
|
||||
class LvlFormatter(log.Formatter):
|
||||
format_dict = {
|
||||
log.DEBUG: "[ %(asctime)s ] [ %(levelname)s ] [ %(module)s:%(lineno)d ] %(msg)s",
|
||||
log.INFO: "[ %(levelname)s ] %(msg)s",
|
||||
log.WARNING: "[ WARNING ] %(msg)s",
|
||||
log.ERROR: "[ %(levelname)s ] %(msg)s",
|
||||
log.CRITICAL: "[ %(levelname)s ] %(msg)s",
|
||||
'framework_error': "[ FRAMEWORK ERROR ] %(msg)s",
|
||||
'analysis_info': "[ ANALYSIS INFO ] %(msg)s"
|
||||
}
|
||||
|
||||
def __init__(self, lvl, fmt=None):
|
||||
log.Formatter.__init__(self, fmt)
|
||||
self.lvl = lvl
|
||||
|
||||
def format(self, record: log.LogRecord):
|
||||
if self.lvl == 'DEBUG':
|
||||
self._style._fmt = self.format_dict[log.DEBUG]
|
||||
else:
|
||||
self._style._fmt = self.format_dict[record.levelno]
|
||||
if 'is_warning' in record.__dict__.keys():
|
||||
self._style._fmt = self.format_dict[log.WARNING]
|
||||
if 'framework_error' in record.__dict__.keys():
|
||||
self._style._fmt = self.format_dict['framework_error']
|
||||
if 'analysis_info' in record.__dict__.keys():
|
||||
self._style._fmt = self.format_dict['analysis_info']
|
||||
return log.Formatter.format(self, record)
|
||||
|
||||
|
||||
class TagFilter(log.Filter):
|
||||
def __init__(self, regex: str):
|
||||
self.regex = regex
|
||||
|
||||
def filter(self, record: log.LogRecord):
|
||||
if record.__dict__['funcName'] == 'load_grammar': # for nx not to log into our logs
|
||||
return False
|
||||
if self.regex:
|
||||
if 'tag' in record.__dict__.keys():
|
||||
tag = record.__dict__['tag']
|
||||
return re.findall(self.regex, tag)
|
||||
else:
|
||||
return False
|
||||
return True # if regex wasn't set print all logs
|
||||
|
||||
|
||||
def init_logger(lvl: str, silent: bool):
|
||||
global handler_num
|
||||
log_exp = os.environ.get('MO_LOG_PATTERN')
|
||||
if silent:
|
||||
lvl = 'ERROR'
|
||||
fmt = LvlFormatter(lvl=lvl)
|
||||
handler = log.StreamHandler()
|
||||
handler.setFormatter(fmt)
|
||||
logger = log.getLogger()
|
||||
logger.setLevel(lvl)
|
||||
logger.addFilter(TagFilter(regex=log_exp))
|
||||
if handler_num == 0 and len(logger.handlers) == 0:
|
||||
logger.addHandler(handler)
|
||||
handler_num += 1
|
||||
|
||||
def get_logger_state():
|
||||
logger = log.getLogger()
|
||||
return logger.level, copy(logger.filters), copy(logger.handlers)
|
||||
|
||||
def restore_logger_state(state: tuple):
|
||||
level, filters, handlers = state
|
||||
logger = log.getLogger()
|
||||
logger.setLevel(level)
|
||||
logger.filters = filters
|
||||
logger.handlers = handlers
|
||||
|
||||
|
||||
def progress_bar(function: callable):
|
||||
"""
|
||||
Decorator for model conversion pipeline progress display
|
||||
Works in combination with function: mo.utils.class_registration.apply_transform
|
||||
"""
|
||||
|
||||
def wrapper(*args, **kwargs):
|
||||
for arg in ['graph', 'curr_transform_num', 'num_transforms']:
|
||||
msg = 'Progress bar decorator is enabled for Model Optimizer transformation applying cycle only. ' \
|
||||
'Argument `{}` {}'
|
||||
|
||||
assert arg in kwargs, msg.format(arg, 'is missing')
|
||||
assert kwargs[arg] is not None, msg.format(arg, 'should not be None')
|
||||
|
||||
if 'progress' in kwargs['graph'].graph['cmd_params'] and kwargs['graph'].graph['cmd_params'].progress:
|
||||
bar_len = 20
|
||||
total_replacers_count = kwargs['num_transforms']
|
||||
|
||||
def progress(i):
|
||||
return int((i + 1) / total_replacers_count * bar_len)
|
||||
|
||||
def percent(i):
|
||||
return (i + 1) / total_replacers_count * 100
|
||||
|
||||
end = '' if not kwargs['graph'].graph['cmd_params'].stream_output else '\n'
|
||||
curr_i = kwargs['curr_transform_num']
|
||||
print('\rProgress: [{:{}}]{:>7.2f}% done'.format('.' * progress(curr_i), bar_len, percent(curr_i)), end=end)
|
||||
|
||||
sys.stdout.flush()
|
||||
|
||||
function(*args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
||||
def progress_printer(argv: Namespace):
|
||||
"""
|
||||
A higher-order factory function returning a configurable callback displaying a progress bar
|
||||
Depending on the configuration stored in 'argv' the progress bar can be one-line, multi-line, or silent.
|
||||
"""
|
||||
def _progress_bar(progress, total, completed, endline):
|
||||
bar_len = 20
|
||||
|
||||
def dots():
|
||||
return '.' * int(progress * bar_len)
|
||||
|
||||
print('\rProgress: [{:{}}]{:>7.2f}% done'.format(dots(), bar_len, progress*100), end=endline)
|
||||
sys.stdout.flush()
|
||||
|
||||
def no_progress_bar(progress, total, completed):
|
||||
""" A 'dummy' progressbar which doesn't print anything """
|
||||
pass
|
||||
|
||||
def oneline_progress_bar(progress, total, completed):
|
||||
""" A callback that always prints the progress in the same line (mimics real GUI progress bar)"""
|
||||
_progress_bar(progress, total, completed, '')
|
||||
|
||||
def newline_progress_bar(progress, total, completed):
|
||||
""" A callback that prints an updated progress bar in separate lines """
|
||||
_progress_bar(progress, total, completed, '\n')
|
||||
|
||||
if "progress" in argv and argv.progress:
|
||||
if "stream_output" in argv and argv.stream_output:
|
||||
return newline_progress_bar
|
||||
else:
|
||||
return oneline_progress_bar
|
||||
else:
|
||||
return no_progress_bar
|
||||
from openvino.tools.ovc.logger import init_logger, LvlFormatter, TagFilter, get_logger_state, restore_logger_state, \
|
||||
progress_bar, progress_printer # pylint: disable=no-name-in-module,import-error
|
||||
|
|
@ -1,29 +1,4 @@
|
|||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
|
||||
class Telemetry(object):
|
||||
"""
|
||||
Stab file for the Telemetry class which is used when Telemetry class is not available.
|
||||
"""
|
||||
|
||||
def __init__(self, *arg, **kwargs):
|
||||
pass
|
||||
|
||||
def send_event(self, *arg, **kwargs):
|
||||
pass
|
||||
|
||||
def send_error(self, *arg, **kwargs):
|
||||
pass
|
||||
|
||||
def start_session(self, *arg, **kwargs):
|
||||
pass
|
||||
|
||||
def end_session(self, *arg, **kwargs):
|
||||
pass
|
||||
|
||||
def force_shutdown(self, *arg, **kwargs):
|
||||
pass
|
||||
|
||||
def send_stack_trace(self, *arg, **kwargs):
|
||||
pass
|
||||
from openvino.tools.ovc.telemetry_stub import Telemetry # pylint: disable=no-name-in-module,import-error
|
||||
|
|
|
|||
|
|
@ -1,18 +1,15 @@
|
|||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
import argparse
|
||||
from collections import Counter
|
||||
|
||||
import numpy as np
|
||||
import numbers
|
||||
|
||||
from openvino.tools.ovc.telemetry_utils import init_mo_telemetry, send_framework_info, get_tid, \
|
||||
send_conversion_result, arg_to_str, send_params_info # pylint: disable=no-name-in-module,import-error
|
||||
|
||||
from openvino.tools.mo.front.common.partial_infer.utils import is_fully_defined, unmask_shape, int64_array
|
||||
from openvino.tools.mo.graph.graph import Graph
|
||||
from openvino.tools.mo.middle.pattern_match import for_graph_and_each_sub_graph_recursively
|
||||
from openvino.tools.mo.utils.cli_parser import get_params_with_paths_list
|
||||
from openvino.tools.mo.utils.telemetry_params import telemetry_params
|
||||
from openvino.tools.mo.utils.version import VersionChecker
|
||||
from openvino.tools.mo.utils.utils import check_values_equal
|
||||
|
||||
try:
|
||||
import openvino_telemetry as tm
|
||||
|
|
@ -20,10 +17,6 @@ except ImportError:
|
|||
import openvino.tools.mo.utils.telemetry_stub as tm
|
||||
|
||||
|
||||
def init_mo_telemetry():
|
||||
_ = tm.Telemetry(tid=get_tid(), app_name='Model Optimizer', app_version=VersionChecker().get_mo_simplified_version())
|
||||
|
||||
|
||||
def send_op_names_info(framework: str, graph: Graph):
|
||||
"""
|
||||
This function sends information about operations in model.
|
||||
|
|
@ -68,58 +61,3 @@ def send_shapes_info(framework: str, graph: Graph):
|
|||
t.send_event('mo', 'input_shapes', message_str)
|
||||
t.send_event('mo', 'partially_defined_shape',
|
||||
"{partially_defined_shape:" + is_partially_defined + ",fw:" + framework + "}")
|
||||
|
||||
|
||||
def arg_to_str(arg):
|
||||
# This method converts to string only known types, otherwise returns string with name of the type
|
||||
from openvino.runtime import PartialShape, Shape, Type, Layout
|
||||
if isinstance(arg, (PartialShape, Shape, Type, Layout)):
|
||||
return str(arg)
|
||||
if isinstance(arg, (str, numbers.Number, bool)):
|
||||
return str(arg)
|
||||
return str(type(arg))
|
||||
|
||||
|
||||
def send_params_info(argv: argparse.Namespace, cli_parser: argparse.ArgumentParser):
|
||||
"""
|
||||
This function sends information about used command line parameters.
|
||||
:param argv: command line parameters.
|
||||
:param cli_parser: command line parameters parser.
|
||||
"""
|
||||
t = tm.Telemetry()
|
||||
params_with_paths = get_params_with_paths_list()
|
||||
for arg in vars(argv):
|
||||
arg_value = getattr(argv, arg)
|
||||
if not check_values_equal(arg_value, cli_parser.get_default(arg)):
|
||||
if arg in params_with_paths:
|
||||
# If command line argument value is a directory or a path to file it is not sent
|
||||
# as it may contain confidential information. "1" value is used instead.
|
||||
param_str = arg + ":" + str(1)
|
||||
else:
|
||||
param_str = arg + ":" + arg_to_str(arg_value)
|
||||
|
||||
t.send_event('mo', 'cli_parameters', param_str)
|
||||
|
||||
|
||||
def send_framework_info(framework: str):
|
||||
"""
|
||||
This function sends information about used framework.
|
||||
:param framework: framework name.
|
||||
"""
|
||||
t = tm.Telemetry()
|
||||
t.send_event('mo', 'framework', framework)
|
||||
|
||||
|
||||
def get_tid():
|
||||
"""
|
||||
This function returns the ID of the database to send telemetry.
|
||||
"""
|
||||
return telemetry_params['TID']
|
||||
|
||||
|
||||
def send_conversion_result(conversion_result: str, need_shutdown=True):
|
||||
t = tm.Telemetry()
|
||||
t.send_event('mo', 'conversion_result', conversion_result)
|
||||
t.end_session('mo')
|
||||
if need_shutdown:
|
||||
t.force_shutdown(1.0)
|
||||
|
|
|
|||
|
|
@ -10,24 +10,7 @@ from typing import Callable
|
|||
import numpy as np
|
||||
|
||||
from openvino.tools.mo.front.common.partial_infer.utils import dynamic_dimension
|
||||
|
||||
try:
|
||||
import openvino_telemetry as tm
|
||||
except ImportError:
|
||||
import openvino.tools.mo.utils.telemetry_stub as tm
|
||||
|
||||
|
||||
def refer_to_faq_msg(question_num: int):
|
||||
try:
|
||||
t = tm.Telemetry()
|
||||
t.send_event('mo', 'error_info', "faq:" + str(question_num))
|
||||
except Exception:
|
||||
# Telemetry can be not initialized if it is used in MO IR Reader
|
||||
pass
|
||||
|
||||
return '\n For more information please refer to Model Optimizer FAQ, question #{0}. ' \
|
||||
'(https://docs.openvino.ai/2023.0/openvino_docs_MO_DG_prepare_model_Model_Optimizer_FAQ.html' \
|
||||
'?question={0}#question-{0})'.format(question_num)
|
||||
from openvino.tools.ovc.utils import refer_to_faq_msg, check_values_equal # pylint: disable=no-name-in-module,import-error
|
||||
|
||||
|
||||
class NamedAttrsClass:
|
||||
|
|
@ -145,14 +128,3 @@ def unique_by(xs: list, predicate: Callable) -> list:
|
|||
"""
|
||||
groups = group_by_with_binary_predicate(xs, predicate)
|
||||
return [group[0] for group in groups]
|
||||
|
||||
|
||||
def check_values_equal(val1, val2):
|
||||
# This method is needed to check equality of values where some values can be None
|
||||
if val1 is None and val2 is None:
|
||||
return True
|
||||
if val1 is None:
|
||||
return False
|
||||
if val2 is None:
|
||||
return False
|
||||
return val1 == val2
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ from openvino.runtime import get_version as get_ie_version
|
|||
from openvino.tools.mo.utils.error import Error
|
||||
from openvino.tools.mo.utils.find_ie_version import find_ie_version
|
||||
from openvino.tools.mo.utils.utils import get_mo_root_dir
|
||||
from openvino.tools.ovc.version import extract_release_version, simplify_version, extract_hash_from_version, \
|
||||
SingletonMetaClass # pylint: disable=no-name-in-module,import-error
|
||||
|
||||
|
||||
def get_version_file_path():
|
||||
|
|
@ -39,28 +41,6 @@ def get_version():
|
|||
return f.readline().replace('\n', '')
|
||||
|
||||
|
||||
def extract_release_version(version: str):
|
||||
patterns = [
|
||||
# captures release version set by CI for example: '2021.1.0-1028-55e4d5673a8'
|
||||
r"^([0-9]+).([0-9]+)*",
|
||||
# captures release version generated by MO from release branch, for example: 'custom_releases/2021/1_55e4d567'
|
||||
r"_releases/([0-9]+)/([0-9]+)_*"
|
||||
]
|
||||
|
||||
for pattern in patterns:
|
||||
m = re.search(pattern, version)
|
||||
if m and len(m.groups()) == 2:
|
||||
return m.group(1), m.group(2)
|
||||
return None, None
|
||||
|
||||
|
||||
def simplify_version(version: str):
|
||||
release_version = extract_release_version(version)
|
||||
if release_version == (None, None):
|
||||
return "custom"
|
||||
return "{}.{}".format(*release_version)
|
||||
|
||||
|
||||
def get_simplified_mo_version():
|
||||
return simplify_version(get_version())
|
||||
|
||||
|
|
@ -79,25 +59,6 @@ def get_simplified_ie_version(env=dict(), version=None):
|
|||
return simplify_version(version)
|
||||
|
||||
|
||||
def extract_hash_from_version(full_version: str):
|
||||
res = re.findall(r'[-_]([a-f0-9]{7,40})', full_version)
|
||||
if len(res) > 0:
|
||||
return res[0]
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
class SingletonMetaClass(type):
|
||||
def __init__(self, cls_name, super_classes, dic):
|
||||
self.__single_instance = None
|
||||
super().__init__(cls_name, super_classes, dic)
|
||||
|
||||
def __call__(cls, *args, **kwargs):
|
||||
if cls.__single_instance is None:
|
||||
cls.__single_instance = super(SingletonMetaClass, cls).__call__(*args, **kwargs)
|
||||
return cls.__single_instance
|
||||
|
||||
|
||||
class VersionChecker(metaclass=SingletonMetaClass):
|
||||
def __init__(self):
|
||||
self.runtime_checked = False
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ from unit_tests.mo.unit_test_with_mocked_telemetry import UnitTestWithMockedTele
|
|||
|
||||
try:
|
||||
# pylint: disable=no-name-in-module,import-error
|
||||
from openvino.tools.mo.back.preprocessing import apply_preprocessing
|
||||
from openvino.tools.ovc.moc_frontend.preprocessing import apply_preprocessing
|
||||
|
||||
# pylint: disable=no-name-in-module,import-error
|
||||
import openvino.runtime.opset8 as ops
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
import unittest
|
||||
|
||||
from openvino.tools.mo.moc_frontend.extractor import decode_name_with_port
|
||||
from openvino.tools.ovc.moc_frontend.extractor import decode_name_with_port
|
||||
from openvino.tools.mo.utils.error import Error
|
||||
|
||||
import pytest
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ class TestConvertImplTmpIrsCleanup(unittest.TestCase):
|
|||
return False
|
||||
|
||||
def test_tmp_irs_cleanup_convert_impl_1(self):
|
||||
with patch("openvino.tools.mo.back.offline_transformations.apply_offline_transformations") as emit_ir_func:
|
||||
with patch("openvino.tools.ovc.moc_frontend.offline_transformations.apply_offline_transformations") as emit_ir_func:
|
||||
emit_ir_func.side_effect = Error('offline transformations step has failed')
|
||||
|
||||
params = {'input_model': self.test_model_file, 'input_model_is_text': True, 'input': 'x[3],y[1 3]',
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import openvino.runtime.opset10 as opset10
|
|||
from openvino.runtime import Model, serialize, Core, PartialShape, Dimension
|
||||
|
||||
from openvino.tools.mo.utils.ir_reader.restore_graph import restore_graph_from_ir, save_restored_graph
|
||||
from openvino.tools.mo.utils.logger import init_logger
|
||||
from openvino.tools.ovc.logger import init_logger
|
||||
|
||||
# required to be in global area to run MO IR Reader
|
||||
init_logger('ERROR', False)
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import json
|
|||
import argparse
|
||||
from openvino.tools.mo.convert_impl import prepare_ir
|
||||
from openvino.frontend import FrontEndManager # pylint: disable=no-name-in-module,import-error
|
||||
from openvino.tools.mo.moc_frontend.analysis import json_model_analysis_dump
|
||||
|
||||
|
||||
try:
|
||||
import openvino_telemetry as tm
|
||||
|
|
@ -112,7 +112,7 @@ class TestMoFallback(unittest.TestCase):
|
|||
os.remove(name)
|
||||
|
||||
|
||||
@patch('openvino.tools.mo.moc_frontend.analysis.json_model_analysis_print')
|
||||
@patch('openvino.tools.ovc.moc_frontend.analysis.json_model_analysis_print')
|
||||
def test_model(self, json_print):
|
||||
args = base_args_config()
|
||||
args.input_model = "test_model.onnx"
|
||||
|
|
@ -132,7 +132,7 @@ class TestMoFallback(unittest.TestCase):
|
|||
"add_out": {"shape": "None", "data_type": "None", "value": "None"}}')
|
||||
|
||||
|
||||
@patch('openvino.tools.mo.moc_frontend.analysis.json_model_analysis_print')
|
||||
@patch('openvino.tools.ovc.moc_frontend.analysis.json_model_analysis_print')
|
||||
def test_model_with_dyn_shapes(self, json_print):
|
||||
args = base_args_config()
|
||||
args.input_model = "test_model_2.onnx"
|
||||
|
|
@ -156,7 +156,7 @@ class TestMoFallback(unittest.TestCase):
|
|||
"add_out": {"shape": "None", "data_type": "None", "value": "None"}}')
|
||||
|
||||
|
||||
@patch('openvino.tools.mo.moc_frontend.analysis.json_model_analysis_print')
|
||||
@patch('openvino.tools.ovc.moc_frontend.analysis.json_model_analysis_print')
|
||||
def test_multi_outputs_model(self, json_print):
|
||||
args = base_args_config()
|
||||
args.input_model = "test_model_3.onnx"
|
||||
|
|
|
|||
|
|
@ -9,8 +9,7 @@ from contextlib import redirect_stdout
|
|||
from unittest.mock import patch
|
||||
|
||||
from openvino.tools.mo.main import main
|
||||
from openvino.tools.mo.utils.get_ov_update_message import get_tf_fe_message, get_compression_message, \
|
||||
get_try_legacy_fe_message
|
||||
from openvino.tools.ovc.get_ov_update_message import get_tf_fe_message
|
||||
|
||||
|
||||
def arg_parse_helper(input_model,
|
||||
|
|
@ -56,36 +55,6 @@ def arg_parse_helper(input_model,
|
|||
)
|
||||
|
||||
|
||||
class TestInfoMessagesTFFE(unittest.TestCase):
|
||||
@patch('argparse.ArgumentParser.parse_args',
|
||||
return_value=arg_parse_helper(input_model="model_int32.pbtxt",
|
||||
use_legacy_frontend=False, use_new_frontend=True,
|
||||
framework=None, input_model_is_text=True))
|
||||
def test_api20_only(self, mock_argparse):
|
||||
f = io.StringIO()
|
||||
with redirect_stdout(f):
|
||||
main(argparse.ArgumentParser())
|
||||
std_out = f.getvalue()
|
||||
tf_fe_message_found = get_tf_fe_message() in std_out
|
||||
assert tf_fe_message_found
|
||||
|
||||
@patch('openvino.tools.mo.convert_impl.driver', side_effect=Exception('MESSAGE'))
|
||||
def run_fail_tf_fe(self, mock_driver):
|
||||
from openvino.tools.mo import convert_model
|
||||
path = os.path.dirname(__file__)
|
||||
convert_model(os.path.join(path, "test_models", "model_int32.pbtxt"), silent=False)
|
||||
|
||||
def test_suggest_legacy_fe(self):
|
||||
f = io.StringIO()
|
||||
with redirect_stdout(f):
|
||||
try:
|
||||
self.run_fail_tf_fe()
|
||||
except:
|
||||
pass
|
||||
std_out = f.getvalue()
|
||||
assert get_try_legacy_fe_message() in std_out
|
||||
|
||||
|
||||
class TestInfoMessagesTFFEWithFallback(unittest.TestCase):
|
||||
@patch('argparse.ArgumentParser.parse_args',
|
||||
return_value=arg_parse_helper(input_model="model_switch_merge.pbtxt",
|
||||
|
|
@ -100,17 +69,3 @@ class TestInfoMessagesTFFEWithFallback(unittest.TestCase):
|
|||
tf_fe_message_found = get_tf_fe_message() in std_out
|
||||
assert not tf_fe_message_found, 'TF FE Info message is found for the fallback case'
|
||||
|
||||
|
||||
class TestInfoMessagesCompressFP16(unittest.TestCase):
|
||||
@patch('argparse.ArgumentParser.parse_args',
|
||||
return_value=arg_parse_helper(input_model="model_int32.pbtxt",
|
||||
use_legacy_frontend=False, use_new_frontend=True,
|
||||
compress_to_fp16=True,
|
||||
framework=None, input_model_is_text=True))
|
||||
def test_compress_to_fp16(self, mock_argparse):
|
||||
f = io.StringIO()
|
||||
with redirect_stdout(f):
|
||||
main(argparse.ArgumentParser())
|
||||
std_out = f.getvalue()
|
||||
fp16_compression_message_found = get_compression_message() in std_out
|
||||
assert fp16_compression_message_found
|
||||
|
|
|
|||
|
|
@ -40,272 +40,10 @@ class TestMoFreezePlaceholderTFFE(unittest.TestCase):
|
|||
assert values.dtype == dtype
|
||||
assert np.allclose(values, expected)
|
||||
|
||||
@generate(
|
||||
*[
|
||||
(
|
||||
"in1[1 4]->[1.0 2.0 3.0 4.0],in2[1 4]{f32}->[1.0 2.0 3.0 4.0]",
|
||||
{},
|
||||
np.array([2.0, 4.0, 6.0, 8.0]),
|
||||
np.float32,
|
||||
),
|
||||
(
|
||||
"in2{f32}->[0.0 0.0 0.0 0.0]",
|
||||
{"in1": np.array([[1.0, 2.0], [3.0, 4.0]])},
|
||||
np.array([[1.0, 2.0], [3.0, 4.0]]),
|
||||
np.float32,
|
||||
),
|
||||
(
|
||||
"in2->[1.0 15.0 15.5 1.0]",
|
||||
{"in1": np.array([[2.0, 4.0], [12.0, 8.0]])},
|
||||
np.array([[3.0, 19.0], [27.5, 9.0]]),
|
||||
np.float32,
|
||||
),
|
||||
(
|
||||
"in1[1 4]{i32}->[1 2 3 4],in2[1 4]{i32}->[1 2 3 4]",
|
||||
{},
|
||||
np.array([2.0, 4.0, 6.0, 8.0]),
|
||||
np.int32,
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_fp32(self, input_freezing_value, inputs, expected,
|
||||
dtype):
|
||||
self.basic("model_fp32.pbtxt", input_freezing_value, inputs, dtype, expected)
|
||||
|
||||
@generate(
|
||||
*[
|
||||
(
|
||||
"in1[1 4]->[1 2 3 4],in2[1 4]{i32}->[1 2 3 4]",
|
||||
{},
|
||||
np.array([1, 4, 9, 16]),
|
||||
np.int32,
|
||||
),
|
||||
(
|
||||
"in2->[2 5 6 7 3 2]",
|
||||
{"in1": np.array([[2, 4, 1], [1, 2, 8]])},
|
||||
np.array([[4, 20, 6], [7, 6, 16]]),
|
||||
np.int32,
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_int32(self, input_freezing_value, inputs, expected,
|
||||
dtype=None):
|
||||
self.basic("model_int32.pbtxt", input_freezing_value, inputs, dtype, expected)
|
||||
|
||||
@generate(
|
||||
*[
|
||||
(
|
||||
"in1[2]->[True False],in2[2]->[True True]",
|
||||
{},
|
||||
np.array([True, False], dtype=bool),
|
||||
bool,
|
||||
),
|
||||
(
|
||||
"in2[2,3]->[True,True,False,True,True,False]",
|
||||
{"in1": np.array([[False, True, True], [False, True, True]], dtype=bool)},
|
||||
np.array([[False, True, False], [False, True, False]], dtype=bool),
|
||||
bool,
|
||||
),
|
||||
(
|
||||
"in2[]->True",
|
||||
{"in1": np.array([[False, True, True], [False, True, True]], dtype=bool)},
|
||||
np.array([[False, True, True], [False, True, True]], dtype=bool),
|
||||
bool,
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_bool(self, input_freezing_value, inputs, expected,
|
||||
dtype=None):
|
||||
self.basic("model_bool.pbtxt", input_freezing_value, inputs, dtype, expected)
|
||||
|
||||
@generate(
|
||||
*[
|
||||
(
|
||||
"in1[3]->[1 2 3],in2[3]->[4 5 6],cond->False",
|
||||
{},
|
||||
np.array([4, 5, 6], dtype=np.float32),
|
||||
np.float32,
|
||||
None
|
||||
),
|
||||
(
|
||||
None,
|
||||
{"in1": np.array([2.0, 4.0, 6.0], dtype=np.float32),
|
||||
"in2": np.array([1.0, 3.0, 5.0], dtype=np.float32)},
|
||||
np.array([2, 4, 6], dtype=np.float32),
|
||||
np.float32,
|
||||
"cond->False",
|
||||
None,
|
||||
True # fill a bug to investigate why compilation of this model is hang on
|
||||
),
|
||||
# case: input_shape + freeze_placeholder_with_value
|
||||
(
|
||||
None,
|
||||
{"in2": np.array([1.0, 3.0, 5.0], dtype=np.float32)},
|
||||
np.array([2, 4, 6], dtype=np.float32),
|
||||
np.float32,
|
||||
"in1->[2.0 4.0 6.0],cond->True",
|
||||
"[3]",
|
||||
False
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_bool2(self, input_freezing_value, inputs, expected,
|
||||
dtype=None, freeze_placeholder_with_value=None, input_shape=None, only_conversion=False):
|
||||
self.basic("model_bool2.pbtxt", input_freezing_value, inputs, dtype, expected, freeze_placeholder_with_value,
|
||||
input_shape, only_conversion)
|
||||
|
||||
@generate(
|
||||
*[
|
||||
(
|
||||
"add:0[3],z",
|
||||
{"add:0": np.array([4, 5, 6], dtype=np.float32), "z": np.array([1, 2, 3], dtype=np.float32)},
|
||||
np.array([4, 10, 18], dtype=np.float32),
|
||||
np.float32,
|
||||
None
|
||||
),
|
||||
(
|
||||
"add:0{i32}[3],z{i32}",
|
||||
{"add:0": np.array([4, 5, 6], dtype=np.int32), "z": np.array([1, 2, 3], dtype=np.int32)},
|
||||
np.array([4, 10, 18], dtype=np.int32),
|
||||
np.int32,
|
||||
None
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_cutting_fp32(self, input_freezing_value, inputs, expected,
|
||||
dtype=None, freeze_placeholder_with_value=None, input_shape=None, only_conversion=False):
|
||||
self.basic("model_three_inputs.pbtxt", input_freezing_value, inputs, dtype, expected,
|
||||
freeze_placeholder_with_value,
|
||||
input_shape, only_conversion, True)
|
||||
|
||||
@generate(
|
||||
*[
|
||||
(
|
||||
"x[1,4],y[4]",
|
||||
{"x": np.array([[3, 2, 1, 5]], dtype=np.int32), "y": np.array([0, -1, -7, 8], dtype=np.int32)},
|
||||
np.array([[3, 1, -6, 13]], dtype=np.int32),
|
||||
np.int32,
|
||||
None
|
||||
),
|
||||
(
|
||||
"x,y",
|
||||
{"x": np.array([[-3, 20, 1]], dtype=np.int32), "y": np.array([[10, -11, -17]], dtype=np.int32)},
|
||||
np.array([[7, 9, -16]], dtype=np.int32),
|
||||
np.int32,
|
||||
None
|
||||
),
|
||||
(
|
||||
"x",
|
||||
{"x": np.array([[-3, 20, 1]], dtype=np.int32)},
|
||||
np.array([[-2, 22, 4], [1, 25, 7]], dtype=np.int32),
|
||||
np.int32,
|
||||
None
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_placeholder_with_default(self, inputs, inputs_data, expected,
|
||||
dtype=None, freeze_placeholder_with_value=None, input_shape=None,
|
||||
only_conversion=False):
|
||||
self.basic("placeholder_with_default.pbtxt", inputs, inputs_data, dtype, expected,
|
||||
freeze_placeholder_with_value,
|
||||
input_shape, only_conversion, True)
|
||||
|
||||
@generate(
|
||||
*[
|
||||
(
|
||||
"x[4],y->2.0",
|
||||
{"x": np.array([3, 2, 1, 5], dtype=np.float32)},
|
||||
np.array([6, 4, 2, 10], dtype=np.float32),
|
||||
np.float32,
|
||||
None
|
||||
),
|
||||
(
|
||||
"x[1],y->[2.0,3.0]",
|
||||
{"x": np.array([3], dtype=np.float32)},
|
||||
np.array([6, 9], dtype=np.float32),
|
||||
np.float32,
|
||||
None
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_freeze_placeholder_with_unknown_rank(self, inputs, inputs_data, expected,
|
||||
dtype=None, freeze_placeholder_with_value=None, input_shape=None,
|
||||
only_conversion=False):
|
||||
self.basic("mul_with_unknown_rank_y.pbtxt", inputs, inputs_data, dtype, expected,
|
||||
freeze_placeholder_with_value,
|
||||
input_shape, only_conversion, True)
|
||||
|
||||
def test_conversion_failure_fallback_default(self):
|
||||
self.basic("ctc_model_based.pbtxt", None, None, None, None,
|
||||
None, None, True, True, False, False)
|
||||
|
||||
def test_conversion_failure_fallback_use_new_frontend(self):
|
||||
with self.assertRaisesRegex(Exception,
|
||||
"\[TensorFlow Frontend\] Internal error, no translator found for operation\(s\)\: "
|
||||
"Enter\, Exit\, LoopCond\, Merge\, NextIteration\, Switch\, TensorArrayGatherV3\, "
|
||||
"TensorArraySizeV3\, TensorArrayV3"):
|
||||
self.basic("ctc_model_based.pbtxt", None, None, None, None,
|
||||
None, None, True, True, True, False)
|
||||
|
||||
@unittest.skip("88349: Fix auto-pruning in legacy FE")
|
||||
def test_conversion_model_oneshot_iterator_use_legacy_frontend(self):
|
||||
self.basic("model_oneshot_iterator.pbtxt", None, None, None, None,
|
||||
None, None, True, True, False, True)
|
||||
|
||||
def test_conversion_model_oneshot_iterator_default(self):
|
||||
self.basic("model_oneshot_iterator.pbtxt", None, None, None, None,
|
||||
None, None, True, True, False, False)
|
||||
|
||||
@generate(
|
||||
*[
|
||||
(
|
||||
"in2{f32}->[0.0 0.0 0.0 0.0]",
|
||||
{"in1": np.array([[1.0, 2.0], [3.0, 4.0]])},
|
||||
np.array([[1.0, 2.0], [3.0, 4.0]]),
|
||||
np.float32,
|
||||
),
|
||||
(
|
||||
"in2->[1.0 15.0 15.5 1.0]",
|
||||
{"in1": np.array([[2.0, 4.0], [12.0, 8.0]])},
|
||||
np.array([[3.0, 19.0], [27.5, 9.0]]),
|
||||
np.float32,
|
||||
),
|
||||
],
|
||||
)
|
||||
@unittest.skip("109220: Use generating script for this test model instead of Git LFS")
|
||||
def test_conversion_model_with_non_standard_extension(self, input_freezing_value, inputs, expected,
|
||||
dtype):
|
||||
self.basic("model_fp32.frozen", input_freezing_value, inputs, dtype, expected, only_conversion=False,
|
||||
input_model_is_text=False, use_new_frontend=True,
|
||||
use_legacy_frontend=False)
|
||||
|
||||
@unittest.skip("109220: Make TF FE to return the error")
|
||||
def test_conversion_dir_model(self):
|
||||
with self.assertRaisesRegex(Exception,
|
||||
"Internal error or inconsistent input model: the frontend supports "
|
||||
"only frozen binary protobuf format."):
|
||||
self.basic(".", None, None, None, None,
|
||||
only_conversion=True, input_model_is_text=False, use_new_frontend=True,
|
||||
use_legacy_frontend=False)
|
||||
|
||||
@generate(
|
||||
*[
|
||||
(
|
||||
{"x": np.array([1, 2], dtype=np.int32), "y": np.array([4], dtype=np.int32)},
|
||||
np.array([-3, -2], dtype=np.int32),
|
||||
np.int32,
|
||||
),
|
||||
(
|
||||
{"x": np.array([20, 25], dtype=np.int32), "y": np.array([10], dtype=np.int32)},
|
||||
np.array([30, 35], dtype=np.int32),
|
||||
np.int32,
|
||||
)
|
||||
],
|
||||
)
|
||||
def test_conversion_pbtxt_model_with_inference(self, inputs, expected, dtype):
|
||||
self.basic("model_with_if.pbtxt", None, inputs, dtype, expected, only_conversion=False,
|
||||
input_model_is_text=False, use_new_frontend=True, use_legacy_frontend=False)
|
||||
|
||||
@generate(
|
||||
*[
|
||||
# legacy frontend
|
||||
|
|
@ -323,21 +61,6 @@ class TestMoFreezePlaceholderTFFE(unittest.TestCase):
|
|||
np.array([0, 0], dtype=np.int32),
|
||||
np.int32, False, True,
|
||||
),
|
||||
# new frontend
|
||||
(
|
||||
"model_add_with_undefined_constant.pbtxt",
|
||||
"x[2,3]",
|
||||
{"x": np.array([[12, 13, 10], [11, 14, 16]], dtype=np.float32)},
|
||||
np.array([[12, 13, 10], [11, 14, 16]], dtype=np.float32),
|
||||
np.float32, True, False,
|
||||
),
|
||||
(
|
||||
"model_mul_with_undefined_constant.pbtxt",
|
||||
"x[2]",
|
||||
{"x": np.array([11, -12], dtype=np.int32)},
|
||||
np.array([0, 0], dtype=np.int32),
|
||||
np.int32, True, False,
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_conversion_model_with_undefined_constant(self, model_name, argv_input, inputs, expected, dtype,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import os
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
|
|
@ -9,38 +8,8 @@ from generator import generator, generate
|
|||
|
||||
from openvino.tools.mo.convert import convert_model
|
||||
|
||||
|
||||
@generator
|
||||
class TestMoFreezePlaceholderTFFE(unittest.TestCase):
|
||||
@generate(
|
||||
*[
|
||||
# the default frontend
|
||||
(
|
||||
False, False, None
|
||||
),
|
||||
(
|
||||
False, False, "tf"
|
||||
),
|
||||
# new frontend
|
||||
(
|
||||
True, False, None
|
||||
),
|
||||
(
|
||||
True, False, "tf"
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_conversion_fake_pb_model(self, use_new_frontend, use_legacy_frontend, framework):
|
||||
with self.assertRaisesRegex(Exception,
|
||||
"Internal error or inconsistent input model: the frontend supports frozen formats"
|
||||
" \(.pb and .pbtxt\), SavedModel and MetaGraph \(.meta\), and v1 checkpoints."):
|
||||
path = os.path.dirname(__file__)
|
||||
input_model = os.path.join(path, "test_models", "fake.pb")
|
||||
|
||||
convert_model(input_model,
|
||||
use_new_frontend=use_new_frontend, use_legacy_frontend=use_legacy_frontend,
|
||||
framework=framework)
|
||||
|
||||
@generate(
|
||||
*[
|
||||
# the default frontend
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
cmake_minimum_required (VERSION 3.13)
|
||||
|
||||
project(OpenVINOConverter)
|
||||
|
||||
#
|
||||
# Packages & settings
|
||||
#
|
||||
|
||||
if(NOT DEFINED OpenVINO_SOURCE_DIR)
|
||||
get_filename_component(OpenVINO_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../.." REALPATH)
|
||||
endif()
|
||||
|
||||
if(NOT IEDevScripts_FOUND)
|
||||
find_package(IEDevScripts REQUIRED
|
||||
PATHS "${OpenVINO_SOURCE_DIR}/cmake/developer_package"
|
||||
NO_CMAKE_FIND_ROOT_PATH
|
||||
NO_DEFAULT_PATH)
|
||||
endif()
|
||||
|
||||
#
|
||||
# Installation rules
|
||||
#
|
||||
|
||||
ov_get_pyversion(pyversion)
|
||||
ov_cpack_add_component(${OV_CPACK_COMP_PYTHON_OPENVINO}_${pyversion}
|
||||
HIDDEN)
|
||||
|
||||
install(DIRECTORY ${OpenVINOConverter_SOURCE_DIR}/openvino
|
||||
DESTINATION ${OV_CPACK_PYTHONDIR}
|
||||
COMPONENT ${OV_CPACK_COMP_PYTHON_OPENVINO}_${pyversion}
|
||||
${OV_CPACK_COMP_PYTHON_OPENVINO_EXCLUDE_ALL}
|
||||
USE_SOURCE_PERMISSIONS)
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from openvino.tools.ovc.convert import convert_model, InputCutInfo, LayoutMap
|
||||
|
||||
try:
|
||||
import openvino.runtime
|
||||
openvino.runtime.convert_model = convert_model
|
||||
openvino.runtime.InputCutInfo = InputCutInfo
|
||||
openvino.runtime.LayoutMap = LayoutMap
|
||||
except:
|
||||
pass
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import sys
|
||||
|
||||
from openvino.tools.ovc.telemetry_utils import init_mo_telemetry
|
||||
from openvino.tools.ovc.main import main
|
||||
|
||||
init_mo_telemetry()
|
||||
sys.exit(main())
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,366 @@
|
|||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# flake8: noqa
|
||||
# mypy: ignore-errors
|
||||
|
||||
import os
|
||||
import pathlib
|
||||
from collections import namedtuple
|
||||
from typing import Any
|
||||
|
||||
from openvino.runtime import PartialShape, Shape, Layout, Model
|
||||
|
||||
from openvino.tools.ovc.convert_impl import _convert
|
||||
from openvino.tools.ovc.logger import get_logger_state, restore_logger_state
|
||||
from openvino.tools.ovc.cli_parser import get_all_cli_parser
|
||||
|
||||
InputCutInfo = namedtuple("InputInfo", ["name", "shape", "type", "value"], defaults=[None, None, None, None])
|
||||
LayoutMap = namedtuple("LayoutMap", ["source_layout", "target_layout"], defaults=[None, None])
|
||||
|
||||
|
||||
def convert_model(
|
||||
input_model: [str, pathlib.Path, Any] = None,
|
||||
|
||||
# Optional parameters
|
||||
help: bool = False,
|
||||
framework: [str] = None,
|
||||
|
||||
# Framework-agnostic parameters
|
||||
input: [str, list, tuple, InputCutInfo] = None,
|
||||
output: [str, list] = None,
|
||||
input_shape: [str, PartialShape, Shape, list] = None,
|
||||
example_input: Any = None,
|
||||
batch: int = None,
|
||||
mean_values: [str, dict, list] = (),
|
||||
scale_values: [str, dict, list] = (),
|
||||
scale: [str, float] = None,
|
||||
reverse_input_channels: bool = False,
|
||||
source_layout: [str, Layout, dict] = (),
|
||||
target_layout: [str, Layout, dict] = (),
|
||||
layout: [str, Layout, LayoutMap, list, dict] = (),
|
||||
compress_to_fp16: bool = False,
|
||||
extensions: [str, pathlib.Path, list, Any] = None,
|
||||
transform: [str, list, tuple] = "",
|
||||
transformations_config: [str, pathlib.Path] = None,
|
||||
silent: bool = True,
|
||||
log_level: str = 'ERROR',
|
||||
version: bool = None,
|
||||
progress: bool = False,
|
||||
stream_output: bool = False,
|
||||
|
||||
# PaddlePaddle-specific parameters:
|
||||
example_output: Any = None,
|
||||
|
||||
# TensorFlow*-specific parameters
|
||||
input_model_is_text: bool = None,
|
||||
input_checkpoint: [str, pathlib.Path] = None,
|
||||
input_meta_graph: [str, pathlib.Path] = None,
|
||||
saved_model_dir: [str, pathlib.Path] = None,
|
||||
saved_model_tags: [str, list] = None,
|
||||
tensorflow_custom_operations_config_update: [str, pathlib.Path] = None,
|
||||
tensorflow_object_detection_api_pipeline_config: [str, pathlib.Path] = None,
|
||||
tensorboard_logdir: [str, pathlib.Path] = None,
|
||||
tensorflow_custom_layer_libraries: [str, pathlib.Path] = None,
|
||||
|
||||
# MXNet-specific parameters:
|
||||
input_symbol: [str, pathlib.Path] = None,
|
||||
nd_prefix_name: str = None,
|
||||
pretrained_model_name: str = None,
|
||||
save_params_from_nd: bool = None,
|
||||
legacy_mxnet_model: bool = None,
|
||||
enable_ssd_gluoncv: bool = False,
|
||||
|
||||
# Caffe*-specific parameters:
|
||||
input_proto: [str, pathlib.Path] = None,
|
||||
caffe_parser_path: [str, pathlib.Path] = None,
|
||||
k: [str, pathlib.Path] = None,
|
||||
disable_omitting_optional: bool = False,
|
||||
enable_flattening_nested_params: bool = False,
|
||||
|
||||
# Kaldi-specific parameters:
|
||||
counts: [str, pathlib.Path] = None,
|
||||
remove_output_softmax: bool = False,
|
||||
remove_memory: bool = False,
|
||||
|
||||
**args
|
||||
) -> Model:
|
||||
"""
|
||||
Converts the model from original framework to OpenVino Model.
|
||||
|
||||
Args:
|
||||
:param help:
|
||||
Print available parameters.
|
||||
:param framework:
|
||||
Name of the framework used to train the input model.
|
||||
|
||||
Framework-agnostic parameters:
|
||||
:param input_model:
|
||||
Model object in original framework (PyTorch, Tensorflow) or path to model file.
|
||||
Tensorflow*: a file with a pre-trained model (binary or text .pb file after freezing).
|
||||
Caffe*: a model proto file with model weights
|
||||
|
||||
Supported formats of input model:
|
||||
|
||||
PaddlePaddle
|
||||
paddle.hapi.model.Model
|
||||
paddle.fluid.dygraph.layers.Layer
|
||||
paddle.fluid.executor.Executor
|
||||
|
||||
PyTorch
|
||||
torch.nn.Module
|
||||
torch.jit.ScriptModule
|
||||
torch.jit.ScriptFunction
|
||||
|
||||
TF
|
||||
tf.compat.v1.Graph
|
||||
tf.compat.v1.GraphDef
|
||||
tf.compat.v1.wrap_function
|
||||
tf.compat.v1.session
|
||||
|
||||
TF2 / Keras
|
||||
tf.keras.Model
|
||||
tf.keras.layers.Layer
|
||||
tf.function
|
||||
tf.Module
|
||||
tf.train.checkpoint
|
||||
|
||||
:param input:
|
||||
Input can be set by passing a list of InputCutInfo objects or by a list
|
||||
of tuples. Each tuple can contain optionally input name, input
|
||||
type or input shape. Example: input=("op_name", PartialShape([-1,
|
||||
3, 100, 100]), Type(np.float32)). Alternatively input can be set by
|
||||
a string or list of strings of the following format. Quoted list of comma-separated
|
||||
input nodes names with shapes, data types, and values for freezing.
|
||||
If operation names are specified, the order of inputs in converted
|
||||
model will be the same as order of specified operation names (applicable for TF2, ONNX, MxNet).
|
||||
The shape and value are specified as comma-separated lists. The data type of input node is specified
|
||||
in braces and can have one of the values: f64 (float64), f32 (float32), f16 (float16), i64
|
||||
(int64), i32 (int32), u8 (uint8), boolean (bool). Data type is optional.
|
||||
If it's not specified explicitly then there are two options: if input
|
||||
node is a parameter, data type is taken from the original node dtype,
|
||||
if input node is not a parameter, data type is set to f32. Example, to set
|
||||
`input_1` with shape [1,100], and Parameter node `sequence_len` with
|
||||
scalar input with value `150`, and boolean input `is_training` with
|
||||
`False` value use the following format: "input_1[1,100],sequence_len->150,is_training->False".
|
||||
Another example, use the following format to set input port 0 of the node
|
||||
`node_name1` with the shape [3,4] as an input node and freeze output
|
||||
port 1 of the node `node_name2` with the value [20,15] of the int32 type
|
||||
and shape [2]: "0:node_name1[3,4],node_name2:1[2]{i32}->[20,15]".
|
||||
:param output:
|
||||
The name of the output operation of the model or list of names. For TensorFlow*,
|
||||
do not add :0 to this name.The order of outputs in converted model is the
|
||||
same as order of specified operation names.
|
||||
:param input_shape:
|
||||
Input shape(s) that should be fed to an input node(s) of the model. Input
|
||||
shapes can be defined by passing a list of objects of type PartialShape,
|
||||
Shape, [Dimension, ...] or [int, ...] or by a string of the following
|
||||
format. Shape is defined as a comma-separated list of integer numbers
|
||||
enclosed in parentheses or square brackets, for example [1,3,227,227]
|
||||
or (1,227,227,3), where the order of dimensions depends on the framework
|
||||
input layout of the model. For example, [N,C,H,W] is used for ONNX* models
|
||||
and [N,H,W,C] for TensorFlow* models. The shape can contain undefined
|
||||
dimensions (? or -1) and should fit the dimensions defined in the input
|
||||
operation of the graph. Boundaries of undefined dimension can be specified
|
||||
with ellipsis, for example [1,1..10,128,128]. One boundary can be
|
||||
undefined, for example [1,..100] or [1,3,1..,1..]. If there are multiple
|
||||
inputs in the model, "input_shape" should contain definition of shape
|
||||
for each input separated by a comma, for example: [1,3,227,227],[2,4]
|
||||
for a model with two inputs with 4D and 2D shapes. Alternatively, specify
|
||||
shapes with the "input" option.
|
||||
:param example_input:
|
||||
Sample of model input in original framework.
|
||||
For PyTorch it can be torch.Tensor.
|
||||
For Tensorflow it can be tf.Tensor or numpy.ndarray.
|
||||
For PaddlePaddle it can be Paddle Variable.
|
||||
:param batch:
|
||||
Set batch size. It applies to 1D or higher dimension inputs.
|
||||
The default dimension index for the batch is zero.
|
||||
Use a label 'n' in "layout" or "source_layout" option to set the batch dimension.
|
||||
For example, "x(hwnc)" defines the third dimension to be the batch.
|
||||
:param mean_values:
|
||||
Mean values to be used for the input image per channel. Mean values can
|
||||
be set by passing a dictionary, where key is input name and value is mean
|
||||
value. For example mean_values={'data':[255,255,255],'info':[255,255,255]}.
|
||||
Or mean values can be set by a string of the following format. Values to
|
||||
be provided in the (R,G,B) or [R,G,B] format. Can be defined for desired
|
||||
input of the model, for example: mean_values="data[255,255,255],info[255,255,255]".
|
||||
The exact meaning and order of channels depend on how the original model
|
||||
was trained.
|
||||
:param scale_values:
|
||||
Scale values to be used for the input image per channel. Scale values
|
||||
can be set by passing a dictionary, where key is input name and value is
|
||||
scale value. For example scale_values={'data':[255,255,255],'info':[255,255,255]}.
|
||||
Or scale values can be set by a string of the following format. Values
|
||||
are provided in the (R,G,B) or [R,G,B] format. Can be defined for desired
|
||||
input of the model, for example: scale_values="data[255,255,255],info[255,255,255]".
|
||||
The exact meaning and order of channels depend on how the original model
|
||||
was trained. If both "mean_values" and "scale_values" are specified,
|
||||
the mean is subtracted first and then scale is applied regardless of
|
||||
the order of options in command line.
|
||||
:param scale:
|
||||
All input values coming from original network inputs will be divided
|
||||
by this value. When a list of inputs is overridden by the "input" parameter,
|
||||
this scale is not applied for any input that does not match with the original
|
||||
input of the model. If both "mean_values" and "scale" are specified,
|
||||
the mean is subtracted first and then scale is applied regardless of
|
||||
the order of options in command line.
|
||||
:param reverse_input_channels:
|
||||
Switch the input channels order from RGB to BGR (or vice versa). Applied
|
||||
to original inputs of the model if and only if a number of channels equals
|
||||
3. When "mean_values"/"scale_values" are also specified, reversing
|
||||
of channels will be applied to user's input data first, so that numbers
|
||||
in "mean_values" and "scale_values" go in the order of channels used
|
||||
in the original model. In other words, if both options are specified,
|
||||
then the data flow in the model looks as following: Parameter -> ReverseInputChannels
|
||||
-> Mean apply-> Scale apply -> the original body of the model.
|
||||
:param source_layout:
|
||||
Layout of the input or output of the model in the framework. Layout can
|
||||
be set by passing a dictionary, where key is input name and value is LayoutMap
|
||||
object. Or layout can be set by string of the following format. Layout
|
||||
can be specified in the short form, e.g. nhwc, or in complex form, e.g.
|
||||
"[n,h,w,c]". Example for many names: "in_name1([n,h,w,c]),in_name2(nc),out_name1(n),out_name2(nc)".
|
||||
Layout can be partially defined, "?" can be used to specify undefined
|
||||
layout for one dimension, "..." can be used to specify undefined layout
|
||||
for multiple dimensions, for example "?c??", "nc...", "n...c", etc.
|
||||
:param target_layout:
|
||||
Same as "source_layout", but specifies target layout that will be in
|
||||
the model after processing by ModelOptimizer.
|
||||
:param layout:
|
||||
Combination of "source_layout" and "target_layout". Can't be used
|
||||
with either of them. If model has one input it is sufficient to specify
|
||||
layout of this input, for example "layout" nhwc. To specify layouts
|
||||
of many tensors, names must be provided, for example: layout="name1(nchw),name2(nc)".
|
||||
It is possible to instruct ModelOptimizer to change layout, for example:
|
||||
layout="name1(nhwc->nchw),name2(cn->nc)".
|
||||
Also "*" in long layout form can be used to fuse dimensions, for example "[n,c,...]->[n*c,...]".
|
||||
:param compress_to_fp16:
|
||||
If the original model has FP32 weights or biases, they are compressed
|
||||
to FP16. All intermediate data is kept in original precision. Option
|
||||
can be specified alone as "compress_to_fp16", or explicit True/False
|
||||
values can be set, for example: "compress_to_fp16=False", or "compress_to_fp16=True"
|
||||
:param extensions:
|
||||
Paths to libraries (.so or .dll) with extensions, comma-separated
|
||||
list of paths, objects derived from BaseExtension class or lists of
|
||||
objects. For the legacy MO path (if "use_legacy_frontend" is used),
|
||||
a directory or a comma-separated list of directories with extensions
|
||||
are supported. To disable all extensions including those that are placed
|
||||
at the default location, pass an empty string.
|
||||
:param transform:
|
||||
Apply additional transformations. 'transform' can be set by a list
|
||||
of tuples, where the first element is transform name and the second element
|
||||
is transform parameters. For example: [('LowLatency2', {{'use_const_initializer':
|
||||
False}}), ...] transform="transformation_name1[args],transformation_name2..."
|
||||
where [args] is key=value pairs separated by semicolon. Examples:
|
||||
transform="LowLatency2" or
|
||||
transform="Pruning" or
|
||||
transform="LowLatency2[use_const_initializer=False]" or
|
||||
transform="MakeStateful[param_res_names=
|
||||
{'input_name_1':'output_name_1','input_name_2':'output_name_2'}]"
|
||||
Available transformations: "LowLatency2", "MakeStateful", "Pruning"
|
||||
:param transformations_config:
|
||||
Use the configuration file with transformations description or pass
|
||||
object derived from BaseExtension class. Transformations file can
|
||||
be specified as relative path from the current directory, as absolute
|
||||
path or as relative path from the mo root directory.
|
||||
:param silent:
|
||||
Prevent any output messages except those that correspond to log level
|
||||
equals ERROR, that can be set with the following option: "log_level".
|
||||
By default, log level is already ERROR.
|
||||
:param log_level:
|
||||
Logger level of logging massages from MO.
|
||||
Expected one of ['CRITICAL', 'ERROR', 'WARN', 'WARNING', 'INFO', 'DEBUG', 'NOTSET'].
|
||||
:param version:
|
||||
Version of Model Conversion API
|
||||
:param progress:
|
||||
Enable model conversion progress display.
|
||||
:param stream_output:
|
||||
Switch model conversion progress display to a multiline mode.
|
||||
|
||||
PaddlePaddle-specific parameters:
|
||||
:param example_output:
|
||||
Sample of model output in original framework. For PaddlePaddle it can be Paddle Variable.
|
||||
|
||||
TensorFlow*-specific parameters:
|
||||
:param input_model_is_text:
|
||||
TensorFlow*: treat the input model file as a text protobuf format. If
|
||||
not specified, the convert_model() treats it as a binary file by default.
|
||||
:param input_checkpoint:
|
||||
TensorFlow*: variables file to load.
|
||||
:param input_meta_graph:
|
||||
Tensorflow*: a file with a meta-graph of the model before freezing
|
||||
:param saved_model_dir:
|
||||
TensorFlow*: directory with a model in SavedModel format of TensorFlow
|
||||
1.x or 2.x version.
|
||||
:param saved_model_tags:
|
||||
Group of tag(s) of the MetaGraphDef to load, in string format, separated
|
||||
by ','. For tag-set contains multiple tags, all tags must be passed in.
|
||||
:param tensorflow_custom_operations_config_update:
|
||||
TensorFlow*: update the configuration file with node name patterns
|
||||
with input/output nodes information.
|
||||
:param tensorflow_object_detection_api_pipeline_config:
|
||||
TensorFlow*: path to the pipeline configuration file used to generate
|
||||
model created with help of Object Detection API.
|
||||
:param tensorboard_logdir:
|
||||
TensorFlow*: dump the input graph to a given directory that should be
|
||||
used with TensorBoard.
|
||||
:param tensorflow_custom_layer_libraries:
|
||||
TensorFlow*: comma separated list of shared libraries with TensorFlow*
|
||||
custom operations implementation.
|
||||
|
||||
MXNet-specific parameters:
|
||||
:param input_symbol:
|
||||
Symbol file (for example, model-symbol.json) that contains a topology
|
||||
structure and layer attributes
|
||||
:param nd_prefix_name:
|
||||
Prefix name for args.nd and argx.nd files.
|
||||
:param pretrained_model_name:
|
||||
Name of a pretrained MXNet model without extension and epoch number.
|
||||
This model will be merged with args.nd and argx.nd files
|
||||
:param save_params_from_nd:
|
||||
Enable saving built parameters file from .nd files
|
||||
:param legacy_mxnet_model:
|
||||
Enable MXNet loader to make a model compatible with the latest MXNet
|
||||
version. Use only if your model was trained with MXNet version lower
|
||||
than 1.0.0
|
||||
:param enable_ssd_gluoncv:
|
||||
Enable pattern matchers replacers for converting gluoncv ssd topologies.
|
||||
|
||||
Caffe*-specific parameters:
|
||||
:param input_proto:
|
||||
Deploy-ready prototxt file that contains a topology structure and
|
||||
layer attributes
|
||||
:param caffe_parser_path:
|
||||
Path to Python Caffe* parser generated from caffe.proto
|
||||
:param k:
|
||||
Path to CustomLayersMapping.xml to register custom layers
|
||||
:param disable_omitting_optional:
|
||||
Disable omitting optional attributes to be used for custom layers.
|
||||
Use this option if you want to transfer all attributes of a custom layer
|
||||
to IR. Default behavior is to transfer the attributes with default values
|
||||
and the attributes defined by the user to IR.
|
||||
:param enable_flattening_nested_params:
|
||||
Enable flattening optional params to be used for custom layers. Use
|
||||
this option if you want to transfer attributes of a custom layer to IR
|
||||
with flattened nested parameters. Default behavior is to transfer
|
||||
the attributes without flattening nested parameters.
|
||||
|
||||
Kaldi-specific parameters:
|
||||
:param counts:
|
||||
Path to the counts file
|
||||
:param remove_output_softmax:
|
||||
Removes the SoftMax layer that is the output layer
|
||||
:param remove_memory:
|
||||
Removes the Memory layer and use additional inputs outputs instead
|
||||
|
||||
Returns:
|
||||
openvino.runtime.Model
|
||||
"""
|
||||
params = locals()
|
||||
logger_state = get_logger_state()
|
||||
del params['args']
|
||||
params.update(args)
|
||||
cli_parser = get_all_cli_parser()
|
||||
ov_model, _ = _convert(cli_parser, params, True)
|
||||
restore_logger_state(logger_state)
|
||||
return ov_model
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# flake8: noqa
|
||||
# mypy: ignore-errors
|
||||
|
||||
import numpy as np
|
||||
|
||||
from openvino.tools.ovc.error import Error
|
||||
|
||||
"""
|
||||
Packed data of custom types are stored in numpy uint8 data type.
|
||||
To distinguish true uint8 and custom data we introduce this class not to store,
|
||||
but to have unique data type in SUPPORTED_DATA_TYPES map
|
||||
"""
|
||||
|
||||
|
||||
class packed_U1(np.generic):
|
||||
pass
|
||||
|
||||
|
||||
class packed_U4(np.generic):
|
||||
pass
|
||||
|
||||
|
||||
class packed_I4(np.generic):
|
||||
pass
|
||||
|
||||
|
||||
SUPPORTED_DATA_TYPES = {
|
||||
'float': (np.float32, 'FP32', 'f32'),
|
||||
'half': (np.float16, 'FP16', 'f16'),
|
||||
'FP32': (np.float32, 'FP32', 'f32'),
|
||||
'FP64': (np.float64, 'FP64', 'f64'),
|
||||
'FP16': (np.float16, 'FP16', 'f16'),
|
||||
'I32': (np.int32, 'I32', 'i32'),
|
||||
'I64': (np.int64, 'I64', 'i64'),
|
||||
'int8': (np.int8, 'I8', 'i8'),
|
||||
'int32': (np.int32, 'I32', 'i32'),
|
||||
'int64': (np.int64, 'I64', 'i64'),
|
||||
'bool': (bool, 'BOOL', 'boolean'),
|
||||
'uint8': (np.uint8, 'U8', 'u8'),
|
||||
'uint32': (np.uint32, 'U32', 'u32'),
|
||||
'uint64': (np.uint64, 'U64', 'u64'),
|
||||
|
||||
# custom types
|
||||
'U1': (packed_U1, 'U1', 'u1'),
|
||||
'int4': (packed_I4, 'I4', 'i4'),
|
||||
'uint4': (packed_U4, 'U4', 'u4'),
|
||||
'I4': (packed_I4, 'I4', 'i4'),
|
||||
'U4': (packed_U4, 'U4', 'u4'),
|
||||
}
|
||||
|
||||
|
||||
def data_type_str_to_np(data_type_str: str):
|
||||
return SUPPORTED_DATA_TYPES[data_type_str][0] if data_type_str in SUPPORTED_DATA_TYPES else None
|
||||
|
||||
|
||||
def data_type_str_to_precision(data_type_str: str):
|
||||
return SUPPORTED_DATA_TYPES[data_type_str][1] if data_type_str in SUPPORTED_DATA_TYPES else None
|
||||
|
||||
|
||||
def data_type_str_to_destination_type(data_type_str: str):
|
||||
return SUPPORTED_DATA_TYPES[data_type_str][2] if data_type_str in SUPPORTED_DATA_TYPES else None
|
||||
|
||||
|
||||
def np_data_type_to_precision(np_data_type):
|
||||
for np_t, precision, _ in SUPPORTED_DATA_TYPES.values():
|
||||
if np_t == np_data_type:
|
||||
return precision
|
||||
raise Error('Data type "{}" is not supported'.format(np_data_type))
|
||||
|
||||
|
||||
def np_data_type_to_destination_type(np_data_type):
|
||||
for np_t, _, destination_type in SUPPORTED_DATA_TYPES.values():
|
||||
if np_t == np_data_type:
|
||||
return destination_type
|
||||
raise Error('Data type "{}" is not supported'.format(np_data_type))
|
||||
|
||||
|
||||
def destination_type_to_np_data_type(dst_type):
|
||||
for np_t, _, destination_type in SUPPORTED_DATA_TYPES.values():
|
||||
if destination_type == dst_type:
|
||||
return np_t
|
||||
raise Error('Destination type "{}" is not supported'.format(dst_type))
|
||||
|
||||
|
||||
def precision_to_destination_type(data_type_str):
|
||||
for _, precision, destination_type in SUPPORTED_DATA_TYPES.values():
|
||||
if precision == data_type_str:
|
||||
return destination_type
|
||||
raise Error('Data type "{}" is not supported'.format(data_type_str))
|
||||
|
|
@ -0,0 +1,831 @@
|
|||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# flake8: noqa
|
||||
# mypy: ignore-errors
|
||||
|
||||
import argparse
|
||||
import datetime
|
||||
import logging as log
|
||||
import os
|
||||
import sys
|
||||
import traceback
|
||||
from collections import OrderedDict
|
||||
from pathlib import Path
|
||||
|
||||
try:
|
||||
import openvino_telemetry as tm
|
||||
except ImportError:
|
||||
import openvino.tools.ovc.telemetry_stub as tm
|
||||
|
||||
from openvino.tools.ovc.moc_frontend.check_config import legacy_transformations_config_used, \
|
||||
tensorflow_custom_operations_config_update_used, new_extensions_used
|
||||
from openvino.tools.ovc.moc_frontend.pipeline import moc_pipeline
|
||||
from openvino.tools.ovc.moc_frontend.moc_emit_ir import moc_emit_ir
|
||||
from openvino.tools.ovc.convert_data_type import destination_type_to_np_data_type
|
||||
from openvino.tools.ovc.cli_parser import check_available_transforms, \
|
||||
get_advanced_cli_options, get_available_front_ends, get_caffe_cli_options, \
|
||||
get_common_cli_options, get_kaldi_cli_options, get_layout_values, get_freeze_placeholder_values, \
|
||||
get_mean_scale_dictionary, get_mxnet_cli_options, get_onnx_cli_options, \
|
||||
get_placeholder_shapes, get_tf_cli_options, parse_transform, parse_tuple_pairs, \
|
||||
get_model_name_from_args, depersonalize, get_mo_convert_params, input_to_input_cut_info, \
|
||||
input_shape_to_input_cut_info, freeze_placeholder_to_input_cut_info
|
||||
|
||||
from openvino.tools.ovc.error import Error, FrameworkError, legacy_path_error
|
||||
from openvino.tools.ovc.get_ov_update_message import get_ov_update_message, get_ov_api20_message, \
|
||||
get_tf_fe_message, get_try_legacy_fe_message, get_compression_message
|
||||
from openvino.tools.ovc.version import VersionChecker
|
||||
from openvino.tools.ovc.utils import deduce_legacy_frontend_by_namespace, refer_to_faq_msg, check_values_equal
|
||||
from openvino.tools.ovc.logger import init_logger, progress_printer
|
||||
from openvino.tools.ovc.telemetry_utils import send_params_info, send_conversion_result, \
|
||||
get_tid
|
||||
from openvino.tools.ovc.moc_frontend.check_config import legacy_extensions_used
|
||||
from openvino.tools.ovc.moc_frontend.check_config import default_path as extensions_default_path
|
||||
from openvino.tools.ovc.moc_frontend.pytorch_frontend_utils import get_pytorch_decoder, extract_input_info_from_example
|
||||
from openvino.tools.ovc.moc_frontend.paddle_frontend_utils import paddle_frontend_converter
|
||||
from openvino.tools.ovc.moc_frontend.shape_utils import parse_input_shapes
|
||||
|
||||
# pylint: disable=no-name-in-module,import-error
|
||||
from openvino.frontend import FrontEndManager, OpConversionFailure, ProgressReporterExtension, TelemetryExtension
|
||||
from openvino.runtime import get_version as get_rt_version
|
||||
from openvino.runtime import Type, PartialShape
|
||||
|
||||
try:
|
||||
from openvino.frontend.tensorflow.utils import type_supported_by_tf_fe, create_tf_graph_iterator, \
|
||||
extract_model_graph # pylint: disable=no-name-in-module,import-error
|
||||
|
||||
tf_frontend_with_python_bindings_installed = True
|
||||
except (ModuleNotFoundError, ImportError):
|
||||
tf_frontend_with_python_bindings_installed = False
|
||||
|
||||
|
||||
def replace_ext(name: str, old: str, new: str):
|
||||
base, ext = os.path.splitext(name)
|
||||
log.debug("base: {}, ext: {}".format(base, ext))
|
||||
if ext == old:
|
||||
return base + new
|
||||
|
||||
|
||||
def print_argv(argv: argparse.Namespace, is_caffe: bool, is_tf: bool, is_mxnet: bool, is_kaldi: bool, is_onnx: bool,
|
||||
model_name: str):
|
||||
print('Model Conversion arguments:')
|
||||
props = OrderedDict()
|
||||
props['common_args'] = get_common_cli_options(model_name)
|
||||
props['advanced_args'] = get_advanced_cli_options()
|
||||
if is_caffe:
|
||||
props['caffe_args'] = get_caffe_cli_options()
|
||||
if is_tf:
|
||||
props['tf_args'] = get_tf_cli_options()
|
||||
if is_mxnet:
|
||||
props['mxnet_args'] = get_mxnet_cli_options()
|
||||
if is_kaldi:
|
||||
props['kaldi_args'] = get_kaldi_cli_options()
|
||||
if is_onnx:
|
||||
props['onnx_args'] = get_onnx_cli_options()
|
||||
|
||||
framework_specifics_map = {
|
||||
'common_args': 'Common parameters:',
|
||||
'advanced_args': 'Advanced parameters:',
|
||||
'caffe_args': 'Caffe specific parameters:',
|
||||
'tf_args': 'TensorFlow specific parameters:',
|
||||
'mxnet_args': 'MXNet specific parameters:',
|
||||
'kaldi_args': 'Kaldi specific parameters:',
|
||||
'onnx_args': 'ONNX specific parameters:',
|
||||
}
|
||||
|
||||
lines = []
|
||||
for key in props:
|
||||
lines.append(framework_specifics_map[key])
|
||||
for (op, desc) in props[key].items():
|
||||
if isinstance(desc, list):
|
||||
lines.append('\t{}: \t{}'.format(desc[0], desc[1](getattr(argv, op, 'NONE'))))
|
||||
else:
|
||||
if op == 'k':
|
||||
default_path = os.path.join(os.path.dirname(sys.argv[0]),
|
||||
'openvino/tools/mo/front/caffe/CustomLayersMapping.xml')
|
||||
if getattr(argv, op, 'NONE') == default_path:
|
||||
lines.append('\t{}: \t{}'.format(desc, 'Default'))
|
||||
continue
|
||||
lines.append('\t{}: \t{}'.format(desc, getattr(argv, op, 'NONE')))
|
||||
print('\n'.join(lines), flush=True)
|
||||
|
||||
|
||||
def legacy_framework_check(is_caffe, is_mxnet, is_kaldi):
|
||||
if is_caffe:
|
||||
legacy_path_error("The provided model is from Caffe framework. This is legacy functionality. ")
|
||||
if is_mxnet:
|
||||
legacy_path_error("The provided model is from MxNet framework. This is legacy functionality. ")
|
||||
if is_kaldi:
|
||||
legacy_path_error("The provided model is from Kaldi framework. This is legacy functionality. ")
|
||||
|
||||
|
||||
def check_legacy_args(non_default_params, python_api_used):
|
||||
ignored_cli_options = ["output_dir", "model_name"]
|
||||
legacy_groups = ['Kaldi-specific parameters:', 'Caffe*-specific parameters:', 'MXNet-specific parameters:']
|
||||
tf_legacy_args = ['tensorflow_custom_operations_config_update', 'tensorflow_object_detection_api_pipeline_config',
|
||||
'tensorboard_logdir', 'tensorflow_custom_layer_libraries', 'saved_model_tags']
|
||||
mo_convert_params = get_mo_convert_params()
|
||||
|
||||
for key, value in non_default_params.items():
|
||||
if key in ignored_cli_options:
|
||||
if python_api_used:
|
||||
print("The provided option \"{}\" is applicable in command line tool only. The option will be ignored.".format(key))
|
||||
for group in legacy_groups:
|
||||
if key in mo_convert_params[group]:
|
||||
legacy_path_error("The provided option \"{}\" refers to legacy functionality. ".format(key))
|
||||
if key in tf_legacy_args:
|
||||
legacy_path_error("The provided option \"{}\" refers to legacy functionality. ".format(key))
|
||||
|
||||
|
||||
|
||||
def arguments_post_parsing(argv: argparse.Namespace):
|
||||
use_legacy_frontend = argv.use_legacy_frontend
|
||||
use_new_frontend = argv.use_new_frontend
|
||||
if argv.extensions is None:
|
||||
argv.extensions = [extensions_default_path()]
|
||||
|
||||
if use_new_frontend and use_legacy_frontend:
|
||||
raise Error('Options "use_new_frontend" and "use_legacy_frontend" must not be used simultaneously.')
|
||||
|
||||
if use_legacy_frontend:
|
||||
legacy_path_error('Option "use_legacy_frontend" was used, but legacy frontends are not available. ')
|
||||
|
||||
moc_front_end, available_moc_front_ends = get_moc_frontends(argv)
|
||||
|
||||
if not moc_front_end and use_new_frontend:
|
||||
raise Error('Option "use_new_frontend" is specified but the Model Conversion API is unable to find new frontend. '
|
||||
'Please ensure that your environment contains new frontend for the input model format or '
|
||||
'try to install openvino-dev and convert the model using convert_model() from openvino.tools.mo.')
|
||||
|
||||
is_tf, is_caffe, is_mxnet, is_kaldi, is_onnx = \
|
||||
deduce_legacy_frontend_by_namespace(argv) if not moc_front_end else [False, False, False, False, False]
|
||||
|
||||
legacy_framework_check(is_caffe, is_mxnet, is_kaldi)
|
||||
|
||||
is_legacy_frontend = any([is_tf, is_caffe, is_mxnet, is_kaldi, is_onnx])
|
||||
|
||||
# handle a default case, i.e. use_new_frontend and use_legacy_frontend are not specified, when no frontend is found
|
||||
if not is_legacy_frontend and not moc_front_end:
|
||||
legacy_frameworks = ['tf', 'caffe', 'mxnet', 'kaldi', 'onnx']
|
||||
frameworks = list(set(legacy_frameworks + available_moc_front_ends))
|
||||
if not argv.framework:
|
||||
raise Error('Framework name can not be deduced from the given options: {}={}. '
|
||||
'Please use "framework" with one from the list: {}.',
|
||||
'"input_model="', argv.input_model, frameworks)
|
||||
elif argv.framework not in frameworks:
|
||||
if argv.framework == 'ir':
|
||||
raise Error('OpenVINO IR is passed as input_model in convert_model/mo, the IR doesn\'t need '
|
||||
'conversion, please use it in runtime for inference with read_model/compile_model.')
|
||||
raise Error('Framework {} is not a valid target. Please use "framework" with one from the list: {}. ' +
|
||||
refer_to_faq_msg(15), argv.framework, frameworks)
|
||||
|
||||
if is_tf and not argv.input_model and not argv.saved_model_dir and not argv.input_meta_graph:
|
||||
raise Error('Path to input model or saved model dir is required: use "input_model", "saved_model_dir" or '
|
||||
'"input_meta_graph"')
|
||||
elif is_onnx and not argv.input_model:
|
||||
raise Error('Path to input model is required: use "input_model".')
|
||||
|
||||
log.debug("Model Conversion API started")
|
||||
|
||||
log.debug('Output model name would be {}{{.xml, .bin}}'.format(argv.model_name))
|
||||
|
||||
if not argv.silent:
|
||||
print_argv(argv, is_caffe, is_tf, is_mxnet, is_kaldi, is_onnx, argv.model_name)
|
||||
|
||||
argv.data_type = 'FP32' # if compression was enabled will be restored back to 'FP16' after apply_offline_transformations
|
||||
|
||||
# This is just to check that transform key is valid and transformations are available
|
||||
check_available_transforms(parse_transform(argv.transform))
|
||||
|
||||
if argv.scale and argv.scale_values:
|
||||
raise Error(
|
||||
'Both "scale" and "scale_values" are defined. Specify either scale factor or scale values per input ' +
|
||||
'channels. ' + refer_to_faq_msg(19))
|
||||
|
||||
if argv.scale and argv.scale < 1.0:
|
||||
log.error("The scale value is less than 1.0. This is most probably an issue because the scale value specifies "
|
||||
"floating point value which all input values will be *divided*.", extra={'is_warning': True})
|
||||
|
||||
if argv.input_model and (is_tf and argv.saved_model_dir):
|
||||
raise Error('Both "input_model" and "saved_model_dir" are defined. '
|
||||
'Specify either input model or saved model directory.')
|
||||
if is_tf:
|
||||
if argv.saved_model_tags is not None:
|
||||
if ' ' in argv.saved_model_tags:
|
||||
raise Error('Incorrect saved model tag was provided. Specify "saved_model_tags" with no spaces in it')
|
||||
argv.saved_model_tags = argv.saved_model_tags.split(',')
|
||||
|
||||
if hasattr(argv, 'is_python_api_used') and argv.is_python_api_used:
|
||||
python_api_params_parsing(argv)
|
||||
else:
|
||||
argv.inputs_list, argv.placeholder_shapes, argv.placeholder_data_types = get_placeholder_shapes(
|
||||
argv.input, argv.input_shape, argv.batch)
|
||||
argv.freeze_placeholder_with_value, argv.input = get_freeze_placeholder_values(
|
||||
argv.input,
|
||||
argv.freeze_placeholder_with_value)
|
||||
argv.unnamed_freeze_placeholder_with_value = {}
|
||||
argv.output = argv.output.split(',') if argv.output else None
|
||||
argv.layout_values = get_layout_values(argv.layout, argv.source_layout, argv.target_layout)
|
||||
mean_values = parse_tuple_pairs(argv.mean_values)
|
||||
scale_values = parse_tuple_pairs(argv.scale_values)
|
||||
mean_scale = get_mean_scale_dictionary(mean_values, scale_values, argv.input)
|
||||
argv.mean_scale_values = mean_scale
|
||||
|
||||
log.debug("Placeholder shapes : {}".format(argv.placeholder_shapes))
|
||||
|
||||
return argv
|
||||
|
||||
|
||||
def check_fallback(argv: argparse.Namespace):
|
||||
fallback_reasons = {}
|
||||
|
||||
# Some frontend such as PDPD does not have legacy path so it has no reasons to fallback
|
||||
if not any(deduce_legacy_frontend_by_namespace(argv)):
|
||||
return fallback_reasons
|
||||
|
||||
if argv.use_new_frontend:
|
||||
return fallback_reasons
|
||||
|
||||
fallback_reasons['extensions'] = legacy_extensions_used
|
||||
fallback_reasons['transformations_config'] = legacy_transformations_config_used
|
||||
fallback_reasons['tensorflow_custom_operations_config_update'] = tensorflow_custom_operations_config_update_used
|
||||
|
||||
reasons = [reason for reason, is_applicable in fallback_reasons.items() if is_applicable(argv)]
|
||||
return reasons
|
||||
|
||||
|
||||
def update_fallback_with_conversion_error(use_new_frontend: bool, is_tf: bool, ex_msg: str, fallback_reasons: list):
|
||||
import re
|
||||
if not is_tf:
|
||||
# this sort of fallback is only used by TensorFlow Frontend
|
||||
return False
|
||||
|
||||
if use_new_frontend:
|
||||
# this option forces to use new TensorFlow Frontend
|
||||
# so it is not possible for the fallback
|
||||
return False
|
||||
|
||||
# for TensorFlow FE we have a set of operations that should lead to the fallback to the legacy
|
||||
conversion_error_re = r"^(\[TensorFlow\ Frontend\]\ Internal\ error\,\ no\ translator\ found\ for\ operation\(s\)\:\ )((\w+)(\,\ \w+)*)$"
|
||||
conversion_error_match = re.findall(conversion_error_re, ex_msg, re.MULTILINE)
|
||||
all_fallback_operations = [
|
||||
# corresponds to TF1 While operation
|
||||
"TensorArrayScatterV3", "TensorArrayV3", "TensorArraySizeV3", "TensorArrayGatherV3",
|
||||
"LoopCond", "Enter", "NextIteration", "Exit",
|
||||
# corresponds to TF1 If and TF1 While operations
|
||||
"Switch", "Merge",
|
||||
# corresponds to operations with complex tensors
|
||||
"FFT", "FFT2D", "FFT3D", "IFFT", "IFFT2D", "IFFT3D",
|
||||
"RFFT", "RFFT2D", "RFFT3D", "IRFFT", "IRFFT2D", "IRFFT3D",
|
||||
"Complex", "ComplexAbs", "Real", "Imag",
|
||||
]
|
||||
if len(conversion_error_match) < 1 or len(conversion_error_match[0]) != 4:
|
||||
# no match for the fallback by unsupported operation
|
||||
return False
|
||||
|
||||
unsupported_operations = conversion_error_match[0][1].replace(" ", "").split(",")
|
||||
fallback_operations = [operation for operation in unsupported_operations if operation in all_fallback_operations]
|
||||
|
||||
if len(fallback_operations) == 0:
|
||||
return False
|
||||
|
||||
fallback_reasons.append("Fallback to the legacy TF FE due to operation(s): " + ', '.join(fallback_operations))
|
||||
return True
|
||||
|
||||
|
||||
def get_default_frontends():
|
||||
# Set which frontend to use by default, values should be 'new' or 'legacy'
|
||||
default_frontends = {
|
||||
'onnx': 'new',
|
||||
'tf': 'new'
|
||||
}
|
||||
return default_frontends
|
||||
|
||||
|
||||
def get_moc_frontends(argv: argparse.Namespace):
|
||||
fem = argv.feManager
|
||||
|
||||
# Read user flags:
|
||||
use_legacy_frontend = argv.use_legacy_frontend
|
||||
use_new_frontend = argv.use_new_frontend
|
||||
|
||||
if not fem or use_legacy_frontend:
|
||||
return None, []
|
||||
|
||||
available_moc_front_ends = get_available_front_ends(fem)
|
||||
|
||||
if not argv.framework and argv.input_model:
|
||||
moc_front_end = fem.load_by_model(argv.input_model)
|
||||
if not moc_front_end:
|
||||
return None, available_moc_front_ends
|
||||
argv.framework = moc_front_end.get_name()
|
||||
elif argv.framework in available_moc_front_ends:
|
||||
moc_front_end = fem.load_by_framework(argv.framework)
|
||||
else:
|
||||
return None, []
|
||||
|
||||
default_frontends = get_default_frontends()
|
||||
# Disable MOC frontend if default is set to legacy and no user override
|
||||
if default_frontends.get(moc_front_end.get_name()) == 'legacy' and not use_new_frontend:
|
||||
return None, available_moc_front_ends
|
||||
|
||||
# This check as a workaround to skip IR frontend
|
||||
if not moc_front_end.get_name() in available_moc_front_ends:
|
||||
return None, available_moc_front_ends
|
||||
|
||||
return moc_front_end, available_moc_front_ends
|
||||
|
||||
|
||||
def prepare_ir(argv: argparse.Namespace):
|
||||
# TODO: remove this workaround once new TensorFlow frontend supports non-frozen formats: checkpoint, MetaGraph, and SavedModel
|
||||
# Now it converts all TensorFlow formats to the frozen .pb format in case new TensorFlow frontend
|
||||
is_tf, _, _, _, _ = deduce_legacy_frontend_by_namespace(argv)
|
||||
argv = arguments_post_parsing(argv)
|
||||
t = tm.Telemetry()
|
||||
|
||||
graph = None
|
||||
fallback_reasons = []
|
||||
moc_front_end, available_moc_front_ends = get_moc_frontends(argv)
|
||||
if moc_front_end:
|
||||
fallback_reasons = check_fallback(argv)
|
||||
if len(fallback_reasons) == 0:
|
||||
if is_tf and tf_frontend_with_python_bindings_installed and \
|
||||
type_supported_by_tf_fe(argv.input_model):
|
||||
argv.input_model = create_tf_graph_iterator(argv.input_model,
|
||||
argv.placeholder_shapes,
|
||||
argv.placeholder_data_types,
|
||||
getattr(argv, "example_input", None))
|
||||
try:
|
||||
t.send_event("mo", "conversion_method", moc_front_end.get_name() + "_frontend")
|
||||
moc_front_end.add_extension(TelemetryExtension("mo", t.send_event, t.send_error, t.send_stack_trace))
|
||||
moc_front_end.add_extension(ProgressReporterExtension(progress_printer(argv)))
|
||||
if legacy_transformations_config_used(argv):
|
||||
raise Error('Legacy extensions are not supported for the new frontend')
|
||||
if legacy_extensions_used(argv):
|
||||
raise Error('Legacy transformations configuration is not supported for the new frontend')
|
||||
if tensorflow_custom_operations_config_update_used(argv) and is_tf:
|
||||
raise Error('TensorFlow custom operation config is not supported for the new frontend')
|
||||
if new_extensions_used(argv):
|
||||
for extension in argv.extensions:
|
||||
moc_front_end.add_extension(extension)
|
||||
ngraph_function = moc_pipeline(argv, moc_front_end)
|
||||
return graph, ngraph_function
|
||||
except OpConversionFailure as ex:
|
||||
# in some set of operations (TF1 While), we have to fallback to the Legacy TensorFlow Frontend
|
||||
# this is the second attempt for the fallback
|
||||
if not update_fallback_with_conversion_error(argv.use_new_frontend, is_tf, str(ex), fallback_reasons):
|
||||
# re-throw exception for all frontends except TensorFlow FE
|
||||
# and in case unexpected conversion failures
|
||||
raise
|
||||
|
||||
if len(fallback_reasons) > 0:
|
||||
reasons_message = ", ".join(fallback_reasons)
|
||||
t.send_event("mo", "fallback_reason", reasons_message)
|
||||
log.warning("The IR preparation cannot be executed with new frontend. "
|
||||
f"The detailed reason why fallback to legacy is needed: not supported {reasons_message} were used. " +
|
||||
refer_to_faq_msg(105))
|
||||
assert not hasattr(argv, 'is_fallback'), '`is_fallback` argument must not exist.'
|
||||
argv.is_fallback = True
|
||||
|
||||
t.send_event("mo", "conversion_method", "mo_legacy")
|
||||
legacy_path_error("The provided model cannot be converted with new frontend, as fallback to legacy is needed. ")
|
||||
return None, None
|
||||
|
||||
|
||||
def check_model_object(argv):
|
||||
model = argv['input_model']
|
||||
if 'tensorflow' in sys.modules:
|
||||
if tf_frontend_with_python_bindings_installed and extract_model_graph(argv):
|
||||
return "tf"
|
||||
if 'torch' in sys.modules:
|
||||
import torch
|
||||
if isinstance(model, (torch.nn.Module, torch.jit.ScriptFunction)):
|
||||
return "pytorch"
|
||||
try:
|
||||
from openvino.frontend.pytorch.decoder import TorchScriptPythonDecoder
|
||||
|
||||
if isinstance(model, TorchScriptPythonDecoder):
|
||||
return "pytorch"
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
import io
|
||||
if isinstance(model, io.BytesIO):
|
||||
return 'onnx'
|
||||
|
||||
if 'paddle' in sys.modules:
|
||||
import paddle
|
||||
if isinstance(model, paddle.hapi.model.Model) or isinstance(model,
|
||||
paddle.fluid.dygraph.layers.Layer) or isinstance(
|
||||
model, paddle.fluid.executor.Executor):
|
||||
return "paddle"
|
||||
|
||||
raise Error('Unknown model type: {}'.format(type(model)))
|
||||
|
||||
|
||||
def driver(argv: argparse.Namespace, non_default_params: dict):
|
||||
init_logger(argv.log_level.upper(), argv.silent)
|
||||
|
||||
# Log dictionary with non-default cli parameters where complex classes are excluded.
|
||||
log.debug(str(non_default_params))
|
||||
|
||||
start_time = datetime.datetime.now()
|
||||
|
||||
graph, ngraph_function = prepare_ir(argv)
|
||||
legacy_path = False
|
||||
if graph is not None:
|
||||
legacy_path_error()
|
||||
else:
|
||||
res_ngraph_function = moc_emit_ir(ngraph_function, argv)
|
||||
|
||||
if res_ngraph_function is None:
|
||||
return res_ngraph_function
|
||||
|
||||
if not argv.silent:
|
||||
elapsed_time = datetime.datetime.now() - start_time
|
||||
print('[ SUCCESS ] Total execution time: {:.2f} seconds. '.format(elapsed_time.total_seconds()))
|
||||
try:
|
||||
import resource
|
||||
mem_usage = round(resource.getrusage(resource.RUSAGE_SELF).ru_maxrss / 1024)
|
||||
if sys.platform == 'darwin':
|
||||
mem_usage = round(mem_usage / 1024)
|
||||
print('[ SUCCESS ] Memory consumed: {} MB. '.format(mem_usage))
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
return res_ngraph_function, legacy_path
|
||||
|
||||
|
||||
def args_dict_to_list(cli_parser, **kwargs):
|
||||
# This method is needed to prepare args from convert_model() for args_parse().
|
||||
# The method will not be needed when cli_parser checks are moved from cli_parser to a separate pass.
|
||||
import inspect
|
||||
from openvino.tools.ovc import convert_model
|
||||
signature = inspect.signature(convert_model)
|
||||
result = []
|
||||
for key, value in kwargs.items():
|
||||
if value is None:
|
||||
continue
|
||||
if key in signature.parameters and check_values_equal(signature.parameters[key].default, value):
|
||||
continue
|
||||
if check_values_equal(cli_parser.get_default(key), value):
|
||||
continue
|
||||
# skip parser checking for non str objects
|
||||
if not isinstance(value, (str, bool)):
|
||||
continue
|
||||
result.append('--{}'.format(key))
|
||||
if not isinstance(value, bool):
|
||||
result.append(value)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def get_non_default_params(argv, cli_parser):
|
||||
import numbers
|
||||
import inspect
|
||||
from openvino.tools.ovc import convert_model
|
||||
|
||||
signature = inspect.signature(convert_model)
|
||||
# make dictionary with parameters which have non-default values to be serialized in IR in rt_info
|
||||
non_default_params = {}
|
||||
for arg, arg_value in vars(argv).items():
|
||||
if arg in signature.parameters and check_values_equal(arg_value, signature.parameters[arg].default):
|
||||
continue
|
||||
if check_values_equal(arg_value, cli_parser.get_default(arg)):
|
||||
continue
|
||||
value = depersonalize(arg_value, arg)
|
||||
# Skip complex classes in params to prevent
|
||||
# serializing it to rt_info
|
||||
if isinstance(value, (str, bool, numbers.Number)):
|
||||
non_default_params[arg] = value
|
||||
return non_default_params
|
||||
|
||||
|
||||
def params_to_string(**kwargs):
|
||||
all_params = {}
|
||||
for key, value in get_mo_convert_params().items():
|
||||
all_params.update(value)
|
||||
|
||||
for key, value in kwargs.items():
|
||||
if key in all_params:
|
||||
param_data = all_params[key]
|
||||
if param_data.to_string is not None:
|
||||
kwargs[key] = param_data.to_string(value)
|
||||
return kwargs
|
||||
|
||||
|
||||
def add_line_breaks(text: str, char_num: int, line_break: str):
|
||||
words = text.replace('\n', "\n ").split(" ")
|
||||
cnt = 0
|
||||
for i, w in enumerate(words):
|
||||
cnt += len(w)
|
||||
if '\n' in w:
|
||||
cnt = len(w) - w.find('\n') - 1
|
||||
if cnt > char_num:
|
||||
if words[i][-1] not in ['\n', '\t']:
|
||||
words[i] = w + '\n'
|
||||
cnt = 0
|
||||
text = ' '.join(words).replace("\n ", "\n")
|
||||
return line_break + text.replace("\n", line_break)
|
||||
|
||||
|
||||
def show_mo_convert_help():
|
||||
mo_convert_params = get_mo_convert_params()
|
||||
for group_name, group in mo_convert_params.items():
|
||||
print(group_name)
|
||||
for param_name in group:
|
||||
param_data = group[param_name]
|
||||
text = param_data.description.replace(" ", '')
|
||||
text = add_line_breaks(text, 56, "\n\t\t\t")
|
||||
print(" :param {} {}".format(param_name, text))
|
||||
print()
|
||||
|
||||
|
||||
def input_model_is_object(argv):
|
||||
# Input model can be set as object only for "input_model" parameter.
|
||||
# "saved_model_dir" or meta specific options are only used to store paths to the input model.
|
||||
if 'input_model' not in argv:
|
||||
return False
|
||||
if isinstance(argv['input_model'], (str, Path)):
|
||||
return False
|
||||
if argv['input_model'] is None:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def python_api_params_parsing(argv: argparse.Namespace):
|
||||
"""
|
||||
Parses params passed to convert_model and wraps resulting values into dictionaries or lists.
|
||||
After working of this method following values are set in argv:
|
||||
|
||||
argv.input, argv.inputs_list - list of input names. Both values are used in some parts of MO.
|
||||
Could be good to refactor it and use only one of these values.
|
||||
|
||||
argv.placeholder_shapes - dictionary where key is node name, value is PartialShape,
|
||||
or list of PartialShape if node names were not set.
|
||||
|
||||
argv.placeholder_data_types - dictionary where key is node name, value is node np.type,
|
||||
or list of np.types if node names were not set.
|
||||
|
||||
argv.freeze_placeholder_with_value - dictionary where key is node name, value is np.ndarray
|
||||
|
||||
argv.unnamed_freeze_placeholder_with_value - list with np.ndarray
|
||||
|
||||
:param argv: MO arguments
|
||||
"""
|
||||
# Parse input to list of InputCutInfo
|
||||
inputs = input_to_input_cut_info(argv.input)
|
||||
|
||||
# Make list of input names
|
||||
input_names_list = []
|
||||
for inp in inputs:
|
||||
if inp.name is not None:
|
||||
input_names_list.append(inp.name)
|
||||
if len(input_names_list) > 0:
|
||||
assert len(input_names_list) == len(inputs), "\"input\" parameter has unnamed inputs and named inputs. " \
|
||||
"Please either set names for all inputs, " \
|
||||
"or do not set names for all inputs."
|
||||
argv.inputs_list = input_names_list
|
||||
argv.input = ','.join(input_names_list)
|
||||
|
||||
# Parse input_shape param and update InputCutInfo list
|
||||
input_shape_to_input_cut_info(argv.input_shape, inputs)
|
||||
|
||||
# Parse freeze_placeholder_with_value.
|
||||
# values for freezing can be set both by named and unnamed approach if
|
||||
# 'input' was used without names and 'freeze_placeholder_with_value' was used with names.
|
||||
# So named and unnamed values are stored separately.
|
||||
argv.freeze_placeholder_with_value, argv.unnamed_freeze_placeholder_with_value = \
|
||||
freeze_placeholder_to_input_cut_info(argv.freeze_placeholder_with_value, inputs)
|
||||
|
||||
if len(input_names_list) > 0:
|
||||
# Named inputs case
|
||||
shape_dict = {}
|
||||
data_type_dict = {}
|
||||
for inp in inputs:
|
||||
if inp.shape is not None:
|
||||
# Wrap shape to PartialShape for uniformity of stored values
|
||||
shape_dict[inp.name] = PartialShape(inp.shape)
|
||||
else:
|
||||
shape_dict[inp.name] = None
|
||||
if inp.type is not None:
|
||||
# Convert type to numpy type for uniformity of stored values
|
||||
if isinstance(inp.type, str):
|
||||
data_type_dict[inp.name] = destination_type_to_np_data_type(inp.type)
|
||||
elif isinstance(inp.type, Type):
|
||||
data_type_dict[inp.name] = inp.type.to_dtype().type
|
||||
else:
|
||||
data_type_dict[inp.name] = inp.type
|
||||
argv.placeholder_shapes = shape_dict if shape_dict else None
|
||||
argv.placeholder_data_types = data_type_dict if data_type_dict else {}
|
||||
else:
|
||||
# Unnamed inputs case
|
||||
shape_list = []
|
||||
data_type_list = []
|
||||
for inp in inputs:
|
||||
if inp.shape is not None:
|
||||
# Wrap shape to PartialShape for uniformity of stored values
|
||||
shape_list.append(PartialShape(inp.shape))
|
||||
if inp.type is not None:
|
||||
# Convert type to numpy type for uniformity of stored values
|
||||
if isinstance(inp.type, str):
|
||||
data_type_list.append(destination_type_to_np_data_type(inp.type))
|
||||
elif isinstance(inp.type, Type):
|
||||
data_type_list.append(inp.type.to_dtype().type)
|
||||
else:
|
||||
data_type_list.append(inp.type)
|
||||
argv.placeholder_shapes = shape_list if shape_list else None
|
||||
argv.placeholder_data_types = data_type_list if data_type_list else {}
|
||||
if argv.framework == "pytorch" and getattr(argv, "example_input", None) is not None:
|
||||
extract_input_info_from_example(argv, inputs)
|
||||
|
||||
|
||||
def pack_params_to_args_namespace(args: dict, cli_parser: argparse.ArgumentParser):
|
||||
if len(args) > 0:
|
||||
args_string = params_to_string(**args)
|
||||
argv, _ = cli_parser.parse_known_args(args_dict_to_list(cli_parser, **args_string))
|
||||
|
||||
# get list of all available params for convert_model()
|
||||
all_params = {}
|
||||
for key, value in get_mo_convert_params().items():
|
||||
all_params.update(value)
|
||||
|
||||
# check that there are no unknown params provided
|
||||
for key, value in args_string.items():
|
||||
if key not in argv and key not in all_params.keys():
|
||||
raise Error("Unrecognized argument: {}".format(key))
|
||||
|
||||
# Non string params like input_model or extensions are ignored by parse_args()
|
||||
# so we need to set them in argv separately
|
||||
if value is not None and not check_values_equal(getattr(argv, key, None), value):
|
||||
setattr(argv, key, value)
|
||||
else:
|
||||
argv = cli_parser.parse_args()
|
||||
return argv
|
||||
|
||||
|
||||
def update_args_for_saved_model_dir(args: dict):
|
||||
"""
|
||||
If directory is set in 'input_model' argument, the directory is considered as TF saved model.
|
||||
In this case this method updates args and moves saved model directory to 'saved_model_dir' param.
|
||||
:param args: dictionary with arguments from user
|
||||
"""
|
||||
if 'saved_model_dir' in args and args['saved_model_dir'] is not None and \
|
||||
'input_model' in args and args['input_model'] is not None:
|
||||
raise Error("Both \"input_model\" and \"saved_model_dir\" are defined. "
|
||||
"Please specify either \"input_model\" or \"saved_model_dir\" directory.")
|
||||
|
||||
if 'input_model' in args and isinstance(args['input_model'], (str, Path)) and os.path.isdir(args['input_model']):
|
||||
args['saved_model_dir'] = args['input_model']
|
||||
args['input_model'] = None
|
||||
|
||||
|
||||
def silent_is_false(argv: argparse.Namespace):
|
||||
return argv is not None and hasattr(argv, 'silent') and argv.silent is False
|
||||
|
||||
|
||||
def framework_is_tf(args, argv):
|
||||
if input_model_is_object(args) and check_model_object(args) == "tf":
|
||||
return True
|
||||
if argv is not None:
|
||||
is_tf, _, _, _, _ = deduce_legacy_frontend_by_namespace(argv)
|
||||
return is_tf
|
||||
return False
|
||||
|
||||
|
||||
def _convert(cli_parser: argparse.ArgumentParser, args, python_api_used):
|
||||
if 'help' in args and args['help']:
|
||||
show_mo_convert_help()
|
||||
return None, None
|
||||
framework = None
|
||||
simplified_ie_version = VersionChecker().get_ie_simplified_version()
|
||||
telemetry = tm.Telemetry(tid=get_tid(), app_name='Model Conversion API', app_version=simplified_ie_version)
|
||||
telemetry.start_session('mo')
|
||||
telemetry.send_event('mo', 'version', simplified_ie_version)
|
||||
# Initialize logger with 'ERROR' as default level to be able to form nice messages
|
||||
# before arg parser deliver log_level requested by user
|
||||
init_logger('ERROR', False)
|
||||
argv = None
|
||||
try:
|
||||
model_framework = None
|
||||
inp_model_is_object = input_model_is_object(args)
|
||||
if inp_model_is_object:
|
||||
model_framework = check_model_object(args)
|
||||
if model_framework == "pytorch":
|
||||
example_inputs = None
|
||||
if 'example_input' in args and args['example_input'] is not None:
|
||||
example_inputs = args['example_input']
|
||||
elif 'example_inputs' in args:
|
||||
raise AssertionError(
|
||||
"'example_inputs' argument is not recognized, maybe you meant to provide 'example_input'?")
|
||||
|
||||
decoder = get_pytorch_decoder(args['input_model'], parse_input_shapes(args), example_inputs, args)
|
||||
if model_framework == "paddle":
|
||||
example_inputs = None
|
||||
if 'example_input' in args and args['example_input'] is not None:
|
||||
example_inputs = args['example_input']
|
||||
|
||||
example_outputs = None
|
||||
if 'example_output' in args and args['example_output'] is not None:
|
||||
example_outputs = args['example_output']
|
||||
paddle_runtime_converter = paddle_frontend_converter(args['input_model'], example_inputs,
|
||||
example_outputs)
|
||||
pdmodel = paddle_runtime_converter.convert_paddle_to_pdmodel()
|
||||
args['input_model'] = pdmodel
|
||||
args['framework'] = model_framework
|
||||
|
||||
update_args_for_saved_model_dir(args)
|
||||
|
||||
argv = pack_params_to_args_namespace(args, cli_parser)
|
||||
|
||||
argv.feManager = FrontEndManager()
|
||||
frameworks = list(set(['tf', 'caffe', 'mxnet', 'kaldi', 'onnx'] + (get_available_front_ends(argv.feManager)
|
||||
if argv.feManager else [])))
|
||||
framework = argv.framework if hasattr(argv, 'framework') and argv.framework is not None else framework
|
||||
if framework is not None:
|
||||
assert framework in frameworks, "error: argument \"framework\": invalid choice: '{}'. " \
|
||||
"Expected one of {}.".format(framework, frameworks)
|
||||
setattr(argv, 'framework', framework)
|
||||
|
||||
# send telemetry with params info
|
||||
send_params_info(argv, cli_parser)
|
||||
|
||||
non_default_params = get_non_default_params(argv, cli_parser)
|
||||
check_legacy_args(non_default_params, python_api_used)
|
||||
argv.is_python_api_used = python_api_used
|
||||
|
||||
if inp_model_is_object:
|
||||
argv.model_name = "model"
|
||||
if not hasattr(argv, "model_name") or argv.model_name is None:
|
||||
argv.model_name = get_model_name_from_args(argv)
|
||||
|
||||
if model_framework is not None:
|
||||
if argv.framework is not None:
|
||||
if argv.framework != model_framework:
|
||||
raise Error("Provided model does not correspond to provided framework. The provided "
|
||||
"framework is {}, the model type is {} which is expected to be {} framework.".format(
|
||||
argv.framework,
|
||||
type(argv.input_model),
|
||||
model_framework))
|
||||
else:
|
||||
argv.framework = model_framework
|
||||
|
||||
ov_model, legacy_path = driver(argv, {"conversion_parameters": non_default_params})
|
||||
|
||||
if inp_model_is_object and model_framework == "paddle":
|
||||
if paddle_runtime_converter:
|
||||
paddle_runtime_converter.destroy()
|
||||
|
||||
# add MO meta data to model
|
||||
ov_model.set_rt_info(get_rt_version(), "Runtime_version")
|
||||
ov_model.set_rt_info(str(legacy_path), "legacy_frontend")
|
||||
for key, value in non_default_params.items():
|
||||
ov_model.set_rt_info(str(value), ["conversion_parameters", str(key)])
|
||||
|
||||
if silent_is_false(argv) or not python_api_used:
|
||||
if 'compress_to_fp16' in argv and argv.compress_to_fp16:
|
||||
print(get_compression_message())
|
||||
|
||||
ov_update_message = get_ov_update_message()
|
||||
ov_api20_message = get_ov_api20_message()
|
||||
if ov_update_message is not None:
|
||||
print(ov_update_message)
|
||||
if ov_api20_message is not None and ov_model is not None:
|
||||
print(ov_api20_message)
|
||||
is_fallback = getattr(argv, 'is_fallback', False)
|
||||
if not argv.use_legacy_frontend and framework_is_tf(args, argv) and not is_fallback:
|
||||
# now TF FE is default frontend for TensorFlow models conversion
|
||||
print(get_tf_fe_message())
|
||||
|
||||
send_conversion_result('success')
|
||||
return ov_model, argv
|
||||
|
||||
except Exception as e:
|
||||
if silent_is_false(argv) or not python_api_used:
|
||||
if isinstance(e, (FileNotFoundError, NotADirectoryError)):
|
||||
log.error('File {} was not found'.format(str(e).split('No such file or directory:')[1]))
|
||||
log.debug(traceback.format_exc())
|
||||
elif isinstance(e, Error):
|
||||
log.error(e)
|
||||
log.debug(traceback.format_exc())
|
||||
elif isinstance(e, FrameworkError):
|
||||
log.error(e, extra={'framework_error': True})
|
||||
log.debug(traceback.format_exc())
|
||||
else:
|
||||
log.error("-------------------------------------------------")
|
||||
log.error("----------------- INTERNAL ERROR ----------------")
|
||||
log.error("Unexpected exception happened.")
|
||||
log.error("Please contact Model Conversion API developers and forward the following information:")
|
||||
log.error(str(e))
|
||||
log.error(traceback.format_exc())
|
||||
log.error("---------------- END OF BUG REPORT --------------")
|
||||
log.error("-------------------------------------------------")
|
||||
is_fallback = getattr(argv, 'is_fallback', False) if argv is not None else False
|
||||
if not argv.use_legacy_frontend and framework_is_tf(args, argv) and not is_fallback:
|
||||
print(get_try_legacy_fe_message())
|
||||
|
||||
send_conversion_result('fail')
|
||||
if python_api_used:
|
||||
raise e.with_traceback(None)
|
||||
else:
|
||||
return None, argv
|
||||
|
|
@ -1,6 +1,9 @@
|
|||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# flake8: noqa
|
||||
# mypy: ignore-errors
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
|
@ -19,7 +22,7 @@ def get_imported_module_version(imported_module):
|
|||
installed_version = getattr(imported_module, attr, None)
|
||||
if isinstance(installed_version, str):
|
||||
return installed_version
|
||||
else:
|
||||
else:
|
||||
installed_version = None
|
||||
|
||||
if installed_version is None:
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# flake8: noqa
|
||||
# mypy: ignore-errors
|
||||
|
||||
import re
|
||||
|
||||
class BasicError(Exception):
|
||||
""" Base class for all exceptions in Model Conversion API
|
||||
|
||||
It operates like Exception but when it is converted to str,
|
||||
it formats string as args[0].format(*args[1:]), where
|
||||
args are arguments provided when an exception instance is
|
||||
created.
|
||||
"""
|
||||
|
||||
def __str__(self):
|
||||
if len(self.args) <= 1:
|
||||
return Exception.__str__(self)
|
||||
return self.args[0].format(*self.args[1:]) # pylint: disable=unsubscriptable-object
|
||||
|
||||
|
||||
class FrameworkError(BasicError):
|
||||
""" User-friendly error: raised when the error on the framework side. """
|
||||
pass
|
||||
|
||||
|
||||
class Error(BasicError):
|
||||
""" User-friendly error: raised when the error on the user side. """
|
||||
pass
|
||||
|
||||
|
||||
class InternalError(BasicError):
|
||||
""" Not user-friendly error: user cannot fix it and it points to the bug inside MO. """
|
||||
pass
|
||||
|
||||
|
||||
def classify_error_type(e):
|
||||
patterns = [
|
||||
# Example: No module named 'openvino._offline_transformations.offline_transformations_api'
|
||||
r"No module named \'\S+\'",
|
||||
# Example: cannot import name 'IECore' from 'openvino.inference_engine' (unknown location)
|
||||
r"cannot import name \'\S+\'",
|
||||
]
|
||||
error_message = str(e)
|
||||
for pattern in patterns:
|
||||
m = re.search(pattern, error_message)
|
||||
if m:
|
||||
return m.group(0)
|
||||
return "undefined"
|
||||
|
||||
|
||||
def legacy_path_error(functionality_description):
|
||||
raise Exception("{}Please try to install openvino-dev and use convert_model() "
|
||||
"from openvino.tools.mo.".format(functionality_description))
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# flake8: noqa
|
||||
# mypy: ignore-errors
|
||||
|
||||
import datetime
|
||||
|
||||
msg_fmt = 'Check for a new version of Intel(R) Distribution of OpenVINO(TM) toolkit here {0} ' \
|
||||
'or on https://github.com/openvinotoolkit/openvino'
|
||||
|
||||
|
||||
def get_ov_update_message():
|
||||
expected_update_date = datetime.date(year=2023, month=12, day=1)
|
||||
current_date = datetime.date.today()
|
||||
|
||||
link = 'https://software.intel.com/content/www/us/en/develop/tools/openvino-toolkit/download.html?cid=other&source=prod&campid=ww_2023_bu_IOTG_OpenVINO-2023-0&content=upg_all&medium=organic'
|
||||
|
||||
return msg_fmt.format(link) if current_date >= expected_update_date else None
|
||||
|
||||
|
||||
def get_ov_api20_message():
|
||||
link = "https://docs.openvino.ai/2023.0/openvino_2_0_transition_guide.html"
|
||||
message = '[ INFO ] The model was converted to IR v11, the latest model format that corresponds to the source DL framework ' \
|
||||
'input/output format. While IR v11 is backwards compatible with OpenVINO Inference Engine API v1.0, ' \
|
||||
'please use API v2.0 (as of 2022.1) to take advantage of the latest improvements in IR v11.\n' \
|
||||
'Find more information about API v2.0 and IR v11 at {}'.format(link)
|
||||
|
||||
return message
|
||||
|
||||
|
||||
def get_tf_fe_message():
|
||||
link = "https://docs.openvino.ai/2023.0/openvino_docs_MO_DG_TensorFlow_Frontend.html"
|
||||
message = '[ INFO ] IR generated by new TensorFlow Frontend is compatible only with API v2.0. Please make sure to use API v2.0.\n' \
|
||||
'Find more information about new TensorFlow Frontend at {}'.format(link)
|
||||
|
||||
return message
|
||||
|
||||
|
||||
def get_compression_message():
|
||||
link = "https://docs.openvino.ai/2023.0/openvino_docs_MO_DG_FP16_Compression.html"
|
||||
message = '[ INFO ] Generated IR will be compressed to FP16. ' \
|
||||
'If you get lower accuracy, please consider disabling compression ' \
|
||||
'by removing argument "compress_to_fp16" or set it to false "compress_to_fp16=False".\n' \
|
||||
'Find more information about compression to FP16 at {}'.format(link)
|
||||
return message
|
||||
|
||||
|
||||
def get_try_legacy_fe_message():
|
||||
message = '[ INFO ] You can also try to install openvino-dev and use convert_model from openvino.tools.mo.\n'
|
||||
return message
|
||||
|
|
@ -1,13 +1,15 @@
|
|||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# flake8: noqa
|
||||
# mypy: ignore-errors
|
||||
|
||||
def get_convert_model_help_specifics():
|
||||
from openvino.tools.mo.utils.cli_parser import CanonicalizeTransformationPathCheckExistenceAction, \
|
||||
from openvino.tools.ovc.cli_parser import CanonicalizeTransformationPathCheckExistenceAction, \
|
||||
CanonicalizePathCheckExistenceAction, CanonicalizeExtensionsPathCheckExistenceAction, \
|
||||
CanonicalizePathCheckExistenceIfNeededAction, readable_file_or_dir, readable_dirs_or_files_or_empty, \
|
||||
check_positive
|
||||
from openvino.tools.mo.utils.version import VersionChecker
|
||||
from openvino.tools.ovc.version import VersionChecker
|
||||
return {
|
||||
'input_model':
|
||||
{'description':
|
||||
|
|
@ -127,7 +129,7 @@ def get_convert_model_help_specifics():
|
|||
{'action': CanonicalizePathCheckExistenceIfNeededAction},
|
||||
'version':
|
||||
{'action': 'version',
|
||||
'version': 'Version of Model Optimizer is: {}'.format(VersionChecker().get_mo_version())},
|
||||
'version': 'Version of Model Optimizer is: {}'.format(VersionChecker().get_ie_version())},
|
||||
'scale':
|
||||
{'type': float,
|
||||
'aliases': {'-s'}},
|
||||
|
|
@ -143,7 +145,7 @@ def get_convert_model_help_specifics():
|
|||
|
||||
# TODO: remove this when internal converting of params to string is removed
|
||||
def get_to_string_methods_for_params():
|
||||
from openvino.tools.mo.utils.cli_parser import path_to_str_or_object, str_list_to_str, \
|
||||
from openvino.tools.ovc.cli_parser import path_to_str_or_object, str_list_to_str, \
|
||||
mean_scale_value_to_str, source_target_layout_to_str, layout_param_to_str, transform_param_to_str, \
|
||||
extensions_to_str_or_extensions_class, batch_to_int, transformations_config_to_str
|
||||
return {
|
||||
|
|
@ -0,0 +1,163 @@
|
|||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# flake8: noqa
|
||||
# mypy: ignore-errors
|
||||
|
||||
import importlib.util
|
||||
import logging as log
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from argparse import Namespace
|
||||
from copy import copy
|
||||
|
||||
# WA for abseil bug that affects logging while importing TF starting 1.14 version
|
||||
# Link to original issue: https://github.com/abseil/abseil-py/issues/99
|
||||
if importlib.util.find_spec('absl') is not None:
|
||||
import absl.logging
|
||||
|
||||
log.root.removeHandler(absl.logging._absl_handler)
|
||||
|
||||
handler_num = 0
|
||||
|
||||
|
||||
class LvlFormatter(log.Formatter):
|
||||
format_dict = {
|
||||
log.DEBUG: "[ %(asctime)s ] [ %(levelname)s ] [ %(module)s:%(lineno)d ] %(msg)s",
|
||||
log.INFO: "[ %(levelname)s ] %(msg)s",
|
||||
log.WARNING: "[ WARNING ] %(msg)s",
|
||||
log.ERROR: "[ %(levelname)s ] %(msg)s",
|
||||
log.CRITICAL: "[ %(levelname)s ] %(msg)s",
|
||||
'framework_error': "[ FRAMEWORK ERROR ] %(msg)s",
|
||||
'analysis_info': "[ ANALYSIS INFO ] %(msg)s"
|
||||
}
|
||||
|
||||
def __init__(self, lvl, fmt=None):
|
||||
log.Formatter.__init__(self, fmt)
|
||||
self.lvl = lvl
|
||||
|
||||
def format(self, record: log.LogRecord):
|
||||
if self.lvl == 'DEBUG':
|
||||
self._style._fmt = self.format_dict[log.DEBUG]
|
||||
else:
|
||||
self._style._fmt = self.format_dict[record.levelno]
|
||||
if 'is_warning' in record.__dict__.keys():
|
||||
self._style._fmt = self.format_dict[log.WARNING]
|
||||
if 'framework_error' in record.__dict__.keys():
|
||||
self._style._fmt = self.format_dict['framework_error']
|
||||
if 'analysis_info' in record.__dict__.keys():
|
||||
self._style._fmt = self.format_dict['analysis_info']
|
||||
return log.Formatter.format(self, record)
|
||||
|
||||
|
||||
class TagFilter(log.Filter):
|
||||
def __init__(self, regex: str):
|
||||
self.regex = regex
|
||||
|
||||
def filter(self, record: log.LogRecord):
|
||||
if record.__dict__['funcName'] == 'load_grammar': # for nx not to log into our logs
|
||||
return False
|
||||
if self.regex:
|
||||
if 'tag' in record.__dict__.keys():
|
||||
tag = record.__dict__['tag']
|
||||
return re.findall(self.regex, tag)
|
||||
else:
|
||||
return False
|
||||
return True # if regex wasn't set print all logs
|
||||
|
||||
|
||||
def init_logger(lvl: str, silent: bool):
|
||||
global handler_num
|
||||
log_exp = os.environ.get('MO_LOG_PATTERN')
|
||||
if silent:
|
||||
lvl = 'ERROR'
|
||||
fmt = LvlFormatter(lvl=lvl)
|
||||
handler = log.StreamHandler()
|
||||
handler.setFormatter(fmt)
|
||||
logger = log.getLogger()
|
||||
logger.setLevel(lvl)
|
||||
logger.addFilter(TagFilter(regex=log_exp))
|
||||
if handler_num == 0 and len(logger.handlers) == 0:
|
||||
logger.addHandler(handler)
|
||||
handler_num += 1
|
||||
|
||||
def get_logger_state():
|
||||
logger = log.getLogger()
|
||||
return logger.level, copy(logger.filters), copy(logger.handlers)
|
||||
|
||||
def restore_logger_state(state: tuple):
|
||||
level, filters, handlers = state
|
||||
logger = log.getLogger()
|
||||
logger.setLevel(level)
|
||||
logger.filters = filters
|
||||
logger.handlers = handlers
|
||||
|
||||
|
||||
def progress_bar(function: callable):
|
||||
"""
|
||||
Decorator for model conversion pipeline progress display
|
||||
Works in combination with function: mo.utils.class_registration.apply_transform
|
||||
"""
|
||||
|
||||
def wrapper(*args, **kwargs):
|
||||
for arg in ['graph', 'curr_transform_num', 'num_transforms']:
|
||||
msg = 'Progress bar decorator is enabled for Model Conversion API transformation applying cycle only. ' \
|
||||
'Argument `{}` {}'
|
||||
|
||||
assert arg in kwargs, msg.format(arg, 'is missing')
|
||||
assert kwargs[arg] is not None, msg.format(arg, 'should not be None')
|
||||
|
||||
if 'progress' in kwargs['graph'].graph['cmd_params'] and kwargs['graph'].graph['cmd_params'].progress:
|
||||
bar_len = 20
|
||||
total_replacers_count = kwargs['num_transforms']
|
||||
|
||||
def progress(i):
|
||||
return int((i + 1) / total_replacers_count * bar_len)
|
||||
|
||||
def percent(i):
|
||||
return (i + 1) / total_replacers_count * 100
|
||||
|
||||
end = '' if not kwargs['graph'].graph['cmd_params'].stream_output else '\n'
|
||||
curr_i = kwargs['curr_transform_num']
|
||||
print('\rProgress: [{:{}}]{:>7.2f}% done'.format('.' * progress(curr_i), bar_len, percent(curr_i)), end=end)
|
||||
|
||||
sys.stdout.flush()
|
||||
|
||||
function(*args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
||||
def progress_printer(argv: Namespace):
|
||||
"""
|
||||
A higher-order factory function returning a configurable callback displaying a progress bar
|
||||
Depending on the configuration stored in 'argv' the progress bar can be one-line, multi-line, or silent.
|
||||
"""
|
||||
def _progress_bar(progress, total, completed, endline):
|
||||
bar_len = 20
|
||||
|
||||
def dots():
|
||||
return '.' * int(progress * bar_len)
|
||||
|
||||
print('\rProgress: [{:{}}]{:>7.2f}% done'.format(dots(), bar_len, progress*100), end=endline)
|
||||
sys.stdout.flush()
|
||||
|
||||
def no_progress_bar(progress, total, completed):
|
||||
""" A 'dummy' progressbar which doesn't print anything """
|
||||
pass
|
||||
|
||||
def oneline_progress_bar(progress, total, completed):
|
||||
""" A callback that always prints the progress in the same line (mimics real GUI progress bar)"""
|
||||
_progress_bar(progress, total, completed, '')
|
||||
|
||||
def newline_progress_bar(progress, total, completed):
|
||||
""" A callback that prints an updated progress bar in separate lines """
|
||||
_progress_bar(progress, total, completed, '\n')
|
||||
|
||||
if "progress" in argv and argv.progress:
|
||||
if "stream_output" in argv and argv.stream_output:
|
||||
return newline_progress_bar
|
||||
else:
|
||||
return oneline_progress_bar
|
||||
else:
|
||||
return no_progress_bar
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
|
||||
try:
|
||||
import openvino_telemetry as tm
|
||||
except ImportError:
|
||||
import openvino.tools.ovc.telemetry_stub as tm
|
||||
from openvino.tools.ovc.convert_impl import _convert
|
||||
from openvino.tools.ovc.version import VersionChecker
|
||||
|
||||
# pylint: disable=no-name-in-module,import-error
|
||||
from openvino.runtime import serialize
|
||||
|
||||
|
||||
def main():
|
||||
from openvino.tools.ovc.cli_parser import get_all_cli_parser
|
||||
ngraph_function, argv = _convert(get_all_cli_parser(), {}, False)
|
||||
if ngraph_function is None:
|
||||
return 1
|
||||
|
||||
output_dir = argv.output_dir if argv.output_dir != '.' else os.getcwd()
|
||||
model_path_no_ext = os.path.normpath(os.path.join(output_dir, argv.model_name))
|
||||
model_path = model_path_no_ext + '.xml'
|
||||
|
||||
serialize(ngraph_function, model_path.encode('utf-8'), model_path.replace('.xml', '.bin').encode('utf-8'))
|
||||
|
||||
print('[ SUCCESS ] Generated IR version {} model.'.format(VersionChecker().get_ie_simplified_version()))
|
||||
print('[ SUCCESS ] XML file: {}'.format(model_path))
|
||||
print('[ SUCCESS ] BIN file: {}'.format(model_path.replace('.xml', '.bin')))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
|
|
@ -1,2 +1,5 @@
|
|||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# flake8: noqa
|
||||
# mypy: ignore-errors
|
||||
|
|
@ -1,9 +1,12 @@
|
|||
# Copyright (C) 2022 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# flake8: noqa
|
||||
# mypy: ignore-errors
|
||||
|
||||
import json
|
||||
from openvino.runtime import PartialShape, Model, Type # pylint: disable=no-name-in-module,import-error
|
||||
from openvino.runtime.utils.types import get_dtype
|
||||
from openvino.tools.ovc.types import get_dtype
|
||||
|
||||
def json_model_analysis_dump(framework_model: Model):
|
||||
|
||||
|
|
@ -1,11 +1,19 @@
|
|||
# Copyright (C) 2022-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# flake8: noqa
|
||||
# mypy: ignore-errors
|
||||
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
|
||||
from openvino.tools.mo.utils import import_extensions
|
||||
from openvino.tools.mo.utils.error import Error
|
||||
from openvino.tools.ovc.error import Error
|
||||
import os
|
||||
|
||||
|
||||
def default_path():
|
||||
EXT_DIR_NAME = '.'
|
||||
return os.path.abspath(os.getcwd().join(EXT_DIR_NAME))
|
||||
|
||||
|
||||
def any_extensions_used(argv: argparse.Namespace):
|
||||
|
|
@ -22,7 +30,7 @@ def any_extensions_used(argv: argparse.Namespace):
|
|||
if not isinstance(ext, str):
|
||||
has_non_str_objects = True
|
||||
continue
|
||||
if len(ext) == 0 or ext == import_extensions.default_path():
|
||||
if len(ext) == 0 or ext == default_path():
|
||||
continue
|
||||
has_non_default_path = True
|
||||
|
||||
|
|
@ -38,7 +46,7 @@ def legacy_extensions_used(argv: argparse.Namespace):
|
|||
for extension in extensions:
|
||||
if not isinstance(extension, str):
|
||||
continue
|
||||
if extension == import_extensions.default_path():
|
||||
if extension == default_path():
|
||||
continue
|
||||
if not Path(extension).is_file():
|
||||
legacy_ext_counter += 1
|
||||
|
|
@ -1,6 +1,9 @@
|
|||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# flake8: noqa
|
||||
# mypy: ignore-errors
|
||||
|
||||
import re
|
||||
from enum import Enum
|
||||
|
||||
|
|
@ -8,8 +11,18 @@ import numpy as np
|
|||
from openvino._pyopenvino import Place, PartialShape
|
||||
|
||||
from openvino.frontend import InputModel # pylint: disable=no-name-in-module,import-error
|
||||
from openvino.tools.mo.front.extractor import raise_no_node, raise_node_name_collision
|
||||
from openvino.tools.mo.utils.error import Error
|
||||
from openvino.tools.ovc.error import Error
|
||||
|
||||
|
||||
def raise_no_node(node_name: str):
|
||||
raise Error('No node with name {}'.format(node_name))
|
||||
|
||||
|
||||
def raise_node_name_collision(node_name: str, found_nodes: list):
|
||||
raise Error('Name collision was found, there are several nodes for mask "{}": {}. '
|
||||
'If your intention was to specify port for node, please instead specify node names connected to '
|
||||
'this port. If your intention was to specify the node name, please add port to the node '
|
||||
'name'.format(node_name, found_nodes))
|
||||
|
||||
|
||||
class IOType(Enum):
|
||||
|
|
@ -91,7 +104,7 @@ def decode_name_with_port(
|
|||
else:
|
||||
return node.get_input_port(input_port_index=int(port_index))
|
||||
else:
|
||||
None
|
||||
return None
|
||||
|
||||
regexp_post = r"(.+):(\d+)"
|
||||
match = re.search(regexp_post, node_name)
|
||||
|
|
@ -153,12 +166,12 @@ def fe_input_user_data_repack(
|
|||
Transforms node names to node ids.
|
||||
:param input_model: current input model
|
||||
:param input_user_shapes: data structure representing user input cutting request. It may be:
|
||||
# None value if user did not provide neither --input nor --input_shape keys
|
||||
# None value if user did not provide neither "input" nor "input_shape" keys
|
||||
# list instance which contains input layer names with or without ports if user provided
|
||||
only --input key
|
||||
only "input" key
|
||||
# dict instance which contains input layer names with or without ports as keys and shapes as
|
||||
values if user provided both --input and --input_shape
|
||||
# np.ndarray if user provided only --input_shape key
|
||||
values if user provided both "input" and "input_shape"
|
||||
# np.ndarray if user provided only "input_shape" key
|
||||
:param freeze_placeholder: dictionary with placeholder names as keys and freezing value as values
|
||||
:param input_user_data_types: dictionary with input nodes and its data types
|
||||
:return: restructured input shapes and freeze placeholder shapes information
|
||||
|
|
@ -188,7 +201,7 @@ def fe_input_user_data_repack(
|
|||
_input_shapes = []
|
||||
_input_names = []
|
||||
model_inputs = input_model.get_inputs()
|
||||
|
||||
|
||||
if isinstance(input_user_shapes, list) and len(input_user_shapes) > 1 and isinstance(input_user_shapes[0],
|
||||
PartialShape):
|
||||
for shape in input_user_shapes:
|
||||
|
|
@ -232,7 +245,7 @@ def fe_input_user_data_repack(
|
|||
elif isinstance(input_user_shapes, PartialShape):
|
||||
# this branch covers the single use of `input_shape` without `input` option
|
||||
# but it can be used along with `freeze_placeholder_with_value` option
|
||||
# for example, --input_shape [3] --freeze_placeholder_with_value "is_training->False"
|
||||
# for example, input_shape [3] freeze_placeholder_with_value "is_training->False"
|
||||
# means the model has two inputs: one is is_training to be frozen, the other to re-write the shape
|
||||
# NOTE: the logic relies on parameters with the single name
|
||||
frozen_names = freeze_placeholder.keys()
|
||||
|
|
@ -415,8 +428,8 @@ def convert_params_lists_to_dicts(input_model,
|
|||
# unnamed_freeze_placeholders is always list, it is not empty only if unnamed inputs were used.
|
||||
for value in unnamed_freeze_placeholders:
|
||||
assert isinstance(value, list), "Got incorrect format of input values. " \
|
||||
"Expected list, " \
|
||||
"got {}.".format(type(value))
|
||||
"Expected list, " \
|
||||
"got {}.".format(type(value))
|
||||
inp_name = find_first_unused_input(model_inputs, freeze_placeholder, {}, "input value")
|
||||
freeze_placeholder[inp_name] = value
|
||||
|
||||
|
|
@ -1,11 +1,14 @@
|
|||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# flake8: noqa
|
||||
# mypy: ignore-errors
|
||||
|
||||
from typing import Callable
|
||||
|
||||
from openvino.runtime import PartialShape # pylint: disable=no-name-in-module,import-error
|
||||
from openvino.tools.mo.utils.error import Error
|
||||
from openvino.tools.mo.utils.utils import refer_to_faq_msg
|
||||
from openvino.tools.ovc.error import Error
|
||||
from openvino.tools.ovc.utils import refer_to_faq_msg
|
||||
|
||||
|
||||
def update_layout_to_dict(inputs: list, layout: [list, dict], get_names_func: Callable):
|
||||
|
|
@ -19,7 +22,7 @@ def update_layout_to_dict(inputs: list, layout: [list, dict], get_names_func: Ca
|
|||
if len(input_names) > 1:
|
||||
raise Error('Layout without name can be specified for models with only one input, '
|
||||
'but provided model has {} inputs: \'{}\'. '
|
||||
'Please specify explicitly input/output name for --layout option'
|
||||
'Please specify explicitly input/output name for "layout" option'
|
||||
.format(len(input_names), input_names))
|
||||
layout = {
|
||||
input_names[0]: {
|
||||
|
|
@ -1,23 +1,23 @@
|
|||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# flake8: noqa
|
||||
# mypy: ignore-errors
|
||||
|
||||
import argparse
|
||||
import os
|
||||
|
||||
from openvino.runtime import Model # pylint: disable=no-name-in-module,import-error
|
||||
|
||||
from openvino.tools.mo.back.preprocessing import apply_preprocessing
|
||||
from openvino.tools.mo.utils.cli_parser import parse_transform
|
||||
from openvino.tools.ovc.cli_parser import parse_transform
|
||||
from openvino.tools.ovc.moc_frontend.preprocessing import apply_preprocessing
|
||||
|
||||
|
||||
def moc_emit_ir(ngraph_function: Model, argv: argparse.Namespace):
|
||||
output_dir = argv.output_dir if argv.output_dir != '.' else os.getcwd()
|
||||
|
||||
# Apply preprocessing (mean/scale/reverse_channels/convert_layout/etc)
|
||||
apply_preprocessing(ov_function=ngraph_function, argv=argv)
|
||||
|
||||
# Apply transformations
|
||||
from openvino.tools.mo.back.offline_transformations import apply_user_transformations, apply_moc_transformations, \
|
||||
from openvino.tools.ovc.moc_frontend.offline_transformations import apply_user_transformations, apply_moc_transformations, \
|
||||
apply_moc_legacy_transformations, apply_fused_names_cleanup
|
||||
|
||||
apply_moc_transformations(ngraph_function)
|
||||
|
|
@ -33,7 +33,7 @@ def moc_emit_ir(ngraph_function: Model, argv: argparse.Namespace):
|
|||
apply_user_transformations(ngraph_function, parse_transform(argv.transform))
|
||||
|
||||
if argv.compress_to_fp16:
|
||||
from openvino.tools.mo.back.offline_transformations import compress_model
|
||||
from openvino.tools.ovc.moc_frontend.offline_transformations import compress_model
|
||||
compress_model(ngraph_function)
|
||||
|
||||
apply_fused_names_cleanup(ngraph_function)
|
||||
|
|
@ -1,14 +1,71 @@
|
|||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# flake8: noqa
|
||||
# mypy: ignore-errors
|
||||
|
||||
import argparse
|
||||
from typing import List
|
||||
|
||||
from openvino.tools.mo.front.extractor import create_params_with_custom_types
|
||||
from openvino.tools.mo.utils.cli_parser import parse_transform
|
||||
from openvino.tools.mo.utils.error import Error
|
||||
from openvino.tools.ovc.cli_parser import parse_transform
|
||||
from openvino.tools.ovc.error import Error
|
||||
from openvino.runtime import Model
|
||||
|
||||
|
||||
def get_new_placeholder_name(node_id: str, is_out_port: bool = False, port: int = 0):
|
||||
"""
|
||||
Forms a name of new placeholder created by cutting a graph
|
||||
:param node_id: a node name that is cut
|
||||
:param is_out_port: it is True iff output port is cut
|
||||
:param port: a port number
|
||||
:return: a name of new placeholder created by cutting a graph
|
||||
"""
|
||||
port_type = '_out' if is_out_port else ''
|
||||
return '{}/placeholder{}_port_{}'.format(node_id, port_type, port)
|
||||
|
||||
|
||||
def create_params_with_custom_types(packed_user_shapes: [None, dict]):
|
||||
"""
|
||||
Compute a list of placeholder names for which an user specifies custom type
|
||||
:param packed_user_shapes: packed data that contains input node names,
|
||||
their port numbers, shapes and data types
|
||||
:return: a list of placeholder names for which an user specifies custom type
|
||||
Example of packed_user_shapes dictionary:
|
||||
packed_user_shapes =
|
||||
{
|
||||
'node_ID':
|
||||
[
|
||||
{'shape': None, 'in': 0},
|
||||
{'shape': None, 'in': 1},
|
||||
],
|
||||
'node_1_ID':
|
||||
[
|
||||
{'shape': [1, 227, 227, 3], 'port': None, 'data_type': np.int32}
|
||||
],
|
||||
'node_2_ID':
|
||||
[
|
||||
{'shape': None, 'out': 3}
|
||||
]
|
||||
}
|
||||
For which the function returns a list ['node_1_ID'] because this node only has custom data type
|
||||
"""
|
||||
if packed_user_shapes is None:
|
||||
return []
|
||||
|
||||
params_with_custom_types = []
|
||||
for input_name in packed_user_shapes:
|
||||
for desc in packed_user_shapes[input_name]:
|
||||
p_name = input_name
|
||||
if 'port' in desc and desc['port'] is None: # neither input nor output port specified
|
||||
user_defined_type = desc.get('data_type', None)
|
||||
else: # need to check the particular port the Parameter was created for
|
||||
p_name = get_new_placeholder_name(input_name, 'out' in desc,
|
||||
desc['out'] if 'out' in desc else desc['in'])
|
||||
user_defined_type = desc.get('data_type', None)
|
||||
if user_defined_type is not None:
|
||||
params_with_custom_types.append(p_name)
|
||||
return params_with_custom_types
|
||||
|
||||
def get_available_transformations():
|
||||
try:
|
||||
from openvino._offline_transformations import apply_low_latency_transformation # pylint: disable=import-error,no-name-in-module
|
||||
|
|
@ -54,7 +111,7 @@ def apply_fused_names_cleanup(func: object):
|
|||
|
||||
|
||||
def apply_offline_transformations(func: Model, argv: argparse.Namespace):
|
||||
from openvino.tools.mo.back.preprocessing import apply_preprocessing # pylint: disable=no-name-in-module,import-error
|
||||
from openvino.tools.ovc.moc_frontend.preprocessing import apply_preprocessing # pylint: disable=no-name-in-module,import-error
|
||||
|
||||
# Apply preprocessing (mean/scale/reverse_channels/convert_layout/etc)
|
||||
apply_preprocessing(ov_function=func, argv=argv)
|
||||
|
|
@ -1,10 +1,14 @@
|
|||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# flake8: noqa
|
||||
# mypy: ignore-errors
|
||||
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
|
||||
class paddle_frontend_converter:
|
||||
def __init__(self, model, inputs=None, outputs=None):
|
||||
self.model = model
|
||||
|
|
@ -1,6 +1,9 @@
|
|||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# flake8: noqa
|
||||
# mypy: ignore-errors
|
||||
|
||||
import argparse
|
||||
import io
|
||||
import logging as log
|
||||
|
|
@ -9,18 +12,34 @@ from copy import copy
|
|||
from typing import List
|
||||
|
||||
import numpy as np
|
||||
import os
|
||||
|
||||
from openvino.frontend import FrontEnd, InputModel, NotImplementedFailure, \
|
||||
Place # pylint: disable=no-name-in-module,import-error
|
||||
from openvino.runtime import PartialShape, Type # pylint: disable=no-name-in-module,import-error
|
||||
from openvino.runtime.utils.types import get_element_type, \
|
||||
from openvino.tools.ovc.types import get_element_type, \
|
||||
get_numpy_ctype # pylint: disable=no-name-in-module,import-error
|
||||
from openvino.tools.mo.middle.passes.infer import validate_batch_in_shape
|
||||
from openvino.tools.mo.moc_frontend.analysis import json_model_analysis_dump
|
||||
from openvino.tools.mo.moc_frontend.extractor import fe_user_data_repack, convert_params_lists_to_dicts, fe_output_user_data_repack
|
||||
from openvino.tools.mo.moc_frontend.layout_utils import update_layout_to_dict, get_dimension_index_by_label
|
||||
from openvino.tools.mo.utils.class_registration import get_enabled_and_disabled_transforms
|
||||
from openvino.tools.mo.utils.error import Error
|
||||
from openvino.tools.ovc.moc_frontend.analysis import json_model_analysis_dump
|
||||
from openvino.tools.ovc.moc_frontend.extractor import fe_user_data_repack, convert_params_lists_to_dicts, fe_output_user_data_repack
|
||||
from openvino.tools.ovc.moc_frontend.layout_utils import update_layout_to_dict, get_dimension_index_by_label
|
||||
from openvino.tools.ovc.error import Error
|
||||
from openvino.tools.ovc.utils import np_map_cast, mo_array, validate_batch_in_shape
|
||||
|
||||
|
||||
def get_enabled_and_disabled_transforms():
|
||||
"""
|
||||
:return: tuple of lists with force enabled and disabled id of transformations.
|
||||
"""
|
||||
disabled_transforms = os.environ['MO_DISABLED_TRANSFORMS'] if 'MO_DISABLED_TRANSFORMS' in os.environ else ''
|
||||
enabled_transforms = os.environ['MO_ENABLED_TRANSFORMS'] if 'MO_ENABLED_TRANSFORMS' in os.environ else ''
|
||||
|
||||
assert isinstance(enabled_transforms, str)
|
||||
assert isinstance(disabled_transforms, str)
|
||||
|
||||
disabled_transforms = disabled_transforms.split(',')
|
||||
enabled_transforms = enabled_transforms.split(',')
|
||||
|
||||
return enabled_transforms, disabled_transforms
|
||||
|
||||
|
||||
def moc_pipeline(argv: argparse.Namespace, moc_front_end: FrontEnd):
|
||||
|
|
@ -194,8 +213,6 @@ def moc_pipeline(argv: argparse.Namespace, moc_front_end: FrontEnd):
|
|||
|
||||
input_model.set_element_type(place, ov_type)
|
||||
# prepare and cast value to dtype
|
||||
from openvino.tools.mo.utils.type_utils import np_map_cast
|
||||
from openvino.tools.mo.front.common.partial_infer.utils import mo_array
|
||||
if isinstance(value, list):
|
||||
casted_list = list()
|
||||
for v in mo_array(value):
|
||||
|
|
@ -1,6 +1,9 @@
|
|||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# flake8: noqa
|
||||
# mypy: ignore-errors
|
||||
|
||||
import argparse
|
||||
import logging as log
|
||||
from copy import copy
|
||||
|
|
@ -9,9 +12,9 @@ from openvino.preprocess import PrePostProcessor # pylint: disable=no-name-in-m
|
|||
# pylint: disable=no-name-in-module,import-error
|
||||
from openvino.runtime import Model, Layout, PartialShape, layout_helpers
|
||||
|
||||
from openvino.tools.mo.moc_frontend.layout_utils import update_layout_to_dict
|
||||
from openvino.tools.mo.utils.error import Error
|
||||
from openvino.tools.mo.utils.utils import refer_to_faq_msg
|
||||
from openvino.tools.ovc.moc_frontend.layout_utils import update_layout_to_dict
|
||||
from openvino.tools.ovc.error import Error
|
||||
from openvino.tools.ovc.utils import refer_to_faq_msg
|
||||
|
||||
|
||||
def update_mean_scale_to_dict(input_nodes: list, mean_scale_val, scale):
|
||||
|
|
@ -19,7 +22,7 @@ def update_mean_scale_to_dict(input_nodes: list, mean_scale_val, scale):
|
|||
Internal function. Updates mean/scale values from array to dictionary
|
||||
:param: input_nodes Inputs of model
|
||||
:param: mean_scale_val Parsed 'mean_scale_val' object from command line arguments
|
||||
:param: scale Global scale factor for all inputs from --scale command line arguments
|
||||
:param: scale Global scale factor for all inputs from scale command line arguments
|
||||
"""
|
||||
if not isinstance(mean_scale_val, dict):
|
||||
if len(mean_scale_val) != len(input_nodes):
|
||||
|
|
@ -1,13 +1,17 @@
|
|||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# flake8: noqa
|
||||
# mypy: ignore-errors
|
||||
|
||||
import logging as log
|
||||
import numpy as np
|
||||
from openvino.tools.mo.moc_frontend.shape_utils import get_static_shape
|
||||
from openvino.tools.mo.utils.error import Error
|
||||
from openvino.tools.ovc.moc_frontend.shape_utils import get_static_shape
|
||||
from openvino.tools.ovc.error import Error
|
||||
from openvino.runtime import Tensor, Type, PartialShape
|
||||
from openvino.runtime.utils.types import get_element_type_str
|
||||
from openvino.tools.mo.utils.cli_parser import input_to_input_cut_info, input_shape_to_input_cut_info
|
||||
from openvino.tools.ovc.types import get_element_type_str
|
||||
from openvino.tools.ovc.cli_parser import input_to_input_cut_info, input_shape_to_input_cut_info
|
||||
|
||||
|
||||
|
||||
def get_pytorch_decoder(model, input_shape, example_inputs, args):
|
||||
|
|
@ -1,10 +1,13 @@
|
|||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# flake8: noqa
|
||||
# mypy: ignore-errors
|
||||
|
||||
import numpy as np
|
||||
from openvino.runtime import PartialShape, Dimension
|
||||
from openvino.tools.mo.utils.error import Error
|
||||
from openvino.tools.mo.utils.cli_parser import get_placeholder_shapes, split_shapes
|
||||
from openvino.tools.ovc.error import Error
|
||||
from openvino.tools.ovc.cli_parser import get_placeholder_shapes, split_shapes
|
||||
|
||||
|
||||
def get_static_shape(shape: [PartialShape, list, tuple], dynamic_value=None):
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import sys
|
||||
|
||||
if __name__ == "__main__":
|
||||
from openvino.tools.ovc.telemetry_utils import init_mo_telemetry
|
||||
from openvino.tools.ovc.main import main
|
||||
|
||||
init_mo_telemetry()
|
||||
sys.exit(main())
|
||||
|
|
@ -1,6 +1,9 @@
|
|||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# flake8: noqa
|
||||
# mypy: ignore-errors
|
||||
|
||||
telemetry_params = {
|
||||
'TID': "UA-17808594-29"
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# flake8: noqa
|
||||
# mypy: ignore-errors
|
||||
|
||||
class Telemetry(object):
|
||||
"""
|
||||
Stab file for the Telemetry class which is used when Telemetry class is not available.
|
||||
"""
|
||||
|
||||
def __init__(self, *arg, **kwargs):
|
||||
pass
|
||||
|
||||
def send_event(self, *arg, **kwargs):
|
||||
pass
|
||||
|
||||
def send_error(self, *arg, **kwargs):
|
||||
pass
|
||||
|
||||
def start_session(self, *arg, **kwargs):
|
||||
pass
|
||||
|
||||
def end_session(self, *arg, **kwargs):
|
||||
pass
|
||||
|
||||
def force_shutdown(self, *arg, **kwargs):
|
||||
pass
|
||||
|
||||
def send_stack_trace(self, *arg, **kwargs):
|
||||
pass
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# flake8: noqa
|
||||
# mypy: ignore-errors
|
||||
|
||||
import argparse
|
||||
import numbers
|
||||
|
||||
from openvino.runtime import get_version as get_rt_version
|
||||
from openvino.tools.ovc.cli_parser import get_params_with_paths_list
|
||||
from openvino.tools.ovc.telemetry_params import telemetry_params
|
||||
from openvino.tools.ovc.utils import check_values_equal
|
||||
|
||||
try:
|
||||
import openvino_telemetry as tm
|
||||
except ImportError:
|
||||
import openvino.tools.ovc.telemetry_stub as tm
|
||||
|
||||
|
||||
def init_mo_telemetry():
|
||||
_ = tm.Telemetry(tid=get_tid(), app_name='Model Conversion API', app_version=get_rt_version())
|
||||
|
||||
|
||||
def send_framework_info(framework: str):
|
||||
"""
|
||||
This function sends information about used framework.
|
||||
:param framework: framework name.
|
||||
"""
|
||||
t = tm.Telemetry()
|
||||
t.send_event('mo', 'framework', framework)
|
||||
|
||||
|
||||
def get_tid():
|
||||
"""
|
||||
This function returns the ID of the database to send telemetry.
|
||||
"""
|
||||
return telemetry_params['TID']
|
||||
|
||||
|
||||
def send_conversion_result(conversion_result: str, need_shutdown=False):
|
||||
t = tm.Telemetry()
|
||||
t.send_event('mo', 'conversion_result', conversion_result)
|
||||
t.end_session('mo')
|
||||
if need_shutdown:
|
||||
t.force_shutdown(1.0)
|
||||
|
||||
|
||||
def arg_to_str(arg):
|
||||
# This method converts to string only known types, otherwise returns string with name of the type
|
||||
from openvino.runtime import PartialShape, Shape, Type, Layout
|
||||
if isinstance(arg, (PartialShape, Shape, Type, Layout)):
|
||||
return str(arg)
|
||||
if isinstance(arg, (str, numbers.Number, bool)):
|
||||
return str(arg)
|
||||
return str(type(arg))
|
||||
|
||||
|
||||
def send_params_info(argv: argparse.Namespace, cli_parser: argparse.ArgumentParser):
|
||||
"""
|
||||
This function sends information about used command line parameters.
|
||||
:param argv: command line parameters.
|
||||
:param cli_parser: command line parameters parser.
|
||||
"""
|
||||
t = tm.Telemetry()
|
||||
params_with_paths = get_params_with_paths_list()
|
||||
for arg in vars(argv):
|
||||
arg_value = getattr(argv, arg)
|
||||
if not check_values_equal(arg_value, cli_parser.get_default(arg)):
|
||||
if arg in params_with_paths:
|
||||
# If command line argument value is a directory or a path to file it is not sent
|
||||
# as it may contain confidential information. "1" value is used instead.
|
||||
param_str = arg + ":" + str(1)
|
||||
else:
|
||||
param_str = arg + ":" + arg_to_str(arg_value)
|
||||
|
||||
t.send_event('mo', 'cli_parameters', param_str)
|
||||
|
|
@ -0,0 +1,159 @@
|
|||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
"""Functions related to converting between Python and numpy types and openvino types."""
|
||||
|
||||
import logging
|
||||
from typing import List, Union
|
||||
|
||||
import numpy as np
|
||||
|
||||
from openvino.runtime.exceptions import OVTypeError
|
||||
from openvino.runtime import Node, Shape, Output, Type
|
||||
from openvino.runtime.op import Constant
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
TensorShape = List[int]
|
||||
NumericData = Union[int, float, np.ndarray]
|
||||
NumericType = Union[type, np.dtype]
|
||||
ScalarData = Union[int, float]
|
||||
NodeInput = Union[Node, NumericData]
|
||||
|
||||
openvino_to_numpy_types_map = [
|
||||
(Type.boolean, bool),
|
||||
(Type.f16, np.float16),
|
||||
(Type.f32, np.float32),
|
||||
(Type.f64, np.float64),
|
||||
(Type.i8, np.int8),
|
||||
(Type.i16, np.int16),
|
||||
(Type.i32, np.int32),
|
||||
(Type.i64, np.int64),
|
||||
(Type.u8, np.uint8),
|
||||
(Type.u16, np.uint16),
|
||||
(Type.u32, np.uint32),
|
||||
(Type.u64, np.uint64),
|
||||
(Type.bf16, np.uint16),
|
||||
]
|
||||
|
||||
openvino_to_numpy_types_str_map = [
|
||||
("boolean", bool),
|
||||
("f16", np.float16),
|
||||
("f32", np.float32),
|
||||
("f64", np.float64),
|
||||
("i8", np.int8),
|
||||
("i16", np.int16),
|
||||
("i32", np.int32),
|
||||
("i64", np.int64),
|
||||
("u8", np.uint8),
|
||||
("u16", np.uint16),
|
||||
("u32", np.uint32),
|
||||
("u64", np.uint64),
|
||||
]
|
||||
|
||||
|
||||
def get_element_type(data_type: NumericType) -> Type:
|
||||
"""Return an ngraph element type for a Python type or numpy.dtype."""
|
||||
if data_type is int:
|
||||
log.warning("Converting int type of undefined bitwidth to 32-bit ngraph integer.")
|
||||
return Type.i32
|
||||
|
||||
if data_type is float:
|
||||
log.warning("Converting float type of undefined bitwidth to 32-bit ngraph float.")
|
||||
return Type.f32
|
||||
|
||||
ov_type = next(
|
||||
(ov_type for (ov_type, np_type) in openvino_to_numpy_types_map if np_type == data_type),
|
||||
None,
|
||||
)
|
||||
if ov_type:
|
||||
return ov_type
|
||||
|
||||
raise OVTypeError("Unidentified data type %s", data_type)
|
||||
|
||||
|
||||
def get_element_type_str(data_type: NumericType) -> str:
|
||||
"""Return an ngraph element type string representation for a Python type or numpy dtype."""
|
||||
if data_type is int:
|
||||
log.warning("Converting int type of undefined bitwidth to 32-bit ngraph integer.")
|
||||
return "i32"
|
||||
|
||||
if data_type is float:
|
||||
log.warning("Converting float type of undefined bitwidth to 32-bit ngraph float.")
|
||||
return "f32"
|
||||
|
||||
ov_type = next(
|
||||
(ov_type for (ov_type, np_type) in openvino_to_numpy_types_str_map if np_type == data_type),
|
||||
None,
|
||||
)
|
||||
if ov_type:
|
||||
return ov_type
|
||||
|
||||
raise OVTypeError("Unidentified data type %s", data_type)
|
||||
|
||||
|
||||
def get_dtype(openvino_type: Type) -> np.dtype:
|
||||
"""Return a numpy.dtype for an openvino element type."""
|
||||
np_type = next(
|
||||
(np_type for (ov_type, np_type) in openvino_to_numpy_types_map if ov_type == openvino_type),
|
||||
None,
|
||||
)
|
||||
|
||||
if np_type:
|
||||
return np.dtype(np_type)
|
||||
|
||||
raise OVTypeError("Unidentified data type %s", openvino_type)
|
||||
|
||||
|
||||
def get_numpy_ctype(openvino_type: Type) -> type:
|
||||
"""Return numpy ctype for an openvino element type."""
|
||||
np_type = next(
|
||||
(np_type for (ov_type, np_type) in openvino_to_numpy_types_map if ov_type == openvino_type),
|
||||
None,
|
||||
)
|
||||
|
||||
if np_type:
|
||||
return np_type
|
||||
|
||||
raise OVTypeError("Unidentified data type %s", openvino_type)
|
||||
|
||||
|
||||
def get_ndarray(data: NumericData) -> np.ndarray:
|
||||
"""Wrap data into a numpy ndarray."""
|
||||
if type(data) == np.ndarray:
|
||||
return data # type: ignore
|
||||
return np.array(data)
|
||||
|
||||
|
||||
def get_shape(data: NumericData) -> TensorShape:
|
||||
"""Return a shape of NumericData."""
|
||||
if type(data) == np.ndarray:
|
||||
return data.shape # type: ignore
|
||||
elif type(data) == list:
|
||||
return [len(data)] # type: ignore
|
||||
return []
|
||||
|
||||
|
||||
def make_constant_node(value: NumericData, dtype: Union[NumericType, Type] = None) -> Constant:
|
||||
"""Return an openvino Constant node with the specified value."""
|
||||
ndarray = get_ndarray(value)
|
||||
if dtype is not None:
|
||||
element_type = get_element_type(dtype) if isinstance(dtype, (type, np.dtype)) else dtype
|
||||
else:
|
||||
element_type = get_element_type(ndarray.dtype)
|
||||
|
||||
return Constant(element_type, Shape(ndarray.shape), ndarray.flatten().tolist())
|
||||
|
||||
|
||||
def as_node(input_value: NodeInput) -> Node:
|
||||
"""Return input values as nodes. Scalars will be converted to Constant nodes."""
|
||||
if issubclass(type(input_value), Node):
|
||||
return input_value
|
||||
if issubclass(type(input_value), Output):
|
||||
return input_value
|
||||
return make_constant_node(input_value)
|
||||
|
||||
|
||||
def as_nodes(*input_values: NodeInput) -> List[Node]:
|
||||
"""Return input values as nodes. Scalars will be converted to Constant nodes."""
|
||||
return [as_node(input_value) for input_value in input_values]
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# flake8: noqa
|
||||
# mypy: ignore-errors
|
||||
|
||||
|
||||
import os
|
||||
import re
|
||||
from typing import Iterable, Union
|
||||
|
||||
import numpy as np
|
||||
from openvino.tools.ovc.error import Error
|
||||
|
||||
try:
|
||||
import openvino_telemetry as tm
|
||||
except ImportError:
|
||||
import openvino.tools.ovc.telemetry_stub as tm
|
||||
|
||||
|
||||
dynamic_dimension = np.ma.masked
|
||||
|
||||
|
||||
def refer_to_faq_msg(question_num: int):
|
||||
try:
|
||||
t = tm.Telemetry()
|
||||
t.send_event('mo', 'error_info', "faq:" + str(question_num))
|
||||
except Exception:
|
||||
# Telemetry can be not initialized if it is used in MO IR Reader
|
||||
pass
|
||||
|
||||
return '\n For more information please refer to Model Conversion API FAQ, question #{0}. ' \
|
||||
'(https://docs.openvino.ai/2023.0/openvino_docs_MO_DG_prepare_model_Model_Optimizer_FAQ.html' \
|
||||
'?question={0}#question-{0})'.format(question_num)
|
||||
|
||||
|
||||
def get_mo_root_dir():
|
||||
"""
|
||||
Return the absolute path to the Model Conversion API root directory (where mo folder is located)
|
||||
:return: path to the MO root directory
|
||||
"""
|
||||
return os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(os.path.realpath(__file__))), os.pardir))
|
||||
|
||||
|
||||
def check_values_equal(val1, val2):
|
||||
# This method is needed to check equality of values where some values can be None
|
||||
if val1 is None and val2 is None:
|
||||
return True
|
||||
if val1 is None:
|
||||
return False
|
||||
if val2 is None:
|
||||
return False
|
||||
return val1 == val2
|
||||
|
||||
|
||||
np_map_cast = {bool: lambda x: bool_cast(x),
|
||||
np.int8: lambda x: np.int8(x),
|
||||
np.int16: lambda x: np.int16(x),
|
||||
np.int32: lambda x: np.int32(x),
|
||||
np.int64: lambda x: np.int64(x),
|
||||
np.uint8: lambda x: np.uint8(x),
|
||||
np.uint16: lambda x: np.uint16(x),
|
||||
np.uint32: lambda x: np.uint32(x),
|
||||
np.uint64: lambda x: np.uint64(x),
|
||||
np.float16: lambda x: np.float16(x),
|
||||
np.float32: lambda x: np.float32(x),
|
||||
np.double: lambda x: np.double(x),
|
||||
str: lambda x: str(x)}
|
||||
|
||||
|
||||
def bool_cast(x):
|
||||
if isinstance(x, str):
|
||||
return False if x.lower() in ['false', '0'] else True if x.lower() in ['true', '1'] else 'unknown_boolean_cast'
|
||||
else:
|
||||
return bool(x)
|
||||
|
||||
|
||||
def mo_array(value: Union[Iterable[Union[float, int]], float, int], dtype=None) -> np.ndarray:
|
||||
"""
|
||||
This function acts in a same way as np.array except for the case when dtype is not provided
|
||||
and np.array return fp64 array this function returns fp32 array
|
||||
"""
|
||||
x = np.array(value, dtype=dtype)
|
||||
if not isinstance(value, np.ndarray) and x.dtype == np.float64 and dtype != np.float64:
|
||||
x = x.astype(np.float32)
|
||||
return x
|
||||
|
||||
|
||||
def validate_batch_in_shape(shape, layer_name: str):
|
||||
"""
|
||||
Raises Error #39 if shape is not valid for setting batch size
|
||||
Parameters
|
||||
----------
|
||||
shape: current shape of layer under validation
|
||||
layer_name: name of layer under validation
|
||||
"""
|
||||
if len(shape) == 0 or (shape[0] is not dynamic_dimension and shape[0] not in (-1, 0, 1)):
|
||||
raise Error(('The input layer {} has a shape {} defined in the model. \n\n' +
|
||||
'When you use "batch" option, Model Conversion API applies its value to the first ' +
|
||||
'element of the shape if it is equal to -1, 0 or 1. Otherwise, this is the ambiguous ' +
|
||||
'situation - it is not known in advance whether the layer has the batch ' +
|
||||
'dimension or not.\n\n For example, you want to set batch dimension equals 100 ' +
|
||||
'for the input layer "data" with shape (10,34). Although you can not use "batch", ' +
|
||||
'you should pass "input_shape=[100,34]" instead of "batch=100". \n\n' +
|
||||
'You can also specify batch dimension by setting "layout". \n\n')
|
||||
.format(layer_name, shape))
|
||||
|
||||
|
||||
def deduce_legacy_frontend_by_namespace(argv):
|
||||
if not hasattr(argv, 'framework') or not argv.framework:
|
||||
if getattr(argv, 'saved_model_dir', None) or getattr(argv, 'input_meta_graph', None):
|
||||
argv.framework = 'tf'
|
||||
elif getattr(argv, 'input_symbol', None) or getattr(argv, 'pretrained_model_name', None):
|
||||
argv.framework = 'mxnet'
|
||||
elif getattr(argv, 'input_proto', None):
|
||||
argv.framework = 'caffe'
|
||||
elif argv.input_model is None:
|
||||
raise Error('Path to input model is required: use "input_model".')
|
||||
else:
|
||||
argv.framework = guess_framework_by_ext(argv.input_model)
|
||||
|
||||
return map(lambda x: argv.framework == x, ['tf', 'caffe', 'mxnet', 'kaldi', 'onnx'])
|
||||
|
||||
|
||||
def guess_framework_by_ext(input_model_path: str) -> int:
|
||||
if re.match(r'^.*\.caffemodel$', input_model_path):
|
||||
return 'caffe'
|
||||
elif re.match(r'^.*\.pb$', input_model_path):
|
||||
return 'tf'
|
||||
elif re.match(r'^.*\.pbtxt$', input_model_path):
|
||||
return 'tf'
|
||||
elif re.match(r'^.*\.params$', input_model_path):
|
||||
return 'mxnet'
|
||||
elif re.match(r'^.*\.nnet$', input_model_path):
|
||||
return 'kaldi'
|
||||
elif re.match(r'^.*\.mdl', input_model_path):
|
||||
return 'kaldi'
|
||||
elif re.match(r'^.*\.onnx$', input_model_path):
|
||||
return 'onnx'
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# flake8: noqa
|
||||
# mypy: ignore-errors
|
||||
|
||||
import re
|
||||
|
||||
from openvino.runtime import get_version as get_ie_version
|
||||
|
||||
|
||||
def extract_release_version(version: str):
|
||||
patterns = [
|
||||
# captures release version set by CI for example: '2021.1.0-1028-55e4d5673a8'
|
||||
r"^([0-9]+).([0-9]+)*",
|
||||
# captures release version generated by MO from release branch, for example: 'custom_releases/2021/1_55e4d567'
|
||||
r"_releases/([0-9]+)/([0-9]+)_*"
|
||||
]
|
||||
|
||||
for pattern in patterns:
|
||||
m = re.search(pattern, version)
|
||||
if m and len(m.groups()) == 2:
|
||||
return m.group(1), m.group(2)
|
||||
return None, None
|
||||
|
||||
|
||||
def simplify_version(version: str):
|
||||
release_version = extract_release_version(version)
|
||||
if release_version == (None, None):
|
||||
return "custom"
|
||||
return "{}.{}".format(*release_version)
|
||||
|
||||
|
||||
def get_simplified_ie_version(version=None):
|
||||
from openvino.runtime import get_version
|
||||
if version is None:
|
||||
version = get_version()
|
||||
|
||||
# To support legacy IE versions
|
||||
m = re.match(r"^([0-9]+).([0-9]+).(.*)", version)
|
||||
if m and len(m.groups()) == 3:
|
||||
return simplify_version(m.group(3))
|
||||
return simplify_version(version)
|
||||
|
||||
|
||||
def extract_hash_from_version(full_version: str):
|
||||
res = re.findall(r'[-_]([a-f0-9]{7,40})', full_version)
|
||||
if len(res) > 0:
|
||||
return res[0]
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
class SingletonMetaClass(type):
|
||||
def __init__(self, cls_name, super_classes, dic):
|
||||
self.__single_instance = None
|
||||
super().__init__(cls_name, super_classes, dic)
|
||||
|
||||
def __call__(cls, *args, **kwargs):
|
||||
if cls.__single_instance is None:
|
||||
cls.__single_instance = super(SingletonMetaClass, cls).__call__(*args, **kwargs)
|
||||
return cls.__single_instance
|
||||
|
||||
|
||||
class VersionChecker(metaclass=SingletonMetaClass):
|
||||
def __init__(self):
|
||||
self.runtime_checked = False
|
||||
self.mo_version = None
|
||||
self.ie_version = None
|
||||
self.mo_simplified_version = None
|
||||
self.ie_simplified_version = None
|
||||
|
||||
def get_ie_version(self):
|
||||
if self.ie_version:
|
||||
return self.ie_version
|
||||
self.ie_version = get_ie_version()
|
||||
return self.ie_version
|
||||
|
||||
def get_ie_simplified_version(self):
|
||||
if self.ie_simplified_version:
|
||||
return self.ie_simplified_version
|
||||
self.ie_simplified_version = get_simplified_ie_version()
|
||||
return self.ie_simplified_version
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import argparse
|
||||
import io
|
||||
import os
|
||||
import unittest
|
||||
from contextlib import redirect_stdout
|
||||
from unittest.mock import patch
|
||||
|
||||
from openvino.tools.ovc.main import main
|
||||
from openvino.tools.ovc.get_ov_update_message import get_tf_fe_message, get_compression_message
|
||||
from openvino.tools.ovc.get_ov_update_message import get_try_legacy_fe_message
|
||||
|
||||
|
||||
def arg_parse_helper(input_model,
|
||||
use_legacy_frontend,
|
||||
use_new_frontend,
|
||||
input_model_is_text,
|
||||
framework,
|
||||
compress_to_fp16=False,
|
||||
freeze_placeholder_with_value=None,
|
||||
tensorflow_object_detection_api_pipeline_config=None):
|
||||
path = os.path.dirname(__file__)
|
||||
input_model = os.path.join(path, "test_models", input_model)
|
||||
|
||||
return argparse.Namespace(
|
||||
input_model=input_model,
|
||||
use_legacy_frontend=use_legacy_frontend,
|
||||
use_new_frontend=use_new_frontend,
|
||||
framework=framework,
|
||||
input_model_is_text=input_model_is_text,
|
||||
log_level='INFO',
|
||||
silent=True,
|
||||
model_name=None,
|
||||
transform=[],
|
||||
scale=None,
|
||||
output=None,
|
||||
input=None,
|
||||
input_shape=None,
|
||||
batch=None,
|
||||
input_checkpoint=None,
|
||||
saved_model_dir=None,
|
||||
input_meta_graph=None,
|
||||
saved_model_tags=None,
|
||||
output_dir='.',
|
||||
mean_values=(),
|
||||
scale_values=(),
|
||||
layout={},
|
||||
source_layout={},
|
||||
target_layout={},
|
||||
freeze_placeholder_with_value=freeze_placeholder_with_value,
|
||||
data_type=None,
|
||||
tensorflow_custom_operations_config_update=None,
|
||||
tensorflow_object_detection_api_pipeline_config=tensorflow_object_detection_api_pipeline_config,
|
||||
compress_to_fp16=compress_to_fp16,
|
||||
extensions=None
|
||||
)
|
||||
|
||||
|
||||
class TestInfoMessagesTFFE(unittest.TestCase):
|
||||
@patch('argparse.ArgumentParser.parse_args',
|
||||
return_value=arg_parse_helper(input_model="model_int32.pbtxt",
|
||||
use_legacy_frontend=False, use_new_frontend=True,
|
||||
framework=None, input_model_is_text=True))
|
||||
def test_api20_only(self, mock_argparse):
|
||||
f = io.StringIO()
|
||||
with redirect_stdout(f):
|
||||
main()
|
||||
std_out = f.getvalue()
|
||||
tf_fe_message_found = get_tf_fe_message() in std_out
|
||||
assert tf_fe_message_found
|
||||
|
||||
@patch('openvino.tools.ovc.convert_impl.driver', side_effect=Exception('MESSAGE'))
|
||||
def run_fail_tf_fe(self, mock_driver):
|
||||
from openvino.tools.ovc import convert_model
|
||||
path = os.path.dirname(__file__)
|
||||
convert_model(os.path.join(path, "test_models", "model_int32.pbtxt"), silent=False)
|
||||
|
||||
def test_suggest_legacy_fe(self):
|
||||
f = io.StringIO()
|
||||
with redirect_stdout(f):
|
||||
try:
|
||||
self.run_fail_tf_fe()
|
||||
except:
|
||||
pass
|
||||
std_out = f.getvalue()
|
||||
assert get_try_legacy_fe_message() in std_out
|
||||
|
||||
|
||||
class TestInfoMessagesTFFEWithFallback(unittest.TestCase):
|
||||
@patch('argparse.ArgumentParser.parse_args',
|
||||
return_value=arg_parse_helper(input_model="model_switch_merge.pbtxt",
|
||||
use_legacy_frontend=False, use_new_frontend=False,
|
||||
framework=None, input_model_is_text=True,
|
||||
freeze_placeholder_with_value="is_training->False"))
|
||||
def test_tf_fe_message_fallback(self, mock_argparse):
|
||||
f = io.StringIO()
|
||||
with redirect_stdout(f):
|
||||
main()
|
||||
std_out = f.getvalue()
|
||||
tf_fe_message_found = get_try_legacy_fe_message() in std_out
|
||||
assert not tf_fe_message_found, 'TF FE Info message is found for the fallback case'
|
||||
|
||||
@patch('argparse.ArgumentParser.parse_args',
|
||||
return_value=arg_parse_helper(input_model="model_int32.pbtxt",
|
||||
use_legacy_frontend=False, use_new_frontend=True,
|
||||
compress_to_fp16=True,
|
||||
framework=None, input_model_is_text=True,
|
||||
tensorflow_object_detection_api_pipeline_config="config.yml"))
|
||||
def test_tf_fe_message_fallback(self, mock_argparse):
|
||||
f = io.StringIO()
|
||||
with redirect_stdout(f):
|
||||
main()
|
||||
std_out = f.getvalue()
|
||||
tf_fe_message_found = "The provided option \"tensorflow_object_detection_api_pipeline_config\" " \
|
||||
"refers to legacy functionality. Please try to install openvino-dev and " \
|
||||
"use convert_model() from openvino.tools.mo." in std_out
|
||||
assert not tf_fe_message_found, 'TF FE Info message is found for the fallback case'
|
||||
|
||||
|
||||
class TestInfoMessagesCompressFP16(unittest.TestCase):
|
||||
@patch('argparse.ArgumentParser.parse_args',
|
||||
return_value=arg_parse_helper(input_model="model_int32.pbtxt",
|
||||
use_legacy_frontend=False, use_new_frontend=True,
|
||||
compress_to_fp16=True,
|
||||
framework=None, input_model_is_text=True))
|
||||
def test_compress_to_fp16(self, mock_argparse):
|
||||
f = io.StringIO()
|
||||
with redirect_stdout(f):
|
||||
main()
|
||||
std_out = f.getvalue()
|
||||
fp16_compression_message_found = get_compression_message() in std_out
|
||||
assert fp16_compression_message_found
|
||||
|
|
@ -0,0 +1,328 @@
|
|||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import os
|
||||
import unittest
|
||||
|
||||
import numpy as np
|
||||
from generator import generator, generate
|
||||
|
||||
from openvino.runtime import Core
|
||||
from openvino.tools.ovc.convert import convert_model
|
||||
|
||||
|
||||
@generator
|
||||
class TestMoFreezePlaceholderTFFE(unittest.TestCase):
|
||||
def basic(self, input_model, argv_input, inputs, dtype, expected, freeze_placeholder_with_value=None,
|
||||
input_shape=None, only_conversion=False, input_model_is_text=True, use_new_frontend=True,
|
||||
use_legacy_frontend=False):
|
||||
path = os.path.dirname(__file__)
|
||||
input_model = os.path.join(path, "test_models", input_model)
|
||||
|
||||
try:
|
||||
model = convert_model(input_model, input=argv_input,
|
||||
freeze_placeholder_with_value=freeze_placeholder_with_value,
|
||||
input_shape=input_shape, input_model_is_text=input_model_is_text,
|
||||
use_new_frontend=use_new_frontend, use_legacy_frontend=use_legacy_frontend,
|
||||
framework="tf")
|
||||
except Exception as ex:
|
||||
self.fail("Model conversion failed due to error: {}".format(ex))
|
||||
|
||||
if only_conversion:
|
||||
return
|
||||
|
||||
ie = Core()
|
||||
exec_net = ie.compile_model(model, "CPU")
|
||||
req = exec_net.create_infer_request()
|
||||
results = req.infer(inputs)
|
||||
values = list(results.values())[0]
|
||||
if dtype is not None:
|
||||
assert values.dtype == dtype
|
||||
assert np.allclose(values, expected)
|
||||
|
||||
@generate(
|
||||
*[
|
||||
(
|
||||
"in1[1 4]->[1.0 2.0 3.0 4.0],in2[1 4]{f32}->[1.0 2.0 3.0 4.0]",
|
||||
{},
|
||||
np.array([2.0, 4.0, 6.0, 8.0]),
|
||||
np.float32,
|
||||
),
|
||||
(
|
||||
"in2{f32}->[0.0 0.0 0.0 0.0]",
|
||||
{"in1": np.array([[1.0, 2.0], [3.0, 4.0]])},
|
||||
np.array([[1.0, 2.0], [3.0, 4.0]]),
|
||||
np.float32,
|
||||
),
|
||||
(
|
||||
"in2->[1.0 15.0 15.5 1.0]",
|
||||
{"in1": np.array([[2.0, 4.0], [12.0, 8.0]])},
|
||||
np.array([[3.0, 19.0], [27.5, 9.0]]),
|
||||
np.float32,
|
||||
),
|
||||
(
|
||||
"in1[1 4]{i32}->[1 2 3 4],in2[1 4]{i32}->[1 2 3 4]",
|
||||
{},
|
||||
np.array([2.0, 4.0, 6.0, 8.0]),
|
||||
np.int32,
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_fp32(self, input_freezing_value, inputs, expected,
|
||||
dtype):
|
||||
self.basic("model_fp32.pbtxt", input_freezing_value, inputs, dtype, expected)
|
||||
|
||||
@generate(
|
||||
*[
|
||||
(
|
||||
"in1[1 4]->[1 2 3 4],in2[1 4]{i32}->[1 2 3 4]",
|
||||
{},
|
||||
np.array([1, 4, 9, 16]),
|
||||
np.int32,
|
||||
),
|
||||
(
|
||||
"in2->[2 5 6 7 3 2]",
|
||||
{"in1": np.array([[2, 4, 1], [1, 2, 8]])},
|
||||
np.array([[4, 20, 6], [7, 6, 16]]),
|
||||
np.int32,
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_int32(self, input_freezing_value, inputs, expected,
|
||||
dtype=None):
|
||||
self.basic("model_int32.pbtxt", input_freezing_value, inputs, dtype, expected)
|
||||
|
||||
@generate(
|
||||
*[
|
||||
(
|
||||
"in1[2]->[True False],in2[2]->[True True]",
|
||||
{},
|
||||
np.array([True, False], dtype=bool),
|
||||
bool,
|
||||
),
|
||||
(
|
||||
"in2[2,3]->[True,True,False,True,True,False]",
|
||||
{"in1": np.array([[False, True, True], [False, True, True]], dtype=bool)},
|
||||
np.array([[False, True, False], [False, True, False]], dtype=bool),
|
||||
bool,
|
||||
),
|
||||
(
|
||||
"in2[]->True",
|
||||
{"in1": np.array([[False, True, True], [False, True, True]], dtype=bool)},
|
||||
np.array([[False, True, True], [False, True, True]], dtype=bool),
|
||||
bool,
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_bool(self, input_freezing_value, inputs, expected,
|
||||
dtype=None):
|
||||
self.basic("model_bool.pbtxt", input_freezing_value, inputs, dtype, expected)
|
||||
|
||||
@generate(
|
||||
*[
|
||||
(
|
||||
"in1[3]->[1 2 3],in2[3]->[4 5 6],cond->False",
|
||||
{},
|
||||
np.array([4, 5, 6], dtype=np.float32),
|
||||
np.float32,
|
||||
None
|
||||
),
|
||||
(
|
||||
None,
|
||||
{"in1": np.array([2.0, 4.0, 6.0], dtype=np.float32),
|
||||
"in2": np.array([1.0, 3.0, 5.0], dtype=np.float32)},
|
||||
np.array([2, 4, 6], dtype=np.float32),
|
||||
np.float32,
|
||||
"cond->False",
|
||||
None,
|
||||
True # fill a bug to investigate why compilation of this model is hang on
|
||||
),
|
||||
# case: input_shape + freeze_placeholder_with_value
|
||||
(
|
||||
None,
|
||||
{"in2": np.array([1.0, 3.0, 5.0], dtype=np.float32)},
|
||||
np.array([2, 4, 6], dtype=np.float32),
|
||||
np.float32,
|
||||
"in1->[2.0 4.0 6.0],cond->True",
|
||||
"[3]",
|
||||
False
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_bool2(self, input_freezing_value, inputs, expected,
|
||||
dtype=None, freeze_placeholder_with_value=None, input_shape=None, only_conversion=False):
|
||||
self.basic("model_bool2.pbtxt", input_freezing_value, inputs, dtype, expected, freeze_placeholder_with_value,
|
||||
input_shape, only_conversion)
|
||||
|
||||
@generate(
|
||||
*[
|
||||
(
|
||||
"add:0[3],z",
|
||||
{"add:0": np.array([4, 5, 6], dtype=np.float32), "z": np.array([1, 2, 3], dtype=np.float32)},
|
||||
np.array([4, 10, 18], dtype=np.float32),
|
||||
np.float32,
|
||||
None
|
||||
),
|
||||
(
|
||||
"add:0{i32}[3],z{i32}",
|
||||
{"add:0": np.array([4, 5, 6], dtype=np.int32), "z": np.array([1, 2, 3], dtype=np.int32)},
|
||||
np.array([4, 10, 18], dtype=np.int32),
|
||||
np.int32,
|
||||
None
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_cutting_fp32(self, input_freezing_value, inputs, expected,
|
||||
dtype=None, freeze_placeholder_with_value=None, input_shape=None, only_conversion=False):
|
||||
self.basic("model_three_inputs.pbtxt", input_freezing_value, inputs, dtype, expected,
|
||||
freeze_placeholder_with_value,
|
||||
input_shape, only_conversion, True)
|
||||
|
||||
@generate(
|
||||
*[
|
||||
(
|
||||
"x[1,4],y[4]",
|
||||
{"x": np.array([[3, 2, 1, 5]], dtype=np.int32), "y": np.array([0, -1, -7, 8], dtype=np.int32)},
|
||||
np.array([[3, 1, -6, 13]], dtype=np.int32),
|
||||
np.int32,
|
||||
None
|
||||
),
|
||||
(
|
||||
"x,y",
|
||||
{"x": np.array([[-3, 20, 1]], dtype=np.int32), "y": np.array([[10, -11, -17]], dtype=np.int32)},
|
||||
np.array([[7, 9, -16]], dtype=np.int32),
|
||||
np.int32,
|
||||
None
|
||||
),
|
||||
(
|
||||
"x",
|
||||
{"x": np.array([[-3, 20, 1]], dtype=np.int32)},
|
||||
np.array([[-2, 22, 4], [1, 25, 7]], dtype=np.int32),
|
||||
np.int32,
|
||||
None
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_placeholder_with_default(self, inputs, inputs_data, expected,
|
||||
dtype=None, freeze_placeholder_with_value=None, input_shape=None,
|
||||
only_conversion=False):
|
||||
self.basic("placeholder_with_default.pbtxt", inputs, inputs_data, dtype, expected,
|
||||
freeze_placeholder_with_value,
|
||||
input_shape, only_conversion, True)
|
||||
|
||||
@generate(
|
||||
*[
|
||||
(
|
||||
"x[4],y->2.0",
|
||||
{"x": np.array([3, 2, 1, 5], dtype=np.float32)},
|
||||
np.array([6, 4, 2, 10], dtype=np.float32),
|
||||
np.float32,
|
||||
None
|
||||
),
|
||||
(
|
||||
"x[1],y->[2.0,3.0]",
|
||||
{"x": np.array([3], dtype=np.float32)},
|
||||
np.array([6, 9], dtype=np.float32),
|
||||
np.float32,
|
||||
None
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_freeze_placeholder_with_unknown_rank(self, inputs, inputs_data, expected,
|
||||
dtype=None, freeze_placeholder_with_value=None, input_shape=None,
|
||||
only_conversion=False):
|
||||
self.basic("mul_with_unknown_rank_y.pbtxt", inputs, inputs_data, dtype, expected,
|
||||
freeze_placeholder_with_value,
|
||||
input_shape, only_conversion, True)
|
||||
|
||||
|
||||
def test_conversion_failure_fallback_use_new_frontend(self):
|
||||
with self.assertRaisesRegex(Exception,
|
||||
"\[TensorFlow Frontend\] Internal error, no translator found for operation\(s\)\: "
|
||||
"Enter\, Exit\, LoopCond\, Merge\, NextIteration\, Switch\, TensorArrayGatherV3\, "
|
||||
"TensorArraySizeV3\, TensorArrayV3"):
|
||||
self.basic("ctc_model_based.pbtxt", None, None, None, None,
|
||||
None, None, True, True, True, False)
|
||||
|
||||
@unittest.skip("88349: Fix auto-pruning in legacy FE")
|
||||
def test_conversion_model_oneshot_iterator_use_legacy_frontend(self):
|
||||
self.basic("model_oneshot_iterator.pbtxt", None, None, None, None,
|
||||
None, None, True, True, False, True)
|
||||
|
||||
def test_conversion_model_oneshot_iterator_default(self):
|
||||
self.basic("model_oneshot_iterator.pbtxt", None, None, None, None,
|
||||
None, None, True, True, False, False)
|
||||
|
||||
@generate(
|
||||
*[
|
||||
(
|
||||
"in2{f32}->[0.0 0.0 0.0 0.0]",
|
||||
{"in1": np.array([[1.0, 2.0], [3.0, 4.0]])},
|
||||
np.array([[1.0, 2.0], [3.0, 4.0]]),
|
||||
np.float32,
|
||||
),
|
||||
(
|
||||
"in2->[1.0 15.0 15.5 1.0]",
|
||||
{"in1": np.array([[2.0, 4.0], [12.0, 8.0]])},
|
||||
np.array([[3.0, 19.0], [27.5, 9.0]]),
|
||||
np.float32,
|
||||
),
|
||||
],
|
||||
)
|
||||
@unittest.skip("109220: Use generating script for this test model instead of Git LFS")
|
||||
def test_conversion_model_with_non_standard_extension(self, input_freezing_value, inputs, expected,
|
||||
dtype):
|
||||
self.basic("model_fp32.frozen", input_freezing_value, inputs, dtype, expected, only_conversion=False,
|
||||
input_model_is_text=False, use_new_frontend=True,
|
||||
use_legacy_frontend=False)
|
||||
|
||||
@unittest.skip("109220: Make TF FE to return the error")
|
||||
def test_conversion_dir_model(self):
|
||||
with self.assertRaisesRegex(Exception,
|
||||
"Internal error or inconsistent input model: the frontend supports "
|
||||
"only frozen binary protobuf format."):
|
||||
self.basic(".", None, None, None, None,
|
||||
only_conversion=True, input_model_is_text=False, use_new_frontend=True,
|
||||
use_legacy_frontend=False)
|
||||
|
||||
@generate(
|
||||
*[
|
||||
(
|
||||
{"x": np.array([1, 2], dtype=np.int32), "y": np.array([4], dtype=np.int32)},
|
||||
np.array([-3, -2], dtype=np.int32),
|
||||
np.int32,
|
||||
),
|
||||
(
|
||||
{"x": np.array([20, 25], dtype=np.int32), "y": np.array([10], dtype=np.int32)},
|
||||
np.array([30, 35], dtype=np.int32),
|
||||
np.int32,
|
||||
)
|
||||
],
|
||||
)
|
||||
def test_conversion_pbtxt_model_with_inference(self, inputs, expected, dtype):
|
||||
self.basic("model_with_if.pbtxt", None, inputs, dtype, expected, only_conversion=False,
|
||||
input_model_is_text=False, use_new_frontend=True, use_legacy_frontend=False)
|
||||
|
||||
@generate(
|
||||
*[
|
||||
# new frontend
|
||||
(
|
||||
"model_add_with_undefined_constant.pbtxt",
|
||||
"x[2,3]",
|
||||
{"x": np.array([[12, 13, 10], [11, 14, 16]], dtype=np.float32)},
|
||||
np.array([[12, 13, 10], [11, 14, 16]], dtype=np.float32),
|
||||
np.float32, True, False,
|
||||
),
|
||||
(
|
||||
"model_mul_with_undefined_constant.pbtxt",
|
||||
"x[2]",
|
||||
{"x": np.array([11, -12], dtype=np.int32)},
|
||||
np.array([0, 0], dtype=np.int32),
|
||||
np.int32, True, False,
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_conversion_model_with_undefined_constant(self, model_name, argv_input, inputs, expected, dtype,
|
||||
use_new_frontend, use_legacy_frontend):
|
||||
self.basic(model_name, argv_input, inputs, dtype, expected, only_conversion=False,
|
||||
input_model_is_text=True, use_new_frontend=use_new_frontend, use_legacy_frontend=use_legacy_frontend)
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import os
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
from generator import generator, generate
|
||||
|
||||
from openvino.tools.ovc.convert import convert_model
|
||||
|
||||
|
||||
@generator
|
||||
class TestMoFreezePlaceholderTFFE(unittest.TestCase):
|
||||
@generate(
|
||||
*[
|
||||
# the default frontend
|
||||
(
|
||||
False, False, None
|
||||
),
|
||||
(
|
||||
False, False, "tf"
|
||||
),
|
||||
# new frontend
|
||||
(
|
||||
True, False, None
|
||||
),
|
||||
(
|
||||
True, False, "tf"
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_conversion_fake_pb_model(self, use_new_frontend, use_legacy_frontend, framework):
|
||||
with self.assertRaisesRegex(Exception,
|
||||
"Internal error or inconsistent input model: the frontend supports frozen formats"
|
||||
" \(.pb and .pbtxt\), SavedModel and MetaGraph \(.meta\), and v1 checkpoints."):
|
||||
path = os.path.dirname(__file__)
|
||||
input_model = os.path.join(path, "test_models", "fake.pb")
|
||||
|
||||
convert_model(input_model,
|
||||
use_new_frontend=use_new_frontend, use_legacy_frontend=use_legacy_frontend,
|
||||
framework=framework)
|
||||
|
|
@ -10,8 +10,8 @@ from generator import generator, generate
|
|||
import openvino.runtime.opset11 as opset11
|
||||
from openvino.runtime import Model
|
||||
from openvino.runtime import PartialShape, Dimension
|
||||
from openvino.tools.mo.convert import convert_model
|
||||
from openvino.tools.mo.utils.error import Error
|
||||
from openvino.tools.ovc.convert import convert_model
|
||||
from openvino.tools.ovc.error import Error
|
||||
|
||||
|
||||
@generator
|
||||
|
|
@ -92,6 +92,6 @@ class TestConversionWithBatchAndLayout(unittest.TestCase):
|
|||
def test_model_expected_failure(self, model_name: str, batch: int, layout: str, refs_shapes: dict):
|
||||
# try to override batch size by default index (without specifying layout)
|
||||
with self.assertRaisesRegex(Error,
|
||||
"When you use -b \(--batch\) option, Model Optimizer applies its value to the first "
|
||||
"When you use \"batch\" option, Model Conversion API applies its value to the first "
|
||||
"element of the shape if it is equal to -1, 0 or 1\."):
|
||||
self.basic_check(model_name, batch, layout, refs_shapes)
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,58 @@
|
|||
node {
|
||||
name: "x"
|
||||
op: "Placeholder"
|
||||
attr {
|
||||
key: "dtype"
|
||||
value {
|
||||
type: DT_FLOAT
|
||||
}
|
||||
}
|
||||
attr {
|
||||
key: "shape"
|
||||
value {
|
||||
shape {
|
||||
dim {
|
||||
size: 2
|
||||
}
|
||||
dim {
|
||||
size: 3
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
node {
|
||||
name: "Const"
|
||||
op: "Const"
|
||||
attr {
|
||||
key: "dtype"
|
||||
value {
|
||||
type: DT_FLOAT
|
||||
}
|
||||
}
|
||||
attr {
|
||||
key: "value"
|
||||
value {
|
||||
tensor {
|
||||
dtype: DT_FLOAT
|
||||
tensor_shape {
|
||||
dim {
|
||||
size: 3
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
node {
|
||||
name: "add"
|
||||
op: "AddV2"
|
||||
input: "x"
|
||||
input: "Const"
|
||||
attr {
|
||||
key: "T"
|
||||
value {
|
||||
type: DT_FLOAT
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue