def __init__(
        self,
        input_features=None,
        output_features=None,
        mode=None,
        spec=None,
        nn_spec=None,
        disable_rank5_shape_mapping=False,
        training_features=None,
        use_float_arraytype=False,
    ):
        """
        Construct a NeuralNetworkBuilder object to build an MLModel specification with a
        model interface, or a NeuralNetwork protobuf message, either from scratch or using an
        existing specification.

        Parameters
        ----------

        input_features: [(str, datatypes.Array)] or None
            List of input feature of the network.
            Each feature is a ``(name, array)`` tuple, where ``name`` is the
            name of the feature, and ``array`` is a ``datatype.Array`` object
            describing the feature type.

            * When ``spec`` is ``None`` (building from scratch), ``input_features`` must not be ``None``.

        output_features: [(str, datatypes.Array or None)] or None
            List of output feature of the network. Each feature is a
            ``(name, array)`` tuple, where ``name`` is the name of the feature,
            and ``array`` is a ``datatypes.Array`` object describing the feature type.

            * The ``array`` can be ``None`` if not known.

            * When ``spec`` is ``None`` (building from scratch), ``output_features`` must not be ``None``.

        mode: str ('classifier', 'regressor' or None)
            Mode (one of ``'classifier'``, ``'regressor'``, or ``None``).

            When ``mode = 'classifier'``, a NeuralNetworkClassifier spec will be
            constructed.  When ``mode = 'regressor'``, a NeuralNetworkRegressor
            spec will be constructed.

        disable_rank5_shape_mapping: bool
            Only applicable for neural networks.

            If True, inputs are no longer forced to map to rank 5 tensors
            (rank is equal to the length of the shape of the tensor).
            Instead, for multi-array inputs ``"EXACT_ARRAY_MAPPING"`` mapping is used, whereas
            for image inputs ``"RANK4_IMAGE_MAPPING"`` is used. For details,
            see description of enums ``NeuralNetworkMultiArrayShapeMapping``
            and ``NeuralNetworkImageShapeMapping`` in NeuralNetwork.proto.

            When ``spec`` is not ``None``, this argument will be ignored.

        spec: None or coremltools.proto.Model_pb2
            If ``None``, a new MLModel spec will be created by the builder with
            input and output features.

            Otherwise, the builder will continue to build on ``spec``.
            This is useful when the MLModel is built incrementally.

        nn_spec: None or coremltools.proto.NeuralNetwork_pb2
            If ``None``, a new, empty NeuralNetwork proto will be created for spec.

            If ``nn_spec`` is not ``None`` and ``spec`` is ``None``, the builder will
            build a NeuralNetwork spec without wrapping it within an MLModel.
            This is useful to create nested NeuralNetworks for models
            with control flow operations.

        use_float_arraytype: bool
            If true, the datatype of input/output multiarrays is set to Float32 instead
            of double.

        Examples
        --------
        .. sourcecode:: python

            # Construct a builder that builds a neural network classifier with a 299 x 299 x 3
            # dimensional input and 1000 dimensional output
            input_features = [("data", datatypes.Array((299, 299, 3)))]
            output_features = [("probs", datatypes.Array((1000,)))]
            builder = NeuralNetworkBuilder(input_features, output_features, mode="classifier")

        See Also
        --------
        set_input, set_output, set_class_labels
        """
        self.spec = spec
        self.nn_spec = nn_spec
        self._disable_rank5_shape_mapping = disable_rank5_shape_mapping
        self.layers = []
        self.layer_specs = {}
        self.named_parameters = []
        self.rank_dict = {}

        if self.spec is not None:  # Existing spec
            if self.nn_spec is None:
                self.nn_spec = _get_nn_spec(self.spec)
                for layer_spec in self.nn_spec.layers:
                    self.layers.append(layer_spec.name)
                    self.layer_specs[layer_spec.name] = layer_spec
            else:
                # Both spec and nn_spec are not None
                raise ValueError(
                    "Attempting to assign another NeuralNetwork Spec to an existing MLModel Spec"
                )
            if input_features is None and output_features is None:
                return

        if (
            self.spec is None and self.nn_spec is not None
        ):  # Building nested Neural Network
            return

        # Set the interface params.
        if self.spec is None:
            self.spec = _proto.Model_pb2.Model()
        self.spec.specificationVersion = _SPECIFICATION_VERSION
        if disable_rank5_shape_mapping:
            self.spec.specificationVersion = _MINIMUM_NDARRAY_SPEC_VERSION

        # When output_features in None, use some dummy sized type
        out_features_with_shape = []
        for out_feature in output_features:
            feat_name, feat_type = out_feature
            if feat_type is None:
                out_features_with_shape.append((str(feat_name), datatypes.Array(1)))
            else:
                out_features_with_shape.append(out_feature)

        # Set interface inputs and outputs
        if len(self.spec.description.input) > 0:
            del self.spec.description.input[:]
        if len(self.spec.description.output) > 0:
            del self.spec.description.output[:]

        if use_float_arraytype:
            array_datatype = _proto.Model_pb2.ArrayFeatureType.FLOAT32
        else:
            array_datatype = _proto.Model_pb2.ArrayFeatureType.DOUBLE

        self.spec = set_transform_interface_params(
            self.spec,
            input_features,
            out_features_with_shape,
            training_features=training_features,
            array_datatype=array_datatype,
        )

        for input in input_features:
            self.rank_dict[input[0]] = len(input[1].dimensions)

        for idx, output_feature in enumerate(output_features):
            if output_features[idx][1] is None:
                self.spec.description.output[idx].type.multiArrayType.ClearField(
                    "shape"
                )

        if self.nn_spec is None:
            if mode == "classifier":
                nn_spec = self.spec.neuralNetworkClassifier
            elif mode == "regressor":
                nn_spec = self.spec.neuralNetworkRegressor
            else:
                nn_spec = self.spec.neuralNetwork
            self.nn_spec = nn_spec

        if disable_rank5_shape_mapping and self.nn_spec:
            self.nn_spec.arrayInputShapeMapping = (
                _proto.NeuralNetwork_pb2.NeuralNetworkMultiArrayShapeMapping.Value(
                    "EXACT_ARRAY_MAPPING"
                )
            )
            self.nn_spec.imageInputShapeMapping = (
                _proto.NeuralNetwork_pb2.NeuralNetworkImageShapeMapping.Value("RANK4_IMAGE_MAPPING")
            )

        Construct a NeuralNetworkBuilder object to build an MLModel specification with a
        model interface, or a NeuralNetwork protobuf message, either from scratch or using an
        existing specification.

        Parameters
        ----------

        input_features: [(str, datatypes.Array)] or None
            List of input feature of the network.
            Each feature is a ``(name, array)`` tuple, where ``name`` is the
            name of the feature, and ``array`` is a ``datatype.Array`` object
            describing the feature type.

            * When ``spec`` is ``None`` (building from scratch), ``input_features`` must not be ``None``.

        output_features: [(str, datatypes.Array or None)] or None
            List of output feature of the network. Each feature is a
            ``(name, array)`` tuple, where ``name`` is the name of the feature,
            and ``array`` is a ``datatypes.Array`` object describing the feature type.

            * The ``array`` can be ``None`` if not known.

            * When ``spec`` is ``None`` (building from scratch), ``output_features`` must not be ``None``.

        mode: str ('classifier', 'regressor' or None)
            Mode (one of ``'classifier'``, ``'regressor'``, or ``None``).

            When ``mode = 'classifier'``, a NeuralNetworkClassifier spec will be
            constructed.  When ``mode = 'regressor'``, a NeuralNetworkRegressor
            spec will be constructed.

        disable_rank5_shape_mapping: bool
            Only applicable for neural networks.

            If True, inputs are no longer forced to map to rank 5 tensors
            (rank is equal to the length of the shape of the tensor).
            Instead, for multi-array inputs ``"EXACT_ARRAY_MAPPING"`` mapping is used, whereas
            for image inputs ``"RANK4_IMAGE_MAPPING"`` is used. For details,
            see description of enums ``NeuralNetworkMultiArrayShapeMapping``
            and ``NeuralNetworkImageShapeMapping`` in NeuralNetwork.proto.

            When ``spec`` is not ``None``, this argument will be ignored.

        spec: None or coremltools.proto.Model_pb2
            If ``None``, a new MLModel spec will be created by the builder with
            input and output features.

            Otherwise, the builder will continue to build on ``spec``.
            This is useful when the MLModel is built incrementally.

        nn_spec: None or coremltools.proto.NeuralNetwork_pb2
            If ``None``, a new, empty NeuralNetwork proto will be created for spec.

            If ``nn_spec`` is not ``None`` and ``spec`` is ``None``, the builder will
            build a NeuralNetwork spec without wrapping it within an MLModel.
            This is useful to create nested NeuralNetworks for models
            with control flow operations.

        use_float_arraytype: bool
            If true, the datatype of input/output multiarrays is set to Float32 instead
            of double.

        Examples
        --------
        .. sourcecode:: python

            # Construct a builder that builds a neural network classifier with a 299 x 299 x 3
            # dimensional input and 1000 dimensional output
            input_features = [("data", datatypes.Array((299, 299, 3)))]
            output_features = [("probs", datatypes.Array((1000,)))]
            builder = NeuralNetworkBuilder(input_features, output_features, mode="classifier")

        See Also
        --------
        set_input, set_output, set_class_labels
        
coremltools/models/neural_network/builder.py