def test_nn_set_training_input(self): builder = self.create_base_builder() builder.set_mean_squared_error_loss(name="mse", input_feature=("output", datatypes.Array(3))) builder.set_adam_optimizer( AdamParams(lr=1e-2, batch=10, beta1=0.9, beta2=0.999, eps=1e-8)) builder.set_epochs(20, allowed_set=[10, 20, 30]) model_path = os.path.join(self.model_dir, "updatable_creation.mlmodel") print(model_path) save_spec(builder.spec, model_path) mlmodel = MLModel(model_path) self.assertTrue(mlmodel is not None) spec = mlmodel.get_spec() self.assertEqual(spec.description.trainingInput[0].name, "input") self.assertEqual( spec.description.trainingInput[0].type.WhichOneof("Type"), "multiArrayType") self.assertEqual(spec.description.trainingInput[1].name, "output_true") self.assertEqual( spec.description.trainingInput[1].type.WhichOneof("Type"), "multiArrayType")
def test_downgrade_specification_version(self): # manually set a invalid specification version self.spec.specificationVersion = -1 model = MLModel(self.spec) assert model.get_spec().specificationVersion == 1 # manually set a high specification version self.spec.specificationVersion = 4 filename = tempfile.mktemp(suffix='.mlmodel') save_spec(self.spec, filename, auto_set_specification_version=True) model = MLModel(filename) assert model.get_spec().specificationVersion == 1 # simple neural network with only spec 1 layer input_features = [('data', datatypes.Array(3))] output_features = [('out', datatypes.Array(3))] builder = NeuralNetworkBuilder(input_features, output_features) builder.add_activation('relu', 'RELU', 'data', 'out') # set a high specification version builder.spec.specificationVersion = 3 model = MLModel(builder.spec) filename = tempfile.mktemp(suffix='.mlmodel') model.save(filename) # load the model back model = MLModel(filename) assert model.get_spec().specificationVersion == 1 # test save without automatic set specification version self.spec.specificationVersion = 3 filename = tempfile.mktemp(suffix='.mlmodel') save_spec(self.spec, filename, auto_set_specification_version=False) model = MLModel(filename) # the specification version should be original assert model.get_spec().specificationVersion == 3
def test_nn_set_training_input(self): builder = self.create_base_builder() builder.set_mean_squared_error_loss(name='mse', input='output', target='target') builder.set_adam_optimizer( AdamParams(lr=1e-2, batch=10, beta1=0.9, beta2=0.999, eps=1e-8)) builder.set_epochs(20, allowed_set=[10, 20, 30]) builder.set_training_input([('input', datatypes.Array(3)), ('target', 'Double')]) model_path = os.path.join(self.model_dir, 'updatable_creation.mlmodel') print(model_path) save_spec(builder.spec, model_path) mlmodel = MLModel(model_path) self.assertTrue(mlmodel is not None) spec = mlmodel.get_spec() self.assertEqual(spec.description.trainingInput[0].name, 'input') self.assertEqual( spec.description.trainingInput[0].type.WhichOneof('Type'), 'multiArrayType') self.assertEqual(spec.description.trainingInput[1].name, 'target') self.assertEqual( spec.description.trainingInput[1].type.WhichOneof('Type'), 'doubleType')
def test_nn_builder_with_training_features(self): input_features = [('input', datatypes.Array(3))] output_features = [('output', None)] training_features = [('input', datatypes.Array(3)), ('target', datatypes.Double)] builder = NeuralNetworkBuilder(input_features, output_features, disable_rank5_shape_mapping=True, training_features=training_features) W1 = _np.random.uniform(-0.5, 0.5, (3, 3)) W2 = _np.random.uniform(-0.5, 0.5, (3, 3)) builder.add_inner_product(name='ip1', W=W1, b=None, input_channels=3, output_channels=3, has_bias=False, input_name='input', output_name='hidden') builder.add_inner_product(name='ip2', W=W2, b=None, input_channels=3, output_channels=3, has_bias=False, input_name='hidden', output_name='output') builder.make_updatable(['ip1', 'ip2']) # or a dict for weightParams builder.set_mean_squared_error_loss(name='mse', input='output', target='target') builder.set_adam_optimizer( AdamParams(lr=1e-2, batch=10, beta1=0.9, beta2=0.999, eps=1e-8)) builder.set_epochs(20, allowed_set=[10, 20, 30]) builder.set_training_input([('input', datatypes.Array(3)), ('target', 'Double')]) model_path = os.path.join(self.model_dir, 'updatable_creation.mlmodel') print(model_path) save_spec(builder.spec, model_path) mlmodel = MLModel(model_path) self.assertTrue(mlmodel is not None) spec = mlmodel.get_spec() self.assertEqual(spec.description.trainingInput[0].name, 'input') self.assertEqual( spec.description.trainingInput[0].type.WhichOneof('Type'), 'multiArrayType') self.assertEqual(spec.description.trainingInput[1].name, 'target') self.assertEqual( spec.description.trainingInput[1].type.WhichOneof('Type'), 'doubleType')
def test_model_creation(self): model = MLModel(self.spec) self.assertIsNotNone(model) filename = tempfile.mktemp(suffix='.mlmodel') save_spec(self.spec, filename) model = MLModel(filename) self.assertIsNotNone(model)
def test_nn_partial_fp16_make_updatable_fail(self): nn_builder = self.create_base_builder() model_path = os.path.join(self.model_dir, "updatable_creation.mlmodel") print(model_path) save_spec(nn_builder.spec, model_path) mlmodel = MLModel(model_path) # fails since updatable models cannot get quantized to FP16 with self.assertRaises(Exception): quantization_utils.quantize_weights(mlmodel, 16, "linear")
def test_nn_builder_with_training_features(self): input_features = [("input", datatypes.Array(3))] output_features = [("output", datatypes.Array(3))] builder = NeuralNetworkBuilder(input_features, output_features) W1 = _np.random.uniform(-0.5, 0.5, (3, 3)) W2 = _np.random.uniform(-0.5, 0.5, (3, 3)) builder.add_inner_product( name="ip1", W=W1, b=None, input_channels=3, output_channels=3, has_bias=False, input_name="input", output_name="hidden", ) builder.add_inner_product( name="ip2", W=W2, b=None, input_channels=3, output_channels=3, has_bias=False, input_name="hidden", output_name="output", ) builder.make_updatable(["ip1", "ip2"]) # or a dict for weightParams builder.set_mean_squared_error_loss(name="mse", input_feature=("output", datatypes.Array(3))) builder.set_adam_optimizer( AdamParams(lr=1e-2, batch=10, beta1=0.9, beta2=0.999, eps=1e-8)) builder.set_epochs(20, allowed_set=[10, 20, 30]) model_path = os.path.join(self.model_dir, "updatable_creation.mlmodel") print(model_path) save_spec(builder.spec, model_path) mlmodel = MLModel(model_path) self.assertTrue(mlmodel is not None) spec = mlmodel.get_spec() self.assertEqual(spec.description.trainingInput[0].name, "input") self.assertEqual( spec.description.trainingInput[0].type.WhichOneof("Type"), "multiArrayType") self.assertEqual(spec.description.trainingInput[1].name, "output_true") self.assertEqual( spec.description.trainingInput[1].type.WhichOneof("Type"), "multiArrayType")
def test_model_creation(self): model = MLModel(self.spec) self.assertIsNotNone(model) package = tempfile.TemporaryDirectory(suffix=".mlpackage") package.cleanup() save_spec(self.spec, package.name) model = MLModel(package.name) self.assertIsNotNone(model) # cleanup MLModelTest._remove_path(package.name)
def test_model_save_no_extension(self): model = MLModel(self.spec) self.assertIsNotNone(model) filename = tempfile.mktemp(suffix="") save_spec(self.spec, filename) # appends .mlmodel extension when it is not provided self.assertFalse(os.path.exists(filename)) filename = filename + ".mlmodel" self.assertTrue(os.path.exists(filename)) model = MLModel(filename) self.assertIsNotNone(model) os.remove(filename)
def test_nn_fp16_make_updatable_fail(self): nn_builder = self.create_base_builder(is_updatable=False) model_path = os.path.join(self.model_dir, "updatable_creation.mlmodel") print(model_path) save_spec(nn_builder.spec, model_path) mlmodel = MLModel(model_path) quantized_model = quantization_utils.quantize_weights( mlmodel, 16, "linear") q_nn_builder = NeuralNetworkBuilder(spec=quantized_model._spec) # fails since an FP16 model cannot be marked updatable with self.assertRaises(ValueError): q_nn_builder.make_updatable(["ip1", "ip2"])
def test_future_version(self): self.spec.specificationVersion = 10000 filename = tempfile.mktemp(suffix='.mlmodel') save_spec(self.spec, filename, auto_set_specification_version=False) model = MLModel(filename) # this model should exist, but throw an exception when we try to use # predict because the engine doesn't support this model version self.assertIsNotNone(model) with self.assertRaises(Exception): try: model.predict({}) except Exception as e: assert 'Core ML model specification version' in str(e) raise self.spec.specificationVersion = 1
def test_nn_partial_fp16_make_updatable_quantized_layer_fail(self): nn_builder = self.create_base_builder(is_updatable=False) model_path = os.path.join(self.model_dir, "updatable_creation.mlmodel") print(model_path) save_spec(nn_builder.spec, model_path) mlmodel = MLModel(model_path) selector = LayerSelector(layer_name='ip2') quantized_model = quantization_utils.quantize_weights( mlmodel, 16, "linear", selector=selector) q_nn_builder = NeuralNetworkBuilder(spec=quantized_model._spec) # fails since model has a layer with FP16 bias with self.assertRaises(ValueError): q_nn_builder.make_updatable(["ip2"])
def onnx_to_coreml(onnx_filename, core_ml_filename): onnx_model = onnx.load(onnx_filename) coreml_model = convert(onnx_model, minimum_ios_deployment_target="13", image_input_names=['image'], preprocessing_args={ "image_scale": 1 / 255.0, "red_bias": 0, "green_bias": 0, "blue_bias": 0 }) builder = coremltools.models.neural_network.NeuralNetworkBuilder( spec=coreml_model.get_spec()) save_spec(builder.spec, core_ml_filename) coremltools.models.neural_network.printer.print_network_spec(builder.spec)
def test_downgrade_specification_version(self): # manually set a invalid specification version self.spec.specificationVersion = -1 model = MLModel(self.spec) if model.get_spec().specificationVersion != 1: raise AssertionError # manually set a high specification version self.spec.specificationVersion = 4 filename = tempfile.mktemp(suffix=".mlmodel") save_spec(self.spec, filename, auto_set_specification_version=True) model = MLModel(filename) if model.get_spec().specificationVersion != 1: raise AssertionError # simple neural network with only spec 1 layer input_features = [("data", datatypes.Array(3))] output_features = [("out", datatypes.Array(3))] builder = NeuralNetworkBuilder(input_features, output_features) builder.add_activation("relu", "RELU", "data", "out") # set a high specification version builder.spec.specificationVersion = 3 model = MLModel(builder.spec) filename = tempfile.mktemp(suffix=".mlmodel") model.save(filename) # load the model back model = MLModel(filename) if model.get_spec().specificationVersion != 1: raise AssertionError # test save without automatic set specification version self.spec.specificationVersion = 3 filename = tempfile.mktemp(suffix=".mlmodel") save_spec(self.spec, filename, auto_set_specification_version=False) model = MLModel(filename) # the specification version should be original if model.get_spec().specificationVersion != 3: raise AssertionError
def test_updatable_model_creation_ce_sgd(self): builder = self.create_base_builder() builder.add_softmax(name="softmax", input_name="output", output_name="softmax_output") builder.set_categorical_cross_entropy_loss(name="cross_entropy", input="softmax_output") builder.set_sgd_optimizer(SgdParams(lr=1e-2, batch=10, momentum=0.0)) builder.set_epochs(20, allowed_set=[10, 20, 30, 40]) model_path = os.path.join(self.model_dir, "updatable_creation.mlmodel") print(model_path) save_spec(builder.spec, model_path) mlmodel = MLModel(model_path) self.assertTrue(mlmodel is not None) spec = mlmodel.get_spec() self.assertTrue(spec.isUpdatable) self.assertTrue(spec.neuralNetwork.layers[0].isUpdatable) self.assertTrue( spec.neuralNetwork.layers[0].innerProduct.weights.isUpdatable) self.assertTrue(spec.neuralNetwork.layers[1].isUpdatable) self.assertTrue( spec.neuralNetwork.layers[1].innerProduct.weights.isUpdatable) self.assertTrue(spec.neuralNetwork.updateParams.lossLayers[0]. categoricalCrossEntropyLossLayer is not None) self.assertTrue( spec.neuralNetwork.updateParams.optimizer.sgdOptimizer is not None) self.assertTrue( _np.isclose( spec.neuralNetwork.updateParams.optimizer.sgdOptimizer. learningRate.defaultValue, 1e-2, atol=1e-4, )) self.assertTrue( _np.isclose( spec.neuralNetwork.updateParams.optimizer.sgdOptimizer. miniBatchSize.defaultValue, 10, atol=1e-4, )) self.assertTrue( _np.isclose( spec.neuralNetwork.updateParams.optimizer.sgdOptimizer. momentum.defaultValue, 0, atol=1e-8, )) self.assertTrue( _np.isclose(spec.neuralNetwork.updateParams.epochs.defaultValue, 20, atol=1e-4)) self.assertTrue(spec.neuralNetwork.updateParams.optimizer.sgdOptimizer. learningRate.range.minValue == 0) self.assertTrue(spec.neuralNetwork.updateParams.optimizer.sgdOptimizer. learningRate.range.maxValue == 1) self.assertTrue(spec.neuralNetwork.updateParams.optimizer.sgdOptimizer. miniBatchSize.set.values == [10]) self.assertTrue(spec.neuralNetwork.updateParams.optimizer.sgdOptimizer. momentum.range.minValue == 0) self.assertTrue(spec.neuralNetwork.updateParams.optimizer.sgdOptimizer. momentum.range.maxValue == 1)
output_name='position_ids_expanded_to_rank5', axes=(1, 2, 3, 4)) builder.add_embedding( name='token_embeddings', input_name='input_ids_expanded_to_rank5', output_name='token_embeddings', W=wte, b=None, input_dim=50257, output_channels=768, has_bias=False, ) builder.add_embedding( name='positional_embeddings', input_name='position_ids_expanded_to_rank5', output_name='positional_embeddings', W=wpe, b=None, input_dim=1024, output_channels=768, has_bias=False, ) builder.add_add_broadcastable( name='embeddings_addition', input_names=['token_embeddings', 'positional_embeddings'], output_name='output_logits') # compile spec to model ## model = coremltools.models.MLModel(builder.spec) save_spec(builder.spec, 'gpt2.mlmodel')
def export_models(config, mask_rcnn_model, classifier_model, mask_model, export_main_path, export_mask_path, export_anchors_path): license = "MIT" author = "Édouard Lavery-Plante" def convert_proposal(layer): params = NeuralNetwork_pb2.CustomLayerParams() params.className = "ProposalLayer" params.description = "Proposes regions of interests and performs NMS." params.parameters["bboxStdDev_count"].intValue = len( layer.bounding_box_std_dev) for idx, value in enumerate(layer.bounding_box_std_dev): params.parameters["bboxStdDev_" + str(idx)].doubleValue = value params.parameters[ "preNMSMaxProposals"].intValue = layer.pre_nms_max_proposals params.parameters["maxProposals"].intValue = layer.max_proposals params.parameters["nmsIOUThreshold"].doubleValue = layer.nms_threshold return params def convert_pyramid(layer): params = NeuralNetwork_pb2.CustomLayerParams() params.className = "PyramidROIAlignLayer" params.parameters["poolSize"].intValue = layer.pool_shape[0] params.parameters["imageWidth"].intValue = layer.image_shape[0] params.parameters["imageHeight"].intValue = layer.image_shape[1] params.description = "Extracts feature maps based on the regions of interest." return params def convert_time_distributed_classifier(layer): params = NeuralNetwork_pb2.CustomLayerParams() params.className = "TimeDistributedClassifierLayer" return params def convert_time_distributed(layer): params = NeuralNetwork_pb2.CustomLayerParams() params.className = "TimeDistributedMaskLayer" params.description = "Applies the Mask graph to each detections along the time dimension." return params def convert_detection(layer): params = NeuralNetwork_pb2.CustomLayerParams() params.className = "DetectionLayer" params.parameters["bboxStdDev_count"].intValue = len( layer.bounding_box_std_dev) for idx, value in enumerate(layer.bounding_box_std_dev): params.parameters["bboxStdDev_" + str(idx)].doubleValue = value params.parameters["maxDetections"].intValue = layer.max_detections params.parameters[ "scoreThreshold"].doubleValue = layer.detection_min_confidence params.parameters[ "nmsIOUThreshold"].doubleValue = layer.detection_nms_threshold params.description = "Outputs detections based on confidence and performs NMS." return params mask_rcnn_model = convert_keras_to_coreml( mask_rcnn_model, input_names=["image"], image_input_names=['image'], output_names=["detections", "mask"], red_bias=-123.7, green_bias=-116.8, blue_bias=-103.9, add_custom_layers=True, custom_conversion_functions={ "ProposalLayer": convert_proposal, "PyramidROIAlign": convert_pyramid, "TimeDistributedClassifier": convert_time_distributed_classifier, "TimeDistributedMask": convert_time_distributed, "DetectionLayer": convert_detection }) mask_rcnn_model.author = author mask_rcnn_model.license = license mask_rcnn_model.short_description = "Mask-RCNN" mask_rcnn_model.input_description["image"] = "Input image" mask_rcnn_model.output_description[ "detections"] = "Detections (y1,x1,y2,x2,classId,score)" mask_rcnn_model.output_description["mask"] = "Masks for the detections" half_model = convert_neural_network_weights_to_fp16(mask_rcnn_model) half_spec = half_model.get_spec() save_spec(half_spec, export_main_path) mask_model_coreml = convert_keras_to_coreml(mask_model, input_names=["feature_map"], output_names=["masks"]) mask_model_coreml.author = author mask_model_coreml.license = license mask_model_coreml.short_description = "Generates a mask for each class for a given feature map" mask_model_coreml.input_description[ "feature_map"] = "Fully processed feature map, ready for mask generation." mask_model_coreml.output_description[ "masks"] = "Masks corresponding to each class" half_mask_model = convert_neural_network_weights_to_fp16(mask_model_coreml) half_mask_spec = half_mask_model.get_spec() save_spec(half_mask_spec, export_mask_path) classifier_model_coreml = convert_keras_to_coreml( classifier_model, input_names=["feature_map"], output_names=["probabilities", "bounding_boxes"]) classifier_model_coreml.author = author classifier_model_coreml.license = license classifier_model_coreml.short_description = "" classifier_model_coreml.input_description[ "feature_map"] = "Fully processed feature map, ready for classification." half_classifier_model = convert_neural_network_weights_to_fp16( classifier_model_coreml) half_classifier_spec = half_classifier_model.get_spec() save_spec(half_classifier_spec, "products/Classifier.mlmodel")
def test_updatable_model_creation_mse_adam(self): builder = self.create_base_builder() builder.set_mean_squared_error_loss(name="mse", input_feature=("output", datatypes.Array(3))) builder.set_adam_optimizer( AdamParams(lr=1e-2, batch=10, beta1=0.9, beta2=0.999, eps=1e-8)) builder.set_epochs(20, allowed_set=[10, 20, 30]) model_path = os.path.join(self.model_dir, "updatable_creation.mlmodel") print(model_path) save_spec(builder.spec, model_path) mlmodel = MLModel(model_path) self.assertTrue(mlmodel is not None) spec = mlmodel.get_spec() self.assertTrue(spec.isUpdatable) self.assertTrue(spec.neuralNetwork.layers[0].isUpdatable) self.assertTrue( spec.neuralNetwork.layers[0].innerProduct.weights.isUpdatable) self.assertTrue(spec.neuralNetwork.layers[1].isUpdatable) self.assertTrue( spec.neuralNetwork.layers[1].innerProduct.weights.isUpdatable) self.assertTrue(spec.neuralNetwork.updateParams.lossLayers[0]. categoricalCrossEntropyLossLayer is not None) self.assertTrue(spec.neuralNetwork.updateParams.optimizer.adamOptimizer is not None) self.assertTrue( _np.isclose( spec.neuralNetwork.updateParams.optimizer.adamOptimizer. learningRate.defaultValue, 1e-2, atol=1e-4, )) self.assertTrue( _np.isclose( spec.neuralNetwork.updateParams.optimizer.adamOptimizer. miniBatchSize.defaultValue, 10, atol=1e-4, )) self.assertTrue( _np.isclose( spec.neuralNetwork.updateParams.optimizer.adamOptimizer.beta1. defaultValue, 0.9, atol=1e-4, )) self.assertTrue( _np.isclose( spec.neuralNetwork.updateParams.optimizer.adamOptimizer.beta2. defaultValue, 0.999, atol=1e-4, )) self.assertTrue( _np.isclose( spec.neuralNetwork.updateParams.optimizer.adamOptimizer.eps. defaultValue, 1e-8, atol=1e-8, )) self.assertTrue( _np.isclose(spec.neuralNetwork.updateParams.epochs.defaultValue, 20, atol=1e-4)) self.assertTrue(spec.neuralNetwork.updateParams.optimizer. adamOptimizer.learningRate.range.minValue == 0) self.assertTrue(spec.neuralNetwork.updateParams.optimizer. adamOptimizer.learningRate.range.maxValue == 1) self.assertTrue(spec.neuralNetwork.updateParams.optimizer. adamOptimizer.miniBatchSize.set.values == [10]) self.assertTrue(spec.neuralNetwork.updateParams.optimizer. adamOptimizer.beta1.range.minValue == 0) self.assertTrue(spec.neuralNetwork.updateParams.optimizer. adamOptimizer.beta1.range.maxValue == 1) self.assertTrue(spec.neuralNetwork.updateParams.optimizer. adamOptimizer.beta2.range.minValue == 0) self.assertTrue(spec.neuralNetwork.updateParams.optimizer. adamOptimizer.beta2.range.maxValue == 1) self.assertTrue(spec.neuralNetwork.updateParams.optimizer. adamOptimizer.eps.range.minValue == 0) self.assertTrue(spec.neuralNetwork.updateParams.optimizer. adamOptimizer.eps.range.maxValue == 1) self.assertTrue( spec.neuralNetwork.updateParams.epochs.set.values == [10, 20, 30])
def test_updatable_model_creation_mse_sgd(self): builder = self.create_base_builder() builder.set_mean_squared_error_loss(name='mse', input='output', target='target') builder.set_sgd_optimizer(SgdParams(lr=1e-2, batch=10, momentum=0.0)) builder.set_epochs(20) model_path = os.path.join(self.model_dir, 'updatable_creation.mlmodel') print(model_path) save_spec(builder.spec, model_path) mlmodel = MLModel(model_path) self.assertTrue(mlmodel is not None) spec = mlmodel.get_spec() self.assertTrue(spec.isUpdatable) self.assertTrue(spec.neuralNetwork.layers[0].isUpdatable) self.assertTrue( spec.neuralNetwork.layers[0].innerProduct.weights.isUpdatable) self.assertTrue(spec.neuralNetwork.layers[1].isUpdatable) self.assertTrue( spec.neuralNetwork.layers[1].innerProduct.weights.isUpdatable) self.assertTrue(spec.neuralNetwork.updateParams.lossLayers[0]. categoricalCrossEntropyLossLayer is not None) self.assertTrue( spec.neuralNetwork.updateParams.optimizer.sgdOptimizer is not None) self.assertTrue( _np.isclose(spec.neuralNetwork.updateParams.optimizer.sgdOptimizer. learningRate.defaultValue, 1e-2, atol=1e-4)) self.assertTrue( _np.isclose(spec.neuralNetwork.updateParams.optimizer.sgdOptimizer. miniBatchSize.defaultValue, 10, atol=1e-4)) self.assertTrue( _np.isclose(spec.neuralNetwork.updateParams.optimizer.sgdOptimizer. momentum.defaultValue, 0, atol=1e-8)) self.assertTrue( _np.isclose(spec.neuralNetwork.updateParams.epochs.defaultValue, 20, atol=1e-4)) self.assertTrue(spec.neuralNetwork.updateParams.optimizer.sgdOptimizer. learningRate.range.minValue == 0) self.assertTrue(spec.neuralNetwork.updateParams.optimizer.sgdOptimizer. learningRate.range.maxValue == 1) self.assertTrue(spec.neuralNetwork.updateParams.optimizer.sgdOptimizer. miniBatchSize.set.values == [10]) self.assertTrue(spec.neuralNetwork.updateParams.optimizer.sgdOptimizer. momentum.range.minValue == 0) self.assertTrue(spec.neuralNetwork.updateParams.optimizer.sgdOptimizer. momentum.range.maxValue == 1)
input_features = [('data', datatypes.Array(*input_dim))] output_features = [('result', datatypes.Array(*output_dim))] weights = np.random.rand(1, input_max_size) bias = np.random.rand(1) builder = NeuralNetworkBuilder(input_features, output_features) builder.add_inner_product(name='ip_layer', W=weights, b=bias, input_channels=input_max_size, output_channels=1, has_bias=True, input_name='data', output_name='result') builder.make_updatable(['ip_layer']) builder.set_mean_squared_error_loss(name='lossLayer', input_feature=output_features[0]) optimizerParams = SgdParams(lr=0.01, batch=1) optimizerParams.set_batch(1, allowed_set=[1, 2, 4, 8, 16, 32]) builder.set_sgd_optimizer(optimizerParams) builder.set_epochs(16, allowed_set=[2, 4, 8, 16, 32, 64, 128, 256]) #builder.spec = convert_neural_network_spec_weights_to_fp16(builder.spec) save_spec(builder.spec, '../core/LinearRegressionModel.mlmodel')
lm_head_weights = lm_head_model.lm_head.weight.data.numpy().reshape( (1, 50257, 768, 1, 1)) builder.add_inner_product(name="lm_head", input_name="ln_f_scaled", output_name="output_logits", input_channels=768, output_channels=50257, W=lm_head_weights, b=None, has_bias=False) # compile spec to model mlmodel = coremltools.models.MLModel(builder.spec) save_spec(builder.spec, f'../Resources/{model_name}-{sequence_length}.mlmodel') # model = coremltools.models.MLModel('gpt2.mlmodel') input_ids = np.zeros(sequence_length) position_ids = np.arange(sequence_length).astype(np.float) input_data = { 'input_ids': input_ids, 'position_ids': position_ids, } # predictions = mlmodel.predict(input_data)["output_logits"] # equal = np.amax(predictions - mlp_conv_proj.detach().numpy()) print(predictions)
def gen_mlmodel2(self, filepattern, out_file): reader = tf.train.NewCheckpointReader(filepattern) img_shape = self._img_ph.shape.as_list() # b, h, w, c input = [ ("img", datatypes.Array(img_shape[3], img_shape[1], img_shape[2])), ("len_pixel", datatypes.Array(1)), ("len_cm", datatypes.Array(1)), ] output = [ ("label", datatypes.Array(self._num_classes)), ] builder = neural_network.NeuralNetworkBuilder(input, output) # CoreML has a bug: # https://github.com/apple/coremltools/pull/45 #builder.add_elementwise(name="div_255", input_names=["img"], output_name="div_255", mode="MULTIPLY", alpha=1.0 / 255) spec_layer = builder.nn_spec.layers.add() spec_layer.name = "div_255" spec_layer.input.append("img") spec_layer.output.append("div_255") spec_layer.multiply.MergeFromString("") spec_layer.multiply.alpha = 1.0 / 255 output_channels = (16, 32, 64, 32) kernel_shape = (3, 3, 3, 3) rate = (1, 2, 4, 8) hidden = {"name": "div_255", "channels": img_shape[3]} for i in range(len(output_channels)): conv_name = "agent/process_img/conv_2d_{}".format(i) if i == 0: conv_name = "agent/process_img/conv_2d" builder.add_convolution(name=conv_name, input_name=hidden["name"], output_name=conv_name, is_deconv=False, kernel_channels=hidden["channels"], output_channels=output_channels[i], height=kernel_shape[i], width=kernel_shape[i], dilation_factors=(rate[i], rate[i]), has_bias=True, W=reader.get_tensor(conv_name + "/w"), b=reader.get_tensor(conv_name + "/b"), groups=1, border_mode="same", stride_height=1, stride_width=1) hidden["name"] = conv_name hidden["channels"] = output_channels[i] tanh_name = "agent/process_img/tanh_{}".format(i) builder.add_activation(name=tanh_name, non_linearity="TANH", input_name=hidden["name"], output_name=tanh_name) hidden["name"] = tanh_name reduce_name = "reduce_wh" builder.add_reduce(name=reduce_name, input_name=hidden["name"], output_name=reduce_name, axis="HW", mode="max") hidden["name"] = reduce_name embedding_name = "embedding" builder.add_elementwise( name=embedding_name, input_names=[hidden["name"], "len_pixel", "len_cm"], output_name=embedding_name, mode="CONCAT") hidden["name"] = embedding_name hidden["channels"] += 2 output_size = (32, ) linear_idx = -1 for opsz in output_size: linear_idx += 1 linear_name = "agent/linear_{}".format(linear_idx) if linear_idx == 0: linear_name = "agent/linear" # CoreML's linear product expects the weights to be of shape # (output_size, input_size), but Tensorflow gives (input_size, output_size) builder.add_inner_product( name=linear_name, has_bias=True, input_name=hidden["name"], input_channels=hidden["channels"], output_name=linear_name, output_channels=opsz, W=np.swapaxes(reader.get_tensor(linear_name + "/w"), 0, 1), b=reader.get_tensor(linear_name + "/b")) hidden["name"] = linear_name hidden["channels"] = opsz tanh_name = "agent/tanh_{}".format(i) builder.add_activation(name=tanh_name, non_linearity="TANH", input_name=hidden["name"], output_name=tanh_name) hidden["name"] = tanh_name linear_idx += 1 linear_name = "agent/linear_{}".format(linear_idx) if linear_idx == 0: linear_name = "agent/linear" builder.add_inner_product(name=linear_name, has_bias=True, input_name=hidden["name"], input_channels=hidden["channels"], output_name=linear_name, output_channels=self._num_classes, W=np.swapaxes( reader.get_tensor(linear_name + "/w"), 0, 1), b=reader.get_tensor(linear_name + "/b")) hidden["name"] = linear_name hidden["channels"] = opsz builder.add_softmax(name="softmax", input_name=hidden["name"], output_name="label") utils.save_spec(builder.spec, out_file)
from coremltools.models.neural_network.flexible_shape_utils import * from coremltools.models.utils import load_spec, save_spec base_path = "../DistractedDriverCreateML/DistractedDriverCreateML/Models/" spec = load_spec(base_path + "DistractedDriverClassifier_1000_it.mlmodel") print("Description before adding new sizes") print(spec.description) image_sizes = [NeuralNetworkImageSize(480, 640)] add_enumerated_image_sizes(spec, feature_name='image', sizes=image_sizes) # img_size_ranges = NeuralNetworkImageSizeRange() # img_size_ranges.add_height_range((299,480)) # img_size_ranges.add_width_range((299,640)) #update_image_size_range(spec, feature_name='image', size_range=img_size_ranges) print("Description after adding new sizes") print(spec.description) save_spec(spec, base_path + "DistractedDriverClassifier_1000_it_spec.mlmodel") # Does not work properly with Create ML model with 299... x 299... flexibility
def _convert_pb_to_mlmodel( tf_model_path, mlmodel_path, output_feature_names, input_name_shape_dict={}, image_input_names=None, is_bgr=False, red_bias=0.0, green_bias=0.0, blue_bias=0.0, gray_bias=0.0, image_scale=1.0, class_labels=None, predicted_feature_name=None, predicted_probabilities_output='', add_custom_layers=False, # type: bool custom_conversion_functions={}, # type: Dict[Text, Any] ): # Load the TF graph with open(tf_model_path, 'rb') as f: serialized = f.read() tf.reset_default_graph() gdef = tf.GraphDef() gdef.ParseFromString(serialized) with tf.Graph().as_default() as g: tf.import_graph_def(gdef, name='') sess = tf.Session(graph=g) OPS = g.get_operations() if 'DecodeJpeg' in [op.type for op in OPS]: raise NotImplementedError( "Unsupported Op of type: DecodeJpeg. " "Kindly refer to the \"examples/inception_v3.ipynb\" notebook, " "on the tfcoreml github page, to see how to strip input " "pre-processing from the TF graph before conversion to CoreML.") # Sort the ops in topological order and check whether the graph has cycles, if yes, error out OPS = _topological_sort_ops(OPS) SHAPE_DICT = {} #Tensor name --> shape ({str: list}) CONSTS = {} #Const Tensor name --> value BLOB_GRAPH = {} #Blob name to list of ops it feeds into # Make Dictionary of Input blob to the list of ops it feeds into for op in OPS: for inp in op.inputs: if inp.name in BLOB_GRAPH: BLOB_GRAPH[inp.name].append(op) for out in op.outputs: if out.name not in BLOB_GRAPH: BLOB_GRAPH[out.name] = [] # Fill in input information input_features = [] output_features = [] input_feed_dict = dict() #Input tensors' values input_feed_dict2 = dict() # used later to find skippable ops # run through all placeholders for op in OPS: output_names = set([compat.as_str_any(x.name) for x in op.outputs]) if op.type == 'Placeholder': # Handle placeholders -- all placeholders are inputs assert not any(filter(output_names.__contains__, output_feature_names)), \ ('Output feature cannot be a placeholder') input_name = compat.as_str_any(op.outputs[0].name) shape = op.outputs[0].get_shape() if not (shape.is_fully_defined() or input_name in input_name_shape_dict): assert False, ("%s is a placeholder with incomplete shape %s" % (input_name, str(shape))) if shape.is_fully_defined(): shape = shape.as_list() else: shape = input_name_shape_dict[input_name] if len(shape) == 0: # scalar - use a 1 input_feed_dict[op.outputs[0]] = 1 input_feed_dict2[op.outputs[0]] = 1 else: input_feed_dict[op.outputs[0]] = np.random.rand(*shape) input_feed_dict2[op.outputs[0]] = 255 * np.random.rand(*shape) SHAPE_DICT[input_name] = shape # Populate SHAPE_DICT: Dictionary for all tensor blobs in the graph and their shapes shapes_wanted = [] # list of output names for op in OPS: for out in op.outputs: shape = out.get_shape() if not shape.is_fully_defined(): shapes_wanted.append((compat.as_str_any(out.name), out)) else: SHAPE_DICT[compat.as_str_any(out.name)] = shape.as_list() if len(shapes_wanted) > 0: print("Shapes not found for %d tensors. " "Executing graph to determine shapes. " % (len(shapes_wanted))) tensor_names, tensors = zip(*shapes_wanted) tensors_evaluated = sess.run(tensors, feed_dict=input_feed_dict) for i in range(len(tensor_names)): SHAPE_DICT[tensor_names[i]] = list(tensors_evaluated[i].shape) # Fill in output information and CONSTS dictionary for op in OPS: output_names = set([compat.as_str_any(x.name) for x in op.outputs]) if any(filter(output_names.__contains__, output_feature_names)): # retrieve model outputs for output in [ x for x in op.outputs if x.name in output_feature_names ]: #infer shape for Core ML tf_shape = SHAPE_DICT[compat.as_str_any(output.name)] shape = _infer_coreml_output_shape(tf_shape) out_name = output.name if shape is None: output_features.append((compat.as_str_any(out_name), None)) else: output_features.append( (compat.as_str_any(out_name), datatypes.Array(*shape))) elif op.type == 'Const': # retrieve all consts and store them in dictionary const = op.outputs[0] CONSTS[compat.as_str_any(const.name)] = sess.run( const, feed_dict=input_feed_dict) if len(output_features) != len(output_feature_names): all_out_names_in_graph = [out_[0] for out_ in output_features] for given_out_name in output_feature_names: if given_out_name not in all_out_names_in_graph: raise ValueError( "output name: {}, was provided, but the Tensorflow graph does not contain a tensor with this name." .format(given_out_name)) # Find "effectively_constant_ops": ops whose output(s) do not change with different valued Graph level inputs # Find "unused_ops" : ops that are not connected to the output(s) unused_ops, effectively_constant_ops = _find_unused_ops( OPS, sess, output_feature_names, input_feed_dict, input_feed_dict2) # return type: List[str], List[str] if not add_custom_layers: _check_unsupported_ops(OPS, output_feature_names, effectively_constant_ops + unused_ops) # Load all the dictionaries in the object of the class "context" context = Context(CONSTS, SHAPE_DICT, OPS, BLOB_GRAPH, output_features) # Interpret Input shapes and fill in input information for Core ML # (now that SHAPE_DICT and CONSTS are complete) sequence_inputs = dict() for input_tensor in input_feed_dict: input_name = compat.as_str_any(input_tensor.name) shape = SHAPE_DICT[input_name] if context.use_dfs_shape_infer: status = interpret_shape(input_name, context) else: status = False if status: print('Automatic shape interpretation succeeded for input blob %s' \ %(input_name)) shape = context.shape_dict_rank_4[input_name] if len(shape) == 4 and shape[0] != 1: sequence_inputs[input_name] = shape[0] # if the consumer of input_tensor is an one-hot encoding op, # treat it as a sequence. consumer_op = input_tensor.consumers()[0] if consumer_op.type == 'OneHot': shape = [ 1, ] sequence_inputs[input_name] = -1 else: shape = _infer_coreml_input_shape(shape) input_features.append( (compat.as_str_any(input_name), datatypes.Array(*shape))) # Set classifier flag is_classifier = class_labels is not None mode = 'classifier' if is_classifier else None # Convert the TF graph with builder input_features = list(input_features) output_features = list(output_features) builder = NeuralNetworkBuilder(input_features, output_features, mode=mode) context.builder = builder context.session = sess context.input_feed_dict = input_feed_dict context.unused_ops = unused_ops context.effectively_constant_ops = effectively_constant_ops context.add_custom_layers = add_custom_layers context.custom_conversion_functions = custom_conversion_functions convert_ops_to_layers(context) sess.close() #optimizations on the nn spec optimize_nn_spec(spec=builder.spec) #Add a description for inputs that are sequences for i, inputs in enumerate(builder.spec.description.input): if inputs.name in sequence_inputs: seq_length = sequence_inputs[inputs.name] if seq_length == -1: builder.spec.description.input[i].shortDescription = \ 'This input is a sequence' else: builder.spec.description.input[i].shortDescription = \ 'This input is a sequence of length ' + str(seq_length) # Add image input identifier if image_input_names is not None and isinstance(image_input_names, _string_types): image_input_names = [image_input_names] # Replace all input/output blob names with ":" to "__" for compatible # auto-generated Objective C / Swift code interface_blob_names = [] for idx, in_blob in enumerate(builder.spec.description.input): interface_blob_names.append(in_blob.name) builder.spec.description.input[idx].name = in_blob.name.replace( ':', '__').replace('/', '__') for idx, out_blob in enumerate(builder.spec.description.output): interface_blob_names.append(out_blob.name) builder.spec.description.output[idx].name = out_blob.name.replace( ':', '__').replace('/', '__') nn_spec = builder.nn_spec for i, spec_layer in enumerate(nn_spec.layers): for j, blob in enumerate(spec_layer.input): name = spec_layer.input[j] if name in interface_blob_names: spec_layer.input[j] = name.replace(':', '__').replace('/', '__') for j, blob in enumerate(spec_layer.output): name = spec_layer.output[j] if name in interface_blob_names: spec_layer.output[j] = name.replace(':', '__').replace('/', '__') if image_input_names is not None: for i, img in enumerate(image_input_names): image_input_names[i] = img.replace(':', '__').replace('/', '__') # Add classifier classes (if applicable) if is_classifier: classes_in = class_labels if isinstance(classes_in, _string_types): import os if not os.path.isfile(classes_in): raise ValueError("Path to class labels (%s) does not exist." % \ classes_in) with open(classes_in, 'r') as f: classes = f.read() classes = classes.splitlines() elif type(classes_in) is list: # list[int or str] classes = classes_in else: raise ValueError('Class labels must be a list of integers / strings,'\ ' or a file path') if predicted_feature_name is not None: builder.set_class_labels( classes, predicted_feature_name=predicted_feature_name, prediction_blob=predicted_probabilities_output) else: builder.set_class_labels(classes) # Set pre-processing parameters builder.set_pre_processing_parameters(image_input_names=image_input_names, is_bgr=is_bgr, red_bias=red_bias, green_bias=green_bias, blue_bias=blue_bias, gray_bias=gray_bias, image_scale=image_scale) utils.save_spec(builder.spec, mlmodel_path) print("\n Core ML model generated. Saved at location: %s \n" % (mlmodel_path)) print('Core ML input(s): \n', builder.spec.description.input) print('Core ML output(s): \n', builder.spec.description.output) # print information about all ops for which custom layers have been added if len(context.ops_converted_to_custom_layers) > 0: print('\n') print("Custom layers have been added to the CoreML model " "corresponding to the following ops in the TF graph: ") for i, op in enumerate(context.ops_converted_to_custom_layers): input_info = [] for input_ in op.inputs: input_info.append( (str(input_.name), context.shape_dict.get(input_.name, str("Shape not available")))) output_info = [] for output_ in op.outputs: output_info.append( (str(output_.name), context.shape_dict.get(output_.name, str("Shape not available")))) print( "{}/{}: op type: {}, op input names and shapes: {}, op output names and shapes: {}" .format(i + 1, len(context.ops_converted_to_custom_layers), op.type, str(input_info), str(output_info))) # Return the protobuf spec spec = builder.spec return MLModel(spec)
name=f"{i}_output_ln", input_name=f"{i}_block_mlp_conv_proj", output_name=f"{i}_output_ln", across_channels=True, normalize_variance=True, epsilon=layer.output_layer_norm.eps ) builder.add_scale( name=f"{i}_output_ln_scaled", input_name=f"{i}_output_ln", output_name=f"{i}_output_ln_scaled", W=layer.output_layer_norm.weight.data.numpy().reshape((1, 1, 768, 1, 1)), b=layer.output_layer_norm.bias.data.numpy().reshape((1, 1, 768, 1, 1)), has_bias=True, shape_scale=[768], shape_bias=[768] ) # compile spec to model # mlmodel = coremltools.models.MLModel(builder.spec) # input_data = { # 'input_ids': np.array([ 7592, 1010, 2026, 3899, 2003, 10140 ]) # } # predictions = mlmodel.predict(input_data)["output_logits"] # print(predictions) save_spec(builder.spec, f'../Resources/distilbert-{sequence_length}-{steps}.mlmodel')
builder.add_inner_product( name="lm_head", input_name="ln_f_scaled", output_name="output_logits", input_channels=768, output_channels=num_tokens, W=lm_head_weights, b=None, has_bias=False, ) # compile spec to model mlmodel = coremltools.models.MLModel(builder.spec) # save_spec(builder.spec, f'../Resources/{model_name}-{sequence_length}-{steps}-2.mlmodel') save_spec(builder.spec, args.output) # model = coremltools.models.MLModel('gpt2.mlmodel') # input_ids = np.zeros(sequence_length) # position_ids = np.arange(sequence_length).astype(np.float) # input_data = { # 'input_ids': input_ids, # 'position_ids': position_ids, # } # predictions = mlmodel.predict(input_data)["output_logits"] # equal = np.amax(predictions - mlp_conv_proj.detach().numpy()) # print(predictions)
def _convert_pb_to_mlmodel(tf_model_path, mlmodel_path, output_feature_names, input_name_shape_dict=None, image_input_names=None, is_bgr=False, red_bias=0.0, green_bias=0.0, blue_bias=0.0, gray_bias=0.0, image_scale=1.0, class_labels=None, predicted_feature_name=None, predicted_probabilities_output=''): if input_name_shape_dict is None: input_name_shape_dict = {} # Load the TF graph with open(tf_model_path, 'rb') as f: serialized = f.read() tf.reset_default_graph() gdef = tf.GraphDef() gdef.ParseFromString(serialized) with tf.Graph().as_default() as g: tf.import_graph_def(gdef, name='') sess = tf.Session(graph=g) OPS = g.get_operations() OPS = _topological_sort_ops(OPS) _check_unsupported_ops(OPS, output_feature_names) SHAPE_DICT = {} #Tensor name --> shape ({str: list}) CONSTS = {} #Const Tensor name --> value BLOB_GRAPH = {} #Blob name to list of ops it feeds into # Make Dictionary of Input blob to the list of ops it feeds into for op in OPS: for inp in op.inputs: if inp.name in BLOB_GRAPH: BLOB_GRAPH[inp.name].append(op) for out in op.outputs: if out.name not in BLOB_GRAPH: BLOB_GRAPH[out.name] = [] # Fill in input information input_features = [] output_features = [] input_feed_dict = dict() #Input tensors' values # run through all placeholders for op in OPS: output_names = set([compat.as_bytes(x.name) for x in op.outputs]) if op.type == 'Placeholder': # Handle placeholders -- all placeholders are inputs assert not filter(output_names.__contains__, output_feature_names), \ ('Output feature cannot be a placeholder') input_name = compat.as_bytes(op.outputs[0].name) shape = op.outputs[0].get_shape() if not (shape.is_fully_defined() or input_name in input_name_shape_dict): assert False, ("%s is a placehoder with incomplete shape %s" % (input_name, str(shape))) if shape.is_fully_defined(): shape = shape.as_list() else: shape = input_name_shape_dict[input_name] if len(shape) == 0: # scalar - use a 1 input_feed_dict[op.outputs[0]] = 1 else: input_feed_dict[op.outputs[0]] = np.random.rand(*shape) SHAPE_DICT[input_name] = shape # Populate SHAPE_DICT: # Dictionary for all tensor blobs in the graph and their shapes shapes_wanted = [] for op in OPS: for out in op.outputs: shape = out.get_shape() if not shape.is_fully_defined(): shapes_wanted.append((compat.as_bytes(out.name), out)) else: SHAPE_DICT[compat.as_bytes(out.name)] = shape.as_list() if len(shapes_wanted) > 0: print("Shapes not found for %d tensors. " "Executing graph to determine shapes. " % (len(shapes_wanted))) tensor_names, tensors = zip(*shapes_wanted) tensors_evaluated = sess.run(tensors, feed_dict=input_feed_dict) for i in range(len(tensor_names)): SHAPE_DICT[tensor_names[i]] = list(tensors_evaluated[i].shape) # Fill in output information and CONSTS dictionary for op in OPS: output_names = set([compat.as_bytes(x.name) for x in op.outputs]) if filter(output_names.__contains__, output_feature_names): # retrieve model outputs for output in [ x for x in op.outputs if x.name in output_feature_names ]: #infer shape for Core ML tf_shape = SHAPE_DICT[compat.as_bytes(output.name)] shape = _infer_coreml_output_shape(tf_shape) out_name = output.name if shape is None: output_features.append((compat.as_bytes(out_name), None)) else: output_features.append( (compat.as_bytes(out_name), datatypes.Array(*shape))) elif op.type == 'Const': # retrieve all consts and store them in dictionary const = op.outputs[0] CONSTS[compat.as_bytes(const.name)] = sess.run( const, feed_dict=input_feed_dict) assert len(output_features) == len(output_feature_names), ( 'Tensorflow Graph does not contain all the provided Output name(s)') # Load all the dictionaries in the object of class context context = Context(CONSTS, SHAPE_DICT, OPS, BLOB_GRAPH, output_features) # Interpret Input shapes and fill in input information for Core ML # (now that SHAPE_DICT and CONSTS are complete) sequence_inputs = dict() for input_tensor in input_feed_dict: input_name = compat.as_bytes(input_tensor.name) shape = SHAPE_DICT[input_name] if context.use_dfs_shape_infer: status = interpret_shape(input_name, context) else: status = False if status: print('Automatic shape interpretation succeeded for input blob %s' \ %(input_name)) shape = context.shape_dict_rank_4[input_name] if len(shape) == 4 and shape[0] != 1: sequence_inputs[input_name] = shape[0] # if the consumer of input_tensor is an one-hot encoding op, # treat it as a sequence. consumer_op = input_tensor.consumers()[0] if consumer_op.type == 'OneHot': shape = [ 1, ] sequence_inputs[input_name] = -1 else: shape = _infer_coreml_input_shape(shape) input_features.append( (compat.as_bytes(input_name), datatypes.Array(*shape))) # Set classifier flag is_classifier = class_labels is not None mode = 'classifier' if is_classifier else None # Convert the TF graph with builder input_features = list(input_features) output_features = list(output_features) builder = NeuralNetworkBuilder(input_features, output_features, mode=mode) context.builder = builder context.session = sess context.input_feed_dict = input_feed_dict convert_ops_to_layers(context) sess.close() #optimizations on the nn spec optimize_nn_spec(builder=builder) #Add a description for inputs that are sequences for i, inputs in enumerate(builder.spec.description.input): if inputs.name in sequence_inputs: seq_length = sequence_inputs[inputs.name] if seq_length == -1: builder.spec.description.input[i].shortDescription = \ 'This input is a sequence' else: builder.spec.description.input[i].shortDescription = \ 'This input is a sequence of length ' + str(seq_length) # Add image input identifier if image_input_names is not None and isinstance(image_input_names, _string_types): image_input_names = [image_input_names] # Replace all input/output blob names with ":" to "__" for compatible # auto-generated Objective C / Swift code interface_blob_names = [] for idx, in_blob in enumerate(builder.spec.description.input): interface_blob_names.append(in_blob.name) builder.spec.description.input[idx].name = in_blob.name.replace( ':', '__').replace('/', '__') for idx, out_blob in enumerate(builder.spec.description.output): interface_blob_names.append(out_blob.name) builder.spec.description.output[idx].name = out_blob.name.replace( ':', '__').replace('/', '__') nn_spec = builder.nn_spec for i, spec_layer in enumerate(nn_spec.layers): for j, blob in enumerate(spec_layer.input): name = spec_layer.input[j] if name in interface_blob_names: spec_layer.input[j] = name.replace(':', '__').replace('/', '__') for j, blob in enumerate(spec_layer.output): name = spec_layer.output[j] if name in interface_blob_names: spec_layer.output[j] = name.replace(':', '__').replace('/', '__') if image_input_names is not None: for i, img in enumerate(image_input_names): image_input_names[i] = img.replace(':', '__').replace('/', '__') # Add classifier classes (if applicable) if is_classifier: classes_in = class_labels if isinstance(classes_in, _string_types): import os if not os.path.isfile(classes_in): raise ValueError("Path to class labels (%s) does not exist." % \ classes_in) with open(classes_in, 'r') as f: classes = f.read() classes = classes.splitlines() elif type(classes_in) is list: # list[int or str] classes = classes_in else: raise ValueError('Class labels must be a list of integers / strings,'\ ' or a file path') if predicted_feature_name is not None: builder.set_class_labels( classes, predicted_feature_name=predicted_feature_name, prediction_blob=predicted_probabilities_output) else: builder.set_class_labels(classes) # Set pre-processing paramsters builder.set_pre_processing_parameters(image_input_names=image_input_names, is_bgr=is_bgr, red_bias=red_bias, green_bias=green_bias, blue_bias=blue_bias, gray_bias=gray_bias, image_scale=image_scale) utils.save_spec(builder.spec, mlmodel_path) print("\n Core ML model generated. Saved at location: %s \n" % (mlmodel_path)) print('Core ML input(s): \n', builder.spec.description.input) print('Core ML output(s): \n', builder.spec.description.output) # Return the protobuf spec spec = builder.spec return MLModel(spec)
def test_updatable_model_creation_ce_adam(self): builder = self.create_base_builder() builder.add_softmax(name='softmax', input_name='output', output_name='softmax_output') builder.set_categorical_cross_entropy_loss(name='cross_entropy', input='softmax_output', target='target') adam_params = AdamParams() adam_params.set_batch(value=10, allowed_set=[10, 20]) builder.set_adam_optimizer(adam_params) builder.set_epochs(20) model_path = os.path.join(self.model_dir, 'updatable_creation.mlmodel') print(model_path) save_spec(builder.spec, model_path) mlmodel = MLModel(model_path) self.assertTrue(mlmodel is not None) spec = mlmodel.get_spec() self.assertTrue(spec.isUpdatable) self.assertTrue(spec.neuralNetwork.layers[0].isUpdatable) self.assertTrue( spec.neuralNetwork.layers[0].innerProduct.weights.isUpdatable) self.assertTrue(spec.neuralNetwork.layers[1].isUpdatable) self.assertTrue( spec.neuralNetwork.layers[1].innerProduct.weights.isUpdatable) self.assertTrue(spec.neuralNetwork.updateParams.lossLayers[0]. categoricalCrossEntropyLossLayer is not None) self.assertTrue(spec.neuralNetwork.updateParams.optimizer.adamOptimizer is not None) self.assertTrue( _np.isclose(spec.neuralNetwork.updateParams.optimizer. adamOptimizer.learningRate.defaultValue, 1e-2, atol=1e-4)) self.assertTrue( _np.isclose(spec.neuralNetwork.updateParams.optimizer. adamOptimizer.miniBatchSize.defaultValue, 10, atol=1e-4)) self.assertTrue( _np.isclose(spec.neuralNetwork.updateParams.optimizer. adamOptimizer.beta1.defaultValue, 0.9, atol=1e-4)) self.assertTrue( _np.isclose(spec.neuralNetwork.updateParams.optimizer. adamOptimizer.beta2.defaultValue, 0.999, atol=1e-4)) self.assertTrue( _np.isclose(spec.neuralNetwork.updateParams.optimizer. adamOptimizer.eps.defaultValue, 1e-8, atol=1e-8)) self.assertTrue( _np.isclose(spec.neuralNetwork.updateParams.epochs.defaultValue, 20, atol=1e-4)) self.assertTrue(spec.neuralNetwork.updateParams.optimizer. adamOptimizer.learningRate.range.minValue == 0) self.assertTrue(spec.neuralNetwork.updateParams.optimizer. adamOptimizer.learningRate.range.maxValue == 1) self.assertTrue(spec.neuralNetwork.updateParams.optimizer. adamOptimizer.miniBatchSize.set.values == [10, 20]) self.assertTrue(spec.neuralNetwork.updateParams.optimizer. adamOptimizer.beta1.range.minValue == 0) self.assertTrue(spec.neuralNetwork.updateParams.optimizer. adamOptimizer.beta1.range.maxValue == 1) self.assertTrue(spec.neuralNetwork.updateParams.optimizer. adamOptimizer.beta2.range.minValue == 0) self.assertTrue(spec.neuralNetwork.updateParams.optimizer. adamOptimizer.beta2.range.maxValue == 1) self.assertTrue(spec.neuralNetwork.updateParams.optimizer. adamOptimizer.eps.range.minValue == 0) self.assertTrue(spec.neuralNetwork.updateParams.optimizer. adamOptimizer.eps.range.maxValue == 1) self.assertTrue( spec.neuralNetwork.updateParams.epochs.set.values == [20])