Exemple #1
0
def _convert_concat_table(builder, name, layer, input_names, output_names):
    layers = layer.modules
    result_outputs = []
    for l in layers:
        l_name = _gen_layer_name(l)
        l_outputs = _convert_layer(builder, l_name, l, input_names, [l_name])
        result_outputs += l_outputs
    return result_outputs
def _convert_full_convolution(builder, name, layer, input_names, output_names):
    input_name = input_names[0]
    output_name = output_names[0]

    k_h, k_w = layer.kH, layer.kW

    pad_h, pad_w = layer.padH, layer.padW

    weight = layer.weight.numpy().transpose((2, 3, 0, 1))
    bias = None
    if layer.bias is not None:
        bias = layer.bias.numpy()

    add_crop = False
    output_ = layer.output.numpy()
    output_shape = (
        output_.shape[-2] + 2 * pad_h,
        output_.shape[-1] + 2 * pad_w
    )
    if pad_h > 0 or pad_w > 0:
        crop_padding_name = _gen_layer_name('padding')
        output_name = name + '_output'
        add_crop = True

    builder.add_convolution(
        name=name,
        kernel_channels=layer.nInputPlane,
        output_channels=layer.nOutputPlane,
        height=k_h,
        width=k_w,
        stride_height=layer.dH,
        stride_width=layer.dW,
        border_mode='valid',
        groups=1,
        W=weight,
        b=bias,
        has_bias=bias is not None,
        is_deconv=True,
        output_shape=output_shape,
        input_name=input_name,
        output_name=output_name,
        dilation_factors=[1, 1]
    )

    if add_crop:
        builder.add_crop(
            name=crop_padding_name,
            left=pad_w,
            right=pad_w,
            top=pad_h,
            bottom=pad_h,
            offset=0,
            input_names=[output_name],
            output_name=output_names[0]
        )

    return output_names
Exemple #3
0
def _convert_parallel_table(builder, name, layer, input_names, output_names):
    layers = layer.modules
    assert len(input_names) == len(layers)
    result_outputs = []
    for i in range(len(layers)):
        l_ = layers[i]
        l_name = _gen_layer_name(l_)
        l_outputs = _convert_layer(builder, l_name, l_, [input_names[i]],
                                   [l_name])
        result_outputs.append(l_outputs[0])
    return result_outputs
Exemple #4
0
def _convert_cdiv_table(builder, name, layer, input_names, output_names):
    assert len(input_names) == 2
    assert len(output_names) == 1

    inverse_layer_name = _gen_layer_name('inverse')
    inverse_layer_output_name = inverse_layer_name + '_output'

    builder.add_unary(name=inverse_layer_name,
                      input_name=input_names[1],
                      output_name=inverse_layer_output_name,
                      mode='inverse')

    builder.add_elementwise(
        name=name,
        input_names=[input_names[0], inverse_layer_output_name],
        output_name=output_names[0],
        mode='MULTIPLY')
    return output_names
Exemple #5
0
def _convert_sequential(builder, name, layer, input_names, output_names):
    layers = layer.modules
    n = len(layers)

    inputs = input_names
    for i in range(n):
        l = layers[i]

        l_outputs = None
        l_name = _gen_layer_name(l)
        if i != (n - 1):
            l_outputs = [l_name]
        else:
            l_outputs = output_names

        l_outputs = _convert_layer(builder, l_name, l, inputs, l_outputs)
        inputs = l_outputs

    return output_names
Exemple #6
0
def _convert_sequential(builder, name, layer, input_names, output_names):
    layers = layer.modules
    n = len(layers)

    inputs = input_names
    for i in range(n):
        l_ = layers[i]

        l_outputs = None
        l_name = _gen_layer_name(l_)
        if i != (n - 1):
            if isinstance(l_.output, list):
                l_outputs = [
                    "{}_{}".format(l_name, i) for i in range(len(l_.output))
                ]
            else:
                l_outputs = [l_name]
        else:
            l_outputs = output_names

        l_outputs = _convert_layer(builder, l_name, l_, inputs, l_outputs)
        inputs = l_outputs

    return output_names
def convert(model,
            input_shapes,
            input_names=['input'],
            output_names=['output'],
            mode=None,
            image_input_names=[],
            preprocessing_args={},
            image_output_names=[],
            deprocessing_args={},
            class_labels=None,
            predicted_feature_name='classLabel',
            unknown_layer_converter_fn=None):
    """
    Convert Torch7 model to CoreML.

    Parameters
    ----------
    model: Torch7 model (loaded with PyTorch) | str
        A trained Torch7 model loaded in python using PyTorch or path to file
        with model (*.t7).

    input_shapes: list of tuples
        Shapes of the input tensors.

    mode: str ('classifier', 'regressor' or None)
        Mode of the converted coreml model:
        'classifier', a NeuralNetworkClassifier spec will be constructed.
        'regressor', a NeuralNetworkRegressor spec will be constructed.

    preprocessing_args: dict
        'is_bgr', 'red_bias', 'green_bias', 'blue_bias', 'gray_bias',
        'image_scale' keys with the same meaning as
        https://apple.github.io/coremltools/generated/coremltools.models.neural_network.html#coremltools.models.neural_network.NeuralNetworkBuilder.set_pre_processing_parameters

    deprocessing_args: dict
        Same as 'preprocessing_args' but for deprocessing.

    class_labels: A string or list of strings.
        As a string it represents the name of the file which contains
        the classification labels (one per line).
        As a list of strings it represents a list of categories that map
        the index of the output of a neural network to labels in a classifier.

    predicted_feature_name: str
        Name of the output feature for the class labels exposed in the Core ML
        model (applies to classifiers only). Defaults to 'classLabel'

    unknown_layer_converter_fn: function with signature:
        (builder, name, layer, input_names, output_names)
            builder: object - instance of NeuralNetworkBuilder class
            name: str - generated layer name
            layer: object - pytorch object for corresponding layer
            input_names: list of strings
            output_names: list of strings
            Returns: list of strings for layer output names
        Callback function to handle unknown for torch2coreml layers


    Returns
    -------
    model: A coreml model.
    """
    _gen_layer_name.called = 0
    _get_layer_converter_fn.unknown_converter_fn = unknown_layer_converter_fn

    if isinstance(model, basestring):
        torch_model = load_lua(model)
    elif isinstance(model, torch.legacy.nn.Sequential):
        torch_model = model
    else:
        raise TypeError(
            "Model must be file path to .t7 file or pytorch loaded model \
            with torch.legacy.nn.Sequential module as root")

    torch_model.evaluate()

    if not isinstance(input_shapes, list):
        raise TypeError("Input shapes should be a list of tuples.")

    for shape in input_shapes:
        if not isinstance(shape, tuple):
            raise TypeError("Input shape should be a tuple.")

    if len(input_names) != len(input_shapes):
        raise ValueError(
            "Input names count must be equal to input shapes count")

    output_shapes = _infer_torch_output_shapes(torch_model, input_shapes)

    if len(output_shapes) != len(output_names):
        raise ValueError(
            "Model has {} outputs, but you set output_names for {}.".format(
                len(output_shapes), len(output_names)))

    # create input/output features
    input_features = []
    for i in range(len(input_names)):
        input_features.append(
            (input_names[i], datatypes.Array(*input_shapes[i])))
    output_features = []
    for i in range(len(output_names)):
        output_features.append(
            (output_names[i], datatypes.Array(*output_shapes[i])))

    builder = NeuralNetworkBuilder(input_features, output_features, mode)

    # build model
    layer_name = _gen_layer_name(torch_model)
    _output_names = output_names[:]
    if len(image_output_names) > 0:
        for i in range(len(_output_names)):
            if _output_names[i] in image_output_names:
                _output_names[i] = _gen_layer_name(_DEPROCESS_LAYER_NAME)

    model_output_names = _layers._convert_layer(builder, layer_name,
                                                torch_model, input_names,
                                                _output_names)

    # set preprocessing parameters
    if len(image_input_names) > 0:
        builder.set_pre_processing_parameters(
            image_input_names=image_input_names,
            is_bgr=preprocessing_args.get('is_bgr', False),
            red_bias=preprocessing_args.get('red_bias', 0.0),
            green_bias=preprocessing_args.get('green_bias', 0.0),
            blue_bias=preprocessing_args.get('blue_bias', 0.0),
            gray_bias=preprocessing_args.get('gray_bias', 0.0),
            image_scale=preprocessing_args.get('image_scale', 1.0))

    # set deprocessing parameters
    if len(image_output_names) > 0:
        for i in range(len(output_names)):
            output_name = output_names[i]
            if output_name in image_output_names:
                output_shape = output_shapes[i]
                if len(output_shape) == 2 or output_shape[0] == 1:
                    is_grayscale = True
                elif output_shape[0] == 3:
                    is_grayscale = False
                else:
                    raise ValueError('Output must be RGB image or Grayscale')
                _set_deprocessing(is_grayscale, builder, deprocessing_args,
                                  model_output_names[i], output_name)

    if class_labels is not None:
        if type(class_labels) is str:
            labels = [l.strip() for l in open(class_labels).readlines()]
        elif type(class_labels) is list:
            labels = class_labels
        else:
            raise TypeError("synset variable of unknown type. Type found: {}. \
                Expected either string or list of strings.".format(
                type(class_labels), ))

        builder.set_class_labels(class_labels=labels,
                                 predicted_feature_name=predicted_feature_name)

    return MLModel(builder.spec)