Save the model in Core ML format.

        See Also
        --------
        save

        Examples
        --------
        >>> model.export_coreml('myModel.mlmodel')

def export_coreml(self, filename):
        """
        Save the model in Core ML format.

        See Also
        --------
        save

        Examples
        --------
        >>> model.export_coreml('myModel.mlmodel')
        """
        import coremltools
        # First define three internal helper functions


        # Internal helper function
        def _create_vision_feature_print_scene():
            prob_name = self.target + 'Probability'

            #
            # Setup the top level (pipeline classifier) spec
            #
            top_spec = coremltools.proto.Model_pb2.Model()
            top_spec.specificationVersion = 3

            desc = top_spec.description
            desc.output.add().name = prob_name
            desc.output.add().name = self.target

            desc.predictedFeatureName = self.target
            desc.predictedProbabilitiesName = prob_name

            input = desc.input.add()
            input.name = self.feature
            input.type.imageType.width = 299
            input.type.imageType.height = 299
            BGR_VALUE = coremltools.proto.FeatureTypes_pb2.ImageFeatureType.ColorSpace.Value('BGR')
            input.type.imageType.colorSpace = BGR_VALUE

            #
            # VisionFeaturePrint extractor
            #
            pipelineClassifier = top_spec.pipelineClassifier
            scene_print = pipelineClassifier.pipeline.models.add()
            scene_print.specificationVersion = 3
            scene_print.visionFeaturePrint.scene.version = 1

            input = scene_print.description.input.add()
            input.name = self.feature
            input.type.imageType.width = 299
            input.type.imageType.height = 299
            input.type.imageType.colorSpace = BGR_VALUE

            output = scene_print.description.output.add()
            output.name = "output_name"
            DOUBLE_ARRAY_VALUE = coremltools.proto.FeatureTypes_pb2.ArrayFeatureType.ArrayDataType.Value('DOUBLE')
            output.type.multiArrayType.dataType = DOUBLE_ARRAY_VALUE
            output.type.multiArrayType.shape.append(2048)

            #
            # Neural Network Classifier, which is just logistic regression, in order to use GPUs
            #
            temp = top_spec.pipelineClassifier.pipeline.models.add()
            temp.specificationVersion = 3

            # Empty inner product layer
            nn_spec = temp.neuralNetworkClassifier
            feature_layer = nn_spec.layers.add()
            feature_layer.name = "feature_layer"
            feature_layer.input.append("output_name")
            feature_layer.output.append("softmax_input")
            fc_layer_params = feature_layer.innerProduct
            fc_layer_params.inputChannels = 2048

            # Softmax layer
            softmax = nn_spec.layers.add()
            softmax.name = "softmax"
            softmax.softmax.MergeFromString(b'')
            softmax.input.append("softmax_input")
            softmax.output.append(prob_name)

            input = temp.description.input.add()
            input.name = "output_name"
            input.type.multiArrayType.dataType = DOUBLE_ARRAY_VALUE
            input.type.multiArrayType.shape.append(2048)

            # Set outputs
            desc = temp.description
            prob_output = desc.output.add()
            prob_output.name = prob_name
            label_output = desc.output.add()
            label_output.name = self.target

            if type(self.classifier.classes[0]) == int:
                prob_output.type.dictionaryType.int64KeyType.MergeFromString(b'')
                label_output.type.int64Type.MergeFromString(b'')
            else:
                prob_output.type.dictionaryType.stringKeyType.MergeFromString(b'')
                label_output.type.stringType.MergeFromString(b'')

            temp.description.predictedFeatureName = self.target
            temp.description.predictedProbabilitiesName = prob_name

            return top_spec


        # Internal helper function
        def _update_last_two_layers(nn_spec):
            # Replace the softmax layer with new coeffients
            num_classes = self.num_classes
            fc_layer = nn_spec.layers[-2]
            fc_layer_params = fc_layer.innerProduct
            fc_layer_params.outputChannels = self.classifier.num_classes
            inputChannels = fc_layer_params.inputChannels
            fc_layer_params.hasBias = True

            coefs = self.classifier.coefficients
            weights = fc_layer_params.weights
            bias = fc_layer_params.bias
            del weights.floatValue[:]
            del bias.floatValue[:]

            import numpy as np
            W = np.array(coefs[coefs['index'] != None]['value'], ndmin = 2).reshape(
                                          inputChannels, num_classes - 1, order = 'F')
            b =  coefs[coefs['index'] == None]['value']
            Wa = np.hstack((np.zeros((inputChannels, 1)), W))
            weights.floatValue.extend(Wa.flatten(order = 'F'))
            bias.floatValue.extend([0.0] + list(b))

        # Internal helper function
        def _set_inputs_outputs_and_metadata(spec, nn_spec):
            # Replace the classifier with the new classes
            class_labels = self.classifier.classes

            probOutput = spec.description.output[0]
            classLabel = spec.description.output[1]
            probOutput.type.dictionaryType.MergeFromString(b'')
            if type(class_labels[0]) == int:
                nn_spec.ClearField('int64ClassLabels')
                probOutput.type.dictionaryType.int64KeyType.MergeFromString(b'')
                classLabel.type.int64Type.MergeFromString(b'')
                del nn_spec.int64ClassLabels.vector[:]
                for c in class_labels:
                    nn_spec.int64ClassLabels.vector.append(c)
            else:
                nn_spec.ClearField('stringClassLabels')
                probOutput.type.dictionaryType.stringKeyType.MergeFromString(b'')
                classLabel.type.stringType.MergeFromString(b'')
                del nn_spec.stringClassLabels.vector[:]
                for c in class_labels:
                    nn_spec.stringClassLabels.vector.append(c)

            prob_name = self.target + 'Probability'
            label_name = self.target
            old_output_name = nn_spec.layers[-1].name
            coremltools.models.utils.rename_feature(spec, 'classLabel', label_name)
            coremltools.models.utils.rename_feature(spec, old_output_name, prob_name)
            if nn_spec.layers[-1].name == old_output_name:
                nn_spec.layers[-1].name = prob_name
            if nn_spec.labelProbabilityLayerName == old_output_name:
                nn_spec.labelProbabilityLayerName = prob_name
            coremltools.models.utils.rename_feature(spec, 'data', self.feature)
            if len(nn_spec.preprocessing) > 0:
                nn_spec.preprocessing[0].featureName = self.feature

            mlmodel = coremltools.models.MLModel(spec)
            model_type = 'image classifier (%s)' % self.model
            mlmodel.short_description = _coreml_utils._mlmodel_short_description(model_type)
            mlmodel.input_description[self.feature] = u'Input image'
            mlmodel.output_description[prob_name] = 'Prediction probabilities'
            mlmodel.output_description[label_name] = 'Class label of top prediction'
            _coreml_utils._set_model_metadata(mlmodel, self.__class__.__name__, {
                'model': self.model,
                'target': self.target,
                'features': self.feature,
                'max_iterations': str(self.max_iterations),
            }, version=ImageClassifier._PYTHON_IMAGE_CLASSIFIER_VERSION)

            return mlmodel


        # main part of the export_coreml function
        if self.model in _pre_trained_models.MODELS:
            ptModel = _pre_trained_models.MODELS[self.model]()
            feature_extractor = _image_feature_extractor.MXFeatureExtractor(ptModel)

            coreml_model = feature_extractor.get_coreml_model()
            spec = coreml_model.get_spec()
            nn_spec = spec.neuralNetworkClassifier
        else:     # model == VisionFeaturePrint_Scene
            spec = _create_vision_feature_print_scene()
            nn_spec = spec.pipelineClassifier.pipeline.models[1].neuralNetworkClassifier

        _update_last_two_layers(nn_spec)
        mlmodel = _set_inputs_outputs_and_metadata(spec, nn_spec)
        mlmodel.save(filename)