示例#1
0
 def convert_graph(self, source_graph):
     graph_utils.remove_unreachable(source_graph)
     target_graph = super(Converter, self).convert_graph(
         source_graph)  # type: NNEFGraph
     graph_utils.remove_unreachable(target_graph)
     target_graph.generate_missing_names()
     return target_graph
示例#2
0
    def __call__(self, predict_net_path, init_net_path, value_info_path):
        # type: (str, str, str)->Caffe2Graph

        net_def = caffe2_pb.NetDef()
        with open(predict_net_path, 'rb') as f:
            net_def.ParseFromString(f.read())
        predict_graph = get_graph_from_net_def(net_def)

        net_def = caffe2_pb.NetDef()
        with open(init_net_path, 'rb') as f:
            net_def.ParseFromString(f.read())
        init_graph = get_graph_from_net_def(net_def)

        value_info_graph = get_graph_from_value_info(
            json_utils.load(value_info_path))

        combine_graphs_into_predict_graph(predict_graph, init_graph,
                                          value_info_graph)

        tensor_names = {tensor.name for tensor in predict_graph.tensors}
        for op in list(predict_graph.operations):
            unify_op(op, tensor_names)
            caffe2_shapes.infer_shape(op, self.custom_shapes)
        predict_graph.generate_missing_names()
        graph_utils.remove_unreachable(predict_graph)

        return predict_graph
示例#3
0
    def __call__(self, filename):
        # type: (str)->ONNXGraph

        g = read_onnx_from_protobuf(filename)

        if self._output_names is not None:
            outputs = [
                tensor for tensor in g.tensors
                if tensor.name in self._output_names
            ]

            if len(outputs) != len(self._output_names):
                found_names = [tensor.name for tensor in outputs]
                not_found_names = [
                    output_name for output_name in self._output_names
                    if output_name not in found_names
                ]
                raise utils.NNEFToolsException(
                    "Could not find tensor(s) in graph: {}".format(
                        not_found_names))

            g.outputs = outputs

        graph_utils.remove_unreachable(g)

        if self._infer_shapes:
            onnx_shape_inference.infer_shapes(
                g,
                source_shapes=self._input_shape,
                custom_shapes=self._custom_shapes)

        return g
示例#4
0
def infer_shapes(
        graph,  # type: ONNXGraph
        source_shapes=None,
        # type: typing.Union[typing.Dict[str, typing.List[int]], typing.List[int], int, None]
        custom_shapes=None,  # type: typing.Optional[typing.Dict[str, typing.Callable]]
):
    # type: (...)->None

    shape_functions = dict(_DefaultShapes)
    if custom_shapes:
        shape_functions.update(custom_shapes)

    graph.sort()

    shape_fixer.fix_input_shapes(graph, source_shapes)

    for op in graph.operations:
        # Shape prop
        assert op.name in shape_functions, "No shape function for {}".format(
            op.name)
        inferred_shapes, inferred_dtypes = shape_functions[op.name](op)
        assert not utils.has_le_0(inferred_shapes)
        assert len(inferred_shapes) == len(inferred_dtypes) == len(op.outputs)
        for new_shape, new_dtype, tensor in zip(inferred_shapes,
                                                inferred_dtypes, op.outputs):
            assert utils.compatible_shapes(tensor.shape, new_shape)
            tensor.shape = new_shape
            assert tensor.dtype is None or tensor.dtype == new_dtype
            tensor.dtype = new_dtype

    graph_utils.remove_unreachable(graph)
示例#5
0
 def convert_graph(self, source_graph):
     # type: (CaffeGraph)->NNEFGraph
     caffe_to_nnef_passes.pre_conversion_pass(source_graph)
     target_graph = super(Converter, self).convert_graph(
         source_graph)  # type: NNEFGraph
     graph_utils.remove_unreachable(target_graph)
     target_graph.generate_missing_names()
     return target_graph
示例#6
0
def pre_conversion_transform(g):
    # type: (TFGraph)->None

    trafo_by_op_name = {
        "tf.cast": transform_cast,
        "tf.fill": transform_fill,
        "tf.zeros": transform_zeros_ones_like,
        "tf.ones": transform_zeros_ones_like,
        "tf.zeros_like": transform_zeros_ones_like,
        "tf.ones_like": transform_zeros_ones_like,
        "tf.range": transform_range,
        "tf.strided_slice": transform_strided_slice,
        "tf.nn.fused_batch_norm": transform_fused_batch_norm,
        "_tf.TransposeGrad": transform_transpose_grad,
        "_tf.strided_slice_grad": transform_strided_slice_grad,
        "_tf.sqrt_grad": transform_sqrt_grad,
        "_tf.elu_grad": transform_elu_grad,
        "_tf.relu_grad": transform_relu_grad,
        "_tf.relu6_grad": transform_relu6_grad,
        "_tf.softplus_grad": transform_softplus_grad,
        "_tf.rsqrt_grad": transform_rsqrt_grad,
        "_tf.sigmoid_grad": transform_sigmoid_grad,
        "_tf.tanh_grad": transform_tanh_grad,
        "_tf.reciprocal_grad": transform_reciprocal_grad,
        "_tf.bias_add_grad": transform_bias_add_grad,
        "_tf.MinOrMaxGrad": transform_min_or_max_grad,
        "_tf.lrn_grad": transform_lrn_grad,
    }

    # tf.identity is now not a passthrough, we convert it to copy and the optimizer can remove it
    passthroughs = ["tf.stop_gradient", "tf.nn.dropout"]

    tf_py_unify.unify_ops(g)

    for op in list(g.operations):
        trafo = trafo_by_op_name.get(op.name)
        if trafo:
            trafo(g, op)

    transform_cgf_stb(g)
    transform_bts_conv_stb(g)
    transform_pad(g)
    transform_add_conv(g)
    transform_bias_add_conv(g)

    graph_utils.remove_passthroughs(
        g, is_passthrough=lambda op_: op_.name in passthroughs)
    graph_utils.remove_unreachable(g)

    transform_separate_inputs_and_outputs(g)
    transform_separate_duplicated_outputs(g)

    g.generate_missing_names()
示例#7
0
def convert(tf_graph, enable_default_conversion=False):
    # type: (TFGraph, bool)->None

    tf_graph.sort()

    transform_fuse_bias_add_to_conv(tf_graph)
    transform_fuse_add_to_matmul(tf_graph)
    transform_fuse_activations(tf_graph)

    for tensor in tf_graph.tensors:
        tensor.dtype = _to_tflite_dtype(tensor.dtype)

    for op in list(tf_graph.operations):
        # Conversion
        _DefaultConverters.get(op.name, convert_custom)(op)

    graph_utils.remove_unreachable(tf_graph)
    tf_graph.generate_missing_names()
示例#8
0
    def __call__(self, filename):
        g = read_tf_graph_from_protobuf(filename)

        if self._output_names is not None:
            outputs = [tensor for tensor in g.tensors if tensor.name in self._output_names]

            if len(outputs) != len(self._output_names):
                found_names = [tensor.name for tensor in outputs]
                not_found_names = [output_name for output_name in self._output_names if output_name not in found_names]
                raise utils.NNEFToolsException("Could not find tensor(s) in graph: {}".format(not_found_names))

            g.outputs = outputs

        graph_utils.remove_unreachable(g)

        unsupported_ops = set(op.name for op in g.operations if op.name not in tf_pb_to_tf_py.DefaultConverters)
        if unsupported_ops:
            raise utils.NNEFToolsException("Unsupported operation(s): {}".format(unsupported_ops))
        if self._convert_to_tf_py:
            tf_pb_to_tf_py.evaluate_and_convert(g, source_shapes=self._input_shape)
        return g
示例#9
0
def convert(tf_graph, enable_default_conversion=False):
    # type: (TFGraph, bool)->None

    tf_graph.sort()

    transform_fuse_bias_add_to_conv(tf_graph)
    transform_fuse_add_to_matmul(tf_graph)
    transform_fuse_activations(tf_graph)

    for tensor in tf_graph.tensors:
        tensor.dtype = _to_tflite_dtype(tensor.dtype)

    for op in list(tf_graph.operations):
        # Conversion
        assert enable_default_conversion or op.name in _DefaultConverters, \
            "No tf_py_to_tflite converter for {}".format(op.name)

        if op.name in _DefaultConverters:
            _DefaultConverters[op.name](op)

    graph_utils.remove_unreachable(tf_graph)
    tf_graph.generate_missing_names()
示例#10
0
def propagate(graph, source_shapes=None):
    # type: (ONNXGraph, typing.Union[typing.Dict[str, typing.List[int]], typing.List[int], int, None])->None

    graph.sort()

    shape_fixer.fix_input_shapes(graph, source_shapes)

    for op in graph.operations:
        # Shape prop
        assert op.name in _DefaultPropagators, "No shape propagator for {}".format(
            op.name)
        propagated_shapes, propagated_dtypes = _DefaultPropagators[op.name](op)
        assert not utils.has_le_0(propagated_shapes)
        assert len(propagated_shapes) == len(propagated_dtypes) == len(
            op.outputs)
        for new_shape, new_dtype, tensor in zip(propagated_shapes,
                                                propagated_dtypes, op.outputs):
            assert utils.compatible_shapes(tensor.shape, new_shape)
            tensor.shape = new_shape
            assert tensor.dtype is None or tensor.dtype == new_dtype
            tensor.dtype = new_dtype

    graph_utils.remove_unreachable(graph)
示例#11
0
def convert(tf_graph, enable_default_conversion=False):
    # type: (TFGraph, bool)->None

    tf_graph.sort()

    for tensor in tf_graph.tensors:
        if tensor.name is not None and ':' not in tensor.name:
            # The tf-to-nnef converter distinguishes original and generated tensors based on the presence of the ':'
            tensor.name = tensor.name + ":0"
        tensor.dtype = _to_tf_py_dtype(tensor.dtype)

    for op in list(tf_graph.operations):
        # Conversion
        assert enable_default_conversion or op.name in _DefaultConverters, \
            "No tflite_to_tf_py converter for {}".format(op.name)

        act_fun = op.attribs.get('fused_activation_function', None)
        if act_fun == 'NONE':
            act_fun = None
        output = op.output if act_fun else None

        if op.name in _DefaultConverters:
            _DefaultConverters[op.name](op)

        if act_fun:
            assert act_fun in ["RELU", "RELU6"]
            last_new_op = output.producer
            last_new_op.outputs = (TFTensor(graph=op.graph,
                                            name=None,
                                            shape=list(output.shape),
                                            dtype=output.dtype), )
            TFOperation(graph=last_new_op.graph,
                        name=_to_tf_py_activation_function(act_fun),
                        inputs=last_new_op.output,
                        outputs=output)

    graph_utils.remove_unreachable(tf_graph)
示例#12
0
def post_conversion_pass(g):
    # type: (NNEFGraph)->None
    graph_utils.remove_unreachable(g)
    # _small_variables_to_consts(g)
    _merge_pads(g)
    graph_utils.remove_unreachable(g)
def pre_conversion_pass(g):
    # type: (CaffeGraph)->None
    graph_utils.remove_unreachable(g)
    graph_utils.remove_passthroughs(g, is_passthrough=lambda op: op.name in ('Dropout', 'Silence'))
    _merge_batch_norm_and_scale(g)
    graph_utils.remove_unreachable(g)
示例#14
0
def post_conversion_pass(g):
    # type: (CaffeGraph)->None
    graph_utils.remove_unreachable(g)
    _unite_powers(g)
    _merge_up_bias(g)
    graph_utils.remove_unreachable(g)
示例#15
0
def pre_conversion_pass(g):
    # type: (NNEFGraph)->None
    graph_utils.remove_unreachable(g)
    _create_thresholds(g)
    _create_elus(g)
    graph_utils.remove_unreachable(g)
示例#16
0
def trace(
    network_function,  # type: typing.Callable[[], typing.Any]
    checkpoint_path=None,  # type: typing.Optional[str]
    raise_on_missing_weight=True,  # type: bool
    expand_gradients=False,  # type: bool
    custom_traceable_functions=None  # type: typing.Optional[typing.List[TraceableFunction]]
):
    # type: (...)->TFGraph

    if custom_traceable_functions is None:
        custom_traceable_functions = []

    traceable_functions = DefaultTraceableFunctions + custom_traceable_functions
    for trf in traceable_functions:
        trf.eval_functions()

    functions_by_name = {
        trf.op_proto.op_name: trf.functions
        for trf in traceable_functions
    }
    if expand_gradients:
        del functions_by_name["tf.gradients"]

    tracer = _InvocationTracer(functions_by_name)

    result = tracer.trace(network_function, allow_nesting=expand_gradients)
    result = _eliminate_named_tuples(result)
    invocations = tracer.invocations

    for invocation in invocations:
        invocation.args = _eliminate_named_tuples(invocation.args)
        invocation.result = _eliminate_named_tuples(invocation.result)
    invocations = _eliminate_identities(invocations)

    # _print_invocations(invocations)
    if expand_gradients:
        _fix_strange_grad_functions(invocations)
        invocations = _eliminate_nesting(invocations)
        # _print_invocations(invocations)

    assert not _check_has_untraced_ops(invocations, result), \
        "There were untraced operations. " \
        "Add the untraced operations to custom_functions_to_trace or use only supported operations."

    op_proto_by_name = {
        trf.op_proto.op_name: trf.op_proto
        for trf in traceable_functions
    }
    tf_graph = _to_tf_graph(network_function.__name__, invocations, result,
                            op_proto_by_name)
    graph_utils.remove_unreachable(tf_graph)

    if checkpoint_path:
        checkpoint_reader = tf.contrib.framework.load_checkpoint(
            checkpoint_path)
        for tensor in tf_graph.list_variables():
            assert tensor.name.endswith(
                "/read:0"), "Strange variable name: {}".format(tensor.name)
            var_name = tensor.name[:-len("/read:0")]
            if checkpoint_reader.has_tensor(var_name):
                tensor.data = checkpoint_reader.get_tensor(var_name)
                if not isinstance(tensor.data, np.ndarray):
                    tensor.data = np.array(tensor.data).reshape(tensor.shape)
            elif raise_on_missing_weight:
                assert False, "Checkpoint {} does not have var {}".format(
                    checkpoint_path, var_name)

    return tf_graph
示例#17
0
def transform_remove_inverse_transposes(
        g,  # type: BaseGraph
        transforms_by_name,  # type:typing.Dict[str, typing.List[Transform]]
        merge_into_constants,  # type: bool
        merge_into_variables,  # type: bool
        driver,  # type: DataFormatOptimizationDriver
        transposable_ops=None,  # type: typing.Optional[typing.List[TransposableOperation]]
):
    # type: (...)-> None

    if transposable_ops is None:
        transposable_ops = []

    transposable_op_by_name = {
    }  # type: typing.Dict[str, TransposableOperation]
    transposable_op_by_name.update({top.name: top for top in transposable_ops})

    for op in g.operations:
        if op.name == driver.transpose_op_name and op.output.rank > len(
                driver.get_axes_from_transpose(op)):
            driver.set_axes_on_transpose(
                op,
                driver.get_axes_from_transpose(op) + list(range(
                    op.output.rank))[len(driver.get_axes_from_transpose(op)):])

    matches = _find_inverse_transposes(
        g,
        transposable_op_names=set(six.iterkeys(transposable_op_by_name)),
        merge_into_constants=merge_into_constants,
        merge_into_variables=merge_into_variables,
        driver=driver)

    for axes, subgraph in matches:
        upper_perm = axes if subgraph.started_down else utils.inverse_permutation(
            axes)
        lower_perm = utils.inverse_permutation(upper_perm)

        upper_boundary = [
            be for be in subgraph.boundary_elements if not be.from_up
        ]
        lower_boundary = [
            be for be in subgraph.boundary_elements if be.from_up
        ]

        for _, tensor in upper_boundary:
            if tensor.producer is not None and tensor.producer.name == driver.transpose_op_name:
                if tensor in g.outputs:
                    graph_output = driver.create_tensor(
                        graph=g,
                        name=tensor.name,
                        shape=utils.apply_permutation(
                            tensor.producer.input.shape, upper_perm),
                        dtype=tensor.producer.input.dtype)
                    driver.create_transpose_op(graph=g,
                                               input=tensor.producer.input,
                                               axes=list(upper_perm),
                                               output=graph_output)
                    graph_utils.replace_tensor_in_outputs(
                        g, tensor, graph_output)
                elif (len(tensor.producer.input.consumers) == 1
                      and tensor.producer.input not in g.inputs
                      and tensor.producer.input not in g.outputs):
                    tensor.producer.input.name = tensor.name
                    add_transform(transforms_by_name, tensor.producer.input,
                                  Transpose(lower_perm))
                remove_passthrough_ex(g, tensor.producer)
            else:
                assert (merge_into_variables and tensor.is_variable) \
                       or (merge_into_constants and tensor.is_constant)

                apply_transpose_to_varlike(tensor, lower_perm,
                                           transforms_by_name)

        skipped_ops = set(
            tensor.producer for tensor in
            subgraph.skipped_tensors)  # type: typing.Set[BaseOperation]
        for op in skipped_ops:
            assert op.name in transposable_op_by_name
            transposable_op_by_name[op.name].dg_transpose(
                _transposer, g, op, lower_perm)
            for output in op.outputs:
                if output in g.outputs:
                    graph_output = driver.create_tensor(graph=g,
                                                        name=output.name,
                                                        shape=output.shape,
                                                        dtype=output.dtype)
                    driver.create_transpose_op(graph=g,
                                               input=output,
                                               axes=list(upper_perm),
                                               output=graph_output)

                    graph_utils.replace_tensor_in_outputs(
                        g, output, graph_output)
                    output.name = None
                    output.shape = utils.apply_permutation(
                        output.shape, lower_perm)
                else:
                    output.shape = utils.apply_permutation(
                        output.shape, lower_perm)
                    add_transform(transforms_by_name, output,
                                  Transpose(lower_perm))

        for _, tensor in lower_boundary:
            if tensor.producer is not None and tensor.producer.name == driver.transpose_op_name:
                if tensor in g.outputs:
                    graph_output = driver.create_tensor(
                        graph=g,
                        name=tensor.name,
                        shape=tensor.producer.input.shape,
                        dtype=tensor.producer.input.dtype)

                    driver.create_copy_op(graph=g,
                                          input=tensor.producer.input,
                                          output=graph_output)

                    graph_utils.replace_tensor_in_outputs(
                        g, tensor, graph_output)
                remove_passthrough_ex(g, tensor.producer)
            elif tensor.producer is not None and tensor.producer.name == driver.squeeze_op_name:
                driver.set_axes_on_squeeze(
                    tensor.producer,
                    sorted(
                        Transposer.apply_permutation_to_axes(
                            driver.get_axes_from_squeeze(tensor.producer),
                            lower_perm)))
            else:
                assert False

    graph_utils.remove_unreachable(g)
示例#18
0
def combine_graphs_into_predict_graph(predict_graph, init_graph,
                                      value_info_graph):
    # type: (Caffe2Graph, Caffe2Graph, Caffe2Graph)->None
    input_names = {input.name for input in value_info_graph.inputs}
    predict_tensor_by_name = {
        tensor.name: tensor
        for tensor in predict_graph.tensors
    }
    in_init_but_not_in_predict = []
    for init_tensor in init_graph.tensors:
        if init_tensor.name not in input_names:
            if not init_tensor.producer:
                raise ReadException(
                    "Tensor '{}' does not have a producer in the init-net".
                    format(init_tensor.name))
            init_op = init_tensor.producer
            if init_op.name not in Caffe2DTypeByInitializer:
                raise ReadException("Initializer '{}' is not supported".format(
                    init_op.name))
            if init_tensor.name not in predict_tensor_by_name:
                in_init_but_not_in_predict.append(init_tensor.name)
                continue
            predict_tensor = predict_tensor_by_name[
                init_tensor.name]  # type: Caffe2Tensor
            assert predict_tensor.producer is None and predict_tensor.shape is None
            predict_tensor.shape = list(init_op.attribs['shape'])
            predict_tensor.dtype = Caffe2DTypeByInitializer[init_op.name]
            predict_tensor.data = np.reshape(init_op.attribs['values'],
                                             init_op.attribs['shape'])
            if init_op.name in ('Int8GivenTensorFill',
                                'Int8GivenIntTensorFill'):
                predict_tensor.quantization = Caffe2Quantization(
                    init_op.attribs['Y_scale'],
                    init_op.attribs['Y_zero_point'])
    input_tensors = []
    for value_info_tensor in sorted(value_info_graph.tensors,
                                    key=lambda t: t.name):
        if value_info_tensor.name not in predict_tensor_by_name:
            possible_input_names = ' or '.join(
                sorted([
                    '"' + t.name + '"' for t in predict_graph.tensors
                    if t.producer is None and (
                        t.data is None or t.data.size <= 1)
                ]))
            raise ReadException(
                "Tensor '{}' is in value-info but not in predict-net.\n"
                "Possible input tensors: {}".format(value_info_tensor.name,
                                                    possible_input_names))
        input_tensor = predict_tensor_by_name[value_info_tensor.name]
        assert input_tensor.producer is None and input_tensor.shape is None and input_tensor.data is None
        input_tensor.shape = value_info_tensor.shape
        input_tensor.dtype = value_info_tensor.dtype
        input_tensors.append(input_tensor)
    predict_graph.inputs = input_tensors
    if not predict_graph.outputs:
        predict_graph.outputs = [
            t for t in predict_graph.tensors if not t.consumers
        ]
    graph_utils.remove_unreachable(predict_graph)
    for tensor in predict_graph.tensors:
        if (not tensor.producers and not tensor.is_variable
                and not tensor.is_constant
                and tensor not in predict_graph.inputs):
            raise ReadException(
                "Tensor '{}' has no initializer but is not listed as input in value-info."
                .format(tensor.name))

    if in_init_but_not_in_predict:
        print(
            "Warning: There were tensors in the init-net that are not present in the predict-net: {}"
            .format(in_init_but_not_in_predict))
    for tensor in predict_graph.tensors:
        if tensor.data is not None and tensor.data.size == 0:
            print(
                "Warning: Tensor '{}' possibly missing from value_info.json (has zero size)"
                .format(tensor.name))