Show message with suggestion to try legacy FE in case of conversion error (#17088)

* Moved exception checks to _convert(), added suggestion to try legacy TF in case of conversion fail.

* Added test.

* Added send_conversion_result() method.

* Small correction.

* Update tools/mo/openvino/tools/mo/convert_impl.py

Co-authored-by: Roman Kazantsev <roman.kazantsev@intel.com>

* Moved test_suggest_legacy_fe() test to check_info_messages_test.py.

* Removed not needed import.

* Small correction.

---------

Co-authored-by: Roman Kazantsev <roman.kazantsev@intel.com>
This commit is contained in:
Anastasiia Pnevskaia 2023-04-25 15:57:01 +02:00 committed by GitHub
parent 57d4ca27e6
commit acd424bb5e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 106 additions and 72 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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)

View File

@ -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',