def test_tf2keras_shared_range_dim(use_symbol):
        # Test examples in https://coremltools.readme.io/docs/flexible-inputs
        import tensorflow as tf

        input_dim = 3
        # None denotes seq_len dimension
        x1 = tf.keras.Input(shape=(None,input_dim), name="seq1")
        x2 = tf.keras.Input(shape=(None,input_dim), name="seq2")
        y = x1 + x2
        keras_model = tf.keras.Model(inputs=[x1, x2], outputs=[y])

        # One RangeDim shared by two inputs
        if use_symbol:
            seq_len_dim = ct.RangeDim(symbol='seq_len')
        else:
            # symbol is optional
            seq_len_dim = ct.RangeDim()
        seq1_input = ct.TensorType(name="seq1", shape=(1, seq_len_dim, input_dim))
        seq2_input = ct.TensorType(name="seq2", shape=(1, seq_len_dim, input_dim))
        mlmodel = ct.convert(keras_model,
                inputs=[seq1_input, seq2_input])

        batch = 1
        seq_len = 5
        test_input_x1 = np.random.rand(batch, seq_len, input_dim).astype(np.float32)
        test_input_x2 = np.random.rand(batch, seq_len, input_dim).astype(np.float32)
        expected_val = keras_model([test_input_x1, test_input_x2])
        if ct.utils._is_macos():
            results = mlmodel.predict({
                "seq1": test_input_x1,
                "seq2": test_input_x2})
            np.testing.assert_allclose(results["Identity"], expected_val,
                rtol=1e-4, atol=1e-3)
    def test_torch_outofbound_range_dim(use_symbol):
        import torch

        num_tokens = 3
        embedding_size = 5

        class TestModule(torch.nn.Module):
            def __init__(self):
                super(TestModule, self).__init__()
                self.embedding = torch.nn.Embedding(num_tokens, embedding_size)

            def forward(self, x):
                return self.embedding(x)

        model = TestModule()
        model.eval()

        example_input = torch.randint(high=num_tokens, size=(3,),
                dtype=torch.int64)
        traced_model = torch.jit.trace(model, example_input)

        if use_symbol:
            seq_len_dim = ct.RangeDim(symbol='len', lower_bound=3,
                    upper_bound=5)
        else:
            # symbol is optional
            seq_len_dim = ct.RangeDim(lower_bound=3, upper_bound=5)
        seq_input = ct.TensorType(name="input", shape=(seq_len_dim,),
                dtype=np.int64)
        mlmodel = ct.convert(
            traced_model,
            inputs=[seq_input],
        )

        if ct.utils._is_macos():
            result = mlmodel.predict(
                {"input": example_input.detach().numpy().astype(np.float32)}
            )

            # Verify outputs
            expected = model(example_input)
            name = list(result.keys())[0]
            np.testing.assert_allclose(result[name], expected.detach().numpy())

            # seq_len below/above lower_bound/upper_bound
            with pytest.raises(RuntimeError,
                    match=r"not compatible with the model\'s feature"):
                example_input2 = torch.randint(high=num_tokens, size=(99,),
                        dtype=torch.int64)
                result = mlmodel.predict(
                    {"input": example_input2.detach().numpy().astype(np.float32)}
                )

            with pytest.raises(RuntimeError,
                    match=r"not compatible with the model\'s feature"):
                example_input2 = torch.randint(high=num_tokens, size=(2,),
                        dtype=torch.int64)
                result = mlmodel.predict(
                    {"input": example_input2.detach().numpy().astype(np.float32)}
                )
    def test_torch_range_dim(use_symbol):
        import torch

        num_tokens = 3
        embedding_size = 5

        class TestModule(torch.nn.Module):
            def __init__(self):
                super(TestModule, self).__init__()
                self.embedding = torch.nn.Embedding(num_tokens, embedding_size)

            def forward(self, x):
                return self.embedding(x)

        model = TestModule()
        model.eval()

        example_input = torch.randint(high=num_tokens,
                                      size=(2, ),
                                      dtype=torch.int64)
        traced_model = torch.jit.trace(model, example_input)

        if use_symbol:
            seq_len_dim = ct.RangeDim(symbol='seq_length')
        else:
            # symbol is optional
            seq_len_dim = ct.RangeDim()
        seq_input = ct.TensorType(name="input",
                                  shape=(seq_len_dim, ),
                                  dtype=np.int64)
        mlmodel = ct.convert(
            traced_model,
            inputs=[seq_input],
        )

        if ct.utils._is_macos():
            result = mlmodel.predict(
                {"input": example_input.detach().numpy().astype(np.float32)})

            # Verify outputs
            expected = model(example_input)
            name = list(result.keys())[0]
            np.testing.assert_allclose(result[name], expected.detach().numpy())

            # Try example of different length
            example_input2 = torch.randint(high=num_tokens,
                                           size=(99, ),
                                           dtype=torch.int64)
            result = mlmodel.predict(
                {"input": example_input2.detach().numpy().astype(np.float32)})
            expected = model(example_input2)
            name = list(result.keys())[0]
            np.testing.assert_allclose(result[name], expected.detach().numpy())
    def test_tf2keras_outofbound_range_dim(use_symbol):
        # Test examples in https://coremltools.readme.io/docs/flexible-inputs
        import tensorflow as tf

        input_dim = 3
        # None denotes seq_len dimension
        x = tf.keras.Input(shape=(None, input_dim), name="seq")
        y = x * 2
        keras_model = tf.keras.Model(inputs=[x], outputs=[y])

        if use_symbol:
            seq_len_dim = ct.RangeDim(symbol='sequence_len',
                                      lower_bound=3,
                                      upper_bound=5)
        else:
            seq_len_dim = ct.RangeDim(lower_bound=3, upper_bound=5)
        seq_input = ct.TensorType(name="seq",
                                  shape=(1, seq_len_dim, input_dim))
        mlmodel = ct.convert(keras_model, inputs=[seq_input])

        # seq_len is within bound
        batch = 1
        seq_len = 3
        test_input_x = np.random.rand(batch, seq_len,
                                      input_dim).astype(np.float32)
        expected_val = keras_model([test_input_x])
        if ct.utils._is_macos():
            results = mlmodel.predict({"seq": test_input_x})
            np.testing.assert_allclose(results["Identity"],
                                       expected_val,
                                       rtol=1e-4,
                                       atol=1e-3)

            # seq_len below/above lower_bound/upper_bound
            with pytest.raises(
                    RuntimeError,
                    match=r"not compatible with the model\'s feature"):
                seq_len = 2
                test_input_x = np.random.rand(batch, seq_len,
                                              input_dim).astype(np.float32)
                results = mlmodel.predict({"seq": test_input_x})

            with pytest.raises(
                    RuntimeError,
                    match=r"not compatible with the model\'s feature"):
                seq_len = 6
                test_input_x = np.random.rand(batch, seq_len,
                                              input_dim).astype(np.float32)
                results = mlmodel.predict({"seq": test_input_x})
    def test_tf2keras_optional_input():
        # Test examples in https://coremltools.readme.io/docs/flexible-inputs
        import tensorflow as tf

        input_dim = 3
        # None denotes seq_len dimension
        x1 = tf.keras.Input(shape=(None, input_dim), name="optional_input")
        x2 = tf.keras.Input(shape=(None, input_dim), name="required_input")
        y = x1 + x2
        keras_model = tf.keras.Model(inputs=[x1, x2], outputs=[y])

        seq_len_dim = ct.RangeDim()
        default_value = np.ones((1, 2, input_dim)).astype(np.float32)
        optional_input = ct.TensorType(
            name="optional_input",
            shape=(1, seq_len_dim, input_dim),
            default_value=default_value,
        )
        required_input = ct.TensorType(
            name="required_input",
            shape=(1, seq_len_dim, input_dim),
        )
        mlmodel = ct.convert(keras_model,
                             inputs=[optional_input, required_input])

        batch = 1
        seq_len = 2
        test_input_x2 = np.random.rand(batch, seq_len,
                                       input_dim).astype(np.float32)
        expected_val = keras_model([default_value, test_input_x2])
        if ct.utils._is_macos():
            results = mlmodel.predict({"required_input": test_input_x2})
            np.testing.assert_allclose(results["Identity"],
                                       expected_val,
                                       rtol=1e-4)
Example #6
0
    def test_fully_dynamic_inputs():
        """
        All dims of the inputs are dynamic, and write to slice to one of the
        inputs.
        """
        import torch

        class Model(torch.nn.Module):
            def __init__(self, index):
                super(Model, self).__init__()
                self.index = index

            def forward(self, x, y):
                x[:, int(self.index.item())] = 0.0
                y = y.unsqueeze(0)
                return y, x

        model = Model(torch.tensor(3))
        scripted_model = torch.jit.script(model)

        mlmodel = ct.convert(
            scripted_model,
            inputs=[
                ct.TensorType("x", shape=(ct.RangeDim(), ct.RangeDim())),
                ct.TensorType("y", shape=(ct.RangeDim(), ct.RangeDim()))
            ],
        )

        # running predict() is supported on macOS
        if ct.utils._is_macos():
            x, y = torch.rand(2, 4), torch.rand(1, 2)
            torch_res = model(x, y)
            results = mlmodel.predict({
                "x": x.cpu().detach().numpy(),
                "y": y.cpu().detach().numpy()
            })
            np.testing.assert_allclose(torch_res[0], results['y.3'])
            np.testing.assert_allclose(torch_res[1], results['x'])

            x, y = torch.rand(1, 6), torch.rand(2, 3)
            torch_res = model(x, y)
            results = mlmodel.predict({
                "x": x.cpu().detach().numpy(),
                "y": y.cpu().detach().numpy()
            })
            np.testing.assert_allclose(torch_res[0], results['y.3'])
            np.testing.assert_allclose(torch_res[1], results['x'])
def inject_range_dim(v):
    if isinstance(v, int):
        return v
    if isinstance(v, str):
        vv = v.split("..")
        user_assert(
            len(vv) == 2 and vv[0].isnumeric() and vv[1].isnumeric(),
            "Can not parse shape element {}. Excepted RangeDim, e.g. 1..50".
            format(v))
        return ct.RangeDim(lower_bound=int(vv[0]), upper_bound=int(vv[1]))
    raise ValueError("Can not parse shape element {}, type {}".format(
        v, type(v)))
    def test_image_input_rangedim(self, convert_to):
        example_input = torch.rand(1, 3, 50, 50) * 255
        traced_model = torch.jit.trace(TestConvModule().eval(), example_input)

        input_shape = ct.Shape(shape=(1, 3, ct.RangeDim(25, 100, default=45),
                                      ct.RangeDim(25, 100, default=45)))
        model = ct.convert(traced_model,
                           inputs=[ct.ImageType(shape=input_shape)],
                           convert_to=convert_to)

        spec = model.get_spec()
        assert spec.description.input[0].type.imageType.width == 45
        assert spec.description.input[0].type.imageType.height == 45
        assert spec.description.input[
            0].type.imageType.imageSizeRange.widthRange.lowerBound == 25
        assert spec.description.input[
            0].type.imageType.imageSizeRange.widthRange.upperBound == 100
        _assert_torch_coreml_output_shapes(model,
                                           spec,
                                           traced_model,
                                           example_input,
                                           is_image_input=True)
    def test_multiarray_input_rangedim(self, convert_to):
        if convert_to == "mlprogram" and ct.utils._macos_version() < (12, 0):
            return

        example_input = torch.rand(1, 3, 50, 50) * 100
        traced_model = torch.jit.trace(TestConvModule().eval(), example_input)

        input_shape = ct.Shape(shape=(1, 3, ct.RangeDim(25, 100, default=45),
                                      ct.RangeDim(25, 100, default=45)))
        model = ct.convert(traced_model,
                           inputs=[ct.TensorType(shape=input_shape)],
                           convert_to=convert_to)

        spec = model.get_spec()
        assert list(spec.description.input[0].type.multiArrayType.shape) == [
            1, 3, 45, 45
        ]
        assert spec.description.input[
            0].type.multiArrayType.shapeRange.sizeRanges[2].lowerBound == 25
        assert spec.description.input[
            0].type.multiArrayType.shapeRange.sizeRanges[2].upperBound == 100
        _assert_torch_coreml_output_shapes(model, spec, traced_model,
                                           example_input)
    def test_torch_optional_input():
        import torch

        num_tokens = 3
        embedding_size = 5

        class TestModule(torch.nn.Module):
            def __init__(self):
                super(TestModule, self).__init__()
                self.embedding = torch.nn.Embedding(num_tokens, embedding_size)

            def forward(self, x, y):
                return self.embedding(x) + y

        model = TestModule()
        model.eval()

        example_input = [
            torch.randint(high=num_tokens, size=(2, ), dtype=torch.int64),
            torch.rand(1),
        ]
        traced_model = torch.jit.trace(model, example_input)

        required_input = ct.TensorType(name="required_input",
                                       shape=(ct.RangeDim(), ),
                                       dtype=np.int64)
        default_value = np.array([3]).astype(np.float32)
        optional_input = ct.TensorType(name="optional_input",
                                       shape=(1, ),
                                       default_value=default_value)
        mlmodel = ct.convert(
            traced_model,
            inputs=[required_input, optional_input],
        )

        if ct.utils._is_macos():
            result = mlmodel.predict({
                "required_input":
                example_input[0].detach().numpy().astype(np.float32)
            })

            # Verify outputs
            torch_default_value = torch.tensor([3])
            expected = model(example_input[0].detach(), torch_default_value)
            name = list(result.keys())[0]
            np.testing.assert_allclose(result[name], expected.detach().numpy())
    def test_mil_ranged_image_with_default(self):
        input_shape = [
            ct.ImageType(name="x",
                         shape=(1, 3, 10, ct.RangeDim(10, 30, default=20)))
        ]
        mlmodel = ct.convert(self.basic_network,
                             source="milinternal",
                             convert_to="mlprogram",
                             inputs=input_shape)
        input_spec = mlmodel.get_spec().description.input
        assert len(input_spec) == 1, "1 input expected, got {} instead".format(
            len(input_spec))
        assert input_spec[
            0].name == "x", "input name in MLModel is {}, 'x' is expected".format(
                input_spec[0].name)
        assert input_spec[0].type.WhichOneof(
            "Type") == "imageType", "Expected imageType, got {}".format(
                input_spec[0].type.WhichOneof("Type"))
        assert input_spec[0].type.imageType.WhichOneof(
            "SizeFlexibility"
        ) == "imageSizeRange", "Expected imageSizeRange in ShapeFlexibility"

        spec_H = input_spec[0].type.imageType.height
        spec_W = input_spec[0].type.imageType.width
        assert spec_H == 10 and spec_W == 20, "expected [H, W] == [10, 20], got [{}, {}] instead".format(
            spec_H, spec_W)

        spec_H_range = [
            input_spec[0].type.imageType.imageSizeRange.heightRange.lowerBound,
            input_spec[0].type.imageType.imageSizeRange.heightRange.upperBound
        ]
        spec_W_range = [
            input_spec[0].type.imageType.imageSizeRange.widthRange.lowerBound,
            input_spec[0].type.imageType.imageSizeRange.widthRange.upperBound
        ]
        assert spec_H_range == [10, 10], "Ranged height mismatch"
        assert spec_W_range == [10, 30], "Ranged width mismatch"
    def test_mil_ranged_multiarray_with_default(self):
        input_shape = [
            ct.TensorType(name="x",
                          shape=(1, 3, 10, ct.RangeDim(10, 30, default=20)))
        ]
        mlmodel = ct.convert(self.basic_network,
                             source="milinternal",
                             convert_to="mlprogram",
                             inputs=input_shape)
        input_spec = mlmodel.get_spec().description.input
        assert len(input_spec) == 1, "1 input expected, got {} instead".format(
            len(input_spec))
        assert input_spec[
            0].name == "x", "input name in MLModel is {}, 'x' is expected".format(
                input_spec[0].name)
        assert input_spec[0].type.WhichOneof(
            "Type"
        ) == "multiArrayType", "Expected multiArrayType, got {}".format(
            input_spec[0].type.WhichOneof("Type"))
        assert input_spec[0].type.multiArrayType.WhichOneof(
            "ShapeFlexibility"
        ) == "shapeRange", "Expected shapeRange in ShapeFlexibility"

        spec_default_shape = [
            s for s in input_spec[0].type.multiArrayType.shape
        ]
        ranged_shapes = [(1, 1), (3, 3), (10, 10), (10, 30)]
        spec_ranged_shapes = []
        for range_dim in input_spec[
                0].type.multiArrayType.shapeRange.sizeRanges:
            spec_ranged_shapes.append(
                tuple([range_dim.lowerBound, range_dim.upperBound]))
        assert spec_default_shape == [
            1, 3, 10, 20
        ], "Expected default shape to be [1, 3, 10, 20], got {} instead".format(
            str(spec_default_shape))
        assert spec_ranged_shapes == ranged_shapes, "Enumerated shape mismatch"
    def test_torch_range_dim_lstm(variable_length):
        """
        This example shows how to run LSTM with previous hidden / cell states
        """
        import torch
        import coremltools as ct

        input_size = 3
        hidden_size = 2

        class TestNet(torch.nn.Module):
            def __init__(self):
                super(TestNet, self).__init__()
                self.lstm = torch.nn.LSTM(input_size, hidden_size, 1)

            def forward(self, x, hidden_state, cell_state):
                # LSTM takes in previous hidden and cell states. The first
                # invokation usually have zero vectors as initial states.
                output, (new_hidden_state, new_cell_state) = \
                    self.lstm(x, (hidden_state, cell_state))
                # LSTM hidden / cell states are returned to be managed by the
                # caller (and is fed in as inputs in the next call).
                return output, new_hidden_state, new_cell_state

        model = TestNet()
        model.eval()

        seq_len = 2  # we'll make seq_len dynamic later
        batch = 1
        input_shape = (seq_len, batch, input_size)
        rand_input = torch.rand(*input_shape)
        h_shape = (1, batch, hidden_size)
        rand_h0 = torch.rand(*h_shape)
        rand_c0 = torch.rand(*h_shape)

        traced_model = torch.jit.trace(model, (rand_input, rand_h0, rand_c0))

        # ct.RangeDim() tells coremltools that this dimension can change for
        # each inference example (aka "runtime-determined"). If the sequence
        # length is always the same (e.g., 2 step LSTM would have seq_len == 2)
        # Note that fixed-length models usually run slightly faster
        # than variable length models.
        ct_seq_len = ct.RangeDim() if variable_length else seq_len
        seq_input = ct.TensorType(shape=(ct_seq_len, batch, input_size),
                                  name="seq_input")
        h_input = ct.TensorType(shape=h_shape, name="h_input")
        c_input = ct.TensorType(shape=h_shape, name="c_input")

        mlmodel = ct.convert(
            traced_model,
            inputs=[seq_input, h_input, c_input],
        )

        if ct.utils._is_macos():
            result = mlmodel.predict({
                "seq_input":
                rand_input.detach().numpy().astype(np.float32),
                "h_input":
                rand_h0.detach().numpy().astype(np.float32),
                "c_input":
                rand_c0.detach().numpy().astype(np.float32),
            })

            # Verify outputs
            expected = model(rand_input, rand_h0, rand_c0)
            names = list(result.keys())
            names.sort()
            np.testing.assert_allclose(result[names[0]],
                                       expected[0].detach().numpy(),
                                       atol=1e-4)
            np.testing.assert_allclose(result[names[1]],
                                       expected[1].detach().numpy(),
                                       atol=1e-4)
            np.testing.assert_allclose(result[names[2]],
                                       expected[2].detach().numpy(),
                                       atol=1e-4)

            # Try example of different length
            if variable_length:
                seq_len = 10
                input_shape = (seq_len, batch, input_size)
                rand_input = torch.rand(*input_shape)

                result = mlmodel.predict({
                    "seq_input":
                    rand_input.detach().numpy().astype(np.float32),
                    "h_input":
                    rand_h0.detach().numpy().astype(np.float32),
                    "c_input":
                    rand_c0.detach().numpy().astype(np.float32),
                })
                expected = model(rand_input, rand_h0, rand_c0)
                names = list(result.keys())
                names.sort()
                np.testing.assert_allclose(result[names[0]],
                                           expected[0].detach().numpy(),
                                           atol=1e-4)
                np.testing.assert_allclose(result[names[1]],
                                           expected[1].detach().numpy(),
                                           atol=1e-4)
                np.testing.assert_allclose(result[names[2]],
                                           expected[2].detach().numpy(),
                                           atol=1e-4)
Example #14
0
# Convert to Core ML
model = ct.convert([tf_model], source='tensorflow')

x = np.random.rand(1, 256, 256, 3)
tf_out = model.predict([x])

# convert functions
predict_model = tf.saved_model.load('./models/magenta_colab/predict_incepv3')
transfer_model = tf.saved_model.load('./models/magenta_colab/transfer_incepv3')
concrete_func = predict_model.signatures[
    tf.saved_model.DEFAULT_SERVING_SIGNATURE_DEF_KEY]
print(concrete_func.inputs)
concrete_func.inputs[0].set_shape([1, 256, 256, 3])

# Range for the sequence dimension is "arbitary"
input_shape = ct.Shape(shape=(1, ct.RangeDim(), ct.RangeDim(), 3))
model_input = ct.TensorType(shape=input_shape)

# Convert the model
predict_mlmodel = ct.convert(model=[concrete_func],
                             source='tensorflow',
                             inputs=[model_input])

predict_model = tf.saved_model.load('./models/magenta_colab/predict_incepv3')
predict_model.summary()

model = ct.convert(predict_model, source='tensorflow')


#
def convert_coreml_model_dynamic(saved_model_path,
Example #15
0
# model(data)

# transforms.ToPILImage()(image[0]).show(command='fim')
# to_visualize = ['gray', 'hint', 'hint_ab', 'fake_entr',
#                 'real', 'fake_reg', 'real_ab', 'fake_ab_reg', ]

# visuals = util.get_subset_dict(
#     model.model.get_current_visuals(), to_visualize)

# for key, value in visuals.items():
#     print(key)
#     transforms.ToPILImage()(value[0]).show(command='fim')
output = model(img, hint)
output = util.lab2rgb(output, opt=opt)
transforms.ToPILImage()(output[0]).show(command='fim')

traced_model = torch.jit.trace(model, (img, hint), check_trace=False)

mlmodel = ct.convert(
    model=traced_model,
    inputs=[
        ct.TensorType(name="image",
                      shape=ct.Shape(shape=(1, 3, ct.RangeDim(1, 4096),
                                            ct.RangeDim(1, 4096)))),
        ct.TensorType(name="hint",
                      shape=ct.Shape(shape=(1, 3, ct.RangeDim(1, 4096),
                                            ct.RangeDim(1, 4096)))),
    ])
mlmodel.save("~/color.mlmodel")