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:
parent
57d4ca27e6
commit
acd424bb5e
@ -348,6 +348,6 @@ def convert_model(
|
|||||||
del params['args']
|
del params['args']
|
||||||
params.update(args)
|
params.update(args)
|
||||||
cli_parser = get_all_cli_parser()
|
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)
|
restore_logger_state(logger_state)
|
||||||
return ov_model
|
return ov_model
|
||||||
|
@ -7,6 +7,7 @@ import logging as log
|
|||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
import sys
|
import sys
|
||||||
|
import traceback
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
from distutils.version import LooseVersion
|
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, \
|
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
|
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.version import VersionChecker
|
||||||
from openvino.tools.mo.utils.guess_framework import deduce_legacy_frontend_by_namespace
|
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.logger import init_logger, progress_printer
|
||||||
from openvino.tools.mo.utils.utils import refer_to_faq_msg
|
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.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.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.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
|
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
|
# so we need to set them in argv separately
|
||||||
if value is not None and getattr(argv, key, None) != value:
|
if value is not None and getattr(argv, key, None) != value:
|
||||||
setattr(argv, key, value)
|
setattr(argv, key, value)
|
||||||
argv.is_python_api_used = True
|
|
||||||
else:
|
else:
|
||||||
argv = cli_parser.parse_args()
|
argv = cli_parser.parse_args()
|
||||||
argv.is_python_api_used = False
|
|
||||||
return argv
|
return argv
|
||||||
|
|
||||||
|
|
||||||
@ -835,7 +837,20 @@ def update_args_for_saved_model_dir(args: dict):
|
|||||||
args['input_model'] = None
|
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']:
|
if 'help' in args and args['help']:
|
||||||
show_mo_convert_help()
|
show_mo_convert_help()
|
||||||
return None, None
|
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
|
# Initialize logger with 'ERROR' as default level to be able to form nice messages
|
||||||
# before arg parser deliver log_level requested by user
|
# before arg parser deliver log_level requested by user
|
||||||
init_logger('ERROR', False)
|
init_logger('ERROR', False)
|
||||||
|
argv = None
|
||||||
try:
|
try:
|
||||||
model_framework = None
|
model_framework = None
|
||||||
inp_model_is_object = input_model_is_object(args)
|
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)
|
update_args_for_saved_model_dir(args)
|
||||||
|
|
||||||
argv = pack_params_to_args_namespace(args, cli_parser)
|
argv = pack_params_to_args_namespace(args, cli_parser)
|
||||||
|
argv.is_python_api_used = python_api_used
|
||||||
|
|
||||||
argv.feManager = FrontEndManager()
|
argv.feManager = FrontEndManager()
|
||||||
frameworks = list(set(['tf', 'caffe', 'mxnet', 'kaldi', 'onnx'] + (get_available_front_ends(argv.feManager)
|
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():
|
for key, value in non_default_params.items():
|
||||||
ov_model.set_rt_info(str(value), ["conversion_parameters", str(key)])
|
ov_model.set_rt_info(str(value), ["conversion_parameters", str(key)])
|
||||||
|
|
||||||
telemetry.send_event('mo', 'conversion_result', 'success')
|
if silent_is_false(argv) or not python_api_used:
|
||||||
telemetry.end_session('mo')
|
if 'compress_to_fp16' in argv and argv.compress_to_fp16:
|
||||||
telemetry.force_shutdown(1.0)
|
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
|
return ov_model, argv
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
telemetry.send_event('mo', 'conversion_result', 'fail')
|
if silent_is_false(argv) or not python_api_used:
|
||||||
telemetry.end_session('mo')
|
if isinstance(e, (FileNotFoundError, NotADirectoryError)):
|
||||||
telemetry.force_shutdown(1.0)
|
log.error('File {} was not found'.format(str(e).split('No such file or directory:')[1]))
|
||||||
raise e.with_traceback(None)
|
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
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import logging as log
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
@ -10,69 +9,15 @@ try:
|
|||||||
import openvino_telemetry as tm
|
import openvino_telemetry as tm
|
||||||
except ImportError:
|
except ImportError:
|
||||||
import openvino.tools.mo.utils.telemetry_stub as tm
|
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.convert_impl import _convert
|
||||||
from openvino.tools.mo.pipeline.common import get_ir_version
|
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
|
# pylint: disable=no-name-in-module,import-error
|
||||||
from openvino.frontend import FrontEndManager
|
|
||||||
from openvino.runtime import serialize
|
from openvino.runtime import serialize
|
||||||
|
|
||||||
|
|
||||||
def main(cli_parser: argparse.ArgumentParser, framework=None):
|
def main(cli_parser: argparse.ArgumentParser, framework=None):
|
||||||
# Initialize logger with 'ERROR' as default level to be able to form nice messages
|
ngraph_function, argv = _convert(cli_parser, framework, {}, False)
|
||||||
# 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("-------------------------------------------------")
|
|
||||||
|
|
||||||
if ngraph_function is None:
|
if ngraph_function is None:
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
@ -138,7 +138,7 @@ def convert_pytorch_via_onnx(args, example_inputs, cli_parser, framework, main_c
|
|||||||
|
|
||||||
args['input_model'] = model_onnx
|
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:
|
except Exception as e:
|
||||||
raise e
|
raise e
|
||||||
finally:
|
finally:
|
||||||
|
@ -41,3 +41,8 @@ def get_compression_message():
|
|||||||
'by removing argument --compress_to_fp16 or set it to false --compress_to_fp16=False.\n' \
|
'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)
|
'Find more information about compression to FP16 at {}'.format(link)
|
||||||
return message
|
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
|
||||||
|
@ -103,3 +103,11 @@ def get_tid():
|
|||||||
This function returns the ID of the database to send telemetry.
|
This function returns the ID of the database to send telemetry.
|
||||||
"""
|
"""
|
||||||
return telemetry_params['TID']
|
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)
|
||||||
|
@ -9,7 +9,8 @@ from contextlib import redirect_stdout
|
|||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
from openvino.tools.mo.main import main
|
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,
|
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
|
tf_fe_message_found = get_tf_fe_message() in std_out
|
||||||
assert tf_fe_message_found
|
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):
|
class TestInfoMessagesTFFEWithFallback(unittest.TestCase):
|
||||||
@patch('argparse.ArgumentParser.parse_args',
|
@patch('argparse.ArgumentParser.parse_args',
|
||||||
|
Loading…
Reference in New Issue
Block a user