def infer_shapes(nn_spec, input_spec, input_shape_dict = None):

    """
    Input:

        spec : mlmodel spec
        input_shape_dict: dictionary of  string --> tuple
                      string:  input name
                      tuple: input shape as a 5 length tuple in order (Seq, Batch, C, H, W)

        If input_shape_dict is not provided, input shapes are inferred from the input description in the mlmodel.
        Since the description in the specification only contains values of C,H,W; Seq and Batch dimensions are set to 1.

    Output:

        shape_dict:  dictionary containing all the blobs in the neural network and their shapes, expressed as length 5 tuples,
                     to be interpreted in order (Seq, Batch, C, H, W).
    """

    shape_dict = {}
    if input_shape_dict:
        for key, value in input_shape_dict.items():
            assert len(value) == 5, 'Shape of the input must be of length 5'
            shape_dict[key] = value

    # construct input_shape_dict from the model description
    else:
        for inp in input_spec:
            input_name = inp.name
            C = H = W = 1
            if inp.type.WhichOneof('Type') == 'imageType':
                W = int(inp.type.imageType.width)
                H = int(inp.type.imageType.height)
                colorspace = _FeatureTypes_pb2.ImageFeatureType.ColorSpace.Name(inp.type.imageType.colorSpace)
                if colorspace == 'GRAYSCALE':
                    C = 1
                elif colorspace == 'RGB' or colorspace == 'BGR':
                    C = 3
                else:
                    raise ValueError('Input %s : Invalid Colorspace' %(input_name))
            elif inp.type.WhichOneof('Type') == 'multiArrayType':
                array_shape = inp.type.multiArrayType.shape
                if len(array_shape) == 1:
                    C = array_shape[0]
                elif len(array_shape) == 3:
                    C, H, W = map(int, array_shape)
                else:
                    raise ValueError("Input %s : Multi array must be of length 1 or 3" %(input_name))
            else:
                raise ValueError("Input %s : Input type must be image or multi-array" %(input_name))
            shape_dict[input_name] = (1, 1, C, H, W)

    layers = nn_spec.layers

    for i, layer in enumerate(layers):
        for inp in layer.input:
            assert inp in shape_dict, ('Input %s shape not cannot be determined' %(inp))
        layer_type = layer.WhichOneof('layer')
        if layer_type == 'custom':
            break
        layer_translator = _get_translator_function(layer_type)
        layer_translator(layer, shape_dict)


    return shape_dict
Input:

        spec : mlmodel spec
        input_shape_dict: dictionary of  string --> tuple
                      string:  input name
                      tuple: input shape as a 5 length tuple in order (Seq, Batch, C, H, W)

        If input_shape_dict is not provided, input shapes are inferred from the input description in the mlmodel.
        Since the description in the specification only contains values of C,H,W; Seq and Batch dimensions are set to 1.

    Output:

        shape_dict:  dictionary containing all the blobs in the neural network and their shapes, expressed as length 5 tuples,
                     to be interpreted in order (Seq, Batch, C, H, W).