Exemple #1
0
def UNSUPPORTED(op):
    # type: (ONNXOperation)->typing.Tuple[typing.List[typing.List[int]], typing.List[str]]
    raise utils.NNEFToolsException(
        'ONNX shape prop: Unsupported op: {}'.format(op.name))
def create_input(input_source, np_dtype, shape, allow_bigger_batch=False):
    assert isinstance(input_source,
                      (DefaultInput, RandomInput, ImageInput, NNEFTensorInput))
    np_dtype = np.dtype(np_dtype)
    if isinstance(input_source, DefaultInput):
        if 'float' in np_dtype.name:
            input_source = RandomInput('normal', 0.0, 1.0)
        elif 'int' in np_dtype.name:
            input_source = RandomInput('binomial', 255, 0.5)
        elif 'bool' == np_dtype.name:
            input_source = RandomInput('bernoulli', 0.5)
        else:
            raise utils.NNEFToolsException(
                "Random does not support this dtype: {}".format(np_dtype.name))

    if isinstance(input_source, RandomInput):
        if input_source.algo == 'uniform':
            if 'float' in np_dtype.name:
                return np.random.uniform(input_source.args[0],
                                         input_source.args[1],
                                         shape).astype(np_dtype)
            elif 'int' in np_dtype.name:
                return np.random.randint(
                    int(math.ceil(input_source.args[0])),
                    int(math.floor(input_source.args[1])) + 1, shape, np_dtype)
            else:
                raise Exception(
                    "Random 'uniform' can not be applied to: {}".format(
                        np_dtype.name))
        elif input_source.algo == 'normal':
            if 'float' in np_dtype.name:
                return np.random.normal(input_source.args[0],
                                        input_source.args[1],
                                        shape).astype(np_dtype)
            else:
                raise Exception(
                    "Random 'normal' can not be applied to: {}".format(
                        np_dtype.name))
        elif input_source.algo == 'binomial':
            if 'int' in np_dtype.name:
                return np.random.binomial(input_source.args[0],
                                          input_source.args[1],
                                          shape).astype(np_dtype)
            else:
                raise Exception(
                    "Random 'normal' can not be applied to: {}".format(
                        np_dtype.name))
        elif input_source.algo == 'bernoulli':
            if 'bool' == np_dtype.name:
                return np.random.uniform(0.0, 1.0,
                                         shape) <= input_source.args[0]
            else:
                raise Exception(
                    "Random 'bernoulli' can not be applied to: {}".format(
                        np_dtype.name))
        else:
            assert False
    elif isinstance(input_source, ImageInput):
        import skimage
        import skimage.io
        import skimage.color
        import skimage.transform

        assert shape is None or len(
            shape) == 4, "ImageInput can only produce tensors with rank=4"
        assert input_source.data_format.upper() in [
            ImageInput.DATA_FORMAT_NCHW, ImageInput.DATA_FORMAT_NHWC
        ]
        assert input_source.color_format.upper() in [
            ImageInput.COLOR_FORMAT_RGB, ImageInput.COLOR_FORMAT_BGR
        ]
        imgs = []
        for pattern in input_source.filenames:
            filenames = sorted(glob.glob(os.path.expanduser(pattern)))
            assert filenames, "No files found for path: {}".format(pattern)
            for filename in filenames:
                target_size = None
                if shape is not None:
                    if input_source.data_format.upper(
                    ) == ImageInput.DATA_FORMAT_NCHW:
                        if shape[1] != 3:
                            raise utils.NNEFToolsException(
                                'NCHW image is specified as input, but channel dimension of input tensor is not 3.'
                            )
                        target_size = [shape[2], shape[3]]
                    else:
                        if shape[3] != 3:
                            raise utils.NNEFToolsException(
                                'NHWC image is specified as input, but channel dimension of input tensor is not 3.'
                            )
                        target_size = [shape[1], shape[2]]

                img = skimage.img_as_ubyte(skimage.io.imread(filename))
                if len(img.shape) == 2:
                    img = skimage.color.gray2rgb(img)

                img = img.astype(np.float32)

                if input_source.color_format.upper(
                ) == ImageInput.COLOR_FORMAT_RGB:
                    img = img[...,
                              (0, 1, 2)]  # remove alpha channel if present
                else:
                    img = img[..., (2, 1, 0)]

                if input_source.range:
                    min_ = np.array(input_source.range[0], dtype=np.float32)
                    max_ = np.array(input_source.range[1], dtype=np.float32)
                    scale = (max_ - min_) / 255.0
                    bias = min_
                    img = img * scale + bias

                if input_source.norm:
                    mean = np.array(input_source.norm[0], dtype=np.float32)
                    std = np.array(input_source.norm[1], dtype=np.float32)
                    img = (img - mean) / std

                if target_size is not None:
                    img = skimage.transform.resize(img,
                                                   target_size,
                                                   preserve_range=True,
                                                   anti_aliasing=True,
                                                   mode='reflect')

                img = img.astype(np_dtype)

                if input_source.data_format.upper(
                ) == ImageInput.DATA_FORMAT_NCHW:
                    img = img.transpose((2, 0, 1))

                img = np.expand_dims(img, 0)

                imgs.append(img)
        if shape is not None and len(imgs) < shape[0]:
            print(
                "Info: Network batch size bigger than supplied data, repeating it",
                file=sys.stderr)
            imgs = imgs * ((shape[0] + len(imgs) - 1) // len(imgs))
            imgs = imgs[:shape[0]]
            assert len(imgs) == shape[0]
        assert shape is None or len(imgs) == shape[0] or allow_bigger_batch
        if not all(img.shape == imgs[0].shape for img in imgs):
            raise utils.NNEFToolsException(
                "The size of all images must be the same, or --size must be specified"
            )
        return np.concatenate(tuple(imgs), 0)
    elif isinstance(input_source, NNEFTensorInput):
        with open(input_source.filename) as f:
            return nnef.read_tensor(f)
    else:
        assert False
Exemple #3
0
def run_using_argv(argv):
    try:
        args = get_args(argv)
        write_outputs = args.output_names is None or args.output_names

        if args.input is None:
            if sys.stdin.isatty():
                raise utils.NNEFToolsException("No input provided!")
            utils.set_stdin_to_binary()

        if write_outputs:
            if args.output is None:
                if sys.stdout.isatty():
                    raise utils.NNEFToolsException("No output provided!")
                utils.set_stdout_to_binary()

        parent_dir_of_input_model = os.path.dirname(
            utils.path_without_trailing_separator(args.network))
        tmp_dir = None

        if args.network.endswith('.tgz'):
            nnef_path = tmp_dir = tempfile.mkdtemp(
                prefix="nnef_", dir=parent_dir_of_input_model)
            utils.tgz_extract(args.network, nnef_path)
        else:
            nnef_path = args.network

        try:
            parser_configs = NNEFParserConfig.load_configs(
                args.custom_operations, load_standard=True)

            # read without weights
            reader = nnef_io.Reader(parser_configs=parser_configs,
                                    infer_shapes=False)
            graph = reader(
                os.path.join(nnef_path, 'graph.nnef') if os.path.
                isdir(nnef_path) else nnef_path)

            if args.input is None:
                inputs = tuple(
                    nnef.read_tensor(sys.stdin)
                    for _ in range(len(graph.inputs)))
            elif len(args.input) == 1 and os.path.isdir(args.input[0]):
                inputs = tuple(
                    nnef_io.read_nnef_tensor(
                        os.path.join(args.input[0], tensor.name + '.dat'))
                    for tensor in graph.inputs)
            else:
                inputs = tuple(
                    nnef_io.read_nnef_tensor(path) for path in args.input)

            reader = nnef_io.Reader(parser_configs=parser_configs,
                                    input_shape=tuple(
                                        list(input.shape) for input in inputs))

            graph = reader(nnef_path)

            tensor_hooks = []

            stats_hook = None
            if args.stats:
                stats_hook = backend.StatisticsHook()
                tensor_hooks.append(stats_hook)

            if write_outputs and args.output_names is not None:
                if '*' in args.output_names:
                    tensor_hooks.append(
                        backend.ActivationExportHook(
                            tensor_names=[
                                t.name for t in graph.tensors
                                if not t.is_constant and not t.is_variable
                            ],
                            output_directory=args.output))
                else:
                    tensor_hooks.append(
                        backend.ActivationExportHook(
                            tensor_names=args.output_names,
                            output_directory=args.output))

            if args.permissive:
                backend.try_to_fix_unsupported_attributes(graph)

            outputs = backend.run(nnef_graph=graph,
                                  inputs=inputs,
                                  device=args.device,
                                  custom_operations=get_custom_runners(
                                      args.custom_operations),
                                  tensor_hooks=tensor_hooks)

            if write_outputs and args.output_names is None:
                if args.output is None:
                    for array in outputs:
                        nnef.write_tensor(sys.stdout, array)
                else:
                    for tensor, array in zip(graph.outputs, outputs):
                        nnef_io.write_nnef_tensor(
                            os.path.join(args.output, tensor.name + '.dat'),
                            array)

            if stats_hook:
                if args.stats.endswith('/') or args.stats.endswith('\\'):
                    stats_path = os.path.join(nnef_path, args.stats,
                                              'graph.stats')
                else:
                    stats_path = os.path.join(nnef_path, args.stats)
                stats_hook.save_statistics(stats_path)

            if tmp_dir and (args.stats and _is_inside(nnef_path, args.stats)):
                if args.network.endswith('.tgz'):
                    print("Info: Changing input archive", file=sys.stderr)
                    shutil.move(args.network,
                                args.network + '.nnef-tools-backup')
                    utils.tgz_compress(dir_path=nnef_path,
                                       file_path=args.network)
                    os.remove(args.network + '.nnef-tools-backup')
                else:
                    output_path = args.network.rsplit('.', 1)[0] + '.nnef.tgz'
                    backup_path = output_path + '.nnef-tools-backup'
                    if os.path.exists(output_path):
                        shutil.move(output_path, backup_path)
                    utils.tgz_compress(dir_path=nnef_path,
                                       file_path=output_path)
                    if os.path.exists(backup_path):
                        os.remove(backup_path)
        finally:
            if tmp_dir:
                shutil.rmtree(tmp_dir)
    except utils.NNEFToolsException as e:
        print("Error: " + str(e), file=sys.stderr)
        exit(1)
    except nnef.Error as e:
        print("Error: " + str(e), file=sys.stderr)
        exit(1)
Exemple #4
0
def get_args(argv):
    parser = argparse.ArgumentParser(
        description="NNEF inference tool",
        formatter_class=argparse.RawTextHelpFormatter,
        epilog="""Tips:
- If you refer to a Python package or module that is not in the current directory,
please add its location to PYTHONPATH.
- Quote parameters if they contain spaces or special characters.
""")

    parser.add_argument("network",
                        help="Path of NNEF file, directory or archive")

    parser.add_argument(
        '--input',
        required=False,
        nargs='+',
        help="Path of input tensors.\n"
        "By default they are read from the standard input through a pipe or redirect."
    )

    parser.add_argument(
        '--output',
        required=False,
        help="The path of the output directory.\n"
        "By default the standard output is used, but only if the command is piped or redirected."
    )

    parser.add_argument(
        "--output-names",
        nargs='*',
        help="""List tensor names to ensure that those tensors are exported.
If this option is not specified the graph's output tensors are exported. 
--output-names: Export nothing
--output-names a b c: Export the tensors a, b and c
--output-names '*': Export all activation tensors
 """)

    parser.add_argument("--stats",
                        nargs='?',
                        default=None,
                        const='graph.stats',
                        help="""Set this to export statistics. 
If a path is given it must be relative to the directory of the NNEF model.
--stats: Write stats to graph.stats  
--stats stats.txt: Write stats to stats.txt""")

    parser.add_argument("--permissive",
                        action="store_true",
                        help="""Allow some imprecise evaluations""")

    parser.add_argument("--device",
                        required=False,
                        help="""Set device: cpu, cuda, cuda:0, cuda:1, etc.
Default: cuda if available, cpu otherwise.""")

    parser.add_argument(
        '--custom-operations',
        nargs='*',
        help="""Custom modules: e.g. package.module1 package.module2""")

    args = parser.parse_args(args=argv[1:])

    has_weights = not (os.path.isfile(args.network)
                       and not args.network.endswith('.tgz'))
    if not has_weights:
        raise utils.NNEFToolsException(
            "Error: Seems like you have specified an NNEF file without weights. "
            "Please use generate_weights.py")

    return args
Exemple #5
0
def merge_pads(g):
    # type: (NNEFGraph)->None

    t = matcher.Tensor()
    pad = matcher.Operation(name=['box', 'pad'], outputs=t)
    sliding = matcher.Operation(name=[
        'argmax_pool', 'max_pool', 'max_pool_with_index', 'avg_pool', 'conv'
    ],
                                inputs={0: t})

    def condition(m):
        # type: (matcher.Match)->bool
        if not (m[pad].name == 'pad' or
                (m[pad].name == 'box'
                 and all(s == 1 for s in m[pad].attribs.get('size', []))
                 and all(s == 1 for s in m[pad].attribs.get('stride', []))
                 and all(s == 1 for s in m[pad].attribs.get('dilation', []))
                 and not m[pad].attribs.get('normalize', False))):
            return False

        value = m[pad].attribs.get('_value', 0.0)

        if value not in [0.0, float('-inf')]:
            return False

        if value == float('-inf'):
            if not m[sliding].name in [
                    'argmax_pool', 'max_pool', 'max_pool_with_index'
            ]:
                return False

        if m[pad].attribs.get('border', 'constant') != 'constant':
            return False

        if (m[sliding].attribs.get('border', 'constant') != 'constant'
                and any(p != 0 or q != 0
                        for p, q in m[sliding].attribs.get('padding', []))):
            return False

        if m[sliding].name in ['conv'] and any(
                p != 0 or q != 0
                for p, q in m[pad].attribs.get('padding', [])[:2]):
            return False

        return True

    def action(m):
        # type: (matcher.Match)->None
        value = m[pad].attribs.get('_value', 0.0)
        pad_padding = m[pad].attribs.get('padding', [(0, 0) * m[t].rank])
        sliding_padding = m[sliding].attribs.get('padding',
                                                 [(0, 0) * m[t].rank])

        if m[sliding].name in ['conv']:
            pad_padding = pad_padding[2:]

        assert len(pad_padding) == len(sliding_padding)

        m[sliding].attribs['padding'] = [
            (p + pp, q + qq)
            for (p, q), (pp, qq) in zip(pad_padding, sliding_padding)
        ]
        m[sliding].attribs['border'] = 'ignore' if value == float(
            '-inf') else 'constant'

        graph_utils.remove_passthrough(g, m[pad])

    matcher.for_each(graph=g,
                     pattern=sliding,
                     action=action,
                     condition=condition)

    for op in g.operations:
        if op.name in ['box', 'pad'] and '_value' in op.attribs:
            raise utils.NNEFToolsException(
                'Could not export {} with value={}'.format(
                    op.name, op.attribs['_value']))
Exemple #6
0
def UNSUPPORTED(op):
    # print(op)
    # for i in op.inputs:
    #     print(i)
    raise utils.NNEFToolsException(
        'TFLITE to TF_PY: Unsupported op: {}'.format(op.name))
Exemple #7
0
def read_tf_graph_from_protobuf(filename):
    graph_def = tf_pb.GraphDef()
    with open(filename, 'rb') as file:
        graph_def.ParseFromString(file.read())

    graph = TFGraph()
    attrib_graph = TFGraph(
    )  # just a graph to contain the tensors that are in attributes, no need to return this

    attributes_by_node_name = {}
    outputs_by_node_name = {}
    detected_output_count = _detect_output_counts(graph_def)
    for node in graph_def.node:
        outputs = []
        attributes = _get_attributes(node.attr, attrib_graph)
        output_count = _OutputCount.get(node.op, 1)
        if isinstance(output_count, str):
            output_count = attributes[output_count]
        output_count = max(output_count, detected_output_count.get(node.op, 1))
        assert isinstance(output_count, int)
        if output_count >= 1:
            output = TFTensor(graph, utils.anystr_to_str(node.name))
            outputs.append(output)
            for i in range(1, output_count):
                tensor_name = utils.anystr_to_str(node.name) + ':' + str(i)
                output = TFTensor(graph, tensor_name)
                outputs.append(output)

        outputs_by_node_name[node.name] = outputs
        attributes_by_node_name[node.name] = attributes

    tensor_by_name = {
        tensor.name: tensor
        for outputs in six.itervalues(outputs_by_node_name)
        for tensor in outputs
    }

    placeholders = []
    for node in graph_def.node:
        attributes = attributes_by_node_name[node.name]
        outputs = outputs_by_node_name[node.name]

        if node.op == 'Placeholder':
            assert len(outputs) == 1
            tensor = outputs[0]
            tensor.shape = attributes[
                'shape'] if 'shape' in attributes else None
            tensor.dtype = attributes[
                'dtype'] if 'dtype' in attributes else None
            placeholders.append(tensor)
        elif node.op == 'Const':
            assert len(outputs) == 1
            tensor = outputs[0]
            value = attributes['value']
            if isinstance(value, TFTensor):
                tensor.shape = value.shape
                tensor.dtype = value.dtype
                tensor.data = value.data
            else:
                tensor.data = value
        else:
            input_names = [
                name[:-2] if name.endswith(':0') else name
                for name in node.input
            ]
            input_names = [
                name[1:] if name.startswith('^') else name
                for name in input_names
            ]
            for name in input_names:
                if name not in tensor_by_name:
                    print('Info: List of node types in graph: {}\n'.format(
                        sorted(list({node.op
                                     for node in graph_def.node}))))

                    raise utils.NNEFToolsException(
                        "Tensor {} is used, but it is not clear which operation produced it. "
                        "Probably the graph has unsupported dynamic operations."
                        .format(name))
            inputs = tuple([tensor_by_name[name] for name in input_names])
            TFOperation(graph,
                        name=utils.anystr_to_str(node.op),
                        inputs=inputs,
                        outputs=outputs,
                        attribs=attributes)

    for tensor in graph.tensors:
        if tensor.name is not None and ':' not in tensor.name:
            tensor.name += ':0'

    graph.inputs = OrderedDict([(tensor.name.split(':')[0], tensor)
                                for tensor in placeholders])
    graph_outputs = []
    for op in graph.operations:
        if all(len(output.consumers) == 0 for output in op.outputs):
            for output in op.outputs:
                graph_outputs.append(output)

    graph.outputs = OrderedDict([
        ('output' + str(i) if len(graph_outputs) > 1 else 'output', tensor)
        for i, tensor in enumerate(graph_outputs)
    ])

    return graph
Exemple #8
0
def get_args(argv):
    parser = argparse.ArgumentParser(
        description="Create an NNEF tensor from (a batch of) image(s)",
        formatter_class=argparse.RawTextHelpFormatter,
        epilog="""Image processing steps:
    1. The image is loaded as float32 with range [0, 255].
    2. The image is resized to the given size if specified.
    3. The image is transformed to RGB or BGR as requested.
    4. The image is transformed to the specified range. 
    5. The image is normalized as follows: image = (image - mean) / std
    6. The image is transformed to NCHW or NHWC as requested. 
    7. The image is cast to the requested dtype.""")

    parser.add_argument(
        'input',
        nargs='+',
        help="The path or paths of images, e.g. image.jpg, *.jpg, etc.")
    parser.add_argument(
        '--output',
        required=False,
        help="The path of the output tensor, e.g. tensor.dat.\n"
        "By default the standard output is used, but only if the command is piped or redirected."
    )

    parser.add_argument("--color",
                        choices=['RGB', 'BGR'],
                        default='RGB',
                        type=str.upper,
                        help="Input color format. Default: RGB")

    parser.add_argument("--format",
                        choices=['NCHW', 'NHWC'],
                        default='NCHW',
                        type=str.upper,
                        help="Input data format. Default: NCHW")

    parser.add_argument(
        "--range",
        nargs=2,
        type=float,
        default=[0, 255],
        help="Range for representing the image. Default: 0 255")

    parser.add_argument("--mean",
                        nargs='+',
                        type=float,
                        default=[0],
                        help="Mean to subtract from the image. Default: 0\n"
                        "Can be channel-wise, e.g. 127 128 129")

    parser.add_argument(
        "--std",
        nargs='+',
        type=float,
        default=[1],
        help="Standard deviation to divide the image with. Default: 1\n"
        "Can be channel-wise, e.g. 127 128 129")

    parser.add_argument(
        "--size",
        nargs='+',
        required=False,
        type=int,
        help=
        "Target image size: width [height]. Default: The size of the given image(s).\n"
        "E.g. 224 or 640 480")

    parser.add_argument(
        "--dtype",
        default="float32",
        help="Numpy dtype of the generated tensor. Default: float32")

    args = parser.parse_args(args=argv[1:])

    if args.size is not None:
        if len(args.size) == 1:
            args.size *= 2
        if len(args.size) != 2:
            raise utils.NNEFToolsException(
                "The --size parameter must have 1 or 2 arguments if given!")

    return args
Exemple #9
0
def read(
        path,  # type: str
        parser_configs=None,  # type: typing.Optional[typing.List[NNEFParserConfig]]
        input_shape=None,  # type: _InputShapeType
):
    # type: (...)->NNEFGraph

    if not (path.endswith('.tgz') or path.endswith('.nnef')
            or path.endswith('.txt') or os.path.isdir(path)):
        raise utils.NNEFToolsException(
            "Only .tgz or .nnef or .txt files or directories are supported")

    parser_config = NNEFParserConfig.combine_configs(
        parser_configs if parser_configs else [])

    path_to_load = None
    compressed = False

    try:
        if os.path.isdir(path):
            compressed = False
            with_weights = True
            path_to_load = path
        elif path.endswith('.tgz'):
            compressed = True
            with_weights = True
            path_to_load = tempfile.mkdtemp(prefix="nnef_")
            utils.tgz_extract(path, path_to_load)
        elif path.endswith('.nnef') or path.endswith('.txt'):
            compressed = False
            with_weights = False
            path_to_load = path
        else:
            assert False

        # If there are fragments in the graph and also in parser_config
        # we remove the non-standard fragments from parser_config to avoid duplicate fragment definition
        if parser_config.fragments:
            re_graph = re.compile(r"^graph\s|\sgraph\s")
            re_fragment = re.compile(r"^fragment\s|\sfragment\s")
            graph_nnef_path = os.path.join(
                path_to_load,
                'graph.nnef') if os.path.isdir(path_to_load) else path_to_load
            with open(graph_nnef_path, 'r') as f:
                while True:
                    line = f.readline()
                    if not line:
                        break
                    if re_fragment.search(line):
                        parser_config.fragments = NNEFParserConfig.STANDARD_CONFIG.fragments
                        break
                    if re_graph.search(line):
                        break

        parser_graph = parser_config.load_graph(path_to_load)

        if input_shape is not None:
            if not isinstance(input_shape, (tuple, list, dict)):
                raise utils.NNEFToolsException(
                    "input_shape must be list or dict")

            for op in parser_graph.operations:
                if op.name == 'external':
                    name = op.outputs['output']
                    if isinstance(input_shape, dict):
                        if name in input_shape:
                            op.attribs['shape'] = input_shape[name]
                    elif isinstance(input_shape, tuple):
                        op.attribs['shape'] = input_shape[
                            parser_graph.inputs.index(name)]
                    else:
                        op.attribs['shape'] = input_shape

        parser_config.infer_shapes(parser_graph)
        return _read(parser_graph=parser_graph, with_weights=with_weights)

    finally:
        if compressed and path_to_load:
            shutil.rmtree(path_to_load)
Exemple #10
0
def generic_convert_binary(
        converter,  # type: Converter
        nnef_op,  # type: NNEFOperation
        caffe_graph,  # type: CaffeGraph
        is_commutative=False,  # type: bool
        eltwise_name=None,  # type: typing.Optional[str]
        eltwise_axis_needed=False,  # type: typing.Optional[bool]
        eltwise_operation=None,  # type: typing.Optional[int]
        eltwise_coeff=None,  # type: typing.Optional[typing.List[float]]
        learnable_name=None,  # type: typing.Optional[str]
        scalar_name=None,  # type: typing.Optional[str]
        scalar_arg_name=None,  # type: typing.Optional[str]
        scalar_transform=None,  # type: typing.Optional[typing.Callable[[float], float]]
        scalar_name_left=None,  # type: typing.Optional[str]
        scalar_arg_name_left=None,  # type: typing.Optional[str]
):
    # type: (...)->None

    if not scalar_transform:
        scalar_transform = lambda x: x

    def make_learnable(input, variable, output):
        # type: (CaffeTensor, CaffeTensor, CaffeTensor)->None

        axis = -1
        for j, (i, v) in enumerate(zip(input.shape, variable.shape)):
            if i == v and v != 1:
                axis = j
                break

        if axis == -1:
            if not utils.has_gt_1(variable.shape):
                if variable.rank >= 2 and input.rank >= 2:
                    axis = 1
                else:
                    axis = 0
            else:
                raise utils.NNEFToolsException(
                    "Cannot convert binary op: Variable and input shapes are incompatible"
                )

        num_axes = variable.rank - axis

        variable.shape = variable.shape[axis:]
        variable.data = variable.data.reshape(variable.shape)

        CaffeOperation(graph=caffe_graph,
                       name=learnable_name,
                       inputs=(input, variable),
                       outputs=output,
                       attribs=dict(axis=axis, num_axes=num_axes))

    def make_eltwise(input1, input2, output):
        # type: (CaffeTensor, CaffeTensor, CaffeTensor)->None

        if eltwise_axis_needed:
            axis = -1
            for index, (i, j) in enumerate(zip(input1.shape, input2.shape)):
                if i == j and j != 1:
                    axis = index
                    break

            if axis == -1:
                if not utils.has_gt_1(input2.shape):
                    if input2.rank >= 2 and input1.rank >= 2:
                        axis = 1
                    else:
                        axis = 0
                else:
                    raise utils.NNEFToolsException(
                        "Cannot convert binary op: Input shapes are incompatible"
                    )
            if axis > 0:
                input2 = CaffeOperation(
                    graph=caffe_graph,
                    name="Reshape",
                    inputs=input2,
                    outputs=CaffeTensor(graph=caffe_graph,
                                        shape=input2.shape[axis:]),
                    attribs=dict(shape=input2.shape[axis:])).output
        else:
            axis = None

        eltwise = CaffeOperation(graph=caffe_graph,
                                 name=eltwise_name,
                                 inputs=(input1, input2),
                                 outputs=output)
        if eltwise_operation is not None:
            eltwise.attribs['operation'] = eltwise_operation
        if eltwise_coeff is not None:
            eltwise.attribs['coeff'] = eltwise_coeff
        if axis is not None:
            eltwise.attribs['axis'] = axis

    def make_scalar(input, output, scalar):
        # type: (CaffeTensor, CaffeTensor, typing.Union[bool, int, float])->None
        CaffeOperation(graph=caffe_graph,
                       name=scalar_name,
                       inputs=input,
                       outputs=output,
                       attribs={scalar_arg_name: scalar_transform(scalar)})

    def make_scalar_left(input, output, scalar):
        # type: (CaffeTensor, CaffeTensor, typing.Union[bool, int, float])->None
        CaffeOperation(graph=caffe_graph,
                       name=scalar_name_left,
                       inputs=input,
                       outputs=output,
                       attribs={scalar_arg_name_left: scalar})

    nnef_x, nnef_y = nnef_op.inputs
    x, y = converter.converted_tensors((nnef_x, nnef_y))
    z = converter.converted_tensor(nnef_op.output)

    if (learnable_name and nnef_x.data is None
            and converter.is_unique_variable_or_constant(nnef_y)
            and nnef_y.shape != []):
        make_learnable(input=x, variable=y, output=z)
    elif (learnable_name and is_commutative and nnef_y.data is None
          and converter.is_unique_variable_or_constant(nnef_x)
          and nnef_y.shape != []):
        make_learnable(input=y, variable=x, output=z)
    elif (scalar_name and nnef_x.data is None and nnef_y.data is not None
          and nnef_y.shape == []):
        make_scalar(input=x, output=z, scalar=float(nnef_y.get_numpy_array()))
    elif (scalar_name_left and nnef_y.data is None and nnef_x.data is not None
          and nnef_x.shape == []):
        make_scalar_left(input=y,
                         output=z,
                         scalar=float(nnef_x.get_numpy_array()))
    elif (scalar_name and is_commutative and nnef_y.data is None
          and nnef_x.data is not None and nnef_x.shape == []):
        make_scalar(input=y, output=z, scalar=float(nnef_x.get_numpy_array()))
    elif (eltwise_name is not None and nnef_x.data is None
          and nnef_y.data is None):
        make_eltwise(input1=x, input2=y, output=z)
    else:
        raise utils.NNEFToolsException(
            "Unsupported binary operation: {}".format(nnef_op))
Exemple #11
0
 def caffe_pad(nnef_padding):
     if not all(p == q for p, q in nnef_padding):
         raise utils.NNEFToolsException(
             "Asymmetric padding not supported, padding={}".format(
                 nnef_padding))
     return [p for p, _q in nnef_padding]
Exemple #12
0
def export(
        output_path,  # type: str
        feed_dict,  # type: typing.Dict[typing.Any, np.ndarray]
        conversion_info,  # type: ConversionInfo
        graph=None,  # type: typing.Optional[tf.Graph]
        checkpoint_path=None,  # type: str
        tensors_per_iter=25,  # type: int
        verbose=False,  # type: bool
        init_variables=False,  # type: bool
        input_output_only=False,  # type: bool
):
    # type: (...)->None

    if graph is None:
        graph = tf.get_default_graph()

    has_error = False
    tensor_infos = []

    for tensor_info in conversion_info.tensors:
        if tensor_info.is_variable or (input_output_only
                                       and not tensor_info.is_input
                                       and not tensor_info.is_output):
            continue
        try:
            tensor = graph.get_tensor_by_name(tensor_info.source_name)

            if not graph.is_fetchable(tensor):
                print("Warning: Tensor is not fetchable: {}".format(
                    tensor_info.source_name))
            elif not isinstance(tensor, tf.Tensor):
                print("Warning: Not a tensor: {}".format(
                    tensor_info.source_name))
            else:
                tensor_infos.append(
                    _TensorInfo(internal_name=tensor_info.source_name,
                                external_name=tensor_info.target_name,
                                transforms=tensor_info.transforms,
                                tensor=tensor,
                                target_shape=tensor_info.target_shape))
        except KeyError:
            print("Warning: Tensor not found: {}".format(
                tensor_info.source_name))

    with tf.Session() as sess:
        saver = tf.train.Saver() if checkpoint_path else None
        start = 0
        while start < len(tensor_infos):
            tensors = [
                info.tensor
                for info in tensor_infos[start:start + tensors_per_iter]
            ]

            if init_variables:
                sess.run(tf.global_variables_initializer())
            if checkpoint_path is not None:
                if os.path.isdir(checkpoint_path):
                    saver.restore(sess,
                                  tf.train.latest_checkpoint(checkpoint_path))
                else:
                    saver.restore(sess, checkpoint_path)
            values = sess.run(tensors, feed_dict)

            for i, arr in enumerate(values):
                info = tensor_infos[start + i]
                filename = os.path.join(output_path,
                                        info.external_name + ".dat")

                if np.isnan(arr).any():
                    print("Error: '{}' has nan's".format(info.external_name))
                    has_error = True
                elif not np.isfinite(arr).all():
                    print("Error: '{}' has inf's".format(info.external_name))
                    has_error = True
                try:
                    for transform in info.transforms:
                        arr = transform.apply_np(arr)
                    write_nnef_tensor(filename, np.asarray(arr, order='C'))
                except ValueError as e:
                    print("Error: Can not export '{}': {}".format(
                        info.external_name, e))

            start += len(tensors)

            if verbose:
                print("Info: Exported {}/{}".format(start, len(tensor_infos)))
    if has_error:
        raise utils.NNEFToolsException("There were errors!")
def tf_get_input_shapes(input_shape=None):
    def get_shape_for(name):
        if isinstance(input_shape, dict) and name in input_shape:
            return input_shape[name]
        elif isinstance(input_shape, list):
            return list(input_shape)
        elif utils.is_anyint(input_shape):
            return utils.anyint_to_int(input_shape)
        return None

    if isinstance(input_shape, dict):
        input_shape = {(k + ':0' if ':' not in k else k): v
                       for k, v in six.iteritems(input_shape)}

    placeholders = tf_get_placeholders()
    new_input_shapes = {}

    if input_shape is None:
        if any(
                tf_shape_normalize(tensor.shape) is None
                or -1 in tf_shape_normalize(tensor.shape)
                for tensor in placeholders):
            for tensor in placeholders:
                print("Info: Input shape: {}: {}".format(
                    tensor.name, tf_shape_normalize(tensor.shape)))

    for tensor in placeholders:
        tensor_shape = tf_shape_normalize(tensor.shape)
        shape_for_this = get_shape_for(tensor.name) if tensor.name else None
        if isinstance(shape_for_this, list):
            if not utils.compatible_shapes(tensor_shape, shape_for_this):
                raise utils.NNEFToolsException(
                    "The specified shape is incompatible with the original shape for {}. {} vs. {}"
                    .format(tensor.name, shape_for_this, tensor_shape))
            tensor_shape = shape_for_this
        elif shape_for_this is None or isinstance(shape_for_this, int):
            if tensor_shape is None:
                raise utils.NNEFToolsException(
                    "The full shape must be specified for {}, because it is unknown."
                    .format(tensor.name))
            elif -1 in tensor_shape:
                if shape_for_this is None:
                    shape_for_this = 1
                    print(
                        "Warning: Incomplete input shape is auto-fixed: {}. {} -> {}. "
                        "Use --input-shape if other shape is desired.".format(
                            tensor.name, tensor_shape, [
                                shape_for_this if dim == -1 else dim
                                for dim in tensor_shape
                            ]))
                tensor_shape = [
                    shape_for_this if dim == -1 else dim
                    for dim in tensor_shape
                ]
        else:
            assert False

        if tensor.dtype is None:
            raise utils.NNEFToolsException(
                "An input tensor has incomplete dtype, "
                "we have thought that this is impossible, "
                "please file a bug report to NNEF Tools.")

        new_input_shapes[tensor.name] = (tensor.dtype.name, tensor_shape)

    return new_input_shapes