diff --git a/tools/mo/openvino/tools/mo/convert.py b/tools/mo/openvino/tools/mo/convert.py index 1d15ca2eb70..50e38731a2c 100644 --- a/tools/mo/openvino/tools/mo/convert.py +++ b/tools/mo/openvino/tools/mo/convert.py @@ -348,6 +348,6 @@ def convert_model( del params['args'] params.update(args) cli_parser = get_all_cli_parser() - ov_model, _ = _convert(cli_parser, framework, params) + ov_model, _ = _convert(cli_parser, framework, params, True) restore_logger_state(logger_state) return ov_model diff --git a/tools/mo/openvino/tools/mo/convert_impl.py b/tools/mo/openvino/tools/mo/convert_impl.py index 1ab6dfa5def..2c350b6cd29 100644 --- a/tools/mo/openvino/tools/mo/convert_impl.py +++ b/tools/mo/openvino/tools/mo/convert_impl.py @@ -7,6 +7,7 @@ import logging as log import os import platform import sys +import traceback from collections import OrderedDict from copy import deepcopy from distutils.version import LooseVersion @@ -36,14 +37,17 @@ from openvino.tools.mo.utils.cli_parser import check_available_transforms, \ 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.mo.utils.error import Error +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.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.mo.utils.utils import refer_to_faq_msg -from openvino.tools.mo.utils.telemetry_utils import send_params_info, send_framework_info +from openvino.tools.mo.utils.telemetry_utils import send_params_info, send_framework_info, send_conversion_result, \ + get_tid from openvino.tools.mo.utils.versions_checker import check_requirements, get_environment_setup # pylint: disable=no-name-in-module -from openvino.tools.mo.utils.telemetry_utils import 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, convert_pytorch_via_onnx from openvino.tools.mo.moc_frontend.shape_utils import parse_input_shapes, get_static_shape @@ -812,10 +816,8 @@ def pack_params_to_args_namespace(args: dict, cli_parser: argparse.ArgumentParse # so we need to set them in argv separately if value is not None and getattr(argv, key, None) != value: setattr(argv, key, value) - argv.is_python_api_used = True else: argv = cli_parser.parse_args() - argv.is_python_api_used = False return argv @@ -835,7 +837,20 @@ def update_args_for_saved_model_dir(args: dict): args['input_model'] = None -def _convert(cli_parser: argparse.ArgumentParser, framework, args): +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, framework, args, python_api_used): if 'help' in args and args['help']: show_mo_convert_help() return None, None @@ -846,6 +861,7 @@ def _convert(cli_parser: argparse.ArgumentParser, framework, args): # 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) @@ -869,6 +885,7 @@ def _convert(cli_parser: argparse.ArgumentParser, framework, args): update_args_for_saved_model_dir(args) argv = pack_params_to_args_namespace(args, cli_parser) + argv.is_python_api_used = python_api_used argv.feManager = FrontEndManager() frameworks = list(set(['tf', 'caffe', 'mxnet', 'kaldi', 'onnx'] + (get_available_front_ends(argv.feManager) @@ -909,12 +926,54 @@ def _convert(cli_parser: argparse.ArgumentParser, framework, args): for key, value in non_default_params.items(): ov_model.set_rt_info(str(value), ["conversion_parameters", str(key)]) - telemetry.send_event('mo', 'conversion_result', 'success') - telemetry.end_session('mo') - telemetry.force_shutdown(1.0) + 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: - telemetry.send_event('mo', 'conversion_result', 'fail') - telemetry.end_session('mo') - telemetry.force_shutdown(1.0) - raise e.with_traceback(None) + 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): + analysis_results = AnalysisResults() + if analysis_results.get_messages() is not None: + for el in analysis_results.get_messages(): + log.error(el, extra={'analysis_info': True}) + 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 Optimizer 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 diff --git a/tools/mo/openvino/tools/mo/main.py b/tools/mo/openvino/tools/mo/main.py index ce92e6e23e1..d5fe1bcd08d 100644 --- a/tools/mo/openvino/tools/mo/main.py +++ b/tools/mo/openvino/tools/mo/main.py @@ -2,7 +2,6 @@ # SPDX-License-Identifier: Apache-2.0 import argparse -import logging as log import os import sys @@ -10,69 +9,15 @@ try: import openvino_telemetry as tm except ImportError: import openvino.tools.mo.utils.telemetry_stub as tm -from openvino.tools.mo.utils.get_ov_update_message import get_compression_message from openvino.tools.mo.convert_impl import _convert from openvino.tools.mo.pipeline.common import get_ir_version -from openvino.tools.mo.utils.logger import init_logger -from openvino.tools.mo.utils.error import Error, FrameworkError -import traceback -from openvino.tools.mo.utils.get_ov_update_message import get_ov_update_message, get_ov_api20_message, \ - get_tf_fe_message -from openvino.tools.mo.utils.model_analysis import AnalysisResults -from openvino.tools.mo.utils.guess_framework import deduce_legacy_frontend_by_namespace # pylint: disable=no-name-in-module,import-error -from openvino.frontend import FrontEndManager from openvino.runtime import serialize def main(cli_parser: argparse.ArgumentParser, framework=None): - # 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) - - ngraph_function = None - argv = None - try: - ngraph_function, argv = _convert(cli_parser, framework, {}) - is_tf, _, _, _, _ = deduce_legacy_frontend_by_namespace(argv) - 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 ngraph_function is not None: - print(ov_api20_message) - is_fallback = getattr(argv, 'is_fallback', False) - if not argv.use_legacy_frontend and is_tf and not is_fallback: - # now TF FE is default frontend for TensorFlow models conversion - print(get_tf_fe_message()) - - except (FileNotFoundError, NotADirectoryError) as e: - log.error('File {} was not found'.format(str(e).split('No such file or directory:')[1])) - log.debug(traceback.format_exc()) - except Error as err: - analysis_results = AnalysisResults() - if analysis_results.get_messages() is not None: - for el in analysis_results.get_messages(): - log.error(el, extra={'analysis_info': True}) - log.error(err) - log.debug(traceback.format_exc()) - except FrameworkError as err: - log.error(err, extra={'framework_error': True}) - log.debug(traceback.format_exc()) - except Exception as err: - log.error("-------------------------------------------------") - log.error("----------------- INTERNAL ERROR ----------------") - log.error("Unexpected exception happened.") - log.error("Please contact Model Optimizer developers and forward the following information:") - log.error(str(err)) - log.error(traceback.format_exc()) - log.error("---------------- END OF BUG REPORT --------------") - log.error("-------------------------------------------------") - + ngraph_function, argv = _convert(cli_parser, framework, {}, False) if ngraph_function is None: return 1 diff --git a/tools/mo/openvino/tools/mo/moc_frontend/pytorch_frontend_utils.py b/tools/mo/openvino/tools/mo/moc_frontend/pytorch_frontend_utils.py index 6aefe606753..8de8bee41c5 100644 --- a/tools/mo/openvino/tools/mo/moc_frontend/pytorch_frontend_utils.py +++ b/tools/mo/openvino/tools/mo/moc_frontend/pytorch_frontend_utils.py @@ -138,7 +138,7 @@ def convert_pytorch_via_onnx(args, example_inputs, cli_parser, framework, main_c args['input_model'] = model_onnx - ov_model, argv = main_convert(cli_parser, framework, args) + ov_model, argv = main_convert(cli_parser, framework, args, True) except Exception as e: raise e finally: diff --git a/tools/mo/openvino/tools/mo/utils/get_ov_update_message.py b/tools/mo/openvino/tools/mo/utils/get_ov_update_message.py index 545bc204bab..d515bacde6c 100644 --- a/tools/mo/openvino/tools/mo/utils/get_ov_update_message.py +++ b/tools/mo/openvino/tools/mo/utils/get_ov_update_message.py @@ -41,3 +41,8 @@ def get_compression_message(): '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 diff --git a/tools/mo/openvino/tools/mo/utils/telemetry_utils.py b/tools/mo/openvino/tools/mo/utils/telemetry_utils.py index 665b19470b1..62215923507 100644 --- a/tools/mo/openvino/tools/mo/utils/telemetry_utils.py +++ b/tools/mo/openvino/tools/mo/utils/telemetry_utils.py @@ -103,3 +103,11 @@ 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) diff --git a/tools/mo/unit_tests/moc_tf_fe/check_info_messages_test.py b/tools/mo/unit_tests/moc_tf_fe/check_info_messages_test.py index 31dba2b3c37..554740094d0 100644 --- a/tools/mo/unit_tests/moc_tf_fe/check_info_messages_test.py +++ b/tools/mo/unit_tests/moc_tf_fe/check_info_messages_test.py @@ -9,7 +9,8 @@ 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 +from openvino.tools.mo.utils.get_ov_update_message import get_tf_fe_message, get_compression_message, \ + get_try_legacy_fe_message def arg_parse_helper(input_model, @@ -68,6 +69,22 @@ class TestInfoMessagesTFFE(unittest.TestCase): 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',