diff options
Diffstat (limited to 'src/mlia/devices/cortexa')
-rw-r--r-- | src/mlia/devices/cortexa/__init__.py | 3 | ||||
-rw-r--r-- | src/mlia/devices/cortexa/advice_generation.py | 153 | ||||
-rw-r--r-- | src/mlia/devices/cortexa/advisor.py | 92 | ||||
-rw-r--r-- | src/mlia/devices/cortexa/config.py | 20 | ||||
-rw-r--r-- | src/mlia/devices/cortexa/data_analysis.py | 128 | ||||
-rw-r--r-- | src/mlia/devices/cortexa/data_collection.py | 51 | ||||
-rw-r--r-- | src/mlia/devices/cortexa/events.py | 24 | ||||
-rw-r--r-- | src/mlia/devices/cortexa/handlers.py | 39 | ||||
-rw-r--r-- | src/mlia/devices/cortexa/operator_compatibility.py | 184 | ||||
-rw-r--r-- | src/mlia/devices/cortexa/operators.py | 148 | ||||
-rw-r--r-- | src/mlia/devices/cortexa/reporters.py | 140 |
11 files changed, 0 insertions, 982 deletions
diff --git a/src/mlia/devices/cortexa/__init__.py b/src/mlia/devices/cortexa/__init__.py deleted file mode 100644 index 3a987e7..0000000 --- a/src/mlia/devices/cortexa/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-FileCopyrightText: Copyright 2022, Arm Limited and/or its affiliates. -# SPDX-License-Identifier: Apache-2.0 -"""Cortex-A devices module.""" diff --git a/src/mlia/devices/cortexa/advice_generation.py b/src/mlia/devices/cortexa/advice_generation.py deleted file mode 100644 index bab9530..0000000 --- a/src/mlia/devices/cortexa/advice_generation.py +++ /dev/null @@ -1,153 +0,0 @@ -# SPDX-FileCopyrightText: Copyright 2022, Arm Limited and/or its affiliates. -# SPDX-License-Identifier: Apache-2.0 -"""Cortex-A advice generation.""" -from functools import singledispatchmethod - -from mlia.core.advice_generation import advice_category -from mlia.core.advice_generation import FactBasedAdviceProducer -from mlia.core.common import AdviceCategory -from mlia.core.common import DataItem -from mlia.devices.cortexa.data_analysis import ModelHasCustomOperators -from mlia.devices.cortexa.data_analysis import ModelIsCortexACompatible -from mlia.devices.cortexa.data_analysis import ModelIsNotCortexACompatible -from mlia.devices.cortexa.data_analysis import ModelIsNotTFLiteCompatible -from mlia.devices.cortexa.data_analysis import TFLiteCompatibilityCheckFailed - - -class CortexAAdviceProducer(FactBasedAdviceProducer): - """Cortex-A advice producer.""" - - cortex_a_disclaimer = ( - "Note that the provided compatibility information is general. " - "At runtime individual operators in the given model might fall back to " - "the TensorFlow Lite reference or might produce errors based on the " - "specific parameters." - ) - - @singledispatchmethod - def produce_advice(self, _data_item: DataItem) -> None: # type: ignore - """Produce advice.""" - - @produce_advice.register - @advice_category(AdviceCategory.ALL, AdviceCategory.OPERATORS) - def handle_model_is_cortex_a_compatible( - self, data_item: ModelIsCortexACompatible - ) -> None: - """Advice for Cortex-A compatibility.""" - self.add_advice( - [ - f"Model is fully compatible with {data_item.backend_info} for " - "Cortex-A.", - self.cortex_a_disclaimer, - ] - ) - - @produce_advice.register - @advice_category(AdviceCategory.ALL, AdviceCategory.OPERATORS) - def handle_model_is_not_cortex_a_compatible( - self, data_item: ModelIsNotCortexACompatible - ) -> None: - """Advice for Cortex-A compatibility.""" - if data_item.unsupported_ops: - self.add_advice( - [ - "The following operators are not supported by " - f"{data_item.backend_info} and will fall back to the " - "TensorFlow Lite runtime:", - "\n".join(f" - {op}" for op in data_item.unsupported_ops), - ] - ) - - if data_item.activation_func_support: - self.add_advice( - [ - "The fused activation functions of the following operators " - f"are not supported by {data_item.backend_info}. Please " - "consider using one of the supported activation functions " - "instead:", - "\n".join( - f" - {op}\n" - f" - Used unsupported: {act.used_unsupported}\n" - f" - Supported: {act.supported}" - for op, act in data_item.activation_func_support.items() - ), - ] - ) - - self.add_advice( - [ - "Please, refer to the full table of operators above for more " - "information.", - self.cortex_a_disclaimer, - ] - ) - - @produce_advice.register - @advice_category(AdviceCategory.ALL, AdviceCategory.OPERATORS) - def handle_model_is_not_tflite_compatible( - self, data_item: ModelIsNotTFLiteCompatible - ) -> None: - """Advice for TensorFlow Lite compatibility.""" - if data_item.flex_ops: - self.add_advice( - [ - "The following operators are not natively " - "supported by TensorFlow Lite: " - f"{', '.join(data_item.flex_ops)}.", - "Using select TensorFlow operators in TensorFlow Lite model " - "requires special initialization of TFLiteConverter and " - "TensorFlow Lite run-time.", - "Please refer to the TensorFlow documentation for more " - "details: https://www.tensorflow.org/lite/guide/ops_select", - "Note, such models are not supported by the ML Inference Advisor.", - ] - ) - - if data_item.custom_ops: - self.add_advice( - [ - "The following operators appear to be custom and not natively " - "supported by TensorFlow Lite: " - f"{', '.join(data_item.custom_ops)}.", - "Using custom operators in TensorFlow Lite model " - "requires special initialization of TFLiteConverter and " - "TensorFlow Lite run-time.", - "Please refer to the TensorFlow documentation for more " - "details: https://www.tensorflow.org/lite/guide/ops_custom", - "Note, such models are not supported by the ML Inference Advisor.", - ] - ) - - if not data_item.flex_ops and not data_item.custom_ops: - self.add_advice( - [ - "Model could not be converted into TensorFlow Lite format.", - "Please refer to the table for more details.", - ] - ) - - @produce_advice.register - @advice_category(AdviceCategory.ALL, AdviceCategory.OPERATORS) - def handle_tflite_check_failed( - self, _data_item: TFLiteCompatibilityCheckFailed - ) -> None: - """Advice for the failed TensorFlow Lite compatibility checks.""" - self.add_advice( - [ - "Model could not be converted into TensorFlow Lite format.", - "Please refer to the table for more details.", - ] - ) - - @produce_advice.register - @advice_category(AdviceCategory.ALL, AdviceCategory.OPERATORS) - def handle_model_has_custom_operators( - self, _data_item: ModelHasCustomOperators - ) -> None: - """Advice for the models with custom operators.""" - self.add_advice( - [ - "Models with custom operators require special initialization " - "and currently are not supported by the ML Inference Advisor.", - ] - ) diff --git a/src/mlia/devices/cortexa/advisor.py b/src/mlia/devices/cortexa/advisor.py deleted file mode 100644 index ffbbea5..0000000 --- a/src/mlia/devices/cortexa/advisor.py +++ /dev/null @@ -1,92 +0,0 @@ -# SPDX-FileCopyrightText: Copyright 2022, Arm Limited and/or its affiliates. -# SPDX-License-Identifier: Apache-2.0 -"""Cortex-A MLIA module.""" -from __future__ import annotations - -from pathlib import Path -from typing import Any - -from mlia.core.advice_generation import AdviceProducer -from mlia.core.advisor import DefaultInferenceAdvisor -from mlia.core.advisor import InferenceAdvisor -from mlia.core.common import AdviceCategory -from mlia.core.context import Context -from mlia.core.context import ExecutionContext -from mlia.core.data_analysis import DataAnalyzer -from mlia.core.data_collection import DataCollector -from mlia.core.events import Event -from mlia.core.typing import PathOrFileLike -from mlia.devices.cortexa.advice_generation import CortexAAdviceProducer -from mlia.devices.cortexa.config import CortexAConfiguration -from mlia.devices.cortexa.data_analysis import CortexADataAnalyzer -from mlia.devices.cortexa.data_collection import CortexAOperatorCompatibility -from mlia.devices.cortexa.events import CortexAAdvisorStartedEvent -from mlia.devices.cortexa.handlers import CortexAEventHandler - - -class CortexAInferenceAdvisor(DefaultInferenceAdvisor): - """Cortex-A Inference Advisor.""" - - @classmethod - def name(cls) -> str: - """Return name of the advisor.""" - return "cortex_a_inference_advisor" - - def get_collectors(self, context: Context) -> list[DataCollector]: - """Return list of the data collectors.""" - model = self.get_model(context) - - collectors: list[DataCollector] = [] - - if AdviceCategory.OPERATORS in context.advice_category: - collectors.append(CortexAOperatorCompatibility(model)) - - return collectors - - def get_analyzers(self, context: Context) -> list[DataAnalyzer]: - """Return list of the data analyzers.""" - return [ - CortexADataAnalyzer(), - ] - - def get_producers(self, context: Context) -> list[AdviceProducer]: - """Return list of the advice producers.""" - return [CortexAAdviceProducer()] - - def get_events(self, context: Context) -> list[Event]: - """Return list of the startup events.""" - model = self.get_model(context) - target_profile = self.get_target_profile(context) - - return [ - CortexAAdvisorStartedEvent(model, CortexAConfiguration(target_profile)), - ] - - -def configure_and_get_cortexa_advisor( - context: ExecutionContext, - target_profile: str, - model: str | Path, - output: PathOrFileLike | None = None, - **_extra_args: Any, -) -> InferenceAdvisor: - """Create and configure Cortex-A advisor.""" - if context.event_handlers is None: - context.event_handlers = [CortexAEventHandler(output)] - - if context.config_parameters is None: - context.config_parameters = _get_config_parameters(model, target_profile) - - return CortexAInferenceAdvisor() - - -def _get_config_parameters(model: str | Path, target_profile: str) -> dict[str, Any]: - """Get configuration parameters for the advisor.""" - advisor_parameters: dict[str, Any] = { - "cortex_a_inference_advisor": { - "model": str(model), - "target_profile": target_profile, - }, - } - - return advisor_parameters diff --git a/src/mlia/devices/cortexa/config.py b/src/mlia/devices/cortexa/config.py deleted file mode 100644 index ec0cf0a..0000000 --- a/src/mlia/devices/cortexa/config.py +++ /dev/null @@ -1,20 +0,0 @@ -# SPDX-FileCopyrightText: Copyright 2022, Arm Limited and/or its affiliates. -# SPDX-License-Identifier: Apache-2.0 -"""Cortex-A configuration.""" -from __future__ import annotations - -from mlia.devices.config import IPConfiguration -from mlia.utils.filesystem import get_profile - - -class CortexAConfiguration(IPConfiguration): # pylint: disable=too-few-public-methods - """Cortex-A configuration.""" - - def __init__(self, target_profile: str) -> None: - """Init Cortex-A target configuration.""" - target_data = get_profile(target_profile) - - target = target_data["target"] - if target != "cortex-a": - raise Exception(f"Wrong target {target} for Cortex-A configuration") - super().__init__(target) diff --git a/src/mlia/devices/cortexa/data_analysis.py b/src/mlia/devices/cortexa/data_analysis.py deleted file mode 100644 index 04bc819..0000000 --- a/src/mlia/devices/cortexa/data_analysis.py +++ /dev/null @@ -1,128 +0,0 @@ -# SPDX-FileCopyrightText: Copyright 2022, Arm Limited and/or its affiliates. -# SPDX-License-Identifier: Apache-2.0 -"""Cortex-A data analysis module.""" -from __future__ import annotations - -from collections import defaultdict -from dataclasses import dataclass -from dataclasses import field -from functools import singledispatchmethod - -from mlia.core.common import DataItem -from mlia.core.data_analysis import Fact -from mlia.core.data_analysis import FactExtractor -from mlia.devices.cortexa.operators import CortexACompatibilityInfo -from mlia.devices.cortexa.operators import Operator -from mlia.nn.tensorflow.tflite_compat import TFLiteCompatibilityInfo - - -class CortexADataAnalyzer(FactExtractor): - """Cortex-A data analyzer.""" - - @singledispatchmethod - def analyze_data(self, data_item: DataItem) -> None: # type: ignore - """Analyse the data.""" - - @analyze_data.register - def analyze_operator_compatibility( - self, data_item: CortexACompatibilityInfo - ) -> None: - """Analyse operator compatibility information.""" - if data_item.cortex_a_compatible: - self.add_fact(ModelIsCortexACompatible(data_item.backend_info)) - else: - unsupported_ops = set() - activation_func_support: defaultdict[ - str, ModelIsNotCortexACompatible.ActivationFunctionSupport - ] = defaultdict(ModelIsNotCortexACompatible.ActivationFunctionSupport) - for oper in data_item.operators: - if oper.support_type == Operator.SupportType.OP_NOT_SUPPORTED: - unsupported_ops.add(oper.full_name) - - if oper.support_type == Operator.SupportType.ACTIVATION_NOT_SUPPORTED: - # Add used but unsupported actication functions - activation_func_support[oper.full_name].used_unsupported.add( - oper.activation_func.name - ) - # Add supported activation functions - activation_func_support[oper.full_name].supported.update( - oper.supported_activation_functions - ) - - assert ( - unsupported_ops or activation_func_support or not data_item.operators - ), ( - "The model is marked as not compatible with Cortex-A but there " - "are no unsupported ops activation functions listed." - ) - - self.add_fact( - ModelIsNotCortexACompatible( - data_item.backend_info, unsupported_ops, activation_func_support - ) - ) - - @analyze_data.register - def analyze_tflite_compatibility(self, data_item: TFLiteCompatibilityInfo) -> None: - """Analyze TensorFlow Lite compatibility information.""" - if data_item.compatible: - return - - if data_item.conversion_failed_with_errors: - self.add_fact( - ModelIsNotTFLiteCompatible( - custom_ops=data_item.required_custom_ops, - flex_ops=data_item.required_flex_ops, - ) - ) - - if data_item.check_failed_with_unknown_error: - self.add_fact(TFLiteCompatibilityCheckFailed()) - - if data_item.conversion_failed_for_model_with_custom_ops: - self.add_fact(ModelHasCustomOperators()) - - -@dataclass -class CortexACompatibility(Fact): - """Base class for Cortex-A compatibility providing backend info.""" - - backend_info: str - - -@dataclass -class ModelIsCortexACompatible(CortexACompatibility): - """Model is completely compatible with Cortex-A.""" - - -@dataclass -class ModelIsNotCortexACompatible(CortexACompatibility): - """Model is not compatible with Cortex-A.""" - - @dataclass - class ActivationFunctionSupport: - """Activation function support per operator.""" - - used_unsupported: set[str] = field(default_factory=set) - supported: set[str] = field(default_factory=set) - - unsupported_ops: set[str] - activation_func_support: dict[str, ActivationFunctionSupport] - - -@dataclass -class ModelIsNotTFLiteCompatible(Fact): - """Model could not be converted into TensorFlow Lite format.""" - - custom_ops: list[str] | None = None - flex_ops: list[str] | None = None - - -@dataclass -class TFLiteCompatibilityCheckFailed(Fact): - """TensorFlow Lite compatibility check failed by unknown reason.""" - - -@dataclass -class ModelHasCustomOperators(Fact): - """Model could not be loaded because it contains custom ops.""" diff --git a/src/mlia/devices/cortexa/data_collection.py b/src/mlia/devices/cortexa/data_collection.py deleted file mode 100644 index f4d5a82..0000000 --- a/src/mlia/devices/cortexa/data_collection.py +++ /dev/null @@ -1,51 +0,0 @@ -# SPDX-FileCopyrightText: Copyright 2022, Arm Limited and/or its affiliates. -# SPDX-License-Identifier: Apache-2.0 -"""Data collection module for Cortex-A.""" -from __future__ import annotations - -import logging -from pathlib import Path - -from mlia.core.data_collection import ContextAwareDataCollector -from mlia.devices.cortexa.operators import CortexACompatibilityInfo -from mlia.devices.cortexa.operators import get_cortex_a_compatibility_info -from mlia.nn.tensorflow.config import get_tflite_model -from mlia.nn.tensorflow.tflite_compat import TFLiteChecker -from mlia.nn.tensorflow.tflite_compat import TFLiteCompatibilityInfo -from mlia.nn.tensorflow.utils import is_tflite_model -from mlia.utils.logging import log_action - - -logger = logging.getLogger(__name__) - - -class CortexAOperatorCompatibility(ContextAwareDataCollector): - """Collect operator compatibility information.""" - - def __init__(self, model: Path) -> None: - """Init operator compatibility data collector.""" - self.model = model - - def collect_data(self) -> TFLiteCompatibilityInfo | CortexACompatibilityInfo | None: - """Collect operator compatibility information.""" - if not is_tflite_model(self.model): - with log_action("Checking TensorFlow Lite compatibility ..."): - tflite_checker = TFLiteChecker() - tflite_compat = tflite_checker.check_compatibility(self.model) - - if not tflite_compat.compatible: - return tflite_compat - - tflite_model = get_tflite_model(self.model, self.context) - - with log_action("Checking operator compatibility ..."): - return ( - get_cortex_a_compatibility_info( # pylint: disable=assignment-from-none - Path(tflite_model.model_path) - ) - ) - - @classmethod - def name(cls) -> str: - """Return name of the collector.""" - return "cortex_a_operator_compatibility" diff --git a/src/mlia/devices/cortexa/events.py b/src/mlia/devices/cortexa/events.py deleted file mode 100644 index dece4c7..0000000 --- a/src/mlia/devices/cortexa/events.py +++ /dev/null @@ -1,24 +0,0 @@ -# SPDX-FileCopyrightText: Copyright 2022, Arm Limited and/or its affiliates. -# SPDX-License-Identifier: Apache-2.0 -"""Cortex-A MLIA module events.""" -from dataclasses import dataclass -from pathlib import Path - -from mlia.core.events import Event -from mlia.core.events import EventDispatcher -from mlia.devices.cortexa.config import CortexAConfiguration - - -@dataclass -class CortexAAdvisorStartedEvent(Event): - """Event with Cortex-A advisor parameters.""" - - model: Path - device: CortexAConfiguration - - -class CortexAAdvisorEventHandler(EventDispatcher): - """Event handler for the Cortex-A inference advisor.""" - - def on_cortex_a_advisor_started(self, event: CortexAAdvisorStartedEvent) -> None: - """Handle CortexAAdvisorStarted event.""" diff --git a/src/mlia/devices/cortexa/handlers.py b/src/mlia/devices/cortexa/handlers.py deleted file mode 100644 index 7ed2b75..0000000 --- a/src/mlia/devices/cortexa/handlers.py +++ /dev/null @@ -1,39 +0,0 @@ -# SPDX-FileCopyrightText: Copyright 2022, Arm Limited and/or its affiliates. -# SPDX-License-Identifier: Apache-2.0 -"""Event handler.""" -from __future__ import annotations - -import logging - -from mlia.core.events import CollectedDataEvent -from mlia.core.handlers import WorkflowEventsHandler -from mlia.core.typing import PathOrFileLike -from mlia.devices.cortexa.events import CortexAAdvisorEventHandler -from mlia.devices.cortexa.events import CortexAAdvisorStartedEvent -from mlia.devices.cortexa.operators import CortexACompatibilityInfo -from mlia.devices.cortexa.reporters import cortex_a_formatters -from mlia.nn.tensorflow.tflite_compat import TFLiteCompatibilityInfo - -logger = logging.getLogger(__name__) - - -class CortexAEventHandler(WorkflowEventsHandler, CortexAAdvisorEventHandler): - """CLI event handler.""" - - def __init__(self, output: PathOrFileLike | None = None) -> None: - """Init event handler.""" - super().__init__(cortex_a_formatters, output) - - def on_collected_data(self, event: CollectedDataEvent) -> None: - """Handle CollectedDataEvent event.""" - data_item = event.data_item - - if isinstance(data_item, CortexACompatibilityInfo): - self.reporter.submit(data_item.operators, delay_print=True) - - if isinstance(data_item, TFLiteCompatibilityInfo) and not data_item.compatible: - self.reporter.submit(data_item, delay_print=True) - - def on_cortex_a_advisor_started(self, event: CortexAAdvisorStartedEvent) -> None: - """Handle CortexAAdvisorStarted event.""" - self.reporter.submit(event.device) diff --git a/src/mlia/devices/cortexa/operator_compatibility.py b/src/mlia/devices/cortexa/operator_compatibility.py deleted file mode 100644 index c474e75..0000000 --- a/src/mlia/devices/cortexa/operator_compatibility.py +++ /dev/null @@ -1,184 +0,0 @@ -# SPDX-FileCopyrightText: Copyright 2022, Arm Limited and/or its affiliates. -# SPDX-License-Identifier: Apache-2.0 -"""Collection of Cortex-A operator compatibility information.""" -from __future__ import annotations - -from typing import Any - -ARMNN_TFLITE_DELEGATE: dict[str, dict[str, Any]] = { - "metadata": { - "backend": "Arm NN TensorFlow Lite delegate", - "version": "22.08", - }, - # BUILTIN OPERATORS - "builtin_ops": { - "ABS": {}, - "ADD": {}, - "ARG_MAX": {}, - "ARG_MIN": {}, - "AVERAGE_POOL_2D": { - "supported_fused_activation": [ - "RELU", - "RELU6", - "RELU_N1_TO_1", - "SIGMOID", - "TANH", - "NONE", - ] - }, - "BATCH_TO_SPACE_ND": {}, - "CAST": {}, - "CONCATENATION": { - "supported_fused_activation": [ - "RELU", - "RELU6", - "RELU_N1_TO_1", - "SIGMOID", - "TANH", - "NONE", - ] - }, - "CONV_2D": { - "supported_fused_activation": [ - "RELU", - "RELU6", - "RELU_N1_TO_1", - "SIGMOID", - "TANH", - "NONE", - ] - }, - "CONV_3D": { - "supported_fused_activation": [ - "RELU", - "RELU6", - "RELU_N1_TO_1", - "SIGMOID", - "TANH", - "NONE", - ] - }, - "DEPTH_TO_SPACE": {}, - "DEPTHWISE_CONV_2D": { - "supported_fused_activation": [ - "RELU", - "RELU6", - "RELU_N1_TO_1", - "SIGMOID", - "TANH", - "NONE", - ] - }, - "DEQUANTIZE": {}, - "DIV": {}, - "EQUAL": {}, - "ELU": {}, - "EXP": {}, - "EXPAND_DIMS": {}, - "FILL": {}, - "FLOOR": {}, - "FLOOR_DIV": {}, - "FULLY_CONNECTED": { - "supported_fused_activation": [ - "RELU", - "RELU6", - "RELU_N1_TO_1", - "SIGMOID", - "TANH", - "NONE", - ] - }, - "GATHER": {}, - "GATHER_ND": {}, - "GREATER": {}, - "GREATER_EQUAL": {}, - "HARD_SWISH": {}, - "L2_NORMALIZATION": {}, - "L2_POOL_2D": {}, - "LESS": {}, - "LESS_EQUAL": {}, - "LOCAL_RESPONSE_NORMALIZATION": {}, - "LOG": {}, - "LOGICAL_AND": {}, - "LOGICAL_NOT": {}, - "LOGICAL_OR": {}, - "LOGISTIC": {}, - "LOG_SOFTMAX": {}, - "LSTM": {}, - "MAXIMUM": {}, - "MAX_POOL_2D": { - "supported_fused_activation": [ - "RELU", - "RELU6", - "RELU_N1_TO_1", - "SIGMOID", - "TANH", - "NONE", - ] - }, - "MEAN": {}, - "MINIMUM": {}, - "MIRROR_PAD": {}, - "MUL": {}, - "NEG": {}, - "NOT_EQUAL": {}, - "PACK": {}, - "PAD": {}, - "PADV2": {}, - "PRELU": {}, - "QUANTIZE": {}, - "RANK": {}, - "REDUCE_MAX": {}, - "REDUCE_MIN": {}, - "REDUCE_PROD": {}, - "RELU": {}, - "RELU6": {}, - "RELU_N1_TO_1": {}, - "RESHAPE": {}, - "RESIZE_BILINEAR": {}, - "RESIZE_NEAREST_NEIGHBOR": {}, - "RSQRT": {}, - "SHAPE": {}, - "SIN": {}, - "SOFTMAX": {}, - "SPACE_TO_BATCH_ND": {}, - "SPACE_TO_DEPTH": {}, - "SPLIT": {}, - "SPLIT_V": {}, - "SQRT": {}, - "SQUEEZE": {}, - "STRIDED_SLICE": {}, - "SUB": {}, - "SUM": {}, - "TANH": {}, - "TRANSPOSE": {}, - "TRANSPOSE_CONV": {}, - "UNIDIRECTIONAL_SEQUENCE_LSTM": {}, - "UNPACK": {}, - }, - # CUSTOM OPERATORS - "custom_ops": { - "AveragePool3D": { - "supported_fused_activation": [ - "RELU", - "RELU6", - "RELU_N1_TO_1", - "SIGMOID", - "SIGN_BIT", - "TANH", - "NONE", - ] - }, - "MaxPool3D": { - "supported_fused_activation": [ - "RELU", - "RELU6", - "RELU_N1_TO_1", - "SIGMOID", - "SIGN_BIT", - "TANH", - "NONE", - ] - }, - }, -} diff --git a/src/mlia/devices/cortexa/operators.py b/src/mlia/devices/cortexa/operators.py deleted file mode 100644 index 3e84d64..0000000 --- a/src/mlia/devices/cortexa/operators.py +++ /dev/null @@ -1,148 +0,0 @@ -# SPDX-FileCopyrightText: Copyright 2022, Arm Limited and/or its affiliates. -# SPDX-License-Identifier: Apache-2.0 -"""Cortex-A tools module.""" -from __future__ import annotations - -from dataclasses import dataclass -from enum import Enum -from pathlib import Path -from typing import Any -from typing import ClassVar - -from mlia.devices.cortexa.operator_compatibility import ( - ARMNN_TFLITE_DELEGATE as TFLITE_DELEGATE_COMPAT, -) -from mlia.nn.tensorflow.tflite_graph import Op -from mlia.nn.tensorflow.tflite_graph import parse_subgraphs -from mlia.nn.tensorflow.tflite_graph import TFL_ACTIVATION_FUNCTION - - -@dataclass -class Operator: - """Cortex-A compatibility information of the operator.""" - - BUILTIN_COMPATIBILITY = TFLITE_DELEGATE_COMPAT["builtin_ops"] - CUSTOM_COMPATIBILITY = TFLITE_DELEGATE_COMPAT["custom_ops"] - - class SupportType(Enum): - """Type of operator support.""" - - COMPATIBLE = "Compatible" - OP_NOT_SUPPORTED = "Operator not supported" - ACTIVATION_NOT_SUPPORTED = "Activation not supported" - - name: str - location: str - support_type: SupportType - activation_func: TFL_ACTIVATION_FUNCTION - custom_name: str | None = None - - @property - def is_cortex_a_compatible(self) -> bool: - """Check if this operator is compatible.""" - return self.support_type == Operator.SupportType.COMPATIBLE - - @property - def full_name(self) -> str: - """Returun the full name including the custom name if applicable.""" - return self.name + (f" - '{self.custom_name}'" if self.custom_name else "") - - @property - def is_custom(self) -> bool: - """Check if this is a custom operator.""" - return bool(self.custom_name) - - @property - def compatibility_data(self) -> dict[str, dict[str, Any]]: - """Get the compatibility data (builtin or custom ops).""" - return ( - Operator.CUSTOM_COMPATIBILITY - if self.is_custom - else Operator.BUILTIN_COMPATIBILITY - ) - - @property - def supported_activation_functions(self) -> list[str]: - """Return a list of fused activation functions supported by this op.""" - op_name = self.custom_name if self.custom_name else self.name - return self.compatibility_data[op_name].get("supported_fused_activation", []) - - @classmethod - def from_tflite_op(cls, tfl_op: Op, location: str) -> Operator: - """Create a new instance from TensorFlow Lite operator and location.""" - support_type = cls._get_support_type(tfl_op) - activation_func = ( - tfl_op.builtin_options["fused_activation_function"] - if ( - tfl_op.builtin_options - and "fused_activation_function" in tfl_op.builtin_options - ) - else TFL_ACTIVATION_FUNCTION.NONE - ) - return Operator( - tfl_op.type, - location, - support_type, - activation_func=activation_func, - custom_name=(tfl_op.custom_type if tfl_op.is_custom else None), - ) - - @staticmethod - def _get_support_type(tfl_op: Op) -> Operator.SupportType: - """Get the support type from the TensorFlow Lite operator.""" - compat_data = ( - Operator.CUSTOM_COMPATIBILITY - if tfl_op.is_custom - else Operator.BUILTIN_COMPATIBILITY - ) - op_type = tfl_op.custom_type if tfl_op.is_custom else tfl_op.type - - if op_type not in compat_data: - return Operator.SupportType.OP_NOT_SUPPORTED - - compat_op = compat_data[op_type] - if "supported_fused_activation" in compat_op: - assert tfl_op.builtin_options - assert "fused_activation_function" in tfl_op.builtin_options - if ( - tfl_op.builtin_options["fused_activation_function"] - not in compat_op["supported_fused_activation"] - ): - return Operator.SupportType.ACTIVATION_NOT_SUPPORTED - - return Operator.SupportType.COMPATIBLE - - -@dataclass -class CortexACompatibilityInfo: - """Model's operators.""" - - cortex_a_compatible: bool - operators: list[Operator] - backend_info: ClassVar[str] = ( - f"{TFLITE_DELEGATE_COMPAT['metadata']['backend']} " - f"{TFLITE_DELEGATE_COMPAT['metadata']['version']}" - ) - - -def get_cortex_a_compatibility_info(model_path: Path) -> CortexACompatibilityInfo: - """Return list of model's operators.""" - model = parse_subgraphs(model_path) - - op_list = [ - Operator.from_tflite_op(oper, f"subgraph:{g_idx},oper:{op_idx}") - for g_idx, g in enumerate(model) - for op_idx, oper in enumerate(g) - ] - all_compatible = all(oper.is_cortex_a_compatible for oper in op_list) - compat_info = CortexACompatibilityInfo(all_compatible, op_list) - - return compat_info - - -def report() -> None: - """Generate supported operators report.""" - raise Exception( - "Generating a supported operators report is not " - "currently supported with Cortex-A target profile." - ) diff --git a/src/mlia/devices/cortexa/reporters.py b/src/mlia/devices/cortexa/reporters.py deleted file mode 100644 index 84de10b..0000000 --- a/src/mlia/devices/cortexa/reporters.py +++ /dev/null @@ -1,140 +0,0 @@ -# SPDX-FileCopyrightText: Copyright 2022, Arm Limited and/or its affiliates. -# SPDX-License-Identifier: Apache-2.0 -"""Reports module.""" -from __future__ import annotations - -from typing import Any -from typing import Callable -from typing import cast - -from mlia.core.advice_generation import Advice -from mlia.core.reporters import report_advice -from mlia.core.reporting import Cell -from mlia.core.reporting import Column -from mlia.core.reporting import Format -from mlia.core.reporting import NestedReport -from mlia.core.reporting import Report -from mlia.core.reporting import ReportItem -from mlia.core.reporting import Table -from mlia.devices.cortexa.config import CortexAConfiguration -from mlia.devices.cortexa.operators import Operator -from mlia.nn.tensorflow.tflite_compat import TFLiteCompatibilityInfo -from mlia.utils.console import style_improvement -from mlia.utils.types import is_list_of - - -def report_device(device: CortexAConfiguration) -> Report: - """Generate report for the device.""" - return NestedReport( - "Device information", - "device", - [ - ReportItem("Target", alias="target", value=device.target), - ], - ) - - -def report_tflite_compatiblity(compat_info: TFLiteCompatibilityInfo) -> Report: - """Generate report for the TensorFlow Lite compatibility information.""" - if compat_info.conversion_errors: - return Table( - [ - Column("#", only_for=["plain_text"]), - Column("Operator", alias="operator"), - Column( - "Operator location", - alias="operator_location", - fmt=Format(wrap_width=25), - ), - Column("Error code", alias="error_code"), - Column( - "Error message", alias="error_message", fmt=Format(wrap_width=25) - ), - ], - [ - ( - index + 1, - err.operator, - ", ".join(err.location), - err.code.name, - err.message, - ) - for index, err in enumerate(compat_info.conversion_errors) - ], - name="TensorFlow Lite conversion errors", - alias="tensorflow_lite_conversion_errors", - ) - - return Table( - columns=[ - Column("Reason", alias="reason"), - Column( - "Exception details", - alias="exception_details", - fmt=Format(wrap_width=40), - ), - ], - rows=[ - ( - "TensorFlow Lite compatibility check failed with exception", - str(compat_info.conversion_exception), - ), - ], - name="TensorFlow Lite compatibility errors", - alias="tflite_compatibility", - ) - - -def report_cortex_a_operators(ops: list[Operator]) -> Report: - """Generate report for the operators.""" - return Table( - [ - Column("#", only_for=["plain_text"]), - Column( - "Operator location", - alias="operator_location", - fmt=Format(wrap_width=30), - ), - Column("Operator name", alias="operator_name", fmt=Format(wrap_width=20)), - Column( - "Arm NN TFLite Delegate compatibility", - alias="cortex_a_compatible", - fmt=Format(wrap_width=40), - ), - ], - [ - ( - index + 1, - op.location, - op.full_name, - Cell( - op.support_type, - Format( - wrap_width=30, - style=style_improvement(op.is_cortex_a_compatible), - str_fmt=lambda v: cast(str, v.value), - ), - ), - ) - for index, op in enumerate(ops) - ], - name="Operators", - alias="operators", - ) - - -def cortex_a_formatters(data: Any) -> Callable[[Any], Report]: - """Find appropriate formatter for the provided data.""" - if is_list_of(data, Advice): - return report_advice - - if isinstance(data, CortexAConfiguration): - return report_device - - if isinstance(data, TFLiteCompatibilityInfo): - return report_tflite_compatiblity - - if is_list_of(data, Operator): - return report_cortex_a_operators - - raise Exception(f"Unable to find appropriate formatter for {data}") |