def build_quant_conv_layer(
     self,
     W=None,
     quantization_type="linear",
     nbits=8,
     quant_scale=None,
     quant_bias=None,
     quant_lut=None,
 ):
     input_features = [("data", datatypes.Array(1, 2, 2))]
     output_features = [("out", datatypes.Array(2, 1, 1))]
     builder = NeuralNetworkBuilder(input_features, output_features)
     builder.add_convolution(
         name="conv",
         kernel_channels=1,
         output_channels=2,
         height=2,
         width=2,
         stride_height=1,
         stride_width=1,
         border_mode="valid",
         groups=1,
         W=W,
         b=None,
         has_bias=False,
         input_name="data",
         output_name="out",
         quantization_type=quantization_type,
         nbits=nbits,
         quant_scale=quant_scale,
         quant_bias=quant_bias,
         quant_lut=quant_lut,
     )
     return MLModel(builder.spec)
Exemple #2
0
 def test_convolution_converter(self):
     input_dim = (1, 1, 4, 2)
     output_dim = (1, 1, 4, 2)
     input = [('input', datatypes.Array(*input_dim))]
     output = [('output', datatypes.Array(*output_dim))]
     builder = NeuralNetworkBuilder(input, output)
     weights = numpy.zeros(shape=(1, 1, 2, 2))
     weights[:] = [[1, 1], [-1, -1]]
     bias = numpy.zeros(shape=(1, ))
     bias[:] = 100
     builder.add_convolution(name='Conv',
                             kernel_channels=1,
                             output_channels=1,
                             height=2,
                             width=2,
                             stride_height=1,
                             stride_width=1,
                             border_mode='same',
                             groups=1,
                             W=weights,
                             b=bias,
                             has_bias=True,
                             input_name='input',
                             output_name='output',
                             is_deconv=True,
                             output_shape=(1, 1, 4, 2))
     model_onnx = convert_coreml(builder.spec)
     self.assertTrue(model_onnx is not None)
Exemple #3
0
def verify_convolution(input_dim, filter, padding):
    dtype = "float32"
    N, C, H, W = input_dim
    OC, _, KH, KW = filter
    a_np = np.random.uniform(size=input_dim).astype(dtype)
    w_np = np.random.uniform(size=(OC, C, KH, KW)).astype(dtype)
    w_np_cm = np.transpose(w_np, axes=(2, 3, 1, 0))
    b_np = conv2d_nchw_python(a_np, w_np, [1, 1], padding)
    inputs = [("input1", datatypes.Array(C, H, W))]
    output = [("output", datatypes.Array(*b_np.shape))]
    builder = NeuralNetworkBuilder(inputs, output)
    builder.add_convolution(
        name="conv",
        kernel_channels=3,
        output_channels=OC,
        height=KH,
        width=KW,
        stride_height=1,
        stride_width=1,
        border_mode=padding.lower(),
        groups=1,
        W=w_np_cm,
        b=None,
        has_bias=False,
        is_deconv=False,
        input_name="input1",
        output_name="output",
    )
    model = cm.models.MLModel(builder.spec)
    for target, dev in tvm.testing.enabled_targets():
        out = run_tvm_graph(model, target, dev, [a_np], ["input1"], output_shape=None)
        tvm.testing.assert_allclose(out, b_np, rtol=1e-5)
def make_mlmodel(variables):
    # Specify the inputs and outputs (there can be multiple).
    # Each name corresponds to the input_name/output_name of a layer in the network so
    # that Core ML knows where to insert and extract data.
    input_features = [('image', datatypes.Array(1, IMAGE_HEIGHT, IMAGE_WIDTH))]
    output_features = [('labelValues', datatypes.Array(NUM_LABEL_INDEXES))]
    builder = NeuralNetworkBuilder(input_features, output_features, mode=None)

    # The "name" parameter has no effect on the function of the network. As far as I know
    # it's only used when Xcode fails to load your mlmodel and gives you an error telling
    # you what the problem is.
    # The input_names and output_name are used to link layers to each other and to the
    # inputs and outputs of the model. When adding or removing layers, or renaming their
    # outputs, always make sure you correct the input and output names of the layers
    # before and after them.
    builder.add_elementwise(name='add_layer',
                            input_names=['image'],
                            output_name='add_layer',
                            mode='ADD',
                            alpha=-0.5)

    # Although Core ML internally uses weight matrices of shape
    # (outputChannels, inputChannels, height, width) (as can be found by looking at the
    # protobuf specification comments), add_convolution takes the shape
    # (height, width, inputChannels, outputChannels) (as can be found in the coremltools
    # documentation). The latter shape matches what TensorFlow uses so we don't need to
    # reorder the matrix axes ourselves.
    builder.add_convolution(name='conv2d_1',
                            kernel_channels=1,
                            output_channels=32,
                            height=3,
                            width=3,
                            stride_height=1,
                            stride_width=1,
                            border_mode='same',
                            groups=0,
                            W=variables['W_conv1'].eval(),
                            b=variables['b_conv1'].eval(),
                            has_bias=True,
                            is_deconv=False,
                            output_shape=None,
                            input_name='add_layer',
                            output_name='conv2d_1')

    builder.add_activation(name='relu_1',
                           non_linearity='RELU',
                           input_name='conv2d_1',
                           output_name='relu_1',
                           params=None)

    builder.add_pooling(name='maxpool_1',
                        height=2,
                        width=2,
                        stride_height=2,
                        stride_width=2,
                        layer_type='MAX',
                        padding_type='SAME',
                        input_name='relu_1',
                        output_name='maxpool_1')

    # ...

    builder.add_flatten(name='maxpool_3_flat',
                        mode=1,
                        input_name='maxpool_3',
                        output_name='maxpool_3_flat')

    # We must swap the axes of the weight matrix because add_inner_product takes the shape
    # (outputChannels, inputChannels) whereas TensorFlow uses
    # (inputChannels, outputChannels). Unlike with add_convolution (see the comment
    # above), the shape add_inner_product expects matches what the protobuf specification
    # requires for inner products.
    builder.add_inner_product(name='fc1',
                              W=tf_fc_weights_order_to_mlmodel(
                                  variables['W_fc1'].eval()).flatten(),
                              b=variables['b_fc1'].eval().flatten(),
                              input_channels=6 * 6 * 64,
                              output_channels=1024,
                              has_bias=True,
                              input_name='maxpool_3_flat',
                              output_name='fc1')

    # ...

    builder.add_softmax(name='softmax',
                        input_name='fc2',
                        output_name='labelValues')

    model = MLModel(builder.spec)

    model.short_description = 'Model for recognizing a variety of images drawn on screen with one\'s finger'

    model.input_description['image'] = 'A gesture image to classify'
    model.output_description[
        'labelValues'] = 'The "probability" of each label, in a dense array'

    return model