openvino/model-optimizer/mo/utils/model_analysis.py

125 lines
3.5 KiB
Python

# Copyright (C) 2018-2021 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
import sys
from extensions.front.user_data_repack import UserDataRepack
from extensions.load.loader import LoadFinish
from mo.graph.graph import Graph
from mo.utils import class_registration
from mo.utils.error import Error
class AnalysisResults:
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super(AnalysisResults, cls).__new__(cls, *args, **kwargs)
cls.results = {}
cls.messages = []
return cls._instance
def __getattr__(self, item):
return self.results[item]
def __setattr__(self, key, value):
self.results[key] = value
@classmethod
def get_result(cls, key=None):
if key is not None:
if key in cls.results and cls.results[key] is not None:
return cls.results[key]
else:
return cls.results
@classmethod
def add_result(cls, result, key=None):
if key is not None:
cls.results[key] = result
else:
cls.results.update(result)
@classmethod
def get_messages(cls):
return cls.messages
@classmethod
def add_message(cls, message):
cls.messages.append(message)
class AnalyzeAction(object):
registered_cls = []
registered_ops = {}
excluded_replacers = []
run_not_recursively = True
def find_and_replace_pattern(self, graph: Graph):
analysis_results = AnalysisResults()
failed_analysers = []
try:
result, msg = self.analyze(graph) # pylint: disable=assignment-from-no-return
except SystemExit:
# the analysis transformation printing analysis results to the screen calls sys.exit(0) which in fact raises
# SystemExit exception, so we handle it here
sys.exit(0)
except:
failed_analysers.append(str(self.__class__))
analysis_results.add_result(failed_analysers, 'failed_analysers')
result = None
msg = None
if result is not None:
analysis_results.add_result(result)
if msg is not None:
analysis_results.add_message(msg)
def analyze(self, graph: Graph):
raise Error('The method must be implemented in the sub-class')
def run_before(self):
"""
Returns list of replacer classes which this replacer must be run before.
:return: list of classes
"""
return [AnalysisCollectorAnchor, UserDataRepack]
def run_after(self):
"""
Returns list of replacer classes which this replacer must be run after.
:return: list of classes
"""
return [LoadFinish]
@classmethod
def class_type(cls):
return class_registration.ClassType.FRONT_REPLACER
class AnalysisCollectorAnchor(AnalyzeAction):
"""
All analyzers should depend on this one which is an anchor analyzer to develop custom post-processor of all
analyzers results.
"""
def run_before(self):
return []
def analyze(self, graph: Graph):
pass
def graph_contains_scope(graph: Graph, scope: str):
"""
Checks whether the graph contains node(s) which name starts with "scope" string.
:param graph: graph to check
:param scope: string defining the scope
:return: the result of the check (True/False)
"""
if scope[-1] != '/':
scope += '/'
return any([node.soft_get('name').startswith(scope) for node in graph.get_op_nodes()])