From b125f96465e4081d5a24e2bc8865a3636627f5f6 Mon Sep 17 00:00:00 2001 From: Lior Dikstein <78903511+lior-dikstein@users.noreply.github.com> Date: Sun, 22 Dec 2024 15:58:48 +0200 Subject: [PATCH] Refactor Target Platform Capabilities - Phase 3 (#1297) * Refactor Target Platform Capabilities - Phase 3 Remove context manager functionality from the Target Platform Model. Fix all tests and TP models. --------- Co-authored-by: liord Co-authored-by: Ofir Gordon --- .../core/common/graph/base_graph.py | 2 +- .../core/common/graph/base_node.py | 6 +- .../set_node_quantization_config.py | 8 +- .../shift_negative_activation.py | 4 +- .../schema/mct_current_schema.py | 1 + .../schema/schema_functions.py | 9 +- .../target_platform_capabilities/schema/v1.py | 233 +++++------------- .../target_platform/__init__.py | 1 - .../target_platform/current_tp_model.py | 67 ----- .../target_platform/target_platform_model.py | 30 --- .../operations_to_layers.py | 2 +- .../target_platform_capabilities.py | 11 +- .../tpc_models/imx500_tpc/v1/tp_model.py | 101 ++++---- .../tpc_models/imx500_tpc/v1_lut/tp_model.py | 106 ++++---- .../tpc_models/imx500_tpc/v1_pot/tp_model.py | 110 +++++---- .../tpc_models/imx500_tpc/v2/tp_model.py | 103 ++++---- .../tpc_models/imx500_tpc/v2_lut/tp_model.py | 104 ++++---- .../tpc_models/imx500_tpc/v3/tp_model.py | 116 ++++----- .../tpc_models/imx500_tpc/v3_lut/tp_model.py | 106 ++++---- .../tpc_models/imx500_tpc/v4/tp_model.py | 173 ++++++------- .../tpc_models/qnnpack_tpc/v1/tp_model.py | 50 ++-- .../tpc_models/tflite_tpc/v1/tp_model.py | 112 ++++----- .../helpers/generate_test_tp_model.py | 46 ++-- tests/common_tests/test_tp_model.py | 170 +++++++------ .../tflite_int8/imx500_int8_tp_model.py | 68 ++--- .../feature_networks/activation_16bit_test.py | 13 +- .../bn_attributes_quantization_test.py | 12 +- .../const_quantization_test.py | 4 +- .../feature_networks/manual_bit_selection.py | 14 +- .../feature_networks/mixed_precision_tests.py | 16 +- .../weights_mixed_precision_tests.py | 29 +-- .../function_tests/test_custom_layer.py | 13 +- .../function_tests/test_hmse_error_method.py | 8 +- .../function_tests/test_layer_fusing.py | 98 +++++--- .../test_quant_config_filtering.py | 2 +- .../non_parallel_tests/test_keras_tp_model.py | 99 ++++---- .../function_tests/layer_fusing_test.py | 117 +++++---- .../function_tests/test_pytorch_tp_model.py | 108 ++++---- .../test_quant_config_filtering.py | 2 +- .../feature_models/activation_16bit_test.py | 18 +- .../bn_attributes_quantization_test.py | 12 +- .../feature_models/const_quantization_test.py | 7 +- .../feature_models/manual_bit_selection.py | 20 +- .../mixed_precision_activation_test.py | 17 +- .../mixed_precision_weights_test.py | 31 ++- 45 files changed, 1115 insertions(+), 1264 deletions(-) delete mode 100644 model_compression_toolkit/target_platform_capabilities/target_platform/current_tp_model.py delete mode 100644 model_compression_toolkit/target_platform_capabilities/target_platform/target_platform_model.py diff --git a/model_compression_toolkit/core/common/graph/base_graph.py b/model_compression_toolkit/core/common/graph/base_graph.py index 2266afa74..432a81f39 100644 --- a/model_compression_toolkit/core/common/graph/base_graph.py +++ b/model_compression_toolkit/core/common/graph/base_graph.py @@ -105,7 +105,7 @@ def set_tpc(self, Logger.critical(f'MCT does not support optimizing Keras custom layers. Found a layer of type {n.type}. ' ' Please add the custom layer to Target Platform Capabilities (TPC), or file a feature ' 'request or an issue if you believe this should be supported.') # pragma: no cover - if any([qc.default_weight_attr_config.enable_weights_quantization for qc in n.get_qco(tpc).quantization_config_list]): + if any([qc.default_weight_attr_config.enable_weights_quantization for qc in n.get_qco(tpc).quantization_configurations]): Logger.critical(f'Layer identified: {n.type}. MCT does not support weight quantization for Keras custom layers.') # pragma: no cover self.tpc = tpc diff --git a/model_compression_toolkit/core/common/graph/base_node.py b/model_compression_toolkit/core/common/graph/base_node.py index 90429b761..67c4f2f57 100644 --- a/model_compression_toolkit/core/common/graph/base_node.py +++ b/model_compression_toolkit/core/common/graph/base_node.py @@ -582,12 +582,12 @@ def filter_node_qco_by_graph(self, tpc: TargetPlatformCapabilities, """ # Filter quantization config options that don't match the graph. _base_config = node_qc_options.base_config - _node_qc_options = node_qc_options.quantization_config_list + _node_qc_options = node_qc_options.quantization_configurations if len(next_nodes): next_nodes_qc_options = [_node.get_qco(tpc) for _node in next_nodes] next_nodes_supported_input_bitwidth = min([max_input_activation_n_bits(op_cfg) for qc_opts in next_nodes_qc_options - for op_cfg in qc_opts.quantization_config_list]) + for op_cfg in qc_opts.quantization_configurations]) # Filter node's QC options that match next nodes input bit-width. _node_qc_options = [_option for _option in _node_qc_options @@ -599,7 +599,7 @@ def filter_node_qco_by_graph(self, tpc: TargetPlatformCapabilities, if any([node_qc_options.base_config.activation_n_bits > max_input_activation_n_bits(qc_opt.base_config) for qc_opt in next_nodes_qc_options]): # base_config activation bits doesn't match next node supported input bit-width -> replace with - # a qco from quantization_config_list with maximum activation bit-width. + # a qco from quantization_configurations with maximum activation bit-width. if len(_node_qc_options) > 0: output_act_bitwidth = {qco.activation_n_bits: i for i, qco in enumerate(_node_qc_options)} _base_config = _node_qc_options[output_act_bitwidth[max(output_act_bitwidth)]] diff --git a/model_compression_toolkit/core/common/quantization/set_node_quantization_config.py b/model_compression_toolkit/core/common/quantization/set_node_quantization_config.py index 5d4d18441..93045cdd6 100644 --- a/model_compression_toolkit/core/common/quantization/set_node_quantization_config.py +++ b/model_compression_toolkit/core/common/quantization/set_node_quantization_config.py @@ -101,7 +101,7 @@ def filter_node_qco_by_graph(node: BaseNode, """ # Filter quantization config options that don't match the graph. _base_config = node_qc_options.base_config - _node_qc_options = node_qc_options.quantization_config_list + _node_qc_options = node_qc_options.quantization_configurations # Build next_nodes list by appending to the node's next nodes list all nodes that are quantization preserving. _next_nodes = graph.get_next_nodes(node) @@ -109,7 +109,7 @@ def filter_node_qco_by_graph(node: BaseNode, while len(_next_nodes): n = _next_nodes.pop(0) qco = n.get_qco(tpc) - qp = [qc.quantization_preserving for qc in qco.quantization_config_list] + qp = [qc.quantization_preserving for qc in qco.quantization_configurations] if not all(qp) and any(qp): Logger.error(f'Attribute "quantization_preserving" should be the same for all QuantizaionConfigOptions in {n}.') if qp[0]: @@ -120,7 +120,7 @@ def filter_node_qco_by_graph(node: BaseNode, next_nodes_qc_options = [_node.get_qco(tpc) for _node in next_nodes] next_nodes_supported_input_bitwidth = min([max_input_activation_n_bits(op_cfg) for qc_opts in next_nodes_qc_options - for op_cfg in qc_opts.quantization_config_list]) + for op_cfg in qc_opts.quantization_configurations]) # Filter node's QC options that match next nodes input bit-width. _node_qc_options = [_option for _option in _node_qc_options @@ -132,7 +132,7 @@ def filter_node_qco_by_graph(node: BaseNode, if any([node_qc_options.base_config.activation_n_bits > max_input_activation_n_bits(qc_opt.base_config) for qc_opt in next_nodes_qc_options]): # base_config activation bits doesn't match next node supported input bit-width -> replace with - # a qco from quantization_config_list with maximum activation bit-width. + # a qco from quantization_configurations with maximum activation bit-width. if len(_node_qc_options) > 0: output_act_bitwidth = {qco.activation_n_bits: i for i, qco in enumerate(_node_qc_options)} _base_config = _node_qc_options[output_act_bitwidth[max(output_act_bitwidth)]] diff --git a/model_compression_toolkit/core/common/substitutions/shift_negative_activation.py b/model_compression_toolkit/core/common/substitutions/shift_negative_activation.py index 73e216885..a04906b30 100644 --- a/model_compression_toolkit/core/common/substitutions/shift_negative_activation.py +++ b/model_compression_toolkit/core/common/substitutions/shift_negative_activation.py @@ -392,7 +392,7 @@ def shift_negative_function(graph: Graph, bypass_candidate_qc.activation_quantization_cfg.activation_quantization_params[SIGNED] = False graph.shift_stats_collector(bypass_node, np.array(shift_value)) - add_node_qco = add_node.get_qco(graph.tpc).quantization_config_list + add_node_qco = add_node.get_qco(graph.tpc).quantization_configurations for op_qc_idx, candidate_qc in enumerate(add_node.candidates_quantization_cfg): for attr in add_node.get_node_weights_attributes(): candidate_qc.weights_quantization_cfg.get_attr_config(attr).enable_weights_quantization = False @@ -535,7 +535,7 @@ def apply_shift_negative_correction(graph: Graph, # Skip substitution if QuantizationMethod is uniform. node_qco = n.get_qco(graph.tpc) if any([op_qc.activation_quantization_method is QuantizationMethod.UNIFORM - for op_qc in node_qco.quantization_config_list]): + for op_qc in node_qco.quantization_configurations]): continue if snc_node_types.apply(n): diff --git a/model_compression_toolkit/target_platform_capabilities/schema/mct_current_schema.py b/model_compression_toolkit/target_platform_capabilities/schema/mct_current_schema.py index ee6c85ea1..80bf1ce5e 100644 --- a/model_compression_toolkit/target_platform_capabilities/schema/mct_current_schema.py +++ b/model_compression_toolkit/target_platform_capabilities/schema/mct_current_schema.py @@ -1,5 +1,6 @@ import model_compression_toolkit.target_platform_capabilities.schema.v1 as schema +OperatorSetNames = schema.OperatorSetNames Signedness = schema.Signedness AttributeQuantizationConfig = schema.AttributeQuantizationConfig OpQuantizationConfig = schema.OpQuantizationConfig diff --git a/model_compression_toolkit/target_platform_capabilities/schema/schema_functions.py b/model_compression_toolkit/target_platform_capabilities/schema/schema_functions.py index 84633abb3..36b2001a9 100644 --- a/model_compression_toolkit/target_platform_capabilities/schema/schema_functions.py +++ b/model_compression_toolkit/target_platform_capabilities/schema/schema_functions.py @@ -64,10 +64,10 @@ def get_default_op_quantization_config(tp_model: TargetPlatformModel) -> OpQuant Raises: AssertionError: If the default quantization configuration list contains more than one configuration option. """ - assert len(tp_model.default_qco.quantization_config_list) == 1, \ + assert len(tp_model.default_qco.quantization_configurations) == 1, \ f"Default quantization configuration options must contain only one option, " \ - f"but found {len(tp_model.default_qco.quantization_config_list)} configurations." # pragma: no cover - return tp_model.default_qco.quantization_config_list[0] + f"but found {len(tp_model.default_qco.quantization_configurations)} configurations." # pragma: no cover + return tp_model.default_qco.quantization_configurations[0] def is_opset_in_model(tp_model: TargetPlatformModel, opset_name: str) -> bool: @@ -82,8 +82,7 @@ def is_opset_in_model(tp_model: TargetPlatformModel, opset_name: str) -> bool: bool: True if an OperatorsSet with the given name exists in the target platform model, otherwise False. """ - return opset_name in [x.name for x in tp_model.operator_set] - + return tp_model.operator_set is not None and opset_name in [x.name for x in tp_model.operator_set] def get_opset_by_name(tp_model: TargetPlatformModel, opset_name: str) -> Optional[OperatorsSetBase]: """ diff --git a/model_compression_toolkit/target_platform_capabilities/schema/v1.py b/model_compression_toolkit/target_platform_capabilities/schema/v1.py index 4353a7d98..29dc647f9 100644 --- a/model_compression_toolkit/target_platform_capabilities/schema/v1.py +++ b/model_compression_toolkit/target_platform_capabilities/schema/v1.py @@ -21,8 +21,6 @@ from model_compression_toolkit.constants import FLOAT_BITWIDTH from model_compression_toolkit.logger import Logger from model_compression_toolkit.target_platform_capabilities.constants import OPS_SET_LIST -from model_compression_toolkit.target_platform_capabilities.target_platform.current_tp_model import \ - _current_tp_model class OperatorSetNames(Enum): OPSET_CONV = "Conv" @@ -61,7 +59,6 @@ class OperatorSetNames(Enum): OPSET_DROPOUT = "Dropout" OPSET_SPLIT = "Split" OPSET_CHUNK = "Chunk" - OPSET_UNBIND = "Unbind" OPSET_MAXPOOL = "MaxPool" OPSET_SIZE = "Size" OPSET_SHAPE = "Shape" @@ -74,6 +71,7 @@ class OperatorSetNames(Enum): OPSET_ZERO_PADDING2d = "ZeroPadding2D" OPSET_CAST = "Cast" OPSET_STRIDED_SLICE = "StridedSlice" + OPSET_SSD_POST_PROCESS = "SSDPostProcess" @classmethod def get_values(cls): @@ -225,10 +223,10 @@ class QuantizationConfigOptions: QuantizationConfigOptions wraps a set of quantization configurations to consider during the quantization of an operator. Attributes: - quantization_config_list (List[OpQuantizationConfig]): List of possible OpQuantizationConfig to gather. + quantization_configurations (Tuple[OpQuantizationConfig]): Tuple of possible OpQuantizationConfig to gather. base_config (Optional[OpQuantizationConfig]): Fallback OpQuantizationConfig to use when optimizing the model in a non-mixed-precision manner. """ - quantization_config_list: List[OpQuantizationConfig] + quantization_configurations: Tuple[OpQuantizationConfig] base_config: Optional[OpQuantizationConfig] = None def __post_init__(self): @@ -236,32 +234,32 @@ def __post_init__(self): Post-initialization processing for input validation. Raises: - Logger critical if quantization_config_list is not a list, contains invalid elements, or if base_config is not set correctly. + Logger critical if quantization_configurations is not a tuple, contains invalid elements, or if base_config is not set correctly. """ - # Validate `quantization_config_list` - if not isinstance(self.quantization_config_list, list): + # Validate `quantization_configurations` + if not isinstance(self.quantization_configurations, tuple): Logger.critical( - f"'quantization_config_list' must be a list, but received: {type(self.quantization_config_list)}.") # pragma: no cover - for cfg in self.quantization_config_list: + f"'quantization_configurations' must be a tuple, but received: {type(self.quantization_configurations)}.") # pragma: no cover + for cfg in self.quantization_configurations: if not isinstance(cfg, OpQuantizationConfig): Logger.critical( f"Each option must be an instance of 'OpQuantizationConfig', but found an object of type: {type(cfg)}.") # pragma: no cover # Handle base_config - if len(self.quantization_config_list) > 1: + if len(self.quantization_configurations) > 1: if self.base_config is None: Logger.critical(f"For multiple configurations, a 'base_config' is required for non-mixed-precision optimization.") # pragma: no cover - if not any(self.base_config == cfg for cfg in self.quantization_config_list): - Logger.critical(f"'base_config' must be included in the quantization config options list.") # pragma: no cover - elif len(self.quantization_config_list) == 1: + if not any(self.base_config == cfg for cfg in self.quantization_configurations): + Logger.critical(f"'base_config' must be included in the quantization config options.") # pragma: no cover + elif len(self.quantization_configurations) == 1: if self.base_config is None: - object.__setattr__(self, 'base_config', self.quantization_config_list[0]) - elif self.base_config != self.quantization_config_list[0]: + object.__setattr__(self, 'base_config', self.quantization_configurations[0]) + elif self.base_config != self.quantization_configurations[0]: Logger.critical( - "'base_config' should be the same as the sole item in 'quantization_config_list'.") # pragma: no cover + "'base_config' should be the same as the sole item in 'quantization_configurations'.") # pragma: no cover - elif len(self.quantization_config_list) == 0: - Logger.critical("'QuantizationConfigOptions' requires at least one 'OpQuantizationConfig'. The provided list is empty.") # pragma: no cover + elif len(self.quantization_configurations) == 0: + Logger.critical("'QuantizationConfigOptions' requires at least one 'OpQuantizationConfig'. The provided configurations is empty.") # pragma: no cover def clone_and_edit(self, **kwargs) -> 'QuantizationConfigOptions': """ @@ -274,10 +272,10 @@ def clone_and_edit(self, **kwargs) -> 'QuantizationConfigOptions': A new instance of QuantizationConfigOptions with updated configurations. """ updated_base_config = replace(self.base_config, **kwargs) - updated_configs_list = [ - replace(cfg, **kwargs) for cfg in self.quantization_config_list + updated_configs = [ + replace(cfg, **kwargs) for cfg in self.quantization_configurations ] - return replace(self, base_config=updated_base_config, quantization_config_list=updated_configs_list) + return replace(self, base_config=updated_base_config, quantization_configurations=tuple(updated_configs)) def clone_and_edit_weight_attribute(self, attrs: List[str] = None, **kwargs) -> 'QuantizationConfigOptions': """ @@ -292,7 +290,7 @@ def clone_and_edit_weight_attribute(self, attrs: List[str] = None, **kwargs) -> """ updated_base_config = self.base_config updated_configs = [] - for qc in self.quantization_config_list: + for qc in self.quantization_configurations: if attrs is None: attrs_to_update = list(qc.attr_weights_configs_mapping.keys()) else: @@ -300,7 +298,7 @@ def clone_and_edit_weight_attribute(self, attrs: List[str] = None, **kwargs) -> # Ensure all attributes exist in the config for attr in attrs_to_update: if attr not in qc.attr_weights_configs_mapping: - Logger.critical(f"{attr} does not exist in {qc}.") + Logger.critical(f"{attr} does not exist in {qc}.") # pragma: no cover updated_attr_mapping = { attr: qc.attr_weights_configs_mapping[attr].clone_and_edit(**kwargs) for attr in attrs_to_update @@ -308,7 +306,7 @@ def clone_and_edit_weight_attribute(self, attrs: List[str] = None, **kwargs) -> if qc == updated_base_config: updated_base_config = replace(updated_base_config, attr_weights_configs_mapping=updated_attr_mapping) updated_configs.append(replace(qc, attr_weights_configs_mapping=updated_attr_mapping)) - return replace(self, base_config=updated_base_config, quantization_config_list=updated_configs) + return replace(self, base_config=updated_base_config, quantization_configurations=tuple(updated_configs)) def clone_and_map_weights_attr_keys(self, layer_attrs_mapping: Optional[Dict[str, str]]) -> 'QuantizationConfigOptions': """ @@ -322,7 +320,7 @@ def clone_and_map_weights_attr_keys(self, layer_attrs_mapping: Optional[Dict[str """ updated_configs = [] new_base_config = self.base_config - for qc in self.quantization_config_list: + for qc in self.quantization_configurations: if layer_attrs_mapping is None: new_attr_mapping = {} else: @@ -333,7 +331,7 @@ def clone_and_map_weights_attr_keys(self, layer_attrs_mapping: Optional[Dict[str if qc == self.base_config: new_base_config = replace(qc, attr_weights_configs_mapping=new_attr_mapping) updated_configs.append(replace(qc, attr_weights_configs_mapping=new_attr_mapping)) - return replace(self, base_config=new_base_config, quantization_config_list=updated_configs) + return replace(self, base_config=new_base_config, quantization_configurations=tuple(updated_configs)) def get_info(self) -> Dict[str, Any]: """ @@ -342,7 +340,7 @@ def get_info(self) -> Dict[str, Any]: Returns: dict: Information about the quantization configuration options as a dictionary. """ - return {f'option {i}': cfg.get_info() for i, cfg in enumerate(self.quantization_config_list)} + return {f'option {i}': cfg.get_info() for i, cfg in enumerate(self.quantization_configurations)} @dataclass(frozen=True) @@ -350,22 +348,7 @@ class TargetPlatformModelComponent: """ Component of TargetPlatformModel (Fusing, OperatorsSet, etc.). """ - - def __post_init__(self): - """ - Post-initialization to register the component with the current TargetPlatformModel. - """ - _current_tp_model.get().append_component(self) - - def get_info(self) -> Dict[str, Any]: - """ - Get information about the component to display. - - Returns: - Dict[str, Any]: Returns an empty dictionary. The actual component should override - this method to provide relevant information. - """ - return {} + pass @dataclass(frozen=True) @@ -374,12 +357,7 @@ class OperatorsSetBase(TargetPlatformModelComponent): Base class to represent a set of a target platform model component of operator set types. Inherits from TargetPlatformModelComponent. """ - def __post_init__(self): - """ - Post-initialization to ensure the component is registered with the TargetPlatformModel. - Calls the parent class's __post_init__ method to append this component to the current TargetPlatformModel. - """ - super().__post_init__() + pass @dataclass(frozen=True) @@ -394,23 +372,9 @@ class OperatorsSet(OperatorsSetBase): is_default (bool): Indicates whether this set is the default quantization configuration for the TargetPlatformModel or a fusing set. """ - name: str + name: Union[str, OperatorSetNames] qc_options: QuantizationConfigOptions = None - def __post_init__(self): - """ - Post-initialization processing to mark the operator set as default if applicable. - - Calls the parent class's __post_init__ method and sets `is_default` to True - if this set corresponds to the default quantization configuration for the - TargetPlatformModel or if it is a fusing set. - - """ - super().__post_init__() - is_fusing_set = self.qc_options is None - is_default = _current_tp_model.get().default_qco == self.qc_options or is_fusing_set - object.__setattr__(self, 'is_default', is_default) - def get_info(self) -> Dict[str, Any]: """ Get information about the set as a dictionary. @@ -419,83 +383,67 @@ def get_info(self) -> Dict[str, Any]: Dict[str, Any]: A dictionary containing the set name and whether it is the default quantization configuration. """ - return {"name": self.name, - "is_default_qc": self.is_default} + return {"name": self.name} @dataclass(frozen=True) class OperatorSetConcat(OperatorsSetBase): """ - Concatenate a list of operator sets to treat them similarly in different places (like fusing). + Concatenate a tuple of operator sets to treat them similarly in different places (like fusing). Attributes: - op_set_list (List[OperatorsSet]): List of operator sets to group. + operators_set (Tuple[OperatorsSet]): Tuple of operator sets to group. qc_options (None): Configuration options for the set, always None for concatenated sets. - name (str): Concatenated name generated from the names of the operator sets in the list. + name (str): Concatenated name generated from the names of the operator sets. """ - op_set_list: List[OperatorsSet] = field(default_factory=list) + operators_set: Tuple[OperatorsSet] qc_options: None = field(default=None, init=False) - name: str = None def __post_init__(self): """ Post-initialization processing to generate the concatenated name and set it as the `name` attribute. Calls the parent class's __post_init__ method and creates a concatenated name - by joining the names of all operator sets in `op_set_list`. + by joining the names of all operator sets in `operators_set`. """ - super().__post_init__() # Generate the concatenated name from the operator sets - concatenated_name = "_".join([op.name for op in self.op_set_list]) + concatenated_name = "_".join([op.name.value if hasattr(op.name, "value") else op.name for op in self.operators_set]) # Set the inherited name attribute using `object.__setattr__` since the dataclass is frozen object.__setattr__(self, "name", concatenated_name) - def get_info(self) -> Dict[str, Any]: - """ - Get information about the concatenated set as a dictionary. - - Returns: - Dict[str, Any]: A dictionary containing the concatenated name and - the list of names of the operator sets in `op_set_list`. - """ - return {"name": self.name, - OPS_SET_LIST: [s.name for s in self.op_set_list]} - @dataclass(frozen=True) class Fusing(TargetPlatformModelComponent): """ - Fusing defines a list of operators that should be combined and treated as a single operator, + Fusing defines a tuple of operators that should be combined and treated as a single operator, hence no quantization is applied between them. Attributes: - operator_groups_list (Tuple[Union[OperatorsSet, OperatorSetConcat]]): A list of operator groups, + operator_groups (Tuple[Union[OperatorsSet, OperatorSetConcat]]): A tuple of operator groups, each being either an OperatorSetConcat or an OperatorsSet. name (str): The name for the Fusing instance. If not provided, it is generated from the operator groups' names. """ - operator_groups_list: Tuple[Union[OperatorsSet, OperatorSetConcat]] - name: str = None + operator_groups: Tuple[Union[OperatorsSet, OperatorSetConcat]] def __post_init__(self): """ Post-initialization processing for input validation and name generation. - Calls the parent class's __post_init__ method, validates the operator_groups_list, + Calls the parent class's __post_init__ method, validates the operator_groups, and generates the name if not explicitly provided. Raises: - Logger critical if operator_groups_list is not a list or if it contains fewer than two operators. + Logger critical if operator_groups is not a tuple or if it contains fewer than two operators. """ - super().__post_init__() - # Validate the operator_groups_list - if not isinstance(self.operator_groups_list, list): + # Validate the operator_groups + if not isinstance(self.operator_groups, tuple): Logger.critical( - f"List of operator groups should be of type list but is {type(self.operator_groups_list)}.") # pragma: no cover - if len(self.operator_groups_list) < 2: + f"Operator groups should be of type 'tuple' but is {type(self.operator_groups)}.") # pragma: no cover + if len(self.operator_groups) < 2: Logger.critical("Fusing cannot be created for a single operator.") # pragma: no cover # Generate the name from the operator groups if not provided - generated_name = '_'.join([x.name for x in self.operator_groups_list]) + generated_name = '_'.join([x.name.value if hasattr(x.name, 'value') else x.name for x in self.operator_groups]) object.__setattr__(self, 'name', generated_name) def contains(self, other: Any) -> bool: @@ -512,11 +460,11 @@ def contains(self, other: Any) -> bool: return False # Check for containment by comparing operator groups - for i in range(len(self.operator_groups_list) - len(other.operator_groups_list) + 1): - for j in range(len(other.operator_groups_list)): - if self.operator_groups_list[i + j] != other.operator_groups_list[j] and not ( - isinstance(self.operator_groups_list[i + j], OperatorSetConcat) and ( - other.operator_groups_list[j] in self.operator_groups_list[i + j].op_set_list)): + for i in range(len(self.operator_groups) - len(other.operator_groups) + 1): + for j in range(len(other.operator_groups)): + if self.operator_groups[i + j] != other.operator_groups[j] and not ( + isinstance(self.operator_groups[i + j], OperatorSetConcat) and ( + other.operator_groups[j] in self.operator_groups[i + j].operators_set)): break else: # If all checks pass, the other Fusing instance is contained @@ -534,8 +482,8 @@ def get_info(self) -> Union[Dict[str, str], str]: or just the sequence of operator groups if no name is set. """ if self.name is not None: - return {self.name: ' -> '.join([x.name for x in self.operator_groups_list])} - return ' -> '.join([x.name for x in self.operator_groups_list]) + return {self.name: ' -> '.join([x.name for x in self.operator_groups])} + return ' -> '.join([x.name for x in self.operator_groups]) @dataclass(frozen=True) @@ -550,8 +498,8 @@ class TargetPlatformModel: tpc_platform_type (Optional[str]): Type of the platform for the Target Platform Configuration. add_metadata (bool): Flag to determine if metadata should be added. name (str): Name of the Target Platform Model. - operator_set (List[OperatorsSetBase]): List of operator sets within the model. - fusing_patterns (List[Fusing]): List of fusing patterns for the model. + operator_set (Tuple[OperatorsSetBase]): Tuple of operator sets within the model. + fusing_patterns (Tuple[Fusing]): Tuple of fusing patterns for the model. is_simd_padding (bool): Indicates if SIMD padding is applied. SCHEMA_VERSION (int): Version of the schema for the Target Platform Model. """ @@ -561,8 +509,8 @@ class TargetPlatformModel: tpc_platform_type: Optional[str] add_metadata: bool = True name: str = "default_tp_model" - operator_set: List[OperatorsSetBase] = field(default_factory=list) - fusing_patterns: List[Fusing] = field(default_factory=list) + operator_set: Tuple[OperatorsSetBase] = None + fusing_patterns: Tuple[Fusing] = None is_simd_padding: bool = False SCHEMA_VERSION: int = 1 @@ -578,26 +526,12 @@ def __post_init__(self): # Validate `default_qco` if not isinstance(self.default_qco, QuantizationConfigOptions): Logger.critical("'default_qco' must be an instance of QuantizationConfigOptions.") # pragma: no cover - if len(self.default_qco.quantization_config_list) != 1: + if len(self.default_qco.quantization_configurations) != 1: Logger.critical("Default QuantizationConfigOptions must contain exactly one option.") # pragma: no cover - def append_component(self, tp_model_component: TargetPlatformModelComponent): - """ - Attach a TargetPlatformModel component to the model (like Fusing or OperatorsSet). - - Args: - tp_model_component (TargetPlatformModelComponent): Component to attach to the model. - - Raises: - Logger critical if the component is not an instance of Fusing or OperatorsSetBase. - """ - if isinstance(tp_model_component, Fusing): - self.fusing_patterns.append(tp_model_component) - elif isinstance(tp_model_component, OperatorsSetBase): - self.operator_set.append(tp_model_component) - else: - Logger.critical( - f"Attempted to append an unrecognized TargetPlatformModelComponent of type: {type(tp_model_component)}.") # pragma: no cover + opsets_names = [op.name.value if hasattr(op.name, "value") else op.name for op in self.operator_set] if self.operator_set else [] + if len(set(opsets_names)) != len(opsets_names): + Logger.critical("Operator Sets must have unique names.") # pragma: no cover def get_info(self) -> Dict[str, Any]: """ @@ -608,51 +542,10 @@ def get_info(self) -> Dict[str, Any]: """ return { "Model name": self.name, - "Operators sets": [o.get_info() for o in self.operator_set], - "Fusing patterns": [f.get_info() for f in self.fusing_patterns], + "Operators sets": [o.get_info() for o in self.operator_set] if self.operator_set else [], + "Fusing patterns": [f.get_info() for f in self.fusing_patterns] if self.fusing_patterns else [], } - def __validate_model(self): - """ - Validate the model's configuration to ensure its integrity. - - Raises: - Logger critical if the model contains multiple operator sets with the same name. - """ - opsets_names = [op.name for op in self.operator_set] - if len(set(opsets_names)) != len(opsets_names): - Logger.critical("Operator Sets must have unique names.") # pragma: no cover - - def __enter__(self) -> 'TargetPlatformModel': - """ - Start defining the TargetPlatformModel using a 'with' statement. - - Returns: - TargetPlatformModel: The initialized TargetPlatformModel object. - """ - _current_tp_model.set(self) - return self - - def __exit__(self, exc_type, exc_value, tb) -> 'TargetPlatformModel': - """ - Finalize and validate the TargetPlatformModel at the end of the 'with' clause. - - Args: - exc_type: Exception type, if any occurred. - exc_value: Exception value, if any occurred. - tb: Traceback object, if an exception occurred. - - Raises: - The exception raised in the 'with' block, if any. - - Returns: - TargetPlatformModel: The validated TargetPlatformModel object. - """ - if exc_value is not None: - raise exc_value - self.__validate_model() - _current_tp_model.reset() - return self def show(self): """ diff --git a/model_compression_toolkit/target_platform_capabilities/target_platform/__init__.py b/model_compression_toolkit/target_platform_capabilities/target_platform/__init__.py index e01363b71..249cec797 100644 --- a/model_compression_toolkit/target_platform_capabilities/target_platform/__init__.py +++ b/model_compression_toolkit/target_platform_capabilities/target_platform/__init__.py @@ -15,7 +15,6 @@ from model_compression_toolkit.target_platform_capabilities.target_platform.targetplatform2framework.attribute_filter import AttributeFilter from model_compression_toolkit.target_platform_capabilities.target_platform.targetplatform2framework import TargetPlatformCapabilities, OperationsSetToLayers, Smaller, SmallerEq, NotEq, Eq, GreaterEq, Greater, LayerFilterParams, OperationsToLayers, get_current_tpc -from model_compression_toolkit.target_platform_capabilities.target_platform.target_platform_model import get_default_quantization_config_options from model_compression_toolkit.target_platform_capabilities.schema.mct_current_schema import TargetPlatformModel, OperatorsSet, \ OperatorSetConcat, Signedness, AttributeQuantizationConfig, OpQuantizationConfig, QuantizationConfigOptions, Fusing diff --git a/model_compression_toolkit/target_platform_capabilities/target_platform/current_tp_model.py b/model_compression_toolkit/target_platform_capabilities/target_platform/current_tp_model.py deleted file mode 100644 index 4c236522a..000000000 --- a/model_compression_toolkit/target_platform_capabilities/target_platform/current_tp_model.py +++ /dev/null @@ -1,67 +0,0 @@ -# Copyright 2022 Sony Semiconductor Israel, Inc. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ============================================================================== - -from model_compression_toolkit.logger import Logger - -def get_current_tp_model(): - """ - - Returns: The current TargetPlatformModel that is being used and accessed. - - """ - return _current_tp_model.get() - - -class CurrentTPModel: - """ - Wrapper of the current TargetPlatformModel object that is being accessed and defined. - """ - - def __init__(self): - super(CurrentTPModel, self).__init__() - self.tp_model = None - - def get(self): - """ - - Returns: The current TargetPlatformModel that is being defined. - - """ - if self.tp_model is None: - Logger.critical('Target platform model is not initialized.') # pragma: no cover - return self.tp_model - - def reset(self): - """ - - Reset the current TargetPlatformModel so a new TargetPlatformModel can be wrapped and - used as the current TargetPlatformModel object. - - """ - self.tp_model = None - - def set(self, tp_model): - """ - Set and wrap a TargetPlatformModel as the current TargetPlatformModel. - - Args: - tp_model: TargetPlatformModel to set as the current TargetPlatformModel to access and use. - - """ - self.tp_model = tp_model - - -# Use a single instance for the current model. -_current_tp_model = CurrentTPModel() diff --git a/model_compression_toolkit/target_platform_capabilities/target_platform/target_platform_model.py b/model_compression_toolkit/target_platform_capabilities/target_platform/target_platform_model.py deleted file mode 100644 index f2b6dec49..000000000 --- a/model_compression_toolkit/target_platform_capabilities/target_platform/target_platform_model.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright 2022 Sony Semiconductor Israel, Inc. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ============================================================================== - -from model_compression_toolkit.target_platform_capabilities.target_platform.current_tp_model import get_current_tp_model -from model_compression_toolkit.target_platform_capabilities.schema.mct_current_schema import QuantizationConfigOptions - - -def get_default_quantization_config_options() -> QuantizationConfigOptions: - """ - - Returns: The default QuantizationConfigOptions of the model. This is the options - to use when a layer's options is queried and it wasn't specified in the TargetPlatformCapabilities. - The default QuantizationConfigOptions always contains a single option. - - """ - return get_current_tp_model().default_qco - - diff --git a/model_compression_toolkit/target_platform_capabilities/target_platform/targetplatform2framework/operations_to_layers.py b/model_compression_toolkit/target_platform_capabilities/target_platform/targetplatform2framework/operations_to_layers.py index aa378ff16..ad9508d8c 100644 --- a/model_compression_toolkit/target_platform_capabilities/target_platform/targetplatform2framework/operations_to_layers.py +++ b/model_compression_toolkit/target_platform_capabilities/target_platform/targetplatform2framework/operations_to_layers.py @@ -90,7 +90,7 @@ def get_layers_by_op(self, return o.layers if isinstance(op, OperatorSetConcat): # If its a concat - return all layers from all OperatorsSets that in the OperatorSetConcat layers = [] - for o in op.op_set_list: + for o in op.operators_set: layers.extend(self.get_layers_by_op(o)) return layers Logger.warning(f'{op.name} is not in model.') diff --git a/model_compression_toolkit/target_platform_capabilities/target_platform/targetplatform2framework/target_platform_capabilities.py b/model_compression_toolkit/target_platform_capabilities/target_platform/targetplatform2framework/target_platform_capabilities.py index 924069c82..d29d52e28 100644 --- a/model_compression_toolkit/target_platform_capabilities/target_platform/targetplatform2framework/target_platform_capabilities.py +++ b/model_compression_toolkit/target_platform_capabilities/target_platform/targetplatform2framework/target_platform_capabilities.py @@ -100,8 +100,10 @@ def get_fusing_patterns(self) -> List[List[Any]]: """ res = [] + if self.tp_model.fusing_patterns is None: + return res for p in self.tp_model.fusing_patterns: - ops = [self.get_layers_by_opset(x) for x in p.operator_groups_list] + ops = [self.get_layers_by_opset(x) for x in p.operator_groups] res.extend(itertools.product(*ops)) return [list(x) for x in res] @@ -207,9 +209,10 @@ def remove_fusing_names_from_not_used_list(self): Remove OperatorSets names from the list of the unused sets (so a warning will not be displayed). """ - for f in self.tp_model.fusing_patterns: - for s in f.operator_groups_list: - self.remove_opset_from_not_used_list(s.name) + if self.tp_model.fusing_patterns is not None: + for f in self.tp_model.fusing_patterns: + for s in f.operator_groups: + self.remove_opset_from_not_used_list(s.name) def remove_opset_from_not_used_list(self, opset_to_remove: str): diff --git a/model_compression_toolkit/target_platform_capabilities/tpc_models/imx500_tpc/v1/tp_model.py b/model_compression_toolkit/target_platform_capabilities/tpc_models/imx500_tpc/v1/tp_model.py index f9e94f81d..5a80e258a 100644 --- a/model_compression_toolkit/target_platform_capabilities/tpc_models/imx500_tpc/v1/tp_model.py +++ b/model_compression_toolkit/target_platform_capabilities/tpc_models/imx500_tpc/v1/tp_model.py @@ -153,7 +153,54 @@ def generate_tp_model(default_config: OpQuantizationConfig, # of possible configurations to consider when quantizing a set of operations (in mixed-precision, for example). # If the QuantizationConfigOptions contains only one configuration, # this configuration will be used for the operation quantization: - default_configuration_options = schema.QuantizationConfigOptions([default_config]) + default_configuration_options = schema.QuantizationConfigOptions(tuple([default_config])) + + # Create Mixed-Precision quantization configuration options from the given list of OpQuantizationConfig objects + mixed_precision_configuration_options = schema.QuantizationConfigOptions(tuple(mixed_precision_cfg_list), + base_config=base_config) + + # Create an OperatorsSet to represent a set of operations. + # Each OperatorsSet has a unique label. + # If a quantization configuration options is passed, these options will + # be used for operations that will be attached to this set's label. + # Otherwise, it will be a configure-less set (used in fusing): + operator_set = [] + fusing_patterns = [] + + operator_set.append(schema.OperatorsSet("NoQuantization", + default_configuration_options.clone_and_edit(enable_activation_quantization=False) + .clone_and_edit_weight_attribute(enable_weights_quantization=False))) + + # Define operator sets that use mixed_precision_configuration_options: + conv = schema.OperatorsSet("Conv", mixed_precision_configuration_options) + fc = schema.OperatorsSet("FullyConnected", mixed_precision_configuration_options) + + # Define operations sets without quantization configuration + # options (useful for creating fusing patterns, for example): + any_relu = schema.OperatorsSet("AnyReLU") + add = schema.OperatorsSet("Add") + sub = schema.OperatorsSet("Sub") + mul = schema.OperatorsSet("Mul") + div = schema.OperatorsSet("Div") + prelu = schema.OperatorsSet("PReLU") + swish = schema.OperatorsSet("Swish") + sigmoid = schema.OperatorsSet("Sigmoid") + tanh = schema.OperatorsSet("Tanh") + + operator_set.extend([conv, fc, any_relu, add, sub, mul, div, prelu, swish, sigmoid, tanh]) + # Combine multiple operators into a single operator to avoid quantization between + # them. To do this we define fusing patterns using the OperatorsSets that were created. + # To group multiple sets with regard to fusing, an OperatorSetConcat can be created + activations_after_conv_to_fuse = schema.OperatorSetConcat([any_relu, swish, prelu, sigmoid, tanh]) + activations_after_fc_to_fuse = schema.OperatorSetConcat([any_relu, swish, sigmoid]) + any_binary = schema.OperatorSetConcat([add, sub, mul, div]) + + # ------------------- # + # Fusions + # ------------------- # + fusing_patterns.append(schema.Fusing((conv, activations_after_conv_to_fuse))) + fusing_patterns.append(schema.Fusing((fc, activations_after_fc_to_fuse))) + fusing_patterns.append(schema.Fusing((any_binary, any_relu))) # Create a TargetPlatformModel and set its default quantization config. # This default configuration will be used for all operations @@ -163,57 +210,9 @@ def generate_tp_model(default_config: OpQuantizationConfig, tpc_minor_version=1, tpc_patch_version=0, tpc_platform_type=IMX500_TP_MODEL, + operator_set=tuple(operator_set), + fusing_patterns=tuple(fusing_patterns), name=name, add_metadata=False, is_simd_padding=True) - - # To start defining the model's components (such as operator sets, and fusing patterns), - # use 'with' the TargetPlatformModel instance, and create them as below: - with generated_tpc: - # Create an OperatorsSet to represent a set of operations. - # Each OperatorsSet has a unique label. - # If a quantization configuration options is passed, these options will - # be used for operations that will be attached to this set's label. - # Otherwise, it will be a configure-less set (used in fusing): - - # May suit for operations like: Dropout, Reshape, etc. - default_qco = tp.get_default_quantization_config_options() - schema.OperatorsSet("NoQuantization", - default_qco.clone_and_edit(enable_activation_quantization=False) - .clone_and_edit_weight_attribute(enable_weights_quantization=False)) - - # Create Mixed-Precision quantization configuration options from the given list of OpQuantizationConfig objects - mixed_precision_configuration_options = schema.QuantizationConfigOptions(mixed_precision_cfg_list, - base_config=base_config) - - # Define operator sets that use mixed_precision_configuration_options: - conv = schema.OperatorsSet("Conv", mixed_precision_configuration_options) - fc = schema.OperatorsSet("FullyConnected", mixed_precision_configuration_options) - - # Define operations sets without quantization configuration - # options (useful for creating fusing patterns, for example): - any_relu = schema.OperatorsSet("AnyReLU") - add = schema.OperatorsSet("Add") - sub = schema.OperatorsSet("Sub") - mul = schema.OperatorsSet("Mul") - div = schema.OperatorsSet("Div") - prelu = schema.OperatorsSet("PReLU") - swish = schema.OperatorsSet("Swish") - sigmoid = schema.OperatorsSet("Sigmoid") - tanh = schema.OperatorsSet("Tanh") - - # Combine multiple operators into a single operator to avoid quantization between - # them. To do this we define fusing patterns using the OperatorsSets that were created. - # To group multiple sets with regard to fusing, an OperatorSetConcat can be created - activations_after_conv_to_fuse = schema.OperatorSetConcat([any_relu, swish, prelu, sigmoid, tanh]) - activations_after_fc_to_fuse = schema.OperatorSetConcat([any_relu, swish, sigmoid]) - any_binary = schema.OperatorSetConcat([add, sub, mul, div]) - - # ------------------- # - # Fusions - # ------------------- # - schema.Fusing([conv, activations_after_conv_to_fuse]) - schema.Fusing([fc, activations_after_fc_to_fuse]) - schema.Fusing([any_binary, any_relu]) - return generated_tpc diff --git a/model_compression_toolkit/target_platform_capabilities/tpc_models/imx500_tpc/v1_lut/tp_model.py b/model_compression_toolkit/target_platform_capabilities/tpc_models/imx500_tpc/v1_lut/tp_model.py index 707fa76e1..267dd98ce 100644 --- a/model_compression_toolkit/target_platform_capabilities/tpc_models/imx500_tpc/v1_lut/tp_model.py +++ b/model_compression_toolkit/target_platform_capabilities/tpc_models/imx500_tpc/v1_lut/tp_model.py @@ -19,7 +19,8 @@ from model_compression_toolkit.constants import FLOAT_BITWIDTH from model_compression_toolkit.target_platform_capabilities.constants import KERNEL_ATTR, BIAS_ATTR, WEIGHTS_N_BITS, \ WEIGHTS_QUANTIZATION_METHOD, IMX500_TP_MODEL -from model_compression_toolkit.target_platform_capabilities.schema.mct_current_schema import TargetPlatformModel, Signedness, \ +from model_compression_toolkit.target_platform_capabilities.schema.mct_current_schema import TargetPlatformModel, \ + Signedness, \ AttributeQuantizationConfig, OpQuantizationConfig tp = mct.target_platform @@ -150,7 +151,56 @@ def generate_tp_model(default_config: OpQuantizationConfig, # of possible configurations to consider when quantizing a set of operations (in mixed-precision, for example). # If the QuantizationConfigOptions contains only one configuration, # this configuration will be used for the operation quantization: - default_configuration_options = schema.QuantizationConfigOptions([default_config]) + default_configuration_options = schema.QuantizationConfigOptions(tuple([default_config])) + + # Create Mixed-Precision quantization configuration options from the given list of OpQuantizationConfig objects + mixed_precision_configuration_options = schema.QuantizationConfigOptions(tuple(mixed_precision_cfg_list), + base_config=base_config) + + # Create an OperatorsSet to represent a set of operations. + # Each OperatorsSet has a unique label. + # If a quantization configuration options is passed, these options will + # be used for operations that will be attached to this set's label. + # Otherwise, it will be a configure-less set (used in fusing): + operator_set = [] + fusing_patterns = [] + + # May suit for operations like: Dropout, Reshape, etc. + operator_set.append(schema.OperatorsSet("NoQuantization", + default_configuration_options.clone_and_edit( + enable_activation_quantization=False) + .clone_and_edit_weight_attribute(enable_weights_quantization=False))) + + # Define operator sets that use mixed_precision_configuration_options: + conv = schema.OperatorsSet("Conv", mixed_precision_configuration_options) + fc = schema.OperatorsSet("FullyConnected", mixed_precision_configuration_options) + + # Define operations sets without quantization configuration + # options (useful for creating fusing patterns, for example): + any_relu = schema.OperatorsSet("AnyReLU") + add = schema.OperatorsSet("Add") + sub = schema.OperatorsSet("Sub") + mul = schema.OperatorsSet("Mul") + div = schema.OperatorsSet("Div") + prelu = schema.OperatorsSet("PReLU") + swish = schema.OperatorsSet("Swish") + sigmoid = schema.OperatorsSet("Sigmoid") + tanh = schema.OperatorsSet("Tanh") + + operator_set.extend([conv, fc, any_relu, add, sub, mul, div, prelu, swish, sigmoid, tanh]) + # Combine multiple operators into a single operator to avoid quantization between + # them. To do this we define fusing patterns using the OperatorsSets that were created. + # To group multiple sets with regard to fusing, an OperatorSetConcat can be created + activations_after_conv_to_fuse = schema.OperatorSetConcat([any_relu, swish, prelu, sigmoid, tanh]) + activations_after_fc_to_fuse = schema.OperatorSetConcat([any_relu, swish, sigmoid]) + any_binary = schema.OperatorSetConcat([add, sub, mul, div]) + + # ------------------- # + # Fusions + # ------------------- # + fusing_patterns.append(schema.Fusing((conv, activations_after_conv_to_fuse))) + fusing_patterns.append(schema.Fusing((fc, activations_after_fc_to_fuse))) + fusing_patterns.append(schema.Fusing((any_binary, any_relu))) # Create a TargetPlatformModel and set its default quantization config. # This default configuration will be used for all operations @@ -160,56 +210,8 @@ def generate_tp_model(default_config: OpQuantizationConfig, tpc_minor_version=1, tpc_patch_version=0, tpc_platform_type=IMX500_TP_MODEL, + operator_set=tuple(operator_set), + fusing_patterns=tuple(fusing_patterns), add_metadata=False, name=name) - - # To start defining the model's components (such as operator sets, and fusing patterns), - # use 'with' the TargetPlatformModel instance, and create them as below: - with generated_tpc: - # Create an OperatorsSet to represent a set of operations. - # Each OperatorsSet has a unique label. - # If a quantization configuration options is passed, these options will - # be used for operations that will be attached to this set's label. - # Otherwise, it will be a configure-less set (used in fusing): - - # May suit for operations like: Dropout, Reshape, etc. - default_qco = tp.get_default_quantization_config_options() - schema.OperatorsSet("NoQuantization", - default_qco.clone_and_edit(enable_activation_quantization=False) - .clone_and_edit_weight_attribute(enable_weights_quantization=False)) - - # Create Mixed-Precision quantization configuration options from the given list of OpQuantizationConfig objects - mixed_precision_configuration_options = schema.QuantizationConfigOptions(mixed_precision_cfg_list, - base_config=base_config) - - # Define operator sets that use mixed_precision_configuration_options: - conv = schema.OperatorsSet("Conv", mixed_precision_configuration_options) - fc = schema.OperatorsSet("FullyConnected", mixed_precision_configuration_options) - - # Define operations sets without quantization configuration - # options (useful for creating fusing patterns, for example): - any_relu = schema.OperatorsSet("AnyReLU") - add = schema.OperatorsSet("Add") - sub = schema.OperatorsSet("Sub") - mul = schema.OperatorsSet("Mul") - div = schema.OperatorsSet("Div") - prelu = schema.OperatorsSet("PReLU") - swish = schema.OperatorsSet("Swish") - sigmoid = schema.OperatorsSet("Sigmoid") - tanh = schema.OperatorsSet("Tanh") - - # Combine multiple operators into a single operator to avoid quantization between - # them. To do this we define fusing patterns using the OperatorsSets that were created. - # To group multiple sets with regard to fusing, an OperatorSetConcat can be created - activations_after_conv_to_fuse = schema.OperatorSetConcat([any_relu, swish, prelu, sigmoid, tanh]) - activations_after_fc_to_fuse = schema.OperatorSetConcat([any_relu, swish, sigmoid]) - any_binary = schema.OperatorSetConcat([add, sub, mul, div]) - - # ------------------- # - # Fusions - # ------------------- # - schema.Fusing([conv, activations_after_conv_to_fuse]) - schema.Fusing([fc, activations_after_fc_to_fuse]) - schema.Fusing([any_binary, any_relu]) - return generated_tpc diff --git a/model_compression_toolkit/target_platform_capabilities/tpc_models/imx500_tpc/v1_pot/tp_model.py b/model_compression_toolkit/target_platform_capabilities/tpc_models/imx500_tpc/v1_pot/tp_model.py index 032a42c6a..df17573f8 100644 --- a/model_compression_toolkit/target_platform_capabilities/tpc_models/imx500_tpc/v1_pot/tp_model.py +++ b/model_compression_toolkit/target_platform_capabilities/tpc_models/imx500_tpc/v1_pot/tp_model.py @@ -19,7 +19,8 @@ from model_compression_toolkit.constants import FLOAT_BITWIDTH from model_compression_toolkit.target_platform_capabilities.constants import KERNEL_ATTR, BIAS_ATTR, WEIGHTS_N_BITS, \ IMX500_TP_MODEL -from model_compression_toolkit.target_platform_capabilities.schema.mct_current_schema import TargetPlatformModel, Signedness, \ +from model_compression_toolkit.target_platform_capabilities.schema.mct_current_schema import TargetPlatformModel, \ + Signedness, \ AttributeQuantizationConfig, OpQuantizationConfig tp = mct.target_platform @@ -146,7 +147,57 @@ def generate_tp_model(default_config: OpQuantizationConfig, # of possible configurations to consider when quantizing a set of operations (in mixed-precision, for example). # If the QuantizationConfigOptions contains only one configuration, # this configuration will be used for the operation quantization: - default_configuration_options = schema.QuantizationConfigOptions([default_config]) + default_configuration_options = schema.QuantizationConfigOptions(tuple([default_config])) + + # Create Mixed-Precision quantization configuration options from the given list of OpQuantizationConfig objects + mixed_precision_configuration_options = schema.QuantizationConfigOptions(tuple(mixed_precision_cfg_list), + base_config=base_config) + + # Create an OperatorsSet to represent a set of operations. + # Each OperatorsSet has a unique label. + # If a quantization configuration options is passed, these options will + # be used for operations that will be attached to this set's label. + # Otherwise, it will be a configure-less set (used in fusing): + operator_set = [] + fusing_patterns = [] + + # May suit for operations like: Dropout, Reshape, etc. + operator_set.append(schema.OperatorsSet("NoQuantization", + default_configuration_options.clone_and_edit( + enable_activation_quantization=False) + .clone_and_edit_weight_attribute(enable_weights_quantization=False))) + + # Define operator sets that use mixed_precision_configuration_options: + conv = schema.OperatorsSet("Conv", mixed_precision_configuration_options) + fc = schema.OperatorsSet("FullyConnected", mixed_precision_configuration_options) + + # Define operations sets without quantization configuration + # options (useful for creating fusing patterns, for example): + any_relu = schema.OperatorsSet("AnyReLU") + add = schema.OperatorsSet("Add") + sub = schema.OperatorsSet("Sub") + mul = schema.OperatorsSet("Mul") + div = schema.OperatorsSet("Div") + prelu = schema.OperatorsSet("PReLU") + swish = schema.OperatorsSet("Swish") + sigmoid = schema.OperatorsSet("Sigmoid") + tanh = schema.OperatorsSet("Tanh") + + operator_set.extend([conv, fc, any_relu, add, sub, mul, div, prelu, swish, sigmoid, tanh]) + + # Combine multiple operators into a single operator to avoid quantization between + # them. To do this we define fusing patterns using the OperatorsSets that were created. + # To group multiple sets with regard to fusing, an OperatorSetConcat can be created + activations_after_conv_to_fuse = schema.OperatorSetConcat([any_relu, swish, prelu, sigmoid, tanh]) + activations_after_fc_to_fuse = schema.OperatorSetConcat([any_relu, swish, sigmoid]) + any_binary = schema.OperatorSetConcat([add, sub, mul, div]) + + # ------------------- # + # Fusions + # ------------------- # + fusing_patterns.append(schema.Fusing((conv, activations_after_conv_to_fuse))) + fusing_patterns.append(schema.Fusing((fc, activations_after_fc_to_fuse))) + fusing_patterns.append(schema.Fusing((any_binary, any_relu))) # Create a TargetPlatformModel and set its default quantization config. # This default configuration will be used for all operations @@ -156,56 +207,9 @@ def generate_tp_model(default_config: OpQuantizationConfig, tpc_minor_version=1, tpc_patch_version=0, tpc_platform_type=IMX500_TP_MODEL, + operator_set=tuple(operator_set), + fusing_patterns=tuple(fusing_patterns), + name=name, add_metadata=False, - name=name) - - # To start defining the model's components (such as operator sets, and fusing patterns), - # use 'with' the TargetPlatformModel instance, and create them as below: - with generated_tpc: - # Create an OperatorsSet to represent a set of operations. - # Each OperatorsSet has a unique label. - # If a quantization configuration options is passed, these options will - # be used for operations that will be attached to this set's label. - # Otherwise, it will be a configure-less set (used in fusing): - - # May suit for operations like: Dropout, Reshape, etc. - default_qco = tp.get_default_quantization_config_options() - schema.OperatorsSet("NoQuantization", - default_qco.clone_and_edit(enable_activation_quantization=False) - .clone_and_edit_weight_attribute(enable_weights_quantization=False)) - - # Create Mixed-Precision quantization configuration options from the given list of OpQuantizationConfig objects - mixed_precision_configuration_options = schema.QuantizationConfigOptions(mixed_precision_cfg_list, - base_config=base_config) - - # Define operator sets that use mixed_precision_configuration_options: - conv = schema.OperatorsSet("Conv", mixed_precision_configuration_options) - fc = schema.OperatorsSet("FullyConnected", mixed_precision_configuration_options) - - # Define operations sets without quantization configuration - # options (useful for creating fusing patterns, for example): - any_relu = schema.OperatorsSet("AnyReLU") - add = schema.OperatorsSet("Add") - sub = schema.OperatorsSet("Sub") - mul = schema.OperatorsSet("Mul") - div = schema.OperatorsSet("Div") - prelu = schema.OperatorsSet("PReLU") - swish = schema.OperatorsSet("Swish") - sigmoid = schema.OperatorsSet("Sigmoid") - tanh = schema.OperatorsSet("Tanh") - - # Combine multiple operators into a single operator to avoid quantization between - # them. To do this we define fusing patterns using the OperatorsSets that were created. - # To group multiple sets with regard to fusing, an OperatorSetConcat can be created - activations_after_conv_to_fuse = schema.OperatorSetConcat([any_relu, swish, prelu, sigmoid, tanh]) - activations_after_fc_to_fuse = schema.OperatorSetConcat([any_relu, swish, sigmoid]) - any_binary = schema.OperatorSetConcat([add, sub, mul, div]) - - # ------------------- # - # Fusions - # ------------------- # - schema.Fusing([conv, activations_after_conv_to_fuse]) - schema.Fusing([fc, activations_after_fc_to_fuse]) - schema.Fusing([any_binary, any_relu]) - + is_simd_padding=True) return generated_tpc diff --git a/model_compression_toolkit/target_platform_capabilities/tpc_models/imx500_tpc/v2/tp_model.py b/model_compression_toolkit/target_platform_capabilities/tpc_models/imx500_tpc/v2/tp_model.py index ae7056b99..040b453ca 100644 --- a/model_compression_toolkit/target_platform_capabilities/tpc_models/imx500_tpc/v2/tp_model.py +++ b/model_compression_toolkit/target_platform_capabilities/tpc_models/imx500_tpc/v2/tp_model.py @@ -19,7 +19,8 @@ from model_compression_toolkit.constants import FLOAT_BITWIDTH from model_compression_toolkit.target_platform_capabilities.constants import KERNEL_ATTR, BIAS_ATTR, WEIGHTS_N_BITS, \ IMX500_TP_MODEL -from model_compression_toolkit.target_platform_capabilities.schema.mct_current_schema import TargetPlatformModel, Signedness, \ +from model_compression_toolkit.target_platform_capabilities.schema.mct_current_schema import TargetPlatformModel, \ + Signedness, \ AttributeQuantizationConfig, OpQuantizationConfig tp = mct.target_platform @@ -155,7 +156,54 @@ def generate_tp_model(default_config: OpQuantizationConfig, # of possible configurations to consider when quantizing a set of operations (in mixed-precision, for example). # If the QuantizationConfigOptions contains only one configuration, # this configuration will be used for the operation quantization: - default_configuration_options = schema.QuantizationConfigOptions([default_config]) + default_configuration_options = schema.QuantizationConfigOptions(tuple([default_config])) + + # Create Mixed-Precision quantization configuration options from the given list of OpQuantizationConfig objects + mixed_precision_configuration_options = schema.QuantizationConfigOptions(tuple(mixed_precision_cfg_list), + base_config=base_config) + + # Create an OperatorsSet to represent a set of operations. + # Each OperatorsSet has a unique label. + # If a quantization configuration options is passed, these options will + # be used for operations that will be attached to this set's label. + # Otherwise, it will be a configure-less set (used in fusing): + operator_set = [] + fusing_patterns = [] + # May suit for operations like: Dropout, Reshape, etc. + operator_set.append(schema.OperatorsSet("NoQuantization", default_configuration_options.clone_and_edit( + enable_activation_quantization=False).clone_and_edit_weight_attribute(enable_weights_quantization=False))) + + # Define operator sets that use mixed_precision_configuration_options: + conv = schema.OperatorsSet("Conv", mixed_precision_configuration_options) + fc = schema.OperatorsSet("FullyConnected", mixed_precision_configuration_options) + + # Define operations sets without quantization configuration + # options (useful for creating fusing patterns, for example): + any_relu = schema.OperatorsSet("AnyReLU") + add = schema.OperatorsSet("Add") + sub = schema.OperatorsSet("Sub") + mul = schema.OperatorsSet("Mul") + div = schema.OperatorsSet("Div") + prelu = schema.OperatorsSet("PReLU") + swish = schema.OperatorsSet("Swish") + sigmoid = schema.OperatorsSet("Sigmoid") + tanh = schema.OperatorsSet("Tanh") + + operator_set.extend([conv, fc, any_relu, add, sub, mul, div, prelu, swish, sigmoid, tanh]) + + # Combine multiple operators into a single operator to avoid quantization between + # them. To do this we define fusing patterns using the OperatorsSets that were created. + # To group multiple sets with regard to fusing, an OperatorSetConcat can be created + activations_after_conv_to_fuse = schema.OperatorSetConcat([any_relu, swish, prelu, sigmoid, tanh]) + activations_after_fc_to_fuse = schema.OperatorSetConcat([any_relu, swish, sigmoid]) + any_binary = schema.OperatorSetConcat([add, sub, mul, div]) + + # ------------------- # + # Fusions + # ------------------- # + fusing_patterns.append(schema.Fusing((conv, activations_after_conv_to_fuse))) + fusing_patterns.append(schema.Fusing((fc, activations_after_fc_to_fuse))) + fusing_patterns.append(schema.Fusing((any_binary, any_relu))) # Create a TargetPlatformModel and set its default quantization config. # This default configuration will be used for all operations @@ -165,57 +213,10 @@ def generate_tp_model(default_config: OpQuantizationConfig, tpc_minor_version=2, tpc_patch_version=0, tpc_platform_type=IMX500_TP_MODEL, + operator_set=tuple(operator_set), + fusing_patterns=tuple(fusing_patterns), add_metadata=True, name=name, is_simd_padding=True) - # To start defining the model's components (such as operator sets, and fusing patterns), - # use 'with' the TargetPlatformModel instance, and create them as below: - with generated_tpm: - # Create an OperatorsSet to represent a set of operations. - # Each OperatorsSet has a unique label. - # If a quantization configuration options is passed, these options will - # be used for operations that will be attached to this set's label. - # Otherwise, it will be a configure-less set (used in fusing): - - # May suit for operations like: Dropout, Reshape, etc. - default_qco = tp.get_default_quantization_config_options() - schema.OperatorsSet("NoQuantization", - default_qco.clone_and_edit(enable_activation_quantization=False) - .clone_and_edit_weight_attribute(enable_weights_quantization=False)) - - # Create Mixed-Precision quantization configuration options from the given list of OpQuantizationConfig objects - mixed_precision_configuration_options = schema.QuantizationConfigOptions(mixed_precision_cfg_list, - base_config=base_config) - - # Define operator sets that use mixed_precision_configuration_options: - conv = schema.OperatorsSet("Conv", mixed_precision_configuration_options) - fc = schema.OperatorsSet("FullyConnected", mixed_precision_configuration_options) - - # Define operations sets without quantization configuration - # options (useful for creating fusing patterns, for example): - any_relu = schema.OperatorsSet("AnyReLU") - add = schema.OperatorsSet("Add") - sub = schema.OperatorsSet("Sub") - mul = schema.OperatorsSet("Mul") - div = schema.OperatorsSet("Div") - prelu = schema.OperatorsSet("PReLU") - swish = schema.OperatorsSet("Swish") - sigmoid = schema.OperatorsSet("Sigmoid") - tanh = schema.OperatorsSet("Tanh") - - # Combine multiple operators into a single operator to avoid quantization between - # them. To do this we define fusing patterns using the OperatorsSets that were created. - # To group multiple sets with regard to fusing, an OperatorSetConcat can be created - activations_after_conv_to_fuse = schema.OperatorSetConcat([any_relu, swish, prelu, sigmoid, tanh]) - activations_after_fc_to_fuse = schema.OperatorSetConcat([any_relu, swish, sigmoid]) - any_binary = schema.OperatorSetConcat([add, sub, mul, div]) - - # ------------------- # - # Fusions - # ------------------- # - schema.Fusing([conv, activations_after_conv_to_fuse]) - schema.Fusing([fc, activations_after_fc_to_fuse]) - schema.Fusing([any_binary, any_relu]) - return generated_tpm diff --git a/model_compression_toolkit/target_platform_capabilities/tpc_models/imx500_tpc/v2_lut/tp_model.py b/model_compression_toolkit/target_platform_capabilities/tpc_models/imx500_tpc/v2_lut/tp_model.py index 187ef1100..3797a7127 100644 --- a/model_compression_toolkit/target_platform_capabilities/tpc_models/imx500_tpc/v2_lut/tp_model.py +++ b/model_compression_toolkit/target_platform_capabilities/tpc_models/imx500_tpc/v2_lut/tp_model.py @@ -19,7 +19,8 @@ from model_compression_toolkit.constants import FLOAT_BITWIDTH from model_compression_toolkit.target_platform_capabilities.constants import KERNEL_ATTR, BIAS_ATTR, WEIGHTS_N_BITS, \ WEIGHTS_QUANTIZATION_METHOD, IMX500_TP_MODEL -from model_compression_toolkit.target_platform_capabilities.schema.mct_current_schema import TargetPlatformModel, Signedness, \ +from model_compression_toolkit.target_platform_capabilities.schema.mct_current_schema import TargetPlatformModel, \ + Signedness, \ AttributeQuantizationConfig, OpQuantizationConfig tp = mct.target_platform @@ -152,7 +153,55 @@ def generate_tp_model(default_config: OpQuantizationConfig, # of possible configurations to consider when quantizing a set of operations (in mixed-precision, for example). # If the QuantizationConfigOptions contains only one configuration, # this configuration will be used for the operation quantization: - default_configuration_options = schema.QuantizationConfigOptions([default_config]) + default_configuration_options = schema.QuantizationConfigOptions(tuple([default_config])) + + # Create Mixed-Precision quantization configuration options from the given list of OpQuantizationConfig objects + mixed_precision_configuration_options = schema.QuantizationConfigOptions(tuple(mixed_precision_cfg_list), + base_config=base_config) + + # Create an OperatorsSet to represent a set of operations. + # Each OperatorsSet has a unique label. + # If a quantization configuration options is passed, these options will + # be used for operations that will be attached to this set's label. + # Otherwise, it will be a configure-less set (used in fusing): + operator_set = [] + fusing_patterns = [] + # May suit for operations like: Dropout, Reshape, etc. + operator_set.append(schema.OperatorsSet("NoQuantization", + default_configuration_options.clone_and_edit( + enable_activation_quantization=False) + .clone_and_edit_weight_attribute(enable_weights_quantization=False))) + + # Define operator sets that use mixed_precision_configuration_options: + conv = schema.OperatorsSet("Conv", mixed_precision_configuration_options) + fc = schema.OperatorsSet("FullyConnected", mixed_precision_configuration_options) + + # Define operations sets without quantization configuration + # options (useful for creating fusing patterns, for example): + any_relu = schema.OperatorsSet("AnyReLU") + add = schema.OperatorsSet("Add") + sub = schema.OperatorsSet("Sub") + mul = schema.OperatorsSet("Mul") + div = schema.OperatorsSet("Div") + prelu = schema.OperatorsSet("PReLU") + swish = schema.OperatorsSet("Swish") + sigmoid = schema.OperatorsSet("Sigmoid") + tanh = schema.OperatorsSet("Tanh") + + operator_set.extend([conv, fc, any_relu, add, sub, mul, div, prelu, swish, sigmoid, tanh]) + # Combine multiple operators into a single operator to avoid quantization between + # them. To do this we define fusing patterns using the OperatorsSets that were created. + # To group multiple sets with regard to fusing, an OperatorSetConcat can be created + activations_after_conv_to_fuse = schema.OperatorSetConcat([any_relu, swish, prelu, sigmoid, tanh]) + activations_after_fc_to_fuse = schema.OperatorSetConcat([any_relu, swish, sigmoid]) + any_binary = schema.OperatorSetConcat([add, sub, mul, div]) + + # ------------------- # + # Fusions + # ------------------- # + fusing_patterns.append(schema.Fusing((conv, activations_after_conv_to_fuse))) + fusing_patterns.append(schema.Fusing((fc, activations_after_fc_to_fuse))) + fusing_patterns.append(schema.Fusing((any_binary, any_relu))) # Create a TargetPlatformModel and set its default quantization config. # This default configuration will be used for all operations @@ -162,56 +211,9 @@ def generate_tp_model(default_config: OpQuantizationConfig, tpc_minor_version=2, tpc_patch_version=0, tpc_platform_type=IMX500_TP_MODEL, + operator_set=tuple(operator_set), + fusing_patterns=tuple(fusing_patterns), add_metadata=True, name=name) - # To start defining the model's components (such as operator sets, and fusing patterns), - # use 'with' the TargetPlatformModel instance, and create them as below: - with generated_tpm: - # Create an OperatorsSet to represent a set of operations. - # Each OperatorsSet has a unique label. - # If a quantization configuration options is passed, these options will - # be used for operations that will be attached to this set's label. - # Otherwise, it will be a configure-less set (used in fusing): - - # May suit for operations like: Dropout, Reshape, etc. - default_qco = tp.get_default_quantization_config_options() - schema.OperatorsSet("NoQuantization", - default_qco.clone_and_edit(enable_activation_quantization=False) - .clone_and_edit_weight_attribute(enable_weights_quantization=False)) - - # Create Mixed-Precision quantization configuration options from the given list of OpQuantizationConfig objects - mixed_precision_configuration_options = schema.QuantizationConfigOptions(mixed_precision_cfg_list, - base_config=base_config) - - # Define operator sets that use mixed_precision_configuration_options: - conv = schema.OperatorsSet("Conv", mixed_precision_configuration_options) - fc = schema.OperatorsSet("FullyConnected", mixed_precision_configuration_options) - - # Define operations sets without quantization configuration - # options (useful for creating fusing patterns, for example): - any_relu = schema.OperatorsSet("AnyReLU") - add = schema.OperatorsSet("Add") - sub = schema.OperatorsSet("Sub") - mul = schema.OperatorsSet("Mul") - div = schema.OperatorsSet("Div") - prelu = schema.OperatorsSet("PReLU") - swish = schema.OperatorsSet("Swish") - sigmoid = schema.OperatorsSet("Sigmoid") - tanh = schema.OperatorsSet("Tanh") - - # Combine multiple operators into a single operator to avoid quantization between - # them. To do this we define fusing patterns using the OperatorsSets that were created. - # To group multiple sets with regard to fusing, an OperatorSetConcat can be created - activations_after_conv_to_fuse = schema.OperatorSetConcat([any_relu, swish, prelu, sigmoid, tanh]) - activations_after_fc_to_fuse = schema.OperatorSetConcat([any_relu, swish, sigmoid]) - any_binary = schema.OperatorSetConcat([add, sub, mul, div]) - - # ------------------- # - # Fusions - # ------------------- # - schema.Fusing([conv, activations_after_conv_to_fuse]) - schema.Fusing([fc, activations_after_fc_to_fuse]) - schema.Fusing([any_binary, any_relu]) - return generated_tpm diff --git a/model_compression_toolkit/target_platform_capabilities/tpc_models/imx500_tpc/v3/tp_model.py b/model_compression_toolkit/target_platform_capabilities/tpc_models/imx500_tpc/v3/tp_model.py index 5e07cb7d9..3ff560d5c 100644 --- a/model_compression_toolkit/target_platform_capabilities/tpc_models/imx500_tpc/v3/tp_model.py +++ b/model_compression_toolkit/target_platform_capabilities/tpc_models/imx500_tpc/v3/tp_model.py @@ -19,7 +19,8 @@ from model_compression_toolkit.constants import FLOAT_BITWIDTH from model_compression_toolkit.target_platform_capabilities.constants import KERNEL_ATTR, BIAS_ATTR, WEIGHTS_N_BITS, \ IMX500_TP_MODEL -from model_compression_toolkit.target_platform_capabilities.schema.mct_current_schema import TargetPlatformModel, Signedness, \ +from model_compression_toolkit.target_platform_capabilities.schema.mct_current_schema import TargetPlatformModel, \ + Signedness, \ AttributeQuantizationConfig, OpQuantizationConfig tp = mct.target_platform @@ -155,7 +156,7 @@ def generate_tp_model(default_config: OpQuantizationConfig, # of possible configurations to consider when quantizing a set of operations (in mixed-precision, for example). # If the QuantizationConfigOptions contains only one configuration, # this configuration will be used for the operation quantization: - default_configuration_options = schema.QuantizationConfigOptions([default_config]) + default_configuration_options = schema.QuantizationConfigOptions(tuple([default_config])) # Create a QuantizationConfigOptions for quantizing constants in functional ops. # Constant configuration is similar to the default eight bit configuration except for PoT @@ -166,7 +167,7 @@ def generate_tp_model(default_config: OpQuantizationConfig, default_weight_attr_config=default_config.default_weight_attr_config.clone_and_edit( enable_weights_quantization=True, weights_per_channel_threshold=True, weights_quantization_method=tp.QuantizationMethod.POWER_OF_TWO)) - const_configuration_options = schema.QuantizationConfigOptions([const_config]) + const_configuration_options = schema.QuantizationConfigOptions(tuple([const_config])) # 16 bits inputs and outputs. Currently, only defined for consts since they are used in operators that # support 16 bit as input and output. @@ -174,9 +175,59 @@ def generate_tp_model(default_config: OpQuantizationConfig, supported_input_activation_n_bits=(8, 16)) const_config_input16_output16 = const_config_input16.clone_and_edit( activation_n_bits=16, signedness=Signedness.SIGNED) - const_configuration_options_inout16 = schema.QuantizationConfigOptions([const_config_input16_output16, - const_config_input16], - base_config=const_config_input16) + const_configuration_options_inout16 = schema.QuantizationConfigOptions(tuple([const_config_input16_output16, + const_config_input16]), + base_config=const_config_input16) + + # Create Mixed-Precision quantization configuration options from the given list of OpQuantizationConfig objects + mixed_precision_configuration_options = schema.QuantizationConfigOptions(tuple(mixed_precision_cfg_list), + base_config=base_config) + + # Create an OperatorsSet to represent a set of operations. + # Each OperatorsSet has a unique label. + # If a quantization configuration options is passed, these options will + # be used for operations that will be attached to this set's label. + # Otherwise, it will be a configure-less set (used in fusing): + operator_set = [] + fusing_patterns = [] + # May suit for operations like: Dropout, Reshape, etc. + operator_set.append(schema.OperatorsSet("NoQuantization", + default_configuration_options.clone_and_edit( + enable_activation_quantization=False, + supported_input_activation_n_bits=(8, 16)) + .clone_and_edit_weight_attribute(enable_weights_quantization=False))) + operator_set.append(schema.OperatorsSet("Default16BitInout", const_configuration_options_inout16)) + + # Define operator sets that use mixed_precision_configuration_options: + conv = schema.OperatorsSet("Conv", mixed_precision_configuration_options) + fc = schema.OperatorsSet("FullyConnected", mixed_precision_configuration_options) + + # Define operations sets without quantization configuration + # options (useful for creating fusing patterns, for example): + any_relu = schema.OperatorsSet("AnyReLU") + add = schema.OperatorsSet("Add", const_configuration_options_inout16) + sub = schema.OperatorsSet("Sub", const_configuration_options_inout16) + mul = schema.OperatorsSet("Mul", const_configuration_options_inout16) + div = schema.OperatorsSet("Div", const_configuration_options) + prelu = schema.OperatorsSet("PReLU") + swish = schema.OperatorsSet("Swish") + sigmoid = schema.OperatorsSet("Sigmoid") + tanh = schema.OperatorsSet("Tanh") + + operator_set.extend([conv, fc, any_relu, add, sub, mul, div, prelu, swish, sigmoid, tanh]) + # Combine multiple operators into a single operator to avoid quantization between + # them. To do this we define fusing patterns using the OperatorsSets that were created. + # To group multiple sets with regard to fusing, an OperatorSetConcat can be created + activations_after_conv_to_fuse = schema.OperatorSetConcat([any_relu, swish, prelu, sigmoid, tanh]) + activations_after_fc_to_fuse = schema.OperatorSetConcat([any_relu, swish, sigmoid]) + any_binary = schema.OperatorSetConcat([add, sub, mul, div]) + + # ------------------- # + # Fusions + # ------------------- # + fusing_patterns.append(schema.Fusing((conv, activations_after_conv_to_fuse))) + fusing_patterns.append(schema.Fusing((fc, activations_after_fc_to_fuse))) + fusing_patterns.append(schema.Fusing((any_binary, any_relu))) # Create a TargetPlatformModel and set its default quantization config. # This default configuration will be used for all operations @@ -186,59 +237,10 @@ def generate_tp_model(default_config: OpQuantizationConfig, tpc_minor_version=3, tpc_patch_version=0, tpc_platform_type=IMX500_TP_MODEL, + operator_set=tuple(operator_set), + fusing_patterns=tuple(fusing_patterns), add_metadata=True, name=name, is_simd_padding=True) - # To start defining the model's components (such as operator sets, and fusing patterns), - # use 'with' the TargetPlatformModel instance, and create them as below: - with generated_tpm: - # Create an OperatorsSet to represent a set of operations. - # Each OperatorsSet has a unique label. - # If a quantization configuration options is passed, these options will - # be used for operations that will be attached to this set's label. - # Otherwise, it will be a configure-less set (used in fusing): - - # May suit for operations like: Dropout, Reshape, etc. - default_qco = tp.get_default_quantization_config_options() - schema.OperatorsSet("NoQuantization", - default_qco.clone_and_edit(enable_activation_quantization=False, - supported_input_activation_n_bits=(8, 16)) - .clone_and_edit_weight_attribute(enable_weights_quantization=False)) - schema.OperatorsSet("Default16BitInout", const_configuration_options_inout16) - - # Create Mixed-Precision quantization configuration options from the given list of OpQuantizationConfig objects - mixed_precision_configuration_options = schema.QuantizationConfigOptions(mixed_precision_cfg_list, - base_config=base_config) - - # Define operator sets that use mixed_precision_configuration_options: - conv = schema.OperatorsSet("Conv", mixed_precision_configuration_options) - fc = schema.OperatorsSet("FullyConnected", mixed_precision_configuration_options) - - # Define operations sets without quantization configuration - # options (useful for creating fusing patterns, for example): - any_relu = schema.OperatorsSet("AnyReLU") - add = schema.OperatorsSet("Add", const_configuration_options_inout16) - sub = schema.OperatorsSet("Sub", const_configuration_options_inout16) - mul = schema.OperatorsSet("Mul", const_configuration_options_inout16) - div = schema.OperatorsSet("Div", const_configuration_options) - prelu = schema.OperatorsSet("PReLU") - swish = schema.OperatorsSet("Swish") - sigmoid = schema.OperatorsSet("Sigmoid") - tanh = schema.OperatorsSet("Tanh") - - # Combine multiple operators into a single operator to avoid quantization between - # them. To do this we define fusing patterns using the OperatorsSets that were created. - # To group multiple sets with regard to fusing, an OperatorSetConcat can be created - activations_after_conv_to_fuse = schema.OperatorSetConcat([any_relu, swish, prelu, sigmoid, tanh]) - activations_after_fc_to_fuse = schema.OperatorSetConcat([any_relu, swish, sigmoid]) - any_binary = schema.OperatorSetConcat([add, sub, mul, div]) - - # ------------------- # - # Fusions - # ------------------- # - schema.Fusing([conv, activations_after_conv_to_fuse]) - schema.Fusing([fc, activations_after_fc_to_fuse]) - schema.Fusing([any_binary, any_relu]) - return generated_tpm diff --git a/model_compression_toolkit/target_platform_capabilities/tpc_models/imx500_tpc/v3_lut/tp_model.py b/model_compression_toolkit/target_platform_capabilities/tpc_models/imx500_tpc/v3_lut/tp_model.py index 8b25c33c2..f1de8b6e0 100644 --- a/model_compression_toolkit/target_platform_capabilities/tpc_models/imx500_tpc/v3_lut/tp_model.py +++ b/model_compression_toolkit/target_platform_capabilities/tpc_models/imx500_tpc/v3_lut/tp_model.py @@ -19,7 +19,8 @@ from model_compression_toolkit.constants import FLOAT_BITWIDTH from model_compression_toolkit.target_platform_capabilities.constants import KERNEL_ATTR, BIAS_ATTR, WEIGHTS_N_BITS, \ WEIGHTS_QUANTIZATION_METHOD, IMX500_TP_MODEL -from model_compression_toolkit.target_platform_capabilities.schema.mct_current_schema import TargetPlatformModel, Signedness, \ +from model_compression_toolkit.target_platform_capabilities.schema.mct_current_schema import TargetPlatformModel, \ + Signedness, \ AttributeQuantizationConfig, OpQuantizationConfig tp = mct.target_platform @@ -152,7 +153,7 @@ def generate_tp_model(default_config: OpQuantizationConfig, # of possible configurations to consider when quantizing a set of operations (in mixed-precision, for example). # If the QuantizationConfigOptions contains only one configuration, # this configuration will be used for the operation quantization: - default_configuration_options = schema.QuantizationConfigOptions([default_config]) + default_configuration_options = schema.QuantizationConfigOptions(tuple([default_config])) # Create a QuantizationConfigOptions for quantizing constants in functional ops. # Constant configuration is similar to the default eight bit configuration except for PoT @@ -163,7 +164,55 @@ def generate_tp_model(default_config: OpQuantizationConfig, default_weight_attr_config=default_config.default_weight_attr_config.clone_and_edit( enable_weights_quantization=True, weights_per_channel_threshold=True, weights_quantization_method=tp.QuantizationMethod.POWER_OF_TWO)) - const_configuration_options = schema.QuantizationConfigOptions([const_config]) + const_configuration_options = schema.QuantizationConfigOptions(tuple([const_config])) + + # Create Mixed-Precision quantization configuration options from the given list of OpQuantizationConfig objects + mixed_precision_configuration_options = schema.QuantizationConfigOptions(tuple(mixed_precision_cfg_list), + base_config=base_config) + + # Create an OperatorsSet to represent a set of operations. + # Each OperatorsSet has a unique label. + # If a quantization configuration options is passed, these options will + # be used for operations that will be attached to this set's label. + # Otherwise, it will be a configure-less set (used in fusing): + operator_set = [] + fusing_patterns = [] + # May suit for operations like: Dropout, Reshape, etc. + operator_set.append(schema.OperatorsSet("NoQuantization", + default_configuration_options.clone_and_edit( + enable_activation_quantization=False) + .clone_and_edit_weight_attribute(enable_weights_quantization=False))) + + # Define operator sets that use mixed_precision_configuration_options: + conv = schema.OperatorsSet("Conv", mixed_precision_configuration_options) + fc = schema.OperatorsSet("FullyConnected", mixed_precision_configuration_options) + + # Define operations sets without quantization configuration + # options (useful for creating fusing patterns, for example): + any_relu = schema.OperatorsSet("AnyReLU") + add = schema.OperatorsSet("Add", const_configuration_options) + sub = schema.OperatorsSet("Sub", const_configuration_options) + mul = schema.OperatorsSet("Mul", const_configuration_options) + div = schema.OperatorsSet("Div", const_configuration_options) + prelu = schema.OperatorsSet("PReLU") + swish = schema.OperatorsSet("Swish") + sigmoid = schema.OperatorsSet("Sigmoid") + tanh = schema.OperatorsSet("Tanh") + + operator_set.extend([conv, fc, any_relu, add, sub, mul, div, prelu, swish, sigmoid, tanh]) + # Combine multiple operators into a single operator to avoid quantization between + # them. To do this we define fusing patterns using the OperatorsSets that were created. + # To group multiple sets with regard to fusing, an OperatorSetConcat can be created + activations_after_conv_to_fuse = schema.OperatorSetConcat([any_relu, swish, prelu, sigmoid, tanh]) + activations_after_fc_to_fuse = schema.OperatorSetConcat([any_relu, swish, sigmoid]) + any_binary = schema.OperatorSetConcat([add, sub, mul, div]) + + # ------------------- # + # Fusions + # ------------------- # + fusing_patterns.append(schema.Fusing((conv, activations_after_conv_to_fuse))) + fusing_patterns.append(schema.Fusing((fc, activations_after_fc_to_fuse))) + fusing_patterns.append(schema.Fusing((any_binary, any_relu))) # Create a TargetPlatformModel and set its default quantization config. # This default configuration will be used for all operations @@ -173,56 +222,9 @@ def generate_tp_model(default_config: OpQuantizationConfig, tpc_minor_version=3, tpc_patch_version=0, tpc_platform_type=IMX500_TP_MODEL, + operator_set=tuple(operator_set), + fusing_patterns=tuple(fusing_patterns), add_metadata=True, name=name) - # To start defining the model's components (such as operator sets, and fusing patterns), - # use 'with' the TargetPlatformModel instance, and create them as below: - with generated_tpm: - # Create an OperatorsSet to represent a set of operations. - # Each OperatorsSet has a unique label. - # If a quantization configuration options is passed, these options will - # be used for operations that will be attached to this set's label. - # Otherwise, it will be a configure-less set (used in fusing): - - # May suit for operations like: Dropout, Reshape, etc. - default_qco = tp.get_default_quantization_config_options() - schema.OperatorsSet("NoQuantization", - default_qco.clone_and_edit(enable_activation_quantization=False) - .clone_and_edit_weight_attribute(enable_weights_quantization=False)) - - # Create Mixed-Precision quantization configuration options from the given list of OpQuantizationConfig objects - mixed_precision_configuration_options = schema.QuantizationConfigOptions(mixed_precision_cfg_list, - base_config=base_config) - - # Define operator sets that use mixed_precision_configuration_options: - conv = schema.OperatorsSet("Conv", mixed_precision_configuration_options) - fc = schema.OperatorsSet("FullyConnected", mixed_precision_configuration_options) - - # Define operations sets without quantization configuration - # options (useful for creating fusing patterns, for example): - any_relu = schema.OperatorsSet("AnyReLU") - add = schema.OperatorsSet("Add", const_configuration_options) - sub = schema.OperatorsSet("Sub", const_configuration_options) - mul = schema.OperatorsSet("Mul", const_configuration_options) - div = schema.OperatorsSet("Div", const_configuration_options) - prelu = schema.OperatorsSet("PReLU") - swish = schema.OperatorsSet("Swish") - sigmoid = schema.OperatorsSet("Sigmoid") - tanh = schema.OperatorsSet("Tanh") - - # Combine multiple operators into a single operator to avoid quantization between - # them. To do this we define fusing patterns using the OperatorsSets that were created. - # To group multiple sets with regard to fusing, an OperatorSetConcat can be created - activations_after_conv_to_fuse = schema.OperatorSetConcat([any_relu, swish, prelu, sigmoid, tanh]) - activations_after_fc_to_fuse = schema.OperatorSetConcat([any_relu, swish, sigmoid]) - any_binary = schema.OperatorSetConcat([add, sub, mul, div]) - - # ------------------- # - # Fusions - # ------------------- # - schema.Fusing([conv, activations_after_conv_to_fuse]) - schema.Fusing([fc, activations_after_fc_to_fuse]) - schema.Fusing([any_binary, any_relu]) - return generated_tpm diff --git a/model_compression_toolkit/target_platform_capabilities/tpc_models/imx500_tpc/v4/tp_model.py b/model_compression_toolkit/target_platform_capabilities/tpc_models/imx500_tpc/v4/tp_model.py index 2f658d2f8..53f4b888f 100644 --- a/model_compression_toolkit/target_platform_capabilities/tpc_models/imx500_tpc/v4/tp_model.py +++ b/model_compression_toolkit/target_platform_capabilities/tpc_models/imx500_tpc/v4/tp_model.py @@ -19,7 +19,8 @@ from model_compression_toolkit.constants import FLOAT_BITWIDTH from model_compression_toolkit.target_platform_capabilities.constants import KERNEL_ATTR, BIAS_ATTR, WEIGHTS_N_BITS, \ IMX500_TP_MODEL -from model_compression_toolkit.target_platform_capabilities.schema.mct_current_schema import TargetPlatformModel, Signedness, \ +from model_compression_toolkit.target_platform_capabilities.schema.mct_current_schema import TargetPlatformModel, \ + Signedness, \ AttributeQuantizationConfig, OpQuantizationConfig tp = mct.target_platform @@ -87,7 +88,8 @@ def get_op_quantization_configs() -> \ weights_quantization_method=tp.QuantizationMethod.POWER_OF_TWO, weights_n_bits=8, weights_per_channel_threshold=False, - enable_weights_quantization=False, # TODO: this will changed to True once implementing multi-attributes quantization + enable_weights_quantization=False, + # TODO: this will changed to True once implementing multi-attributes quantization lut_values_bitwidth=None) # define a quantization config to quantize the kernel (for layers where there is a kernel attribute). @@ -176,13 +178,13 @@ def generate_tp_model(default_config: OpQuantizationConfig, # of possible configurations to consider when quantizing a set of operations (in mixed-precision, for example). # If the QuantizationConfigOptions contains only one configuration, # this configuration will be used for the operation quantization: - default_configuration_options = schema.QuantizationConfigOptions([default_config]) + default_configuration_options = schema.QuantizationConfigOptions(tuple([default_config])) default_config_input16 = default_config.clone_and_edit(supported_input_activation_n_bits=(8, 16)) - default_config_options_16bit = schema.QuantizationConfigOptions([default_config_input16, - default_config_input16.clone_and_edit( - activation_n_bits=16, - signedness=Signedness.SIGNED)], - base_config=default_config_input16) + default_config_options_16bit = schema.QuantizationConfigOptions(tuple([default_config_input16, + default_config_input16.clone_and_edit( + activation_n_bits=16, + signedness=Signedness.SIGNED)]), + base_config=default_config_input16) # Create a QuantizationConfigOptions for quantizing constants in functional ops. # Constant configuration is similar to the default eight bit configuration except for PoT @@ -193,7 +195,7 @@ def generate_tp_model(default_config: OpQuantizationConfig, default_weight_attr_config=default_config.default_weight_attr_config.clone_and_edit( enable_weights_quantization=True, weights_per_channel_threshold=True, weights_quantization_method=tp.QuantizationMethod.POWER_OF_TWO)) - const_configuration_options = schema.QuantizationConfigOptions([const_config]) + const_configuration_options = schema.QuantizationConfigOptions(tuple([const_config])) # 16 bits inputs and outputs. Currently, only defined for consts since they are used in operators that # support 16 bit as input and output. @@ -201,9 +203,9 @@ def generate_tp_model(default_config: OpQuantizationConfig, supported_input_activation_n_bits=(8, 16)) const_config_input16_output16 = const_config_input16.clone_and_edit( activation_n_bits=16, signedness=Signedness.SIGNED) - const_configuration_options_inout16 = schema.QuantizationConfigOptions([const_config_input16_output16, - const_config_input16], - base_config=const_config_input16) + const_configuration_options_inout16 = schema.QuantizationConfigOptions(tuple([const_config_input16_output16, + const_config_input16]), + base_config=const_config_input16) const_config_input16_per_tensor = const_config.clone_and_edit( supported_input_activation_n_bits=(8, 16), @@ -213,20 +215,91 @@ def generate_tp_model(default_config: OpQuantizationConfig, ) const_config_input16_output16_per_tensor = const_config_input16_per_tensor.clone_and_edit( activation_n_bits=16, signedness=Signedness.SIGNED) - const_configuration_options_inout16_per_tensor = schema.QuantizationConfigOptions( + const_configuration_options_inout16_per_tensor = schema.QuantizationConfigOptions(tuple( [const_config_input16_output16_per_tensor, - const_config_input16_per_tensor], + const_config_input16_per_tensor]), base_config=const_config_input16_per_tensor) qpreserving_const_config = const_config.clone_and_edit(enable_activation_quantization=False, quantization_preserving=True, default_weight_attr_config=const_config.default_weight_attr_config.clone_and_edit( weights_per_channel_threshold=False)) - qpreserving_const_config_options = schema.QuantizationConfigOptions([qpreserving_const_config]) + qpreserving_const_config_options = schema.QuantizationConfigOptions(tuple([qpreserving_const_config])) mp_cfg_list_16bit = [mp_cfg.clone_and_edit(activation_n_bits=16, signedness=Signedness.SIGNED) for mp_cfg in mixed_precision_cfg_list] + # Create Mixed-Precision quantization configuration options from the given list of OpQuantizationConfig objects + mixed_precision_configuration_options = schema.QuantizationConfigOptions(tuple( + mixed_precision_cfg_list + mp_cfg_list_16bit), + base_config=base_config) + + # Create an OperatorsSet to represent a set of operations. + # Each OperatorsSet has a unique label. + # If a quantization configuration options is passed, these options will + # be used for operations that will be attached to this set's label. + # Otherwise, it will be a configure-less set (used in fusing): + operator_set = [] + fusing_patterns = [] + # May suit for operations like: Dropout, Reshape, etc. + operator_set.append(schema.OperatorsSet(OPSET_NO_QUANTIZATION, + default_configuration_options.clone_and_edit( + enable_activation_quantization=False) + .clone_and_edit_weight_attribute(enable_weights_quantization=False))) + operator_set.append(schema.OperatorsSet(OPSET_QUANTIZATION_PRESERVING, + default_configuration_options.clone_and_edit( + enable_activation_quantization=False, + quantization_preserving=True) + .clone_and_edit_weight_attribute(enable_weights_quantization=False))) + operator_set.append( + schema.OperatorsSet(OPSET_DIMENSION_MANIPULATION_OPS_WITH_WEIGHTS, qpreserving_const_config_options)) + operator_set.append(schema.OperatorsSet(OPSET_DIMENSION_MANIPULATION_OPS, + default_configuration_options.clone_and_edit( + enable_activation_quantization=False, + quantization_preserving=True, + supported_input_activation_n_bits=(8, 16)) + .clone_and_edit_weight_attribute(enable_weights_quantization=False))) + operator_set.append(schema.OperatorsSet(OPSET_MERGE_OPS, const_configuration_options_inout16_per_tensor)) + + # Define operator sets that use mixed_precision_configuration_options: + conv = schema.OperatorsSet(OPSET_CONV, mixed_precision_configuration_options) + fc = schema.OperatorsSet(OPSET_FULLY_CONNECTED, mixed_precision_configuration_options) + + operator_set.append(schema.OperatorsSet(OPSET_BATCH_NORM, default_config_options_16bit)) + + # Note: Operations sets without quantization configuration are useful for creating fusing patterns + any_relu = schema.OperatorsSet(OPSET_ANY_RELU, default_config_options_16bit) + add = schema.OperatorsSet(OPSET_ADD, const_configuration_options_inout16) + sub = schema.OperatorsSet(OPSET_SUB, const_configuration_options_inout16) + mul = schema.OperatorsSet(OPSET_MUL, const_configuration_options_inout16) + div = schema.OperatorsSet(OPSET_DIV, const_configuration_options) + min_max = schema.OperatorsSet(OPSET_MIN_MAX, const_configuration_options_inout16) + prelu = schema.OperatorsSet(OPSET_PRELU, default_config_options_16bit) + swish = schema.OperatorsSet(OPSET_SWISH, default_config_options_16bit) + sigmoid = schema.OperatorsSet(OPSET_SIGMOID, default_config_options_16bit) + tanh = schema.OperatorsSet(OPSET_TANH, default_config_options_16bit) + gelu = schema.OperatorsSet(OPSET_GELU, default_config_options_16bit) + hardsigmoid = schema.OperatorsSet(OPSET_HARDSIGMOID, default_config_options_16bit) + hardswish = schema.OperatorsSet(OPSET_HARDSWISH, default_config_options_16bit) + + operator_set.extend( + [conv, fc, any_relu, add, sub, mul, div, prelu, swish, sigmoid, tanh, min_max, gelu, hardsigmoid, hardswish]) + # Combine multiple operators into a single operator to avoid quantization between + # them. To do this we define fusing patterns using the OperatorsSets that were created. + # To group multiple sets with regard to fusing, an OperatorSetConcat can be created + activations_after_conv_to_fuse = schema.OperatorSetConcat([any_relu, swish, prelu, sigmoid, + tanh, gelu, hardswish, hardsigmoid]) + activations_after_fc_to_fuse = schema.OperatorSetConcat([any_relu, swish, sigmoid, tanh, gelu, + hardswish, hardsigmoid]) + any_binary = schema.OperatorSetConcat([add, sub, mul, div]) + + # ------------------- # + # Fusions + # ------------------- # + fusing_patterns.append(schema.Fusing((conv, activations_after_conv_to_fuse))) + fusing_patterns.append(schema.Fusing((fc, activations_after_fc_to_fuse))) + fusing_patterns.append(schema.Fusing((any_binary, any_relu))) + # Create a TargetPlatformModel and set its default quantization config. # This default configuration will be used for all operations # unless specified otherwise (see OperatorsSet, for example): @@ -235,76 +308,10 @@ def generate_tp_model(default_config: OpQuantizationConfig, tpc_minor_version=4, tpc_patch_version=0, tpc_platform_type=IMX500_TP_MODEL, + operator_set=tuple(operator_set), + fusing_patterns=tuple(fusing_patterns), add_metadata=True, name=name, is_simd_padding=True) - # To start defining the model's components (such as operator sets, and fusing patterns), - # use 'with' the TargetPlatformModel instance, and create them as below: - with generated_tpm: - # Create an OperatorsSet to represent a set of operations. - # Each OperatorsSet has a unique label. - # If a quantization configuration options is passed, these options will - # be used for operations that will be attached to this set's label. - # Otherwise, it will be a configure-less set (used in fusing): - - # May suit for operations like: Dropout, Reshape, etc. - default_qco = tp.get_default_quantization_config_options() - schema.OperatorsSet(OPSET_NO_QUANTIZATION, - default_qco.clone_and_edit(enable_activation_quantization=False) - .clone_and_edit_weight_attribute(enable_weights_quantization=False)) - schema.OperatorsSet(OPSET_QUANTIZATION_PRESERVING, - default_qco.clone_and_edit(enable_activation_quantization=False, - quantization_preserving=True) - .clone_and_edit_weight_attribute(enable_weights_quantization=False)) - schema.OperatorsSet(OPSET_DIMENSION_MANIPULATION_OPS_WITH_WEIGHTS, qpreserving_const_config_options) - schema.OperatorsSet(OPSET_DIMENSION_MANIPULATION_OPS, - default_qco.clone_and_edit(enable_activation_quantization=False, - quantization_preserving=True, - supported_input_activation_n_bits=(8, 16)) - .clone_and_edit_weight_attribute(enable_weights_quantization=False)) - schema.OperatorsSet(OPSET_MERGE_OPS, const_configuration_options_inout16_per_tensor) - - # Create Mixed-Precision quantization configuration options from the given list of OpQuantizationConfig objects - mixed_precision_configuration_options = schema.QuantizationConfigOptions( - mixed_precision_cfg_list + mp_cfg_list_16bit, - base_config=base_config) - - # Define operator sets that use mixed_precision_configuration_options: - conv = schema.OperatorsSet(OPSET_CONV, mixed_precision_configuration_options) - fc = schema.OperatorsSet(OPSET_FULLY_CONNECTED, mixed_precision_configuration_options) - - schema.OperatorsSet(OPSET_BATCH_NORM, default_config_options_16bit) - - # Note: Operations sets without quantization configuration are useful for creating fusing patterns - any_relu = schema.OperatorsSet(OPSET_ANY_RELU, default_config_options_16bit) - add = schema.OperatorsSet(OPSET_ADD, const_configuration_options_inout16) - sub = schema.OperatorsSet(OPSET_SUB, const_configuration_options_inout16) - mul = schema.OperatorsSet(OPSET_MUL, const_configuration_options_inout16) - div = schema.OperatorsSet(OPSET_DIV, const_configuration_options) - schema.OperatorsSet(OPSET_MIN_MAX, const_configuration_options_inout16) - prelu = schema.OperatorsSet(OPSET_PRELU, default_config_options_16bit) - swish = schema.OperatorsSet(OPSET_SWISH, default_config_options_16bit) - sigmoid = schema.OperatorsSet(OPSET_SIGMOID, default_config_options_16bit) - tanh = schema.OperatorsSet(OPSET_TANH, default_config_options_16bit) - gelu = schema.OperatorsSet(OPSET_GELU, default_config_options_16bit) - hardsigmoid = schema.OperatorsSet(OPSET_HARDSIGMOID, default_config_options_16bit) - hardswish = schema.OperatorsSet(OPSET_HARDSWISH, default_config_options_16bit) - - # Combine multiple operators into a single operator to avoid quantization between - # them. To do this we define fusing patterns using the OperatorsSets that were created. - # To group multiple sets with regard to fusing, an OperatorSetConcat can be created - activations_after_conv_to_fuse = schema.OperatorSetConcat([any_relu, swish, prelu, sigmoid, - tanh, gelu, hardswish, hardsigmoid]) - activations_after_fc_to_fuse = schema.OperatorSetConcat([any_relu, swish, sigmoid, tanh, gelu, - hardswish, hardsigmoid]) - any_binary = schema.OperatorSetConcat([add, sub, mul, div]) - - # ------------------- # - # Fusions - # ------------------- # - schema.Fusing([conv, activations_after_conv_to_fuse]) - schema.Fusing([fc, activations_after_fc_to_fuse]) - schema.Fusing([any_binary, any_relu]) - return generated_tpm diff --git a/model_compression_toolkit/target_platform_capabilities/tpc_models/qnnpack_tpc/v1/tp_model.py b/model_compression_toolkit/target_platform_capabilities/tpc_models/qnnpack_tpc/v1/tp_model.py index 232630f30..5a94c4ebf 100644 --- a/model_compression_toolkit/target_platform_capabilities/tpc_models/qnnpack_tpc/v1/tp_model.py +++ b/model_compression_toolkit/target_platform_capabilities/tpc_models/qnnpack_tpc/v1/tp_model.py @@ -18,7 +18,8 @@ import model_compression_toolkit.target_platform_capabilities.schema.mct_current_schema as schema from model_compression_toolkit.constants import FLOAT_BITWIDTH from model_compression_toolkit.target_platform_capabilities.constants import KERNEL_ATTR, BIAS_ATTR, QNNPACK_TP_MODEL -from model_compression_toolkit.target_platform_capabilities.schema.mct_current_schema import TargetPlatformModel, Signedness, \ +from model_compression_toolkit.target_platform_capabilities.schema.mct_current_schema import TargetPlatformModel, \ + Signedness, \ AttributeQuantizationConfig, OpQuantizationConfig tp = mct.target_platform @@ -138,8 +139,28 @@ def generate_tp_model(default_config: OpQuantizationConfig, # of possible configurations to consider when quantizing a set of operations (in mixed-precision, for example). # If the QuantizationConfigOptions contains only one configuration, # this configuration will be used for the operation quantization: - default_configuration_options = schema.QuantizationConfigOptions([default_config]) - + default_configuration_options = schema.QuantizationConfigOptions(tuple([default_config])) + + # Combine operations/modules into a single module. + # Pytorch supports the next fusing patterns: + # [Conv, Relu], [Conv, BatchNorm], [Conv, BatchNorm, Relu], [Linear, Relu] + # Source: # https://pytorch.org/docs/stable/quantization.html#model-preparation-for-quantization-eager-mode + operator_set = [] + fusing_patterns = [] + + conv = schema.OperatorsSet("Conv") + batchnorm = schema.OperatorsSet("BatchNorm") + relu = schema.OperatorsSet("Relu") + linear = schema.OperatorsSet("Linear") + + operator_set.extend([conv, batchnorm, relu, linear]) + # ------------------- # + # Fusions + # ------------------- # + fusing_patterns.append(schema.Fusing((conv, batchnorm, relu))) + fusing_patterns.append(schema.Fusing((conv, batchnorm))) + fusing_patterns.append(schema.Fusing((conv, relu))) + fusing_patterns.append(schema.Fusing((linear, relu))) # Create a TargetPlatformModel and set its default quantization config. # This default configuration will be used for all operations # unless specified otherwise (see OperatorsSet, for example): @@ -148,27 +169,8 @@ def generate_tp_model(default_config: OpQuantizationConfig, tpc_minor_version=1, tpc_patch_version=0, tpc_platform_type=QNNPACK_TP_MODEL, + operator_set=tuple(operator_set), + fusing_patterns=tuple(fusing_patterns), add_metadata=False, name=name) - - # To start defining the model's components (such as operator sets, and fusing patterns), - # use 'with' the target platform model instance, and create them as below: - with generated_tpc: - # Combine operations/modules into a single module. - # Pytorch supports the next fusing patterns: - # [Conv, Relu], [Conv, BatchNorm], [Conv, BatchNorm, Relu], [Linear, Relu] - # Source: # https://pytorch.org/docs/stable/quantization.html#model-preparation-for-quantization-eager-mode - conv = schema.OperatorsSet("Conv") - batchnorm = schema.OperatorsSet("BatchNorm") - relu = schema.OperatorsSet("Relu") - linear = schema.OperatorsSet("Linear") - - # ------------------- # - # Fusions - # ------------------- # - schema.Fusing([conv, batchnorm, relu]) - schema.Fusing([conv, batchnorm]) - schema.Fusing([conv, relu]) - schema.Fusing([linear, relu]) - return generated_tpc diff --git a/model_compression_toolkit/target_platform_capabilities/tpc_models/tflite_tpc/v1/tp_model.py b/model_compression_toolkit/target_platform_capabilities/tpc_models/tflite_tpc/v1/tp_model.py index d269d7f4e..3d664ab97 100644 --- a/model_compression_toolkit/target_platform_capabilities/tpc_models/tflite_tpc/v1/tp_model.py +++ b/model_compression_toolkit/target_platform_capabilities/tpc_models/tflite_tpc/v1/tp_model.py @@ -136,7 +136,61 @@ def generate_tp_model(default_config: OpQuantizationConfig, # of possible configurations to consider when quantizing a set of operations (in mixed-precision, for example). # If the QuantizationConfigOptions contains only one configuration, # this configuration will be used for the operation quantization: - default_configuration_options = schema.QuantizationConfigOptions([default_config]) + default_configuration_options = schema.QuantizationConfigOptions(tuple([default_config])) + + # In TFLite, the quantized operator specifications constraint operators quantization + # differently. For more details: + # https://www.tensorflow.org/lite/performance/quantization_spec#int8_quantized_operator_specifications + operator_set = [] + fusing_patterns = [] + + operator_set.append(schema.OperatorsSet("NoQuantization", + default_configuration_options.clone_and_edit( + quantization_preserving=True))) + + fc = schema.OperatorsSet("FullyConnected", + default_configuration_options.clone_and_edit_weight_attribute(weights_per_channel_threshold=False)) + + operator_set.append(schema.OperatorsSet("L2Normalization", + default_configuration_options.clone_and_edit( + fixed_zero_point=0, fixed_scale=1 / 128))) + operator_set.append(schema.OperatorsSet("LogSoftmax", + default_configuration_options.clone_and_edit( + fixed_zero_point=127, fixed_scale=16 / 256))) + operator_set.append(schema.OperatorsSet("Tanh", + default_configuration_options.clone_and_edit( + fixed_zero_point=0, fixed_scale=1 / 128))) + operator_set.append(schema.OperatorsSet("Softmax", + default_configuration_options.clone_and_edit( + fixed_zero_point=-128, fixed_scale=1 / 256))) + operator_set.append(schema.OperatorsSet("Logistic", + default_configuration_options.clone_and_edit( + fixed_zero_point=-128, fixed_scale=1 / 256))) + + conv2d = schema.OperatorsSet("Conv2d") + kernel = schema.OperatorSetConcat([conv2d, fc]) + + relu = schema.OperatorsSet("Relu") + elu = schema.OperatorsSet("Elu") + activations_to_fuse = schema.OperatorSetConcat([relu, elu]) + + batch_norm = schema.OperatorsSet("BatchNorm") + bias_add = schema.OperatorsSet("BiasAdd") + add = schema.OperatorsSet("Add") + squeeze = schema.OperatorsSet("Squeeze", + qc_options=default_configuration_options.clone_and_edit( + quantization_preserving=True)) + operator_set.extend([fc, conv2d, kernel, relu, elu, batch_norm, bias_add, add, squeeze]) + # ------------------- # + # Fusions + # ------------------- # + # Source: https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/grappler/optimizers/remapper + fusing_patterns.append(schema.Fusing((kernel, bias_add))) + fusing_patterns.append(schema.Fusing((kernel, bias_add, activations_to_fuse))) + fusing_patterns.append(schema.Fusing((conv2d, batch_norm, activations_to_fuse))) + fusing_patterns.append(schema.Fusing((conv2d, squeeze, activations_to_fuse))) + fusing_patterns.append(schema.Fusing((batch_norm, activations_to_fuse))) + fusing_patterns.append(schema.Fusing((batch_norm, add, activations_to_fuse))) # Create a TargetPlatformModel and set its default quantization config. # This default configuration will be used for all operations @@ -145,62 +199,10 @@ def generate_tp_model(default_config: OpQuantizationConfig, default_configuration_options, tpc_minor_version=1, tpc_patch_version=0, + operator_set=tuple(operator_set), + fusing_patterns=tuple(fusing_patterns), tpc_platform_type=TFLITE_TP_MODEL, add_metadata=False, name=name) - # To start defining the model's components (such as operator sets, and fusing patterns), - # use 'with' the TargetPlatformModel instance, and create them as below: - with generated_tpc: - # In TFLite, the quantized operator specifications constraint operators quantization - # differently. For more details: - # https://www.tensorflow.org/lite/performance/quantization_spec#int8_quantized_operator_specifications - schema.OperatorsSet("NoQuantization", - tp.get_default_quantization_config_options().clone_and_edit( - quantization_preserving=True)) - - fc_qco = tp.get_default_quantization_config_options() - fc = schema.OperatorsSet("FullyConnected", - fc_qco.clone_and_edit_weight_attribute(weights_per_channel_threshold=False)) - - schema.OperatorsSet("L2Normalization", - tp.get_default_quantization_config_options().clone_and_edit( - fixed_zero_point=0, fixed_scale=1 / 128)) - schema.OperatorsSet("LogSoftmax", - tp.get_default_quantization_config_options().clone_and_edit( - fixed_zero_point=127, fixed_scale=16 / 256)) - schema.OperatorsSet("Tanh", - tp.get_default_quantization_config_options().clone_and_edit( - fixed_zero_point=0, fixed_scale=1 / 128)) - schema.OperatorsSet("Softmax", - tp.get_default_quantization_config_options().clone_and_edit( - fixed_zero_point=-128, fixed_scale=1 / 256)) - schema.OperatorsSet("Logistic", - tp.get_default_quantization_config_options().clone_and_edit( - fixed_zero_point=-128, fixed_scale=1 / 256)) - - conv2d = schema.OperatorsSet("Conv2d") - kernel = schema.OperatorSetConcat([conv2d, fc]) - - relu = schema.OperatorsSet("Relu") - elu = schema.OperatorsSet("Elu") - activations_to_fuse = schema.OperatorSetConcat([relu, elu]) - - batch_norm = schema.OperatorsSet("BatchNorm") - bias_add = schema.OperatorsSet("BiasAdd") - add = schema.OperatorsSet("Add") - squeeze = schema.OperatorsSet("Squeeze", - qc_options=tp.get_default_quantization_config_options().clone_and_edit( - quantization_preserving=True)) - # ------------------- # - # Fusions - # ------------------- # - # Source: https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/grappler/optimizers/remapper - schema.Fusing([kernel, bias_add]) - schema.Fusing([kernel, bias_add, activations_to_fuse]) - schema.Fusing([conv2d, batch_norm, activations_to_fuse]) - schema.Fusing([conv2d, squeeze, activations_to_fuse]) - schema.Fusing([batch_norm, activations_to_fuse]) - schema.Fusing([batch_norm, add, activations_to_fuse]) - return generated_tpc diff --git a/tests/common_tests/helpers/generate_test_tp_model.py b/tests/common_tests/helpers/generate_test_tp_model.py index 83faaa43e..56dde1c5b 100644 --- a/tests/common_tests/helpers/generate_test_tp_model.py +++ b/tests/common_tests/helpers/generate_test_tp_model.py @@ -107,7 +107,7 @@ def generate_tp_model_with_activation_mp(base_cfg, default_config, mp_bitwidth_c mixed_precision_cfg_list=mp_op_cfg_list, name=name) - mixed_precision_configuration_options = schema.QuantizationConfigOptions(mp_op_cfg_list, + mixed_precision_configuration_options = schema.QuantizationConfigOptions(tuple(mp_op_cfg_list), base_config=base_cfg) operator_sets_dict = {op_set.name: mixed_precision_configuration_options for op_set in base_tp_model.operator_set @@ -126,35 +126,37 @@ def generate_custom_test_tp_model(name: str, base_cfg: OpQuantizationConfig, base_tp_model: schema.TargetPlatformModel, operator_sets_dict: Dict[str, QuantizationConfigOptions] = None): - default_configuration_options = schema.QuantizationConfigOptions([base_cfg]) + default_configuration_options = schema.QuantizationConfigOptions(tuple([base_cfg])) + + operator_set, fusing_patterns = [], [] + + for op_set in base_tp_model.operator_set: + # Add existing OperatorSets from base TP model + if operator_sets_dict is not None and operator_sets_dict.get(op_set.name) is not None: + qc_options = operator_sets_dict[op_set.name] + else: + qc_options = op_set.qc_options + + operator_set.append(schema.OperatorsSet(op_set.name, qc_options)) + + existing_op_sets_names = [op_set.name for op_set in base_tp_model.operator_set] + for op_set_name, op_set_qc_options in operator_sets_dict.items(): + # Add new OperatorSets from the given operator_sets_dict + if op_set_name not in existing_op_sets_names: + operator_set.append( schema.OperatorsSet(op_set_name, op_set_qc_options)) + + for fusion in base_tp_model.fusing_patterns: + fusing_patterns.append(schema.Fusing(fusion.operator_groups)) custom_tp_model = schema.TargetPlatformModel( default_configuration_options, tpc_minor_version=None, tpc_patch_version=None, tpc_platform_type=None, + operator_set=tuple(operator_set), + fusing_patterns=tuple(fusing_patterns), add_metadata=False, name=name) - - with custom_tp_model: - for op_set in base_tp_model.operator_set: - # Add existing OperatorSets from base TP model - if operator_sets_dict is not None and operator_sets_dict.get(op_set.name) is not None: - qc_options = operator_sets_dict[op_set.name] - else: - qc_options = op_set.qc_options - - schema.OperatorsSet(op_set.name, qc_options) - - existing_op_sets_names = [op_set.name for op_set in base_tp_model.operator_set] - for op_set_name, op_set_qc_options in operator_sets_dict.items(): - # Add new OperatorSets from the given operator_sets_dict - if op_set_name not in existing_op_sets_names: - schema.OperatorsSet(op_set_name, op_set_qc_options) - - for fusion in base_tp_model.fusing_patterns: - schema.Fusing(fusion.operator_groups_list) - return custom_tp_model diff --git a/tests/common_tests/test_tp_model.py b/tests/common_tests/test_tp_model.py index 4e96a13df..b36320456 100644 --- a/tests/common_tests/test_tp_model.py +++ b/tests/common_tests/test_tp_model.py @@ -22,45 +22,30 @@ from model_compression_toolkit.target_platform_capabilities.constants import KERNEL_ATTR, BIAS_ATTR from model_compression_toolkit.target_platform_capabilities.schema.schema_functions import \ get_config_options_by_operators_set, is_opset_in_model -from model_compression_toolkit.target_platform_capabilities.target_platform import \ - get_default_quantization_config_options from tests.common_tests.helpers.generate_test_tp_model import generate_test_attr_configs, generate_test_op_qc tp = mct.target_platform TEST_QC = generate_test_op_qc(**generate_test_attr_configs()) -TEST_QCO = schema.QuantizationConfigOptions([TEST_QC]) +TEST_QCO = schema.QuantizationConfigOptions(tuple([TEST_QC])) class TargetPlatformModelingTest(unittest.TestCase): - def test_not_initialized_tp(self): - with self.assertRaises(Exception) as e: - mct.target_platform.get_default_quantization_config_options() - self.assertEqual('Target platform model is not initialized.', str(e.exception)) - - def test_get_default_options(self): - with schema.TargetPlatformModel(TEST_QCO, - tpc_minor_version=None, - tpc_patch_version=None, - tpc_platform_type=None, - add_metadata=False): - self.assertEqual(tp.get_default_quantization_config_options(), TEST_QCO) - def test_immutable_tp(self): - model = schema.TargetPlatformModel(TEST_QCO, - tpc_minor_version=None, - tpc_patch_version=None, - tpc_platform_type=None, - add_metadata=False) + with self.assertRaises(Exception) as e: - with model: - schema.OperatorsSet("opset") - model.operator_set = [] + model = schema.TargetPlatformModel(TEST_QCO, + operator_set=tuple([schema.OperatorsSet("opset")]), + tpc_minor_version=None, + tpc_patch_version=None, + tpc_platform_type=None, + add_metadata=False) + model.operator_set = tuple() self.assertEqual("cannot assign to field 'operator_set'", str(e.exception)) def test_default_options_more_than_single_qc(self): - test_qco = schema.QuantizationConfigOptions([TEST_QC, TEST_QC], base_config=TEST_QC) + test_qco = schema.QuantizationConfigOptions(tuple([TEST_QC, TEST_QC]), base_config=TEST_QC) with self.assertRaises(Exception) as e: schema.TargetPlatformModel(test_qco, tpc_minor_version=None, @@ -74,27 +59,26 @@ def test_tp_model_show(self): tpc_minor_version=None, tpc_patch_version=None, tpc_platform_type=None, + operator_set=tuple([schema.OperatorsSet("opA"), schema.OperatorsSet("opB")]), + fusing_patterns=tuple( + [schema.Fusing((schema.OperatorsSet("opA"), schema.OperatorsSet("opB")))]), add_metadata=False) - with tpm: - a = schema.OperatorsSet("opA") - tpm.show() class OpsetTest(unittest.TestCase): def test_opset_qco(self): + opset_name = "ops_3bit" + qco_3bit = TEST_QCO.clone_and_edit(activation_n_bits=3) + operator_set = [schema.OperatorsSet(opset_name, qco_3bit)] hm = schema.TargetPlatformModel(TEST_QCO, + operator_set=tuple(operator_set), tpc_minor_version=None, tpc_patch_version=None, tpc_platform_type=None, add_metadata=False, name='test') - opset_name = "ops_3bit" - with hm: - qco_3bit = get_default_quantization_config_options().clone_and_edit(activation_n_bits=3) - schema.OperatorsSet(opset_name, qco_3bit) - - for op_qc in get_config_options_by_operators_set(hm, opset_name).quantization_config_list: + for op_qc in get_config_options_by_operators_set(hm, opset_name).quantization_configurations: self.assertEqual(op_qc.activation_n_bits, 3) self.assertTrue(is_opset_in_model(hm, opset_name)) @@ -104,33 +88,33 @@ def test_opset_qco(self): hm.default_qco) def test_opset_concat(self): + operator_set, fusing_patterns = [], [] + + a = schema.OperatorsSet('opset_A') + b = schema.OperatorsSet('opset_B', + TEST_QCO.clone_and_edit(activation_n_bits=2)) + c = schema.OperatorsSet('opset_C') # Just add it without using it in concat + operator_set.extend([a, b, c]) hm = schema.TargetPlatformModel(TEST_QCO, + operator_set=tuple(operator_set), tpc_minor_version=None, tpc_patch_version=None, tpc_platform_type=None, add_metadata=False, name='test') - with hm: - a = schema.OperatorsSet('opset_A') - b = schema.OperatorsSet('opset_B', - get_default_quantization_config_options().clone_and_edit(activation_n_bits=2)) - schema.OperatorsSet('opset_C') # Just add it without using it in concat - schema.OperatorSetConcat([a, b]) - self.assertEqual(len(hm.operator_set), 4) - self.assertTrue(is_opset_in_model(hm, "opset_A_opset_B")) - self.assertTrue(get_config_options_by_operators_set(hm, 'opset_A_opset_B') is None) + self.assertEqual(len(hm.operator_set), 3) + self.assertFalse(is_opset_in_model(hm, "opset_A_opset_B")) def test_non_unique_opset(self): - hm = schema.TargetPlatformModel( - schema.QuantizationConfigOptions([TEST_QC]), - tpc_minor_version=None, - tpc_patch_version=None, - tpc_platform_type=None, - add_metadata=False) with self.assertRaises(Exception) as e: - with hm: - schema.OperatorsSet("conv") - schema.OperatorsSet("conv") + hm = schema.TargetPlatformModel( + schema.QuantizationConfigOptions(tuple([TEST_QC])), + operator_set=tuple([schema.OperatorsSet("conv"), schema.OperatorsSet("conv")]), + tpc_minor_version=None, + tpc_patch_version=None, + tpc_platform_type=None, + add_metadata=False) + self.assertEqual('Operator Sets must have unique names.', str(e.exception)) @@ -138,14 +122,14 @@ class QCOptionsTest(unittest.TestCase): def test_empty_qc_options(self): with self.assertRaises(Exception) as e: - schema.QuantizationConfigOptions([]) + schema.QuantizationConfigOptions(tuple([])) self.assertEqual( - "'QuantizationConfigOptions' requires at least one 'OpQuantizationConfig'. The provided list is empty.", + "'QuantizationConfigOptions' requires at least one 'OpQuantizationConfig'. The provided configurations is empty.", str(e.exception)) def test_list_of_no_qc(self): with self.assertRaises(Exception) as e: - schema.QuantizationConfigOptions([TEST_QC, 3]) + schema.QuantizationConfigOptions(tuple([TEST_QC, 3])) self.assertEqual( 'Each option must be an instance of \'OpQuantizationConfig\', but found an object of type: .', str(e.exception)) @@ -155,14 +139,14 @@ def test_clone_and_edit_options(self): attrs=[KERNEL_ATTR], weights_n_bits=5) - self.assertEqual(modified_options.quantization_config_list[0].activation_n_bits, 3) + self.assertEqual(modified_options.quantization_configurations[0].activation_n_bits, 3) self.assertEqual( - modified_options.quantization_config_list[0].attr_weights_configs_mapping[KERNEL_ATTR].weights_n_bits, 5) + modified_options.quantization_configurations[0].attr_weights_configs_mapping[KERNEL_ATTR].weights_n_bits, 5) def test_qco_without_base_config(self): - schema.QuantizationConfigOptions([TEST_QC]) # Should work fine as it has only one qc. + schema.QuantizationConfigOptions(tuple([TEST_QC])) # Should work fine as it has only one qc. with self.assertRaises(Exception) as e: - schema.QuantizationConfigOptions([TEST_QC, TEST_QC]) # Should raise exception as base_config was not passed + schema.QuantizationConfigOptions(tuple([TEST_QC, TEST_QC])) # Should raise exception as base_config was not passed self.assertEqual( 'For multiple configurations, a \'base_config\' is required for non-mixed-precision optimization.', str(e.exception)) @@ -177,32 +161,38 @@ def test_get_qco_for_none_tpc(self): class FusingTest(unittest.TestCase): def test_fusing_single_opset(self): - hm = schema.TargetPlatformModel( - schema.QuantizationConfigOptions([TEST_QC]), - tpc_minor_version=None, - tpc_patch_version=None, - tpc_platform_type=None, - add_metadata=False) - with hm: - add = schema.OperatorsSet("add") - with self.assertRaises(Exception) as e: - schema.Fusing([add]) - self.assertEqual('Fusing cannot be created for a single operator.', str(e.exception)) + add = schema.OperatorsSet("add") + with self.assertRaises(Exception) as e: + hm = schema.TargetPlatformModel( + schema.QuantizationConfigOptions(tuple([TEST_QC])), + operator_set=tuple([add]), + fusing_patterns=tuple([schema.Fusing(tuple([add]))]), + tpc_minor_version=None, + tpc_patch_version=None, + tpc_platform_type=None, + add_metadata=False) + self.assertEqual('Fusing cannot be created for a single operator.', str(e.exception)) def test_fusing_contains(self): + + operator_set, fusing_patterns = [], [] + + conv = schema.OperatorsSet("conv") + add = schema.OperatorsSet("add") + tanh = schema.OperatorsSet("tanh") + operator_set.extend([conv, add, tanh]) + + fusing_patterns.append(schema.Fusing((conv, add))) + fusing_patterns.append(schema.Fusing((conv, add, tanh))) + hm = schema.TargetPlatformModel( - schema.QuantizationConfigOptions([TEST_QC]), + schema.QuantizationConfigOptions(tuple([TEST_QC])), + operator_set=tuple(operator_set), + fusing_patterns=tuple(fusing_patterns), tpc_minor_version=None, tpc_patch_version=None, tpc_platform_type=None, add_metadata=False) - with hm: - conv = schema.OperatorsSet("conv") - add = schema.OperatorsSet("add") - tanh = schema.OperatorsSet("tanh") - schema.Fusing([conv, add]) - schema.Fusing([conv, add, tanh]) - self.assertEqual(len(hm.fusing_patterns), 2) f0, f1 = hm.fusing_patterns[0], hm.fusing_patterns[1] self.assertTrue(f1.contains(f0)) @@ -211,20 +201,26 @@ def test_fusing_contains(self): self.assertTrue(f1.contains(f1)) def test_fusing_contains_with_opset_concat(self): + operator_set, fusing_patterns = [], [] + + conv = schema.OperatorsSet("conv") + add = schema.OperatorsSet("add") + tanh = schema.OperatorsSet("tanh") + operator_set.extend([conv, add, tanh]) + + add_tanh = schema.OperatorSetConcat((add, tanh)) + fusing_patterns.append(schema.Fusing((conv, add))) + fusing_patterns.append(schema.Fusing((conv, add_tanh))) + fusing_patterns.append(schema.Fusing((conv, add, tanh))) + hm = schema.TargetPlatformModel( - schema.QuantizationConfigOptions([TEST_QC]), + schema.QuantizationConfigOptions(tuple([TEST_QC])), + operator_set=tuple(operator_set), + fusing_patterns=tuple(fusing_patterns), tpc_minor_version=None, tpc_patch_version=None, tpc_platform_type=None, add_metadata=False) - with hm: - conv = schema.OperatorsSet("conv") - add = schema.OperatorsSet("add") - tanh = schema.OperatorsSet("tanh") - add_tanh = schema.OperatorSetConcat([add, tanh]) - schema.Fusing([conv, add]) - schema.Fusing([conv, add_tanh]) - schema.Fusing([conv, add, tanh]) self.assertEqual(len(hm.fusing_patterns), 3) f0, f1, f2 = hm.fusing_patterns[0], hm.fusing_patterns[1], hm.fusing_patterns[2] diff --git a/tests/keras_tests/exporter_tests/tflite_int8/imx500_int8_tp_model.py b/tests/keras_tests/exporter_tests/tflite_int8/imx500_int8_tp_model.py index 209287fbf..07e5f1dae 100644 --- a/tests/keras_tests/exporter_tests/tflite_int8/imx500_int8_tp_model.py +++ b/tests/keras_tests/exporter_tests/tflite_int8/imx500_int8_tp_model.py @@ -66,42 +66,50 @@ def generate_tp_model(default_config: OpQuantizationConfig, base_config: OpQuantizationConfig, mixed_precision_cfg_list: List[OpQuantizationConfig], name: str) -> TargetPlatformModel: - default_configuration_options = schema.QuantizationConfigOptions( - [default_config]) + default_configuration_options = schema.QuantizationConfigOptions(tuple( + [default_config])) + + mixed_precision_configuration_options = schema.QuantizationConfigOptions(tuple(mixed_precision_cfg_list), + base_config=base_config) + + operator_set, fusing_patterns = [], [] + + operator_set.append(schema.OperatorsSet("NoQuantization", + default_configuration_options + .clone_and_edit(enable_activation_quantization=False) + .clone_and_edit_weight_attribute(enable_weights_quantization=False))) + + conv = schema.OperatorsSet("Conv", mixed_precision_configuration_options) + fc = schema.OperatorsSet("FullyConnected", mixed_precision_configuration_options) + + any_relu = schema.OperatorsSet("AnyReLU") + add = schema.OperatorsSet("Add") + sub = schema.OperatorsSet("Sub") + mul = schema.OperatorsSet("Mul") + div = schema.OperatorsSet("Div") + prelu = schema.OperatorsSet("PReLU") + swish = schema.OperatorsSet("Swish") + sigmoid = schema.OperatorsSet("Sigmoid") + tanh = schema.OperatorsSet("Tanh") + + operator_set.extend([conv, fc, any_relu, add, sub, mul, div, prelu, swish, sigmoid, tanh]) + + activations_after_conv_to_fuse = schema.OperatorSetConcat((any_relu, swish, prelu, sigmoid, tanh)) + activations_after_fc_to_fuse = schema.OperatorSetConcat((any_relu, swish, sigmoid)) + any_binary = schema.OperatorSetConcat((add, sub, mul, div)) + + fusing_patterns.append(schema.Fusing((conv, activations_after_conv_to_fuse))) + fusing_patterns.append(schema.Fusing((fc, activations_after_fc_to_fuse))) + fusing_patterns.append(schema.Fusing((any_binary, any_relu))) + generated_tpc = schema.TargetPlatformModel( default_configuration_options, tpc_minor_version=None, tpc_patch_version=None, tpc_platform_type=None, + operator_set=tuple(operator_set), + fusing_patterns=tuple(fusing_patterns), add_metadata=False, name=name) - with generated_tpc: - schema.OperatorsSet("NoQuantization", - tp.get_default_quantization_config_options() - .clone_and_edit(enable_activation_quantization=False) - .clone_and_edit_weight_attribute(enable_weights_quantization=False)) - - mixed_precision_configuration_options = schema.QuantizationConfigOptions(mixed_precision_cfg_list, - base_config=base_config) - - conv = schema.OperatorsSet("Conv", mixed_precision_configuration_options) - fc = schema.OperatorsSet("FullyConnected", mixed_precision_configuration_options) - - any_relu = schema.OperatorsSet("AnyReLU") - add = schema.OperatorsSet("Add") - sub = schema.OperatorsSet("Sub") - mul = schema.OperatorsSet("Mul") - div = schema.OperatorsSet("Div") - prelu = schema.OperatorsSet("PReLU") - swish = schema.OperatorsSet("Swish") - sigmoid = schema.OperatorsSet("Sigmoid") - tanh = schema.OperatorsSet("Tanh") - activations_after_conv_to_fuse = schema.OperatorSetConcat([any_relu, swish, prelu, sigmoid, tanh]) - activations_after_fc_to_fuse = schema.OperatorSetConcat([any_relu, swish, sigmoid]) - any_binary = schema.OperatorSetConcat([add, sub, mul, div]) - schema.Fusing([conv, activations_after_conv_to_fuse]) - schema.Fusing([fc, activations_after_fc_to_fuse]) - schema.Fusing([any_binary, any_relu]) - return generated_tpc diff --git a/tests/keras_tests/feature_networks_tests/feature_networks/activation_16bit_test.py b/tests/keras_tests/feature_networks_tests/feature_networks/activation_16bit_test.py index 2218a8d16..79413a8f5 100644 --- a/tests/keras_tests/feature_networks_tests/feature_networks/activation_16bit_test.py +++ b/tests/keras_tests/feature_networks_tests/feature_networks/activation_16bit_test.py @@ -36,7 +36,7 @@ def get_tpc(self): tpc = mct.get_target_platform_capabilities(TENSORFLOW, IMX500_TP_MODEL, 'v4') # Force Mul base_config to 16bit only mul_op_set = get_op_set('Mul', tpc.tp_model.operator_set) - base_config = [l for l in mul_op_set.qc_options.quantization_config_list if l.activation_n_bits == 16][0] + base_config = [l for l in mul_op_set.qc_options.quantization_configurations if l.activation_n_bits == 16][0] tpc.layer2qco[tf.multiply] = replace(tpc.layer2qco[tf.multiply], base_config=base_config) return tpc @@ -69,15 +69,12 @@ class Activation16BitMixedPrecisionTest(Activation16BitTest): def get_tpc(self): tpc = mct.get_target_platform_capabilities(TENSORFLOW, IMX500_TP_MODEL, 'v3') mul_op_set = get_op_set('Mul', tpc.tp_model.operator_set) - base_config = [l for l in mul_op_set.qc_options.quantization_config_list if l.activation_n_bits == 16][0] - tpc.layer2qco[tf.multiply] = replace(tpc.layer2qco[tf.multiply], base_config=base_config) - mul_op_set.qc_options.quantization_config_list.extend( - [mul_op_set.qc_options.base_config.clone_and_edit(activation_n_bits=4), - mul_op_set.qc_options.base_config.clone_and_edit(activation_n_bits=2)]) - tpc.layer2qco[tf.multiply].quantization_config_list.extend([ + base_config = [l for l in mul_op_set.qc_options.quantization_configurations if l.activation_n_bits == 16][0] + quantization_configurations = list(tpc.layer2qco[tf.multiply].quantization_configurations) + quantization_configurations.extend([ tpc.layer2qco[tf.multiply].base_config.clone_and_edit(activation_n_bits=4), tpc.layer2qco[tf.multiply].base_config.clone_and_edit(activation_n_bits=2)]) - + tpc.layer2qco[tf.multiply] = replace(tpc.layer2qco[tf.multiply], base_config=base_config, quantization_configurations=tuple(quantization_configurations)) return tpc def get_resource_utilization(self): diff --git a/tests/keras_tests/feature_networks_tests/feature_networks/bn_attributes_quantization_test.py b/tests/keras_tests/feature_networks_tests/feature_networks/bn_attributes_quantization_test.py index 8051b7154..56de10dab 100644 --- a/tests/keras_tests/feature_networks_tests/feature_networks/bn_attributes_quantization_test.py +++ b/tests/keras_tests/feature_networks_tests/feature_networks/bn_attributes_quantization_test.py @@ -77,21 +77,19 @@ def _generate_bn_quantized_tpm(quantize_linear): simd_size=32, signedness=Signedness.AUTO) - default_configuration_options = schema.QuantizationConfigOptions([default_op_qc]) - linear_configuration_options = schema.QuantizationConfigOptions([linear_op_qc]) - bn_configuration_options = schema.QuantizationConfigOptions([bn_op_qc]) + default_configuration_options = schema.QuantizationConfigOptions(tuple([default_op_qc])) + linear_configuration_options = schema.QuantizationConfigOptions(tuple([linear_op_qc])) + bn_configuration_options = schema.QuantizationConfigOptions(tuple([bn_op_qc])) generated_tpm = schema.TargetPlatformModel( default_configuration_options, tpc_minor_version=None, tpc_patch_version=None, tpc_platform_type=None, + operator_set=tuple([schema.OperatorsSet("Conv", linear_configuration_options), + schema.OperatorsSet("BN", bn_configuration_options)]), add_metadata=False, name='bn_quantized_tpm') - with generated_tpm: - schema.OperatorsSet("Conv", linear_configuration_options) - schema.OperatorsSet("BN", bn_configuration_options) - return generated_tpm diff --git a/tests/keras_tests/feature_networks_tests/feature_networks/const_quantization_test.py b/tests/keras_tests/feature_networks_tests/feature_networks/const_quantization_test.py index 5d61c9d12..34dc569da 100644 --- a/tests/keras_tests/feature_networks_tests/feature_networks/const_quantization_test.py +++ b/tests/keras_tests/feature_networks_tests/feature_networks/const_quantization_test.py @@ -49,11 +49,11 @@ def create_const_quant_tpc(qmethod): default_weight_attr_config=default_cfg.default_weight_attr_config.clone_and_edit( enable_weights_quantization=True, weights_per_channel_threshold=True, weights_n_bits=16, weights_quantization_method=qmethod)) - const_configuration_options = schema.QuantizationConfigOptions([const_config]) + const_configuration_options = schema.QuantizationConfigOptions(tuple([const_config])) const_merge_config = default_cfg.clone_and_edit( default_weight_attr_config=default_cfg.default_weight_attr_config.clone_and_edit( weights_per_channel_threshold=False)) - const_merge_configuration_options = schema.QuantizationConfigOptions([const_merge_config]) + const_merge_configuration_options = schema.QuantizationConfigOptions(tuple([const_merge_config])) operator_sets_dict = {} operator_sets_dict["Add"] = const_configuration_options diff --git a/tests/keras_tests/feature_networks_tests/feature_networks/manual_bit_selection.py b/tests/keras_tests/feature_networks_tests/feature_networks/manual_bit_selection.py index 243316a21..79e66dacf 100644 --- a/tests/keras_tests/feature_networks_tests/feature_networks/manual_bit_selection.py +++ b/tests/keras_tests/feature_networks_tests/feature_networks/manual_bit_selection.py @@ -135,7 +135,7 @@ def get_tpc(self): tpc = mct.get_target_platform_capabilities(TENSORFLOW, IMX500_TP_MODEL, 'v3') # Force Mul base_config to 16bit only mul_op_set = get_op_set('Mul', tpc.tp_model.operator_set) - base_config = [l for l in mul_op_set.qc_options.quantization_config_list if l.activation_n_bits == 16][0] + base_config = [l for l in mul_op_set.qc_options.quantization_configurations if l.activation_n_bits == 16][0] tpc.layer2qco[tf.multiply] = replace(tpc.layer2qco[tf.multiply], base_config=base_config) return tpc @@ -160,15 +160,13 @@ class Manual16BitWidthSelectionMixedPrecisionTest(Manual16BitWidthSelectionTest) def get_tpc(self): tpc = mct.get_target_platform_capabilities(TENSORFLOW, IMX500_TP_MODEL, 'v3') mul_op_set = get_op_set('Mul', tpc.tp_model.operator_set) - base_config = [l for l in mul_op_set.qc_options.quantization_config_list if l.activation_n_bits == 16][0] - tpc.layer2qco[tf.multiply] = replace(tpc.layer2qco[tf.multiply], base_config=base_config) - mul_op_set.qc_options.quantization_config_list.extend( - [mul_op_set.qc_options.base_config.clone_and_edit(activation_n_bits=4), - mul_op_set.qc_options.base_config.clone_and_edit(activation_n_bits=2)]) - tpc.layer2qco[tf.multiply].quantization_config_list.extend([ + base_config = [l for l in mul_op_set.qc_options.quantization_configurations if l.activation_n_bits == 16][0] + quantization_configurations = list(tpc.layer2qco[tf.multiply].quantization_configurations) + quantization_configurations.extend([ tpc.layer2qco[tf.multiply].base_config.clone_and_edit(activation_n_bits=4), tpc.layer2qco[tf.multiply].base_config.clone_and_edit(activation_n_bits=2)]) - + tpc.layer2qco[tf.multiply] = replace(tpc.layer2qco[tf.multiply], base_config=base_config, + quantization_configurations=tuple(quantization_configurations)) return tpc def get_resource_utilization(self): diff --git a/tests/keras_tests/feature_networks_tests/feature_networks/mixed_precision_tests.py b/tests/keras_tests/feature_networks_tests/feature_networks/mixed_precision_tests.py index 0d8bae6e5..a3ce9bb74 100644 --- a/tests/keras_tests/feature_networks_tests/feature_networks/mixed_precision_tests.py +++ b/tests/keras_tests/feature_networks_tests/feature_networks/mixed_precision_tests.py @@ -643,28 +643,26 @@ def get_tpc(self): [c.clone_and_edit(enable_activation_quantization=False) for c in mixed_precision_cfg_list] cfg = mixed_precision_cfg_list[0] - act_mixed_cfg = schema.QuantizationConfigOptions( - [act_eight_bit_cfg, act_four_bit_cfg, act_two_bit_cfg], + act_mixed_cfg = schema.QuantizationConfigOptions(tuple( + [act_eight_bit_cfg, act_four_bit_cfg, act_two_bit_cfg]), base_config=act_eight_bit_cfg, ) - weight_mixed_cfg = schema.QuantizationConfigOptions( - mixed_precision_cfg_list, + weight_mixed_cfg = schema.QuantizationConfigOptions(tuple( + mixed_precision_cfg_list), base_config=cfg, ) tp_model = schema.TargetPlatformModel( - schema.QuantizationConfigOptions([cfg], cfg), + schema.QuantizationConfigOptions(tuple([cfg]), cfg), tpc_minor_version=None, tpc_patch_version=None, tpc_platform_type=None, + operator_set=tuple([schema.OperatorsSet("Activations", act_mixed_cfg), + schema.OperatorsSet("Weights", weight_mixed_cfg)]), add_metadata=False, name="mp_activation_conf_weights_test") - with tp_model: - schema.OperatorsSet("Activations", act_mixed_cfg) - schema.OperatorsSet("Weights", weight_mixed_cfg) - keras_tpc = tp.TargetPlatformCapabilities(tp_model) with keras_tpc: diff --git a/tests/keras_tests/feature_networks_tests/feature_networks/weights_mixed_precision_tests.py b/tests/keras_tests/feature_networks_tests/feature_networks/weights_mixed_precision_tests.py index 1e6f06deb..45413118f 100644 --- a/tests/keras_tests/feature_networks_tests/feature_networks/weights_mixed_precision_tests.py +++ b/tests/keras_tests/feature_networks_tests/feature_networks/weights_mixed_precision_tests.py @@ -178,13 +178,13 @@ def get_tpc(self): two_bit_cfg = mixed_precision_cfg_list[2] - weight_mixed_cfg = schema.QuantizationConfigOptions( - mixed_precision_cfg_list, + weight_mixed_cfg = schema.QuantizationConfigOptions(tuple( + mixed_precision_cfg_list), base_config=cfg, ) - weight_fixed_cfg = schema.QuantizationConfigOptions( - [two_bit_cfg], + weight_fixed_cfg = schema.QuantizationConfigOptions(tuple( + [two_bit_cfg]), base_config=two_bit_cfg, ) @@ -193,11 +193,10 @@ def get_tpc(self): tpc_minor_version=None, tpc_patch_version=None, tpc_platform_type=None, + operator_set=tuple([schema.OperatorsSet("Weights_mp", weight_mixed_cfg), + schema.OperatorsSet("Weights_fixed", weight_fixed_cfg)]), add_metadata=False, name="mp_part_weights_layers_test") - with tp_model: - schema.OperatorsSet("Weights_mp", weight_mixed_cfg) - schema.OperatorsSet("Weights_fixed", weight_fixed_cfg) keras_tpc = tp.TargetPlatformCapabilities(tp_model) @@ -512,28 +511,26 @@ def get_tpc(self): [c.clone_and_edit(enable_activation_quantization=False) for c in mixed_precision_cfg_list] cfg = mixed_precision_cfg_list[0] - act_mixed_cfg = schema.QuantizationConfigOptions( - [act_eight_bit_cfg, act_four_bit_cfg, act_two_bit_cfg], + act_mixed_cfg = schema.QuantizationConfigOptions(tuple( + [act_eight_bit_cfg, act_four_bit_cfg, act_two_bit_cfg]), base_config=act_eight_bit_cfg, ) - weight_mixed_cfg = schema.QuantizationConfigOptions( - mixed_precision_cfg_list, + weight_mixed_cfg = schema.QuantizationConfigOptions(tuple( + mixed_precision_cfg_list), base_config=cfg, ) tp_model = schema.TargetPlatformModel( - schema.QuantizationConfigOptions([cfg], cfg), + schema.QuantizationConfigOptions(tuple([cfg]), cfg), tpc_minor_version=None, tpc_patch_version=None, tpc_platform_type=None, + operator_set=tuple([schema.OperatorsSet("Activations", act_mixed_cfg), + schema.OperatorsSet("Weights", weight_mixed_cfg)]), add_metadata=False, name="mp_weights_conf_act_test") - with tp_model: - schema.OperatorsSet("Activations", act_mixed_cfg) - schema.OperatorsSet("Weights", weight_mixed_cfg) - keras_tpc = tp.TargetPlatformCapabilities(tp_model) with keras_tpc: diff --git a/tests/keras_tests/function_tests/test_custom_layer.py b/tests/keras_tests/function_tests/test_custom_layer.py index b56f1828b..d01642b20 100644 --- a/tests/keras_tests/function_tests/test_custom_layer.py +++ b/tests/keras_tests/function_tests/test_custom_layer.py @@ -76,18 +76,17 @@ def get_tpc(): simd_size=32, signedness=Signedness.AUTO) - default_configuration_options = schema.QuantizationConfigOptions([base_cfg]) + default_configuration_options = schema.QuantizationConfigOptions(tuple([base_cfg])) + + operator_set = [schema.OperatorsSet("NoQuantization", + default_configuration_options.clone_and_edit(enable_activation_quantization=False) + .clone_and_edit_weight_attribute(enable_weights_quantization=False))] tp_model = schema.TargetPlatformModel(default_configuration_options, + operator_set=tuple(operator_set), tpc_minor_version=None, tpc_patch_version=None, tpc_platform_type=None, add_metadata=False) - with tp_model: - default_qco = tp.get_default_quantization_config_options() - schema.OperatorsSet("NoQuantization", - default_qco.clone_and_edit(enable_activation_quantization=False) - .clone_and_edit_weight_attribute(enable_weights_quantization=False)) - tpc = tp.TargetPlatformCapabilities(tp_model) with tpc: # No need to quantize Flatten and Dropout layers diff --git a/tests/keras_tests/function_tests/test_hmse_error_method.py b/tests/keras_tests/function_tests/test_hmse_error_method.py index 6d1f0f586..8a0cf0673 100644 --- a/tests/keras_tests/function_tests/test_hmse_error_method.py +++ b/tests/keras_tests/function_tests/test_hmse_error_method.py @@ -171,7 +171,7 @@ def test_threshold_selection_hmse_no_gptq(self): def test_threshold_selection_hmse_no_kernel_attr(self): def _generate_bn_quantization_tpc(quant_method, per_channel): cfg, _, _ = get_op_quantization_configs() - conv_qco = schema.QuantizationConfigOptions([cfg], base_config=cfg) + conv_qco = schema.QuantizationConfigOptions(tuple([cfg]), base_config=cfg) # enable BN attributes quantization using the bn_qco = conv_qco.clone_and_edit(attr_weights_configs_mapping= @@ -182,12 +182,10 @@ def _generate_bn_quantization_tpc(quant_method, per_channel): tpc_minor_version=None, tpc_patch_version=None, tpc_platform_type=None, + operator_set=tuple([schema.OperatorsSet("Linear", conv_qco), + schema.OperatorsSet("BN", bn_qco)]), add_metadata=False) - with tp_model: - schema.OperatorsSet("Linear", conv_qco) - schema.OperatorsSet("BN", bn_qco) - tpc = tp.TargetPlatformCapabilities(tp_model) with tpc: diff --git a/tests/keras_tests/function_tests/test_layer_fusing.py b/tests/keras_tests/function_tests/test_layer_fusing.py index f55c31d4f..0cde794b9 100644 --- a/tests/keras_tests/function_tests/test_layer_fusing.py +++ b/tests/keras_tests/function_tests/test_layer_fusing.py @@ -79,29 +79,33 @@ def create_network_4(input_shape): return tf.keras.models.Model(inputs=inputs, outputs=y) -def generate_base_tpc(): +def generate_base_tpc(operator_set, fusing_patterns): base_config, mixed_precision_cfg_list, default_config = get_op_quantization_configs() - default_configuration_options = schema.QuantizationConfigOptions( - [default_config]) + default_configuration_options = schema.QuantizationConfigOptions(tuple( + [default_config])) generated_tp = schema.TargetPlatformModel( default_configuration_options, tpc_minor_version=None, tpc_patch_version=None, tpc_platform_type=None, + operator_set=tuple(operator_set), + fusing_patterns=tuple(fusing_patterns), add_metadata=False, name='layer_fusing_test') - mixed_precision_configuration_options = schema.QuantizationConfigOptions(mixed_precision_cfg_list, - base_config=base_config) - return generated_tp, mixed_precision_configuration_options + return generated_tp def get_tpc_1(): - generated_tp, mixed_precision_configuration_options = generate_base_tpc() - with generated_tp: - conv = schema.OperatorsSet("Conv", mixed_precision_configuration_options) - any_relu = schema.OperatorsSet("AnyReLU") - # Define fusions - schema.Fusing([conv, any_relu]) + base_config, mixed_precision_cfg_list, default_config = get_op_quantization_configs() + mixed_precision_configuration_options = schema.QuantizationConfigOptions(tuple(mixed_precision_cfg_list), + base_config=base_config) + conv = schema.OperatorsSet("Conv", mixed_precision_configuration_options) + any_relu = schema.OperatorsSet("AnyReLU") + operator_set = [conv, any_relu] + # Define fusions + fusing_patterns = [schema.Fusing((conv, any_relu))] + + generated_tp = generate_base_tpc(operator_set, fusing_patterns) keras_tpc = tp.TargetPlatformCapabilities(generated_tp) with keras_tpc: @@ -113,16 +117,20 @@ def get_tpc_1(): def get_tpc_2(): - generated_tp, mixed_precision_configuration_options = generate_base_tpc() - with generated_tp: - conv = schema.OperatorsSet("Conv", mixed_precision_configuration_options) - any_relu = schema.OperatorsSet("AnyReLU") - swish = schema.OperatorsSet("Swish") - sigmoid = schema.OperatorsSet("Sigmoid") - tanh = schema.OperatorsSet("Tanh") - activations_after_conv_to_fuse = schema.OperatorSetConcat([any_relu, swish, sigmoid, tanh]) - # Define fusions - schema.Fusing([conv, activations_after_conv_to_fuse]) + base_config, mixed_precision_cfg_list, default_config = get_op_quantization_configs() + mixed_precision_configuration_options = schema.QuantizationConfigOptions(tuple(mixed_precision_cfg_list), + base_config=base_config) + conv = schema.OperatorsSet("Conv", mixed_precision_configuration_options) + any_relu = schema.OperatorsSet("AnyReLU") + swish = schema.OperatorsSet("Swish") + sigmoid = schema.OperatorsSet("Sigmoid") + tanh = schema.OperatorsSet("Tanh") + operator_set = [conv, any_relu, swish, sigmoid, tanh] + activations_after_conv_to_fuse = schema.OperatorSetConcat([any_relu, swish, sigmoid, tanh]) + # Define fusions + fusing_patterns = [schema.Fusing((conv, activations_after_conv_to_fuse))] + + generated_tp = generate_base_tpc(operator_set, fusing_patterns) keras_tpc = tp.TargetPlatformCapabilities(generated_tp) with keras_tpc: @@ -137,12 +145,16 @@ def get_tpc_2(): def get_tpc_3(): - generated_tp, mixed_precision_configuration_options = generate_base_tpc() - with generated_tp: - conv = schema.OperatorsSet("Conv", mixed_precision_configuration_options) - any_relu = schema.OperatorsSet("AnyReLU") - # Define fusions - schema.Fusing([conv, any_relu]) + base_config, mixed_precision_cfg_list, default_config = get_op_quantization_configs() + mixed_precision_configuration_options = schema.QuantizationConfigOptions(tuple(mixed_precision_cfg_list), + base_config=base_config) + conv = schema.OperatorsSet("Conv", mixed_precision_configuration_options) + any_relu = schema.OperatorsSet("AnyReLU") + operator_set = [conv, any_relu] + # Define fusions + fusing_patterns = [schema.Fusing((conv, any_relu))] + + generated_tp = generate_base_tpc(operator_set, fusing_patterns) keras_tpc = tp.TargetPlatformCapabilities(generated_tp) with keras_tpc: @@ -154,19 +166,23 @@ def get_tpc_3(): def get_tpc_4(): - generated_tp, mixed_precision_configuration_options = generate_base_tpc() - with generated_tp: - conv = schema.OperatorsSet("Conv", mixed_precision_configuration_options) - fc = schema.OperatorsSet("FullyConnected", mixed_precision_configuration_options) - any_relu = schema.OperatorsSet("AnyReLU") - add = schema.OperatorsSet("Add") - swish = schema.OperatorsSet("Swish") - activations_to_fuse = schema.OperatorSetConcat([any_relu, swish]) - # Define fusions - schema.Fusing([conv, activations_to_fuse]) - schema.Fusing([conv, add, activations_to_fuse]) - schema.Fusing([conv, activations_to_fuse, add]) - schema.Fusing([fc, activations_to_fuse]) + base_config, mixed_precision_cfg_list, default_config = get_op_quantization_configs() + mixed_precision_configuration_options = schema.QuantizationConfigOptions(tuple(mixed_precision_cfg_list), + base_config=base_config) + conv = schema.OperatorsSet("Conv", mixed_precision_configuration_options) + fc = schema.OperatorsSet("FullyConnected", mixed_precision_configuration_options) + any_relu = schema.OperatorsSet("AnyReLU") + add = schema.OperatorsSet("Add") + swish = schema.OperatorsSet("Swish") + activations_to_fuse = schema.OperatorSetConcat([any_relu, swish]) + operator_set = [conv, fc, any_relu, add, swish] + # Define fusions + fusing_patterns = [schema.Fusing((conv, activations_to_fuse)), + schema.Fusing((conv, add, activations_to_fuse)), + schema.Fusing((conv, activations_to_fuse, add)), + schema.Fusing((fc, activations_to_fuse))] + + generated_tp = generate_base_tpc(operator_set, fusing_patterns) keras_tpc = tp.TargetPlatformCapabilities(generated_tp) with keras_tpc: diff --git a/tests/keras_tests/function_tests/test_quant_config_filtering.py b/tests/keras_tests/function_tests/test_quant_config_filtering.py index 6e5c3c871..b711b06b2 100644 --- a/tests/keras_tests/function_tests/test_quant_config_filtering.py +++ b/tests/keras_tests/function_tests/test_quant_config_filtering.py @@ -44,7 +44,7 @@ def get_tpc_default_16bit(): tpc = mct.get_target_platform_capabilities(TENSORFLOW, IMX500_TP_MODEL, 'v3') # Force Mul base_config to 16bit only mul_op_set = get_op_set('Mul', tpc.tp_model.operator_set) - base_config = [l for l in mul_op_set.qc_options.quantization_config_list if l.activation_n_bits == 16][0] + base_config = [l for l in mul_op_set.qc_options.quantization_configurations if l.activation_n_bits == 16][0] tpc.layer2qco[tf.multiply] = replace(tpc.layer2qco[tf.multiply], base_config=base_config) return tpc diff --git a/tests/keras_tests/non_parallel_tests/test_keras_tp_model.py b/tests/keras_tests/non_parallel_tests/test_keras_tp_model.py index add49fd26..a018bdd80 100644 --- a/tests/keras_tests/non_parallel_tests/test_keras_tp_model.py +++ b/tests/keras_tests/non_parallel_tests/test_keras_tp_model.py @@ -49,7 +49,7 @@ tp = mct.target_platform TEST_QC = generate_test_op_qc(**generate_test_attr_configs()) -TEST_QCO = schema.QuantizationConfigOptions([TEST_QC]) +TEST_QCO = schema.QuantizationConfigOptions(tuple([TEST_QC])) def get_node(layer) -> BaseNode: @@ -104,14 +104,15 @@ def test_keras_layers_with_params(self): self.assertFalse(get_node(conv).is_match_filter_params(conv_filter_contains)) def test_get_layers_by_op(self): + op_obj = schema.OperatorsSet('opsetA') + hm = schema.TargetPlatformModel( - schema.QuantizationConfigOptions([TEST_QC]), + schema.QuantizationConfigOptions(tuple([TEST_QC])), tpc_minor_version=None, tpc_patch_version=None, tpc_platform_type=None, + operator_set=tuple([op_obj]), add_metadata=False) - with hm: - op_obj = schema.OperatorsSet('opsetA') fw_tp = TargetPlatformCapabilities(hm) with fw_tp: opset_layers = [Conv2D, LayerFilterParams(ReLU, max_value=2)] @@ -121,16 +122,16 @@ def test_get_layers_by_op(self): self.assertEqual(fw_tp.get_layers_by_opset_name('nonExistingOpsetName'), None) def test_get_layers_by_opconcat(self): + op_obj_a = schema.OperatorsSet('opsetA') + op_obj_b = schema.OperatorsSet('opsetB') + op_concat = schema.OperatorSetConcat([op_obj_a, op_obj_b]) hm = schema.TargetPlatformModel( - schema.QuantizationConfigOptions([TEST_QC]), + schema.QuantizationConfigOptions(tuple([TEST_QC])), tpc_minor_version=None, tpc_patch_version=None, tpc_platform_type=None, + operator_set=tuple([op_obj_a, op_obj_b]), add_metadata=False) - with hm: - op_obj_a = schema.OperatorsSet('opsetA') - op_obj_b = schema.OperatorsSet('opsetB') - op_concat = schema.OperatorSetConcat([op_obj_a, op_obj_b]) fw_tp = TargetPlatformCapabilities(hm) with fw_tp: @@ -139,19 +140,18 @@ def test_get_layers_by_opconcat(self): tp.OperationsSetToLayers('opsetA', opset_layers_a) tp.OperationsSetToLayers('opsetB', opset_layers_b) - self.assertEqual(fw_tp.get_layers_by_opset_name('opsetA_opsetB'), opset_layers_a + opset_layers_b) self.assertEqual(fw_tp.get_layers_by_opset(op_concat), opset_layers_a + opset_layers_b) def test_layer_attached_to_multiple_opsets(self): hm = schema.TargetPlatformModel( - schema.QuantizationConfigOptions([TEST_QC]), + schema.QuantizationConfigOptions(tuple([TEST_QC])), tpc_minor_version=None, tpc_patch_version=None, tpc_platform_type=None, + operator_set=tuple([schema.OperatorsSet('opsetA'), + schema.OperatorsSet('opsetB')]), add_metadata=False) - with hm: - schema.OperatorsSet('opsetA') - schema.OperatorsSet('opsetB') + fw_tp = TargetPlatformCapabilities(hm) with self.assertRaises(Exception) as e: @@ -162,15 +162,13 @@ def test_layer_attached_to_multiple_opsets(self): def test_filter_layer_attached_to_multiple_opsets(self): hm = schema.TargetPlatformModel( - schema.QuantizationConfigOptions([TEST_QC]), + schema.QuantizationConfigOptions(tuple([TEST_QC])), tpc_minor_version=None, tpc_patch_version=None, tpc_platform_type=None, + operator_set=tuple([schema.OperatorsSet('opsetA'), + schema.OperatorsSet('opsetB')]), add_metadata=False) - with hm: - schema.OperatorsSet('opsetA') - schema.OperatorsSet('opsetB') - fw_tp = TargetPlatformCapabilities(hm) with self.assertRaises(Exception) as e: with fw_tp: @@ -179,26 +177,28 @@ def test_filter_layer_attached_to_multiple_opsets(self): self.assertEqual('Found layer Activation(activation=relu) in more than one OperatorsSet', str(e.exception)) def test_qco_by_keras_layer(self): - default_qco = schema.QuantizationConfigOptions([TEST_QC]) + operator_set = [] + default_qco = schema.QuantizationConfigOptions(tuple([TEST_QC])) default_qco = default_qco.clone_and_edit(attr_weights_configs_mapping={}) + mixed_precision_configuration_options = schema.QuantizationConfigOptions( + quantization_configurations=tuple([TEST_QC, + TEST_QC.clone_and_edit(attr_to_edit={KERNEL_ATTR: {WEIGHTS_N_BITS: 4}}), + TEST_QC.clone_and_edit(attr_to_edit={KERNEL_ATTR: {WEIGHTS_N_BITS: 2}})]), + base_config=TEST_QC) + + operator_set.append(schema.OperatorsSet("conv", mixed_precision_configuration_options)) + sevenbit_qco = TEST_QCO.clone_and_edit(activation_n_bits=7, + attr_weights_configs_mapping={}) + operator_set.append(schema.OperatorsSet("tanh", sevenbit_qco)) + operator_set.append(schema.OperatorsSet("relu")) + tpm = schema.TargetPlatformModel(default_qco, tpc_minor_version=None, tpc_patch_version=None, tpc_platform_type=None, + operator_set=tuple(operator_set), add_metadata=False, name='test') - with tpm: - mixed_precision_configuration_options = schema.QuantizationConfigOptions( - quantization_config_list=[TEST_QC, - TEST_QC.clone_and_edit(attr_to_edit={KERNEL_ATTR: {WEIGHTS_N_BITS: 4}}), - TEST_QC.clone_and_edit(attr_to_edit={KERNEL_ATTR: {WEIGHTS_N_BITS: 2}})], - base_config=TEST_QC) - - schema.OperatorsSet("conv", mixed_precision_configuration_options) - sevenbit_qco = TEST_QCO.clone_and_edit(activation_n_bits=7, - attr_weights_configs_mapping={}) - schema.OperatorsSet("tanh", sevenbit_qco) - schema.OperatorsSet("relu") tpc_keras = tp.TargetPlatformCapabilities(tpm) with tpc_keras: @@ -216,21 +216,22 @@ def test_qco_by_keras_layer(self): tanh_qco = tanh_node.get_qco(tpc_keras) relu_qco = relu_node.get_qco(tpc_keras) - self.assertEqual(len(conv_qco.quantization_config_list), - len(mixed_precision_configuration_options.quantization_config_list)) - for i in range(len(conv_qco.quantization_config_list)): - self.assertEqual(conv_qco.quantization_config_list[i].attr_weights_configs_mapping[KERAS_KERNEL], - mixed_precision_configuration_options.quantization_config_list[ + self.assertEqual(len(conv_qco.quantization_configurations), + len(mixed_precision_configuration_options.quantization_configurations)) + for i in range(len(conv_qco.quantization_configurations)): + self.assertEqual(conv_qco.quantization_configurations[i].attr_weights_configs_mapping[KERAS_KERNEL], + mixed_precision_configuration_options.quantization_configurations[ i].attr_weights_configs_mapping[KERNEL_ATTR]) self.assertEqual(tanh_qco, sevenbit_qco) self.assertEqual(relu_qco, default_qco) def test_opset_not_in_tp(self): - default_qco = schema.QuantizationConfigOptions([TEST_QC]) + default_qco = schema.QuantizationConfigOptions(tuple([TEST_QC])) hm = schema.TargetPlatformModel(default_qco, tpc_minor_version=None, tpc_patch_version=None, tpc_platform_type=None, + operator_set=tuple([schema.OperatorsSet("opA")]), add_metadata=False) hm_keras = tp.TargetPlatformCapabilities(hm) with self.assertRaises(Exception) as e: @@ -241,18 +242,21 @@ def test_opset_not_in_tp(self): str(e.exception)) def test_keras_fusing_patterns(self): - default_qco = schema.QuantizationConfigOptions([TEST_QC]) + default_qco = schema.QuantizationConfigOptions(tuple([TEST_QC])) + a = schema.OperatorsSet("opA") + b = schema.OperatorsSet("opB") + c = schema.OperatorsSet("opC") + operator_set = [a, b, c] + fusing_patterns = [schema.Fusing((a, b, c)), + schema.Fusing((a, c))] + hm = schema.TargetPlatformModel(default_qco, tpc_minor_version=None, tpc_patch_version=None, tpc_platform_type=None, + operator_set=tuple(operator_set), + fusing_patterns=tuple(fusing_patterns), add_metadata=False) - with hm: - a = schema.OperatorsSet("opA") - b = schema.OperatorsSet("opB") - c = schema.OperatorsSet("opC") - schema.Fusing([a, b, c]) - schema.Fusing([a, c]) hm_keras = tp.TargetPlatformCapabilities(hm) with hm_keras: @@ -274,14 +278,13 @@ def test_keras_fusing_patterns(self): self.assertEqual(p1[1], LayerFilterParams(ReLU, Greater("max_value", 7), negative_slope=0)) def test_get_default_op_qc(self): - default_qco = schema.QuantizationConfigOptions([TEST_QC]) + default_qco = schema.QuantizationConfigOptions(tuple([TEST_QC])) tpm = schema.TargetPlatformModel(default_qco, tpc_minor_version=None, tpc_patch_version=None, tpc_platform_type=None, + operator_set=tuple([schema.OperatorsSet("opA")]), add_metadata=False) - with tpm: - a = schema.OperatorsSet("opA") tpc = tp.TargetPlatformCapabilities(tpm) with tpc: diff --git a/tests/pytorch_tests/function_tests/layer_fusing_test.py b/tests/pytorch_tests/function_tests/layer_fusing_test.py index 6ecdca713..a83144819 100644 --- a/tests/pytorch_tests/function_tests/layer_fusing_test.py +++ b/tests/pytorch_tests/function_tests/layer_fusing_test.py @@ -48,18 +48,6 @@ def get_type(self, fusion): fusion_types = [x.type for x in fusion] return fusion_types - def get_tpc(self): - base_config, mixed_precision_cfg_list, default_config = get_op_quantization_configs() - default_configuration_options = schema.QuantizationConfigOptions([default_config]) - generated_tp = schema.TargetPlatformModel(default_configuration_options, - tpc_minor_version=None, - tpc_patch_version=None, - tpc_platform_type=None, - name='layer_fusing_test') - mixed_precision_configuration_options = schema.QuantizationConfigOptions(mixed_precision_cfg_list, - base_config=base_config) - return generated_tp, mixed_precision_configuration_options - def _compare(self, fused_nodes): self.unit_test.assertTrue(len(fused_nodes) == len(self.expected_fusions), msg=f'Number of fusions is not as expected!') @@ -74,12 +62,23 @@ def __init__(self, unit_test): self.expected_fusions = [[nn.Conv2d, nn.ReLU]] def get_tpc(self): - generated_tp, mixed_precision_configuration_options = super().get_tpc() - with generated_tp: - conv = schema.OperatorsSet("Conv", mixed_precision_configuration_options) - any_relu = schema.OperatorsSet("AnyReLU") - # Define fusions - schema.Fusing([conv, any_relu]) + base_config, mixed_precision_cfg_list, default_config = get_op_quantization_configs() + default_configuration_options = schema.QuantizationConfigOptions(tuple([default_config])) + mixed_precision_configuration_options = schema.QuantizationConfigOptions(tuple(mixed_precision_cfg_list), + base_config=base_config) + conv = schema.OperatorsSet("Conv", mixed_precision_configuration_options) + any_relu = schema.OperatorsSet("AnyReLU") + operator_set = [conv, any_relu] + # Define fusions + fusing_patterns = [schema.Fusing((conv, any_relu))] + generated_tp = schema.TargetPlatformModel(default_configuration_options, + tpc_minor_version=None, + tpc_patch_version=None, + tpc_platform_type=None, + operator_set=tuple(operator_set), + fusing_patterns=tuple(fusing_patterns), + name='layer_fusing_test') + pytorch_tpc = tp.TargetPlatformCapabilities(generated_tp) with pytorch_tpc: @@ -116,12 +115,22 @@ def __init__(self, unit_test): self.expected_fusions = [[Conv2d, Hardtanh], [Conv2d, ReLU], [Conv2d, Sigmoid], [Conv2d, SiLU]] def get_tpc(self): - generated_tp, mixed_precision_configuration_options = super().get_tpc() - with generated_tp: - conv = schema.OperatorsSet("Conv", mixed_precision_configuration_options) - any_act = schema.OperatorsSet("AnyAct") - # Define fusions - schema.Fusing([conv, any_act]) + base_config, mixed_precision_cfg_list, default_config = get_op_quantization_configs() + mixed_precision_configuration_options = schema.QuantizationConfigOptions(tuple(mixed_precision_cfg_list), + base_config=base_config) + default_configuration_options = schema.QuantizationConfigOptions(tuple([default_config])) + conv = schema.OperatorsSet("Conv", mixed_precision_configuration_options) + any_act = schema.OperatorsSet("AnyAct") + operator_set = [conv, any_act] + # Define fusions + fusing_patterns = [schema.Fusing((conv, any_act))] + generated_tp = schema.TargetPlatformModel(default_configuration_options, + tpc_minor_version=None, + tpc_patch_version=None, + tpc_platform_type=None, + operator_set=tuple(operator_set), + fusing_patterns=tuple(fusing_patterns), + name='layer_fusing_test') pytorch_tpc = tp.TargetPlatformCapabilities(generated_tp) with pytorch_tpc: @@ -169,13 +178,22 @@ def __init__(self, unit_test): self.expected_fusions = [[Conv2d, ReLU]] def get_tpc(self): - generated_tp, mixed_precision_configuration_options = super().get_tpc() - with generated_tp: - conv = schema.OperatorsSet("Conv", mixed_precision_configuration_options) - any_act = schema.OperatorsSet("AnyAct") - # Define fusions - schema.Fusing([conv, any_act]) - + base_config, mixed_precision_cfg_list, default_config = get_op_quantization_configs() + mixed_precision_configuration_options = schema.QuantizationConfigOptions(tuple(mixed_precision_cfg_list), + base_config=base_config) + default_configuration_options = schema.QuantizationConfigOptions(tuple([default_config])) + conv = schema.OperatorsSet("Conv", mixed_precision_configuration_options) + any_act = schema.OperatorsSet("AnyAct") + operator_set = [conv, any_act] + # Define fusions + fusing_patterns = [schema.Fusing((conv, any_act))] + generated_tp = schema.TargetPlatformModel(default_configuration_options, + tpc_minor_version=None, + tpc_patch_version=None, + tpc_platform_type=None, + operator_set=tuple(operator_set), + fusing_patterns=tuple(fusing_patterns), + name='layer_fusing_test') pytorch_tpc = tp.TargetPlatformCapabilities(generated_tp) with pytorch_tpc: tp.OperationsSetToLayers("Conv", [Conv2d]) @@ -222,19 +240,30 @@ def __init__(self, unit_test): [Conv2d, ReLU, torch.add], [Linear, SiLU], [Linear, SiLU]] def get_tpc(self): - generated_tp, mixed_precision_configuration_options = super().get_tpc() - with generated_tp: - conv = schema.OperatorsSet("Conv", mixed_precision_configuration_options) - fc = schema.OperatorsSet("FullyConnected", mixed_precision_configuration_options) - any_relu = schema.OperatorsSet("AnyReLU") - add = schema.OperatorsSet("Add") - swish = schema.OperatorsSet("Swish") - activations_to_fuse = schema.OperatorSetConcat([any_relu, swish]) - # Define fusions - schema.Fusing([conv, activations_to_fuse]) - schema.Fusing([conv, add, activations_to_fuse]) - schema.Fusing([conv, activations_to_fuse, add]) - schema.Fusing([fc, activations_to_fuse]) + base_config, mixed_precision_cfg_list, default_config = get_op_quantization_configs() + mixed_precision_configuration_options = schema.QuantizationConfigOptions(tuple(mixed_precision_cfg_list), + base_config=base_config) + default_configuration_options = schema.QuantizationConfigOptions(tuple([default_config])) + conv = schema.OperatorsSet("Conv", mixed_precision_configuration_options) + fc = schema.OperatorsSet("FullyConnected", mixed_precision_configuration_options) + any_relu = schema.OperatorsSet("AnyReLU") + add = schema.OperatorsSet("Add") + swish = schema.OperatorsSet("Swish") + operator_set = [conv, fc, any_relu, add, swish] + activations_to_fuse = schema.OperatorSetConcat([any_relu, swish]) + # Define fusions + fusing_patterns = [schema.Fusing((conv, activations_to_fuse)), + schema.Fusing((conv, add, activations_to_fuse)), + schema.Fusing((conv, activations_to_fuse, add)), + schema.Fusing((fc, activations_to_fuse))] + + generated_tp = schema.TargetPlatformModel(default_configuration_options, + tpc_minor_version=None, + tpc_patch_version=None, + tpc_platform_type=None, + operator_set=tuple(operator_set), + fusing_patterns=tuple(fusing_patterns), + name='layer_fusing_test') pytorch_tpc = tp.TargetPlatformCapabilities(generated_tp) with pytorch_tpc: diff --git a/tests/pytorch_tests/function_tests/test_pytorch_tp_model.py b/tests/pytorch_tests/function_tests/test_pytorch_tp_model.py index 68c597f13..26dd513f5 100644 --- a/tests/pytorch_tests/function_tests/test_pytorch_tp_model.py +++ b/tests/pytorch_tests/function_tests/test_pytorch_tp_model.py @@ -42,7 +42,7 @@ tp = mct.target_platform TEST_QC = generate_test_op_qc(**generate_test_attr_configs()) -TEST_QCO = schema.QuantizationConfigOptions([TEST_QC]) +TEST_QCO = schema.QuantizationConfigOptions(tuple([TEST_QC])) class TestPytorchTPModel(unittest.TestCase): @@ -84,32 +84,34 @@ def test_pytorch_layers_with_params(self): get_node(partial(torch.nn.functional.normalize, p=3.0)).is_match_filter_params(l2norm_tflite_opset)) def test_qco_by_pytorch_layer(self): - default_qco = schema.QuantizationConfigOptions([TEST_QC]) + default_qco = schema.QuantizationConfigOptions(tuple([TEST_QC])) default_qco = default_qco.clone_and_edit(attr_weights_configs_mapping={}) + mixed_precision_configuration_options = schema.QuantizationConfigOptions(tuple( + [TEST_QC, + TEST_QC.clone_and_edit(attr_to_edit={KERNEL_ATTR: {WEIGHTS_N_BITS: 4}}), + TEST_QC.clone_and_edit(attr_to_edit={KERNEL_ATTR: {WEIGHTS_N_BITS: 2}})]), + base_config=TEST_QC) + + operator_set = [] + operator_set.append(schema.OperatorsSet("conv", mixed_precision_configuration_options)) + + sevenbit_qco = TEST_QCO.clone_and_edit(activation_n_bits=7, + attr_weights_configs_mapping={}) + operator_set.append(schema.OperatorsSet("tanh", sevenbit_qco)) + + sixbit_qco = TEST_QCO.clone_and_edit(activation_n_bits=6, + attr_weights_configs_mapping={}) + operator_set.append(schema.OperatorsSet("avg_pool2d_kernel_2", sixbit_qco)) + + operator_set.append(schema.OperatorsSet("avg_pool2d")) + tpm = schema.TargetPlatformModel(default_qco, tpc_minor_version=None, tpc_patch_version=None, tpc_platform_type=None, + operator_set=tuple(operator_set), add_metadata=False, name='test') - with tpm: - mixed_precision_configuration_options = schema.QuantizationConfigOptions( - [TEST_QC, - TEST_QC.clone_and_edit(attr_to_edit={KERNEL_ATTR: {WEIGHTS_N_BITS: 4}}), - TEST_QC.clone_and_edit(attr_to_edit={KERNEL_ATTR: {WEIGHTS_N_BITS: 2}})], - base_config=TEST_QC) - - schema.OperatorsSet("conv", mixed_precision_configuration_options) - - sevenbit_qco = TEST_QCO.clone_and_edit(activation_n_bits=7, - attr_weights_configs_mapping={}) - schema.OperatorsSet("tanh", sevenbit_qco) - - sixbit_qco = TEST_QCO.clone_and_edit(activation_n_bits=6, - attr_weights_configs_mapping={}) - schema.OperatorsSet("avg_pool2d_kernel_2", sixbit_qco) - - schema.OperatorsSet("avg_pool2d") tpc_pytorch = tp.TargetPlatformCapabilities(tpm) with tpc_pytorch: @@ -132,25 +134,27 @@ def test_qco_by_pytorch_layer(self): avg_pool2d_k2_qco = avg_pool2d_k2.get_qco(tpc_pytorch) avg_pool2d_qco = avg_pool2d.get_qco(tpc_pytorch) - self.assertEqual(len(conv_qco.quantization_config_list), - len(mixed_precision_configuration_options.quantization_config_list)) - for i in range(len(conv_qco.quantization_config_list)): - self.assertEqual(conv_qco.quantization_config_list[i].attr_weights_configs_mapping[PYTORCH_KERNEL], - mixed_precision_configuration_options.quantization_config_list[ + self.assertEqual(len(conv_qco.quantization_configurations), + len(mixed_precision_configuration_options.quantization_configurations)) + for i in range(len(conv_qco.quantization_configurations)): + self.assertEqual(conv_qco.quantization_configurations[i].attr_weights_configs_mapping[PYTORCH_KERNEL], + mixed_precision_configuration_options.quantization_configurations[ i].attr_weights_configs_mapping[KERNEL_ATTR]) self.assertEqual(tanh_qco, sevenbit_qco) self.assertEqual(avg_pool2d_k2_qco, sixbit_qco) self.assertEqual(avg_pool2d_qco, default_qco) def test_get_layers_by_op(self): + op_obj = schema.OperatorsSet('opsetA') + hm = schema.TargetPlatformModel( - schema.QuantizationConfigOptions([TEST_QC]), + schema.QuantizationConfigOptions(tuple([TEST_QC])), tpc_minor_version=None, tpc_patch_version=None, tpc_platform_type=None, + operator_set=tuple([op_obj]), add_metadata=False) - with hm: - op_obj = schema.OperatorsSet('opsetA') + fw_tp = TargetPlatformCapabilities(hm) with fw_tp: opset_layers = [torch.nn.Conv2d, LayerFilterParams(torch.nn.Softmax, dim=1)] @@ -159,16 +163,17 @@ def test_get_layers_by_op(self): self.assertEqual(fw_tp.get_layers_by_opset(op_obj), opset_layers) def test_get_layers_by_opconcat(self): + op_obj_a = schema.OperatorsSet('opsetA') + op_obj_b = schema.OperatorsSet('opsetB') + op_concat = schema.OperatorSetConcat([op_obj_a, op_obj_b]) + hm = schema.TargetPlatformModel( - schema.QuantizationConfigOptions([TEST_QC]), + schema.QuantizationConfigOptions(tuple([TEST_QC])), tpc_minor_version=None, tpc_patch_version=None, tpc_platform_type=None, + operator_set=tuple([op_obj_a, op_obj_b]), add_metadata=False) - with hm: - op_obj_a = schema.OperatorsSet('opsetA') - op_obj_b = schema.OperatorsSet('opsetB') - op_concat = schema.OperatorSetConcat([op_obj_a, op_obj_b]) fw_tp = TargetPlatformCapabilities(hm) with fw_tp: @@ -177,19 +182,18 @@ def test_get_layers_by_opconcat(self): tp.OperationsSetToLayers('opsetA', opset_layers_a) tp.OperationsSetToLayers('opsetB', opset_layers_b) - self.assertEqual(fw_tp.get_layers_by_opset_name('opsetA_opsetB'), opset_layers_a + opset_layers_b) self.assertEqual(fw_tp.get_layers_by_opset(op_concat), opset_layers_a + opset_layers_b) def test_layer_attached_to_multiple_opsets(self): hm = schema.TargetPlatformModel( - schema.QuantizationConfigOptions([TEST_QC]), + schema.QuantizationConfigOptions(tuple([TEST_QC])), tpc_minor_version=None, tpc_patch_version=None, tpc_platform_type=None, + operator_set=tuple([ + schema.OperatorsSet('opsetA'), + schema.OperatorsSet('opsetB')]), add_metadata=False) - with hm: - schema.OperatorsSet('opsetA') - schema.OperatorsSet('opsetB') fw_tp = TargetPlatformCapabilities(hm) with self.assertRaises(Exception) as e: @@ -200,14 +204,13 @@ def test_layer_attached_to_multiple_opsets(self): def test_filter_layer_attached_to_multiple_opsets(self): hm = schema.TargetPlatformModel( - schema.QuantizationConfigOptions([TEST_QC]), + schema.QuantizationConfigOptions(tuple([TEST_QC])), tpc_minor_version=None, tpc_patch_version=None, tpc_platform_type=None, + operator_set=tuple([schema.OperatorsSet('opsetA'), + schema.OperatorsSet('opsetB')]), add_metadata=False) - with hm: - schema.OperatorsSet('opsetA') - schema.OperatorsSet('opsetB') fw_tp = TargetPlatformCapabilities(hm) with self.assertRaises(Exception) as e: @@ -217,11 +220,12 @@ def test_filter_layer_attached_to_multiple_opsets(self): self.assertEqual('Found layer Softmax(dim=2) in more than one OperatorsSet', str(e.exception)) def test_opset_not_in_tp(self): - default_qco = schema.QuantizationConfigOptions([TEST_QC]) + default_qco = schema.QuantizationConfigOptions(tuple([TEST_QC])) hm = schema.TargetPlatformModel(default_qco, tpc_minor_version=None, tpc_patch_version=None, tpc_platform_type=None, + operator_set=tuple([schema.OperatorsSet("opA")]), add_metadata=False) hm_pytorch = tp.TargetPlatformCapabilities(hm) with self.assertRaises(Exception) as e: @@ -232,19 +236,21 @@ def test_opset_not_in_tp(self): str(e.exception)) def test_pytorch_fusing_patterns(self): - default_qco = schema.QuantizationConfigOptions( - [TEST_QC]) + default_qco = schema.QuantizationConfigOptions(tuple( + [TEST_QC])) + a = schema.OperatorsSet("opA") + b = schema.OperatorsSet("opB") + c = schema.OperatorsSet("opC") + operator_set = [a, b, c] + fusing_patterns = [schema.Fusing((a, b, c)), + schema.Fusing((a, c))] hm = schema.TargetPlatformModel(default_qco, tpc_minor_version=None, tpc_patch_version=None, tpc_platform_type=None, + operator_set=tuple(operator_set), + fusing_patterns=tuple(fusing_patterns), add_metadata=False) - with hm: - a = schema.OperatorsSet("opA") - b = schema.OperatorsSet("opB") - c = schema.OperatorsSet("opC") - schema.Fusing([a, b, c]) - schema.Fusing([a, c]) hm_keras = tp.TargetPlatformCapabilities(hm) with hm_keras: diff --git a/tests/pytorch_tests/function_tests/test_quant_config_filtering.py b/tests/pytorch_tests/function_tests/test_quant_config_filtering.py index d26bfe3f9..1f398c785 100644 --- a/tests/pytorch_tests/function_tests/test_quant_config_filtering.py +++ b/tests/pytorch_tests/function_tests/test_quant_config_filtering.py @@ -34,7 +34,7 @@ def get_tpc_default_16bit(): tpc = mct.get_target_platform_capabilities(PYTORCH, IMX500_TP_MODEL, 'v3') # Force Mul base_config to 16bit only mul_op_set = get_op_set('Mul', tpc.tp_model.operator_set) - base_config = [l for l in mul_op_set.qc_options.quantization_config_list if l.activation_n_bits == 16][0] + base_config = [l for l in mul_op_set.qc_options.quantization_configurations if l.activation_n_bits == 16][0] tpc.layer2qco[torch.multiply] = replace(tpc.layer2qco[torch.multiply], base_config=base_config) return tpc diff --git a/tests/pytorch_tests/model_tests/feature_models/activation_16bit_test.py b/tests/pytorch_tests/model_tests/feature_models/activation_16bit_test.py index 6d2196053..ca1cf548c 100644 --- a/tests/pytorch_tests/model_tests/feature_models/activation_16bit_test.py +++ b/tests/pytorch_tests/model_tests/feature_models/activation_16bit_test.py @@ -65,7 +65,7 @@ def forward(self, x): def set_16bit_as_default(tpc, required_op_set, required_ops_list): for op in required_ops_list: - base_config = [l for l in tpc.layer2qco[op].quantization_config_list if l.activation_n_bits == 16][0] + base_config = [l for l in tpc.layer2qco[op].quantization_configurations if l.activation_n_bits == 16][0] tpc.layer2qco[op] = replace(tpc.layer2qco[op], base_config=base_config) @@ -107,19 +107,13 @@ class Activation16BitMixedPrecisionTest(Activation16BitTest): def get_tpc(self): tpc = mct.get_target_platform_capabilities(PYTORCH, IMX500_TP_MODEL, 'v3') mul_op_set = get_op_set('Mul', tpc.tp_model.operator_set) - base_config = [l for l in mul_op_set.qc_options.quantization_config_list if l.activation_n_bits == 16][0] - tpc.layer2qco[torch.mul] = replace(tpc.layer2qco[torch.mul], base_config=base_config) - tpc.layer2qco[mul] = replace(tpc.layer2qco[mul], base_config=base_config) - mul_op_set.qc_options.quantization_config_list.extend( - [mul_op_set.qc_options.base_config.clone_and_edit(activation_n_bits=4), - mul_op_set.qc_options.base_config.clone_and_edit(activation_n_bits=2)]) - tpc.layer2qco[torch.mul].quantization_config_list.extend([ + base_config = [l for l in mul_op_set.qc_options.quantization_configurations if l.activation_n_bits == 16][0] + quantization_configurations = list(mul_op_set.qc_options.quantization_configurations) + quantization_configurations.extend([ tpc.layer2qco[torch.mul].base_config.clone_and_edit(activation_n_bits=4), tpc.layer2qco[torch.mul].base_config.clone_and_edit(activation_n_bits=2)]) - tpc.layer2qco[mul].quantization_config_list.extend([ - tpc.layer2qco[mul].base_config.clone_and_edit(activation_n_bits=4), - tpc.layer2qco[mul].base_config.clone_and_edit(activation_n_bits=2)]) - + tpc.layer2qco[torch.mul] = replace(tpc.layer2qco[torch.mul], base_config=base_config, quantization_configurations=tuple(quantization_configurations)) + tpc.layer2qco[mul] = replace(tpc.layer2qco[mul], base_config=base_config, quantization_configurations=tuple(quantization_configurations)) return tpc def get_resource_utilization(self): diff --git a/tests/pytorch_tests/model_tests/feature_models/bn_attributes_quantization_test.py b/tests/pytorch_tests/model_tests/feature_models/bn_attributes_quantization_test.py index e51ead220..88ab07933 100644 --- a/tests/pytorch_tests/model_tests/feature_models/bn_attributes_quantization_test.py +++ b/tests/pytorch_tests/model_tests/feature_models/bn_attributes_quantization_test.py @@ -76,21 +76,19 @@ def _generate_bn_quantized_tpm(quantize_linear): simd_size=32, signedness=Signedness.AUTO) - default_configuration_options = schema.QuantizationConfigOptions([default_op_qc]) - linear_configuration_options = schema.QuantizationConfigOptions([linear_op_qc]) - bn_configuration_options = schema.QuantizationConfigOptions([bn_op_qc]) + default_configuration_options = schema.QuantizationConfigOptions(tuple([default_op_qc])) + linear_configuration_options = schema.QuantizationConfigOptions(tuple([linear_op_qc])) + bn_configuration_options = schema.QuantizationConfigOptions(tuple([bn_op_qc])) generated_tpm = schema.TargetPlatformModel( default_configuration_options, tpc_minor_version=None, tpc_patch_version=None, tpc_platform_type=None, + operator_set=tuple([schema.OperatorsSet("Conv", linear_configuration_options), + schema.OperatorsSet("BN", bn_configuration_options)]), add_metadata=False, name='bn_quantized_tpm') - with generated_tpm: - schema.OperatorsSet("Conv", linear_configuration_options) - schema.OperatorsSet("BN", bn_configuration_options) - return generated_tpm diff --git a/tests/pytorch_tests/model_tests/feature_models/const_quantization_test.py b/tests/pytorch_tests/model_tests/feature_models/const_quantization_test.py index fea672a49..7fd484a0c 100644 --- a/tests/pytorch_tests/model_tests/feature_models/const_quantization_test.py +++ b/tests/pytorch_tests/model_tests/feature_models/const_quantization_test.py @@ -240,23 +240,22 @@ def get_tpc(self): simd_size=32, signedness=Signedness.AUTO) - default_configuration_options = schema.QuantizationConfigOptions([base_cfg]) + default_configuration_options = schema.QuantizationConfigOptions(tuple([base_cfg])) const_config = base_cfg.clone_and_edit(enable_activation_quantization=False, default_weight_attr_config=base_cfg.default_weight_attr_config.clone_and_edit( enable_weights_quantization=True, weights_per_channel_threshold=False, weights_quantization_method=tp.QuantizationMethod.POWER_OF_TWO)) - const_configuration_options = schema.QuantizationConfigOptions([const_config]) + const_configuration_options = schema.QuantizationConfigOptions(tuple([const_config])) tp_model = schema.TargetPlatformModel( default_configuration_options, tpc_minor_version=None, tpc_patch_version=None, tpc_platform_type=None, + operator_set=tuple([schema.OperatorsSet("WeightQuant", const_configuration_options)]), add_metadata=False) - with tp_model: - schema.OperatorsSet("WeightQuant", const_configuration_options) tpc = tp.TargetPlatformCapabilities(tp_model) with tpc: diff --git a/tests/pytorch_tests/model_tests/feature_models/manual_bit_selection.py b/tests/pytorch_tests/model_tests/feature_models/manual_bit_selection.py index 347bebb61..0410c7db4 100644 --- a/tests/pytorch_tests/model_tests/feature_models/manual_bit_selection.py +++ b/tests/pytorch_tests/model_tests/feature_models/manual_bit_selection.py @@ -188,7 +188,7 @@ class Manual16BitTest(ManualBitWidthByLayerNameTest): def get_tpc(self): tpc = mct.get_target_platform_capabilities(PYTORCH, IMX500_TP_MODEL, 'v3') mul_op_set = get_op_set('Mul', tpc.tp_model.operator_set) - base_config = [l for l in mul_op_set.qc_options.quantization_config_list if l.activation_n_bits == 16][0] + base_config = [l for l in mul_op_set.qc_options.quantization_configurations if l.activation_n_bits == 16][0] tpc.layer2qco[torch.mul] = replace(tpc.layer2qco[torch.mul], base_config=base_config) tpc.layer2qco[mul] = replace(tpc.layer2qco[mul] , base_config=base_config) return {'mixed_precision_activation_model': tpc} @@ -202,19 +202,15 @@ class Manual16BitTestMixedPrecisionTest(ManualBitWidthByLayerNameTest): def get_tpc(self): tpc = mct.get_target_platform_capabilities(PYTORCH, IMX500_TP_MODEL, 'v3') mul_op_set = get_op_set('Mul', tpc.tp_model.operator_set) - base_config = [l for l in mul_op_set.qc_options.quantization_config_list if l.activation_n_bits == 16][0] - tpc.layer2qco[torch.mul] = replace(tpc.layer2qco[torch.mul], base_config=base_config) - tpc.layer2qco[mul] = replace(tpc.layer2qco[mul], base_config=base_config) - mul_op_set.qc_options.quantization_config_list.extend( + base_config = [l for l in mul_op_set.qc_options.quantization_configurations if l.activation_n_bits == 16][0] + quantization_configurations = list(mul_op_set.qc_options.quantization_configurations) + quantization_configurations.extend( [mul_op_set.qc_options.base_config.clone_and_edit(activation_n_bits=4), mul_op_set.qc_options.base_config.clone_and_edit(activation_n_bits=2)]) - tpc.layer2qco[torch.mul].quantization_config_list.extend([ - tpc.layer2qco[torch.mul].base_config.clone_and_edit(activation_n_bits=4), - tpc.layer2qco[torch.mul].base_config.clone_and_edit(activation_n_bits=2)]) - tpc.layer2qco[mul].quantization_config_list.extend([ - tpc.layer2qco[mul].base_config.clone_and_edit(activation_n_bits=4), - tpc.layer2qco[mul].base_config.clone_and_edit(activation_n_bits=2)]) - + tpc.layer2qco[torch.mul] = replace(tpc.layer2qco[torch.mul], base_config=base_config, + quantization_configurations=tuple(quantization_configurations)) + tpc.layer2qco[mul] = replace(tpc.layer2qco[mul], base_config=base_config, + quantization_configurations=tuple(quantization_configurations)) return {'mixed_precision_activation_model': tpc} def get_resource_utilization(self): diff --git a/tests/pytorch_tests/model_tests/feature_models/mixed_precision_activation_test.py b/tests/pytorch_tests/model_tests/feature_models/mixed_precision_activation_test.py index e4e387796..e7d3518c9 100644 --- a/tests/pytorch_tests/model_tests/feature_models/mixed_precision_activation_test.py +++ b/tests/pytorch_tests/model_tests/feature_models/mixed_precision_activation_test.py @@ -292,27 +292,26 @@ def get_tpc(self): [c.clone_and_edit(enable_activation_quantization=False) for c in mixed_precision_cfg_list] cfg = mixed_precision_cfg_list[0] - act_mixed_cfg = QuantizationConfigOptions( - [act_eight_bit_cfg, act_four_bit_cfg, act_two_bit_cfg], + act_mixed_cfg = QuantizationConfigOptions(tuple( + [act_eight_bit_cfg, act_four_bit_cfg, act_two_bit_cfg]), base_config=act_eight_bit_cfg, ) - weight_mixed_cfg = QuantizationConfigOptions( - mixed_precision_cfg_list, + weight_mixed_cfg = QuantizationConfigOptions(tuple( + mixed_precision_cfg_list), base_config=cfg, ) - tp_model = TargetPlatformModel(QuantizationConfigOptions([cfg], cfg), + tp_model = TargetPlatformModel(QuantizationConfigOptions(tuple([cfg]), cfg), tpc_minor_version=None, tpc_patch_version=None, tpc_platform_type=None, + operator_set=tuple([ + OperatorsSet("Activations", act_mixed_cfg), + OperatorsSet("Weights", weight_mixed_cfg)]), add_metadata=False, name="mp_activation_conf_weights_test") - with tp_model: - OperatorsSet("Activations", act_mixed_cfg) - OperatorsSet("Weights", weight_mixed_cfg) - torch_tpc = TargetPlatformCapabilities(tp_model) with torch_tpc: diff --git a/tests/pytorch_tests/model_tests/feature_models/mixed_precision_weights_test.py b/tests/pytorch_tests/model_tests/feature_models/mixed_precision_weights_test.py index 38a112550..5468cf50e 100644 --- a/tests/pytorch_tests/model_tests/feature_models/mixed_precision_weights_test.py +++ b/tests/pytorch_tests/model_tests/feature_models/mixed_precision_weights_test.py @@ -141,13 +141,13 @@ def get_tpc(self): two_bit_cfg = mixed_precision_cfg_list[2] - weight_mixed_cfg = schema.QuantizationConfigOptions( - mixed_precision_cfg_list, + weight_mixed_cfg = schema.QuantizationConfigOptions(tuple( + mixed_precision_cfg_list), base_config=cfg, ) - weight_fixed_cfg = schema.QuantizationConfigOptions( - [two_bit_cfg], + weight_fixed_cfg = schema.QuantizationConfigOptions(tuple( + [two_bit_cfg]), base_config=two_bit_cfg, ) @@ -156,10 +156,10 @@ def get_tpc(self): tpc_minor_version=None, tpc_patch_version=None, tpc_platform_type=None, + operator_set=tuple([schema.OperatorsSet("Weights_mp", weight_mixed_cfg), + schema.OperatorsSet("Weights_fixed", weight_fixed_cfg)]), name="mp_part_weights_layers_test") - with tp_model: - schema.OperatorsSet("Weights_mp", weight_mixed_cfg) - schema.OperatorsSet("Weights_fixed", weight_fixed_cfg) + pytorch_tpc = tp.TargetPlatformCapabilities(tp_model) @@ -308,26 +308,25 @@ def get_tpc(self): [c.clone_and_edit(enable_activation_quantization=False) for c in mixed_precision_cfg_list] cfg = mixed_precision_cfg_list[0] - act_mixed_cfg = QuantizationConfigOptions( - [act_eight_bit_cfg, act_four_bit_cfg, act_two_bit_cfg], + act_mixed_cfg = QuantizationConfigOptions(tuple( + [act_eight_bit_cfg, act_four_bit_cfg, act_two_bit_cfg]), base_config=act_eight_bit_cfg, ) - weight_mixed_cfg = QuantizationConfigOptions( - mixed_precision_cfg_list, + weight_mixed_cfg = QuantizationConfigOptions(tuple( + mixed_precision_cfg_list), base_config=cfg, ) - tp_model = TargetPlatformModel(QuantizationConfigOptions([cfg], cfg), + tp_model = TargetPlatformModel(QuantizationConfigOptions(tuple([cfg]), cfg), tpc_minor_version=None, tpc_patch_version=None, tpc_platform_type=None, + operator_set=tuple([ + OperatorsSet("Activations", act_mixed_cfg), + OperatorsSet("Weights", weight_mixed_cfg)]), name="mp_weights_conf_act_test") - with tp_model: - OperatorsSet("Activations", act_mixed_cfg) - OperatorsSet("Weights", weight_mixed_cfg) - torch_tpc = TargetPlatformCapabilities(tp_model) with torch_tpc: