示例#1
0
    def __init__(self, model: tflite.Model, graph: tflite.SubGraph):
        super().__init__(model, graph)

        self.ops = []  # the OP that has TFLite peer
        self.op_all = []  # includes helper OP

        self.inputs = []
        self.outputs = []
        self.initializer = set()
        self.value_info = set()

        self.tflite = graph
        self.TFactory = TensorFactory(model, graph)
        self.OPCFactory = OpFactory(self.TFactory)

        self.setInited()
示例#2
0
    def parse(self):
        logger.debug("Parsing %s...", self.type)
        op = self.tflite
        opcode = self.model.OperatorCodes(op.OpcodeIndex()).BuiltinCode()
        assert(opcode is tflite.BuiltinOperator.TRANSPOSE)

        assert(op.InputsLength() == 2)
        assert(op.OutputsLength() == 1)
        self.parseInput(0)
        self.parseOutput(0)

        ii = op.Inputs(1)
        self.attrs['perm'] = TensorFactory.getData(self.model, self.graph, ii, 'int32')

        self.setParsed()
示例#3
0
    def parse(self):
        logger.debug("Parsing %s...", self.type)

        op = self.tflite
        opcode = self.model.OperatorCodes(op.OpcodeIndex()).BuiltinCode()
        assert(opcode in self.TypeMapping)

        assert(op.InputsLength() == 2)
        assert(op.OutputsLength() == 1)
        it = self.parseInput(0)
        ot = self.parseOutput(0)

        # options
        ai = op.Inputs(1)
        self.attrs['axes'] = TensorFactory.getData(self.model, self.graph, ai, 'int32')
        self.attrs['keepdims'] = 1 if (len(ot.shape) == len(it.shape)) else 0

        self.setParsed()
示例#4
0
    def parse(self):
        logger.debug("Parsing %s...", self.type)

        op = self.tflite
        opcode = self.model.OperatorCodes(op.OpcodeIndex()).BuiltinCode()
        assert(opcode in self.TypeMapping)

        assert(op.InputsLength() == 2)

        # input
        it = self.parseInput(1)

        # options
        ai = op.Inputs(0)
        axis = TensorFactory.getData(self.model, self.graph, ai, 'int32')
        assert(axis.size == 1)
        self.attrs['axis'] = int(axis[0])

        op_opt = op.BuiltinOptions()
        option = tflite.SplitOptions()
        option.Init(op_opt.Bytes, op_opt.Pos)
        # TFLite outputs have same shape
        split_size = option.NumSplits()
        assert(isinstance(split_size, int))
        assert(op.OutputsLength() == split_size)
        self.attrs['split'] = np.zeros(split_size).astype('int')

        # XXX workaround for ONNXRuntime: doesn't support all-zero `split`.
        split = it.shape[self.attrs['axis']] / split_size
        self.attrs['split'] = np.full((split_size,), split).astype('int')

        # output
        for i in range(split_size):
            self.parseOutput(i)

        self.setParsed()
示例#5
0
class Graph(T2OBase):
    def __init__(self, model: tflite.Model, graph: tflite.SubGraph):
        super().__init__(model, graph)

        self.ops = []  # the OP that has TFLite peer
        self.op_all = []  # includes helper OP

        self.inputs = []
        self.outputs = []
        self.initializer = set()
        self.value_info = set()

        self.tflite = graph
        self.TFactory = TensorFactory(model, graph)
        self.OPCFactory = OpFactory(self.TFactory)

        self.setInited()

    def _collectOpAndTensor(self):
        self.op_all.clear()

        # collect operators
        def _recursive(op):
            for cur_op in op.pre:
                _recursive(cur_op)
            self.op_all.append(op)
            for cur_op in op.post:
                _recursive(cur_op)

        for op in self.ops:
            _recursive(op)

        # collect tensors
        assert (len(self.op_all) > 0)
        self.initializer.clear()
        self.value_info.clear()
        for op in self.op_all:
            for t in op.inputs + op.outputs:
                if t.isInitializer:
                    self.initializer.add(t)
                else:
                    self.value_info.add(t)

    def parse(self):
        logger.debug("Parsing the Graph...")
        # operators
        for i in range(self.graph.OperatorsLength()):
            logger.debug("Parsing operator: %d", i)
            op = self.OPCFactory.create(i)
            op.parse()
            self.ops.append(op)

        # inputs
        for i in range(self.graph.InputsLength()):
            # FIXME: assert they have been created.
            index = self.graph.Inputs(i)
            t = self.TFactory.get(index)
            self.inputs.append(t)

        # outputs
        for i in range(self.graph.OutputsLength()):
            index = self.graph.Outputs(i)
            t = self.TFactory.get(index)
            self.outputs.append(t)

        self._collectOpAndTensor()

        self.setParsed()

    def validate(self):
        self._collectOpAndTensor()
        for op in self.op_all:
            op.validate()
        for t in self.initializer | self.value_info:
            t.validate()

    def convert(self, explicit_layouts):
        logger.debug("Converting...")

        logger.debug("Handling data layout...")
        for op in self.ops:
            for t in op.inputs + op.outputs:
                if t.name in explicit_layouts:
                    assert (t.layout is None)
                    layouts = explicit_layouts[t.name]
                    assert (len(layouts) == 2)
                    t.layout = Layout(layouts[0], layouts[1])
        self._propagateLayout()
        self._collectOpAndTensor()

        logger.debug("Translating quantization semantic...")
        for t in self.value_info | self.initializer:
            deqt = handleQuantizationTensor(self.TFactory, t)
            for i, o in enumerate(self.outputs):
                if o == t:
                    self.outputs[i] = deqt
        self._collectOpAndTensor()

        logger.debug("Graph:\n%s", str(self))

        self.validate()
        for op in self.op_all:
            op.convert()

        logger.debug("Making ONNX...")
        onodes = [n.onnx for n in self.op_all]
        oinputs = [t.onnx for t in self.inputs]
        ooutputs = [t.onnx for t in self.outputs]
        initializer = [t.onnx for t in self.initializer]
        value_info = [t.onnx for t in self.value_info]

        self.onnx = helper.make_graph(onodes,
                                      'pre-alpha',
                                      oinputs,
                                      ooutputs,
                                      initializer=initializer,
                                      value_info=value_info)
        self.setConverted()

    def _propagateLayout(self):  # noqa: C901
        logger.debug("Propragating layout across graph...")

        # collect tensors
        T_toWalk = set()
        T_wild = set()
        tensor_count = len(self.value_info) + len(self.initializer)
        for t in self.value_info | self.initializer:
            if t.layout is None:
                T_wild.add(t)
            else:
                T_toWalk.add(t)
        logger.debug(
            "Propagation: %d tensors in total, %d to walk, %d at wild",
            tensor_count, len(T_toWalk), len(T_wild))

        # propagrate layout across graph
        T_ignored = set()
        T_walked = set()
        while (len(T_toWalk) != 0):
            T = T_toWalk.pop()
            logger.debug("Propagation: walking %s", T.shorty)
            for n in T.producers + T.consumers:
                for t in n.propagatableTensors():
                    if t is T:
                        continue
                    if t in T_wild:
                        logger.debug("Propagation: propagated to %s", t.shorty)
                        assert (t.layout is None)
                        T_wild.remove(t)
                        if t.isScalar:
                            T_ignored.add(t)
                        else:
                            t.layout = copy.deepcopy(T.layout)
                            T_toWalk.add(t)
            T_walked.add(T)
        logger.debug("Propagation: wild tensors %d, ignored tensors %d",
                     len(T_wild), len(T_ignored))

        # update tensor and operator
        for t in T_walked:
            t.transform()
        self._collectOpAndTensor()
        for op in self.op_all:
            op.transform()

    def _dump(self, tag, container, useShorty):
        dump = str()
        for e in container:
            dump += '[%s] %s\n' % (tag, e.shorty if useShorty else e)
        return dump

    @property
    def shorty(self):
        string = str()
        string += self._dump('OP', self.op_all, True)
        string += self._dump('Input', self.inputs, True)
        string += self._dump('Output', self.outputs, True)
        string += self._dump('Initializer', self.initializer, True)
        string += self._dump('Value Info', self.value_info, True)
        return string

    def __str__(self):
        string = str()
        string += self._dump('OP', self.op_all, False)
        string += self._dump('Input', self.inputs, False)
        string += self._dump('Output', self.outputs, False)
        string += self._dump('Initializer', self.initializer, False)
        string += self._dump('Value Info', self.value_info, False)
        return string