Beispiel #1
0
    def _init_lnf_from_tf_node_def(tf_node_def):
        lnf = lgf_pb2.LNF()
        lnf.name = tf_node_def.name

        # Node attributes
        lnf.supported = False
        if tf_node_def.op == "LGFSubgraph":
            # Subgraph node
            lnf.subgraph.SetInParent()
            lnf.subgraph.graph.ParseFromString(
                tf_node_def.attr["serialized_subgraph"].s)
        else:
            # Original node
            lnf.original.SetInParent()
            lnf.original.t = graph_types_pb2.TFSavedModel
            lnf.original.op = ImportTFSavedModelBase.OP_MAP.get(
                tf_node_def.op, ops_pb2.UNKNOWN)

            if lnf.original.op == ops_pb2.ENTER:
                lnf.original.attr[
                    lgf_graph.LightGraph.
                    IS_CONST_ATTR].b = tf_node_def.attr["is_constant"].b

            lnf.original.serialized_node = tf_node_def.SerializeToString()

        return lnf
Beispiel #2
0
    def create_simple_node(self,
                           node_name,
                           node_type,
                           inputs,
                           outputs,
                           control_inputs,
                           supported=True):
        new_node = lgf_pb2.LNF()
        new_node.name = node_name
        new_node.supported = supported
        getattr(new_node, node_type).SetInParent()

        # Inputs
        for inp in inputs:
            new_node.inputs.add().CopyFrom(inp)
            new_node.inputs[-1].dtype.CopyFrom(self._get_dtype())

        # Outputs
        for outp in outputs:
            new_node.outputs.add().CopyFrom(outp)
            new_node.outputs[-1].dtype.CopyFrom(self._get_dtype())

        # Control inputs

        new_node.control_inputs.extend(control_inputs)

        return new_node
    def sv_max_graph(inp_shape=(1, 100),
                     inp_dtype_t=dtypes_pb2.DT_QINT,
                     inp_dtype_p=8,
                     num_nodes=1):
        inp1 = lgf_pb2.EdgeInfo()
        inp1.name = "inp_ten1"
        inp1.port = 0
        inp1.dtype.t = inp_dtype_t
        inp1.dtype.p = inp_dtype_p
        inp1.shape.d.extend(inp_shape)

        nodes = []
        last_edge = inp1
        for i in range(num_nodes):
            outp = lgf_pb2.EdgeInfo()
            outp.CopyFrom(inp1)
            outp.name = "out_ten_{0}".format(i)

            n = lgf_pb2.LNF()
            n.name = outp.name
            n.sv_max.SetInParent()
            n.inputs.add().CopyFrom(last_edge)
            n.outputs.add().CopyFrom(outp)
            n.sv_max.scalar = 64
            n.supported = True
            last_edge = n.outputs[0]
            nodes.append(n)

        return lgf_graph.LightGraph(nodes,
                                    input_edges=[inp1],
                                    output_edges=[last_edge])
Beispiel #4
0
    def transform(self, opu_node, light_graph):
        transform_result = self.create_transform_result()

        phasify_node, phasify_subgraph_nodes = self._get_foldable_phasify_nodes(
            opu_node, light_graph)

        if phasify_subgraph_nodes is None:
            return transform_result

        # Create a new opu node
        new_opu_node = lgf_pb2.LNF()
        new_opu_node.CopyFrom(opu_node)
        matmul = opu_op_transform.OPUOpTransform.get_matmul_from_opu_node(
            new_opu_node)
        matmul.phasify_is_folded = True

        # Get phases and dequant scales
        self._get_phases_and_dequant_scales(new_opu_node, light_graph,
                                            phasify_node,
                                            phasify_subgraph_nodes,
                                            transform_result)

        # Compute the dequant bias if necessary
        if matmul.using_quant_bias:
            self._get_dequant_bias(new_opu_node, light_graph, transform_result)

        transform_result.to_replace.add().node.CopyFrom(new_opu_node)
        return transform_result
    def onnx_node_to_lnf(self, onnx_node):
        lnf = lgf_pb2.LNF()
        lnf.name = onnx_node.name
        lnf.supported = False
        lnf.original.SetInParent()
        lnf.original.t = graph_types_pb2.ONNXModel
        lnf.original.op = ImportONNXModel.OP_MAP.get(onnx_node.op_type,
                                                     ops_pb2.UNKNOWN)
        lnf.original.serialized_node = onnx_node.SerializeToString()

        # Node inputs in edge info format are stored here
        node_input_edges = [
            self.onnx_edge_to_edge_info(self.get_name_and_port(input_edge))
            for input_edge in onnx_node.input
        ]
        for node_input_edge_info in node_input_edges:
            lnf.inputs.add().CopyFrom(node_input_edge_info)

        node_output_edges = [
            self.onnx_edge_to_edge_info(self.get_name_and_port(output_edge))
            for output_edge in onnx_node.input
        ]

        lnf.outputs.extend(node_output_edges)

        return lnf
    def _add_cast_node(self, node, input_edge, input_node,
                       matching_output_edge):
        """
        Adds a cast node between the edges, so the graph
        will have input_node --{matching_output_edge}--> cast --{input_edge}--> node
        """
        # Create a cast node
        cast_node = lgf_pb2.LNF()
        cast_node.name = self._get_new_node_name(matching_output_edge.name +
                                                 "_cast")

        # Input and output info
        cast_node.inputs.add().CopyFrom(matching_output_edge)
        cast_node.outputs.add().CopyFrom(input_edge)
        cast_node.outputs[0].name = cast_node.name
        cast_node.outputs[0].port = 0

        self.process_cast_node(cast_node, input_node, node, self._sw_config)

        # Create transform result
        return base_transform.BaseTransform.create_transform_result(
            to_add=[cast_node],
            to_reroute=[
                (transform_result_pb2.ToReroute.edge_reroute.DESCRIPTOR.name,
                 [node.name], input_edge, cast_node.outputs[0])
            ])
Beispiel #7
0
    def transform(self, opu_node, light_graph):
        node_name = opu_node.name
        if opu_op_transform.OPUOpTransform.is_part_of_batch_matmul(
                opu_node,
                light_graph):
            # Currently all unstacked matmul nodes from a batch matmul node
            # share the activation scale. The scale is stored with the
            # name of the original batch matmul node.
            node_name = (tf_batch_matmul_transform.TFSavedModelBatchMatMulV2Transform.
                         get_batch_matmul_node_name(node_name))
        activation_scale_info = self._get_activation_scale_info(node_name)

        # Update the quant params node
        quant_params_node = light_graph.get_node_by_name(
            opu_node.inputs[lgf_pb2.MatMulNode.QUANT_PARAMS_INDEX].name)
        new_quant_params = np.array(
            [[activation_scale_info.scale] * self._hw_specs.dimension,
             [activation_scale_info.bias] * self._hw_specs.dimension])

        new_quant_params_node = self.create_const_node(
            new_quant_params,
            quant_params_node.name,
            quant_params_node.outputs[0].dtype,
            quant_params_node.const.const_type)

        # Update the opu node
        new_opu_node = lgf_pb2.LNF()
        new_opu_node.CopyFrom(opu_node)
        matmul = opu_op_transform.OPUOpTransform.get_matmul_from_opu_node(new_opu_node)
        matmul.using_quant_bias = (activation_scale_info.bias != 0)
        new_opu_node.inputs[lgf_pb2.MatMulNode.QUANT_PARAMS_INDEX].CopyFrom(
            new_quant_params_node.outputs[0])

        # Update phasify node
        phasify_node = light_graph.get_node_by_name(
            opu_node.inputs[lgf_pb2.MatMulNode.PHASES_INDEX].name)
        new_phasify_node = lgf_pb2.LNF()
        new_phasify_node.CopyFrom(phasify_node)
        new_phasify_node.inputs[lgf_pb2.PhasifyNode.QUANT_PARAMS_INPUT_INDEX].CopyFrom(
            new_quant_params_node.outputs[0])

        return self.create_transform_result(
            to_replace=[new_quant_params_node,
                        new_opu_node,
                        new_phasify_node])
Beispiel #8
0
    def init_conv2d_node(self, conv2d_name):
        # Create a distributed depthwise conv2d node
        depthwise_conv2d_node = lgf_pb2.LNF()
        depthwise_conv2d_node.name = conv2d_name
        depthwise_conv2d_node.supported = True
        depthwise_conv2d_node.distributed_depthwise_conv2d.SetInParent()

        return (depthwise_conv2d_node,
                depthwise_conv2d_node.distributed_depthwise_conv2d.conv2d)
Beispiel #9
0
    def init_conv2d_node(self, conv2d_name):
        # Create a block diagonal depthwise conv2d node
        depthwise_conv2d_node = lgf_pb2.LNF()
        depthwise_conv2d_node.name = conv2d_name
        depthwise_conv2d_node.supported = True
        depthwise_conv2d_node.block_diagonal_depthwise_conv2d.SetInParent()

        return (depthwise_conv2d_node,
                depthwise_conv2d_node.block_diagonal_depthwise_conv2d.conv2d)
    def transform(self, opu_node, light_graph):
        # Get hist path and write an empty hist
        hist_keys = self._get_hist_keys(opu_node, light_graph)

        # New opu node
        new_opu_node = lgf_pb2.LNF()
        new_opu_node.CopyFrom(opu_node)
        matmul = opu_op_transform.OPUOpTransform.get_matmul_from_opu_node(
            new_opu_node)
        matmul.turn_off_adc = True
        matmul.hist_keys_before_adc.CopyFrom(hist_keys)

        return self.create_transform_result(to_replace=[new_opu_node])
    def get_transforms(self, light_graph):
        """
        Returns the transforms to collapse supported subgraphs in
        light_graph into single nodes.
        """
        subgraphs = self._get_supported_subgraph_lists(light_graph)

        # Node transformations converting each subgraph into a single node
        to_add = []
        to_reroute = []
        to_output_swap = []
        subgraph_index = self._get_next_subgraph_index(light_graph)
        for subgraph, control_inputs in subgraphs:
            subgraph_node = lgf_pb2.LNF()
            subgraph_node.name = self.get_subgraph_node_name(subgraph_index)
            subgraph_node.supported = False
            subgraph_node.subgraph.SetInParent()
            subgraph_node.subgraph.graph.CopyFrom(subgraph.as_lgf_pb())
            subgraph_node.inputs.extend(subgraph.input_edges())
            subgraph_node.control_inputs.extend(control_inputs)

            for j, old_edge in enumerate(subgraph.output_edges()):
                new_edge = lgf_pb2.EdgeInfo()
                new_edge.CopyFrom(old_edge)
                new_edge.name = subgraph_node.name
                new_edge.port = j
                subgraph_node.outputs.add().CopyFrom(new_edge)

                to_reroute.append((transform_result_pb2.ToReroute.edge_reroute.
                                   DESCRIPTOR.name, [], old_edge, new_edge))

            for old_node in subgraph.nodes():
                to_reroute.append((transform_result_pb2.ToReroute.
                                   control_input_reroute.DESCRIPTOR.name, [],
                                   [old_node.name], [subgraph_node.name]))

            if len(subgraph.output_node_names()):
                to_output_swap.append(
                    (subgraph.output_node_names(), [subgraph_node.name]))

            to_add.append(subgraph_node)

            subgraph_index += 1

        return [
            base_transform.BaseTransform.create_transform_result(
                to_add=to_add,
                to_reroute=to_reroute,
                to_output_swap=to_output_swap)
        ]
    def _modify_opu_node(self, opu_node):
        # New opu node
        new_opu_node = lgf_pb2.LNF()
        new_opu_node.CopyFrom(opu_node)

        # Get dtypes for histograms
        before_adc_dtype = dtypes_pb2.DType()
        before_adc_dtype.t = dtypes_pb2.DT_FLOAT
        before_adc_dtype.p = 32
        after_adc_dtype = opu_node.outputs[0].dtype

        # Get num bins for histograms
        before_adc_num_bins = self._get_num_bins(before_adc_dtype)
        after_adc_num_bins = self._get_num_bins(after_adc_dtype)

        # Get hist keys from node
        matmul = opu_op_transform.OPUOpTransform.get_matmul_from_opu_node(
            new_opu_node)
        hist_keys_before_adc = matmul.hist_keys_before_adc
        hist_keys_after_adc = matmul.hist_keys_after_adc

        # Initialize some things
        hist_keys_before_adc.quant_type = common_pb2.QT_PER_TILE
        hist_keys_after_adc.quant_type = common_pb2.QT_PER_TILE

        # Histogram for each tile
        weight_shape = opu_node.inputs[lgf_pb2.MatMulNode.PHASES_INDEX].shape
        for x in range(weight_shape.d[0]):
            for y in range(weight_shape.d[1]):
                # Add keys to node
                hist_keys_before_adc.keys.append(
                    self._get_new_hist_key(node=opu_node,
                                           x=x,
                                           y=y,
                                           suffix="before_adc"))
                hist_keys_after_adc.keys.append(
                    self._get_new_hist_key(node=opu_node,
                                           x=x,
                                           y=y,
                                           suffix="after_adc"))

                # Initialize histograms
                self._hist_coll.initialize_empty_histogram(
                    hist_keys_before_adc.keys[-1], before_adc_num_bins)
                self._hist_coll.initialize_empty_histogram(
                    hist_keys_after_adc.keys[-1], after_adc_num_bins)

        return base_transform.BaseTransform.create_transform_result(
            to_replace=[new_opu_node])
    def create_supported_nodes(self,
                               matmul_name,
                               input_edge,
                               weights_edge,
                               output_edge,
                               control_inputs,
                               transpose_inputs=False,
                               transpose_weights=False):
        """
        Creates a supported matmul node in standard format

        Params:
            matmul_name: name of original node
            input_edge: edge of the input for the original node
            weights_edge: input edge for the weights, to be fed to phasify
            output_edge: edge of the output for the original node
            control_inputs: a list of node names for the control inputs
            transpose_inputs: if True, transpose the inputs
            transpose_weights: if True, transpose the weights
        """
        # TODO: support transpose of inputs? just insert a tranpose node?
        if transpose_inputs:
            logging.warning(
                "Transpose of vector in MatMul node {} is NOT supported.".
                format(matmul_name))
            return []

        # Create a matmul_node
        matmul_node = lgf_pb2.LNF()
        matmul_node.name = matmul_name
        matmul_node.supported = True
        matmul_node.matmul.SetInParent()

        # Phasify
        to_add = self._create_phasify_node(matmul_node,
                                           weights_edge,
                                           transpose_weights=transpose_weights)

        # Input data
        matmul_node.inputs[lgf_pb2.MatMulNode.INPUT_INDEX].CopyFrom(input_edge)
        matmul_node.inputs[lgf_pb2.MatMulNode.INPUT_INDEX].dtype.CopyFrom(
            self._sw_config.float_type)
        matmul_node.control_inputs.extend(control_inputs)

        # Outputs
        matmul_node.outputs.add().CopyFrom(output_edge)
        matmul_node.outputs[0].dtype.CopyFrom(self._sw_config.float_type)

        return [matmul_node] + to_add
Beispiel #14
0
    def transform(self, node, light_graph):
        activation_scale_info = self._get_activation_scale_info(node.name)

        # Create new node that has a quant scale set
        # Update current node
        new_node = lgf_pb2.LNF()
        new_node.CopyFrom(node)
        node_type = getattr(new_node, new_node.WhichOneof("node"))
        fields = node_type.DESCRIPTOR.fields_by_name
        assert ("quant_scale" in fields)
        assert ("quant_precision" in fields)
        node_type.quant_scale = activation_scale_info.scale
        node_type.quant_precision = self._sw_config.quantized_electronic_op_precision

        return self.create_transform_result(to_replace=[new_node])
Beispiel #15
0
    def transform(self, pad_node, light_graph):
        to_replace = []

        for node_name in light_graph.get_output_node_names_of_node(pad_node):
            conv2d_node = light_graph.get_node_by_name(node_name)

            new_conv2d_node = lgf_pb2.LNF()
            new_conv2d_node.CopyFrom(conv2d_node)
            new_conv2d_node.conv2d.image_attr.padding = self._get_converted_pad_type(
                pad_node, conv2d_node)
            new_conv2d_node.inputs[lgf_pb2.MatMulNode.INPUT_INDEX].CopyFrom(
                pad_node.inputs[0])

            to_replace.append(new_conv2d_node)

        return self.create_transform_result(to_replace=to_replace)
    def init_conv2d_node(self, conv2d_name):
        """
        Initializes a conv2d node

        Params:
            conv2d_name: name for the conv2d node

        Returns:
            a tuple: (a lgf_pb2.LNF() object for the node,
                a lgf_pb2.Conv2DNode() for the conv2d of the node)
        """
        # Create a conv2d_node
        conv2d_node = lgf_pb2.LNF()
        conv2d_node.name = conv2d_name
        conv2d_node.supported = True
        conv2d_node.conv2d.SetInParent()

        return conv2d_node, conv2d_node.conv2d
Beispiel #17
0
    def preprocess_weights(self, weights_edge):
        # Unpack shapes
        filter_height, filter_width, in_channels, channel_multiplier = \
            weights_edge.shape.d
        k = self._hw_specs.dimension
        j = self.num_columns()

        # There are in_channels matrices, each of size
        # [filter_height * filter_width, channel_multiplier]
        # Figure out how many we can stack on each axis
        x_stack = k // (filter_height * filter_width)
        y_stack = j // (channel_multiplier)
        matrices_per_tile = min(x_stack, y_stack)

        # If the matrices are too big to fit into the matmul unit, we cannot
        # do the transform
        if not matrices_per_tile:
            logging.error(
                "Failed to transform Block Diagonal Depthwise Conv2d")
            return False, [], weights_edge

        # Number of opu tiles we will need for in_channels matrices
        num_tiles = np.ceil(in_channels / matrices_per_tile).astype(int)

        # Create depthwise conv2d reshape node
        depthwise_conv2d_reshape_node = lgf_pb2.LNF()
        depthwise_conv2d_reshape_node.name = weights_edge.name + "_depthwise_reshape"
        depthwise_conv2d_reshape_node.supported = True
        (depthwise_conv2d_reshape_node.block_diagonal_depthwise_conv2d_reshape.
         SetInParent())

        input_edge = depthwise_conv2d_reshape_node.inputs.add()
        input_edge.CopyFrom(weights_edge)
        input_edge.dtype.CopyFrom(self._get_dtype())

        output_edge = depthwise_conv2d_reshape_node.outputs.add()
        output_edge.name = depthwise_conv2d_reshape_node.name
        output_edge.port = 0
        output_edge.dtype.CopyFrom(input_edge.dtype)
        output_edge.shape.d.extend([k, num_tiles * j])
        output_edge.shape.batch_dim_indx = -1

        return True, [depthwise_conv2d_reshape_node], output_edge
    def get_transforms(self, light_graph):
        # Create a node that updates variables
        update_variables_node = lgf_pb2.LNF()
        update_variables_node.name = self.UPDATE_VARIABLES_NAME
        update_variables_node.supported = True
        update_variables_node.update_variables.SetInParent()
        update_variables_node.update_variables.update_info.CopyFrom(
            self._update_info)

        update_variables_node.control_inputs.extend(
            light_graph.output_node_names() +
            [e.name for e in light_graph.output_edges()])

        return [
            base_transform.BaseTransform.create_transform_result(
                to_add=[update_variables_node],
                to_output_swap=[(light_graph.output_node_names(),
                                 [update_variables_node.name])])
        ]
    def create_supported_nodes(self,
                               dequant_name,
                               input_edge,
                               output_edge,
                               control_inputs,
                               scales,
                               bias=0,
                               method=lgf_pb2.DQ_STANDARD):
        """
        Creates a supported dequant node in standard format

        Params:
            dequant_name: name of original node
            input_edge: edge of the input for the original node
            output_edge: edge of the output for the original node
            control_inputs: a list of node names for the control inputs
            scales: a list or numpy array of dequant scales
            bias: dequant bias
            method: a lgf_pb2.DequantMethod
        """

        # Create the dequant scales const node
        dequant_scales_node = self.create_const_node(np.array(scales),
                                                     dequant_name + "_scales",
                                                     self._sw_config.float_type,
                                                     lgf_pb2.ConstNode.DEQUANT_SCALE)

        # Create dequant node
        dequant_node = lgf_pb2.LNF()
        dequant_node.name = dequant_name
        dequant_node.inputs.add().CopyFrom(input_edge)
        dequant_node.inputs.add().CopyFrom(dequant_scales_node.outputs[0])
        dequant_node.control_inputs.extend(control_inputs)
        dequant_node.outputs.add().CopyFrom(output_edge)
        dequant_node.supported = True
        dequant_node.dequantize.SetInParent()

        # dequantize attributes
        dequant_node.dequantize.method = method
        dequant_node.dequantize.bias = bias

        return [dequant_node, dequant_scales_node]
    def transform(self, opu_node, light_graph):
        # New opu node
        new_opu_node = lgf_pb2.LNF()
        new_opu_node.CopyFrom(opu_node)
        matmul = opu_op_transform.OPUOpTransform.get_matmul_from_opu_node(
            new_opu_node)
        matmul.turn_off_adc = False

        # Get the old adc scales node
        phasify_node = light_graph.get_node_by_name(
            opu_node.inputs[lgf_pb2.MatMulNode.PHASES_INDEX].name)
        adc_scales_node = light_graph.get_node_by_name(phasify_node.inputs[
            lgf_pb2.PhasifyNode.ADC_SCALES_INPUT_INDEX].name)

        # New adc scales node
        new_adc_scales = self._get_adc_scales(opu_node)
        new_adc_scales_node = self.create_const_node(
            new_adc_scales, adc_scales_node.name,
            adc_scales_node.outputs[0].dtype, adc_scales_node.const.const_type)

        return self.create_transform_result(
            to_replace=[new_opu_node, new_adc_scales_node])
Beispiel #21
0
    def create_supported_nodes(self,
                               quantize_name,
                               input_edge,
                               output_edge,
                               control_inputs,
                               scale,
                               precision,
                               bias=0):
        """
        Creates a supported quant node in standard format

        Params:
            quant_name: name of original node
            input_edge: edge of the input for the original node
            output_edge: edge of the output for the original node
            control_inputs: a list of node names for the control inputs
            scale: quantization scale
            precision: quantization precision
            bias: quantization bias
        """

        # Replace the Quantize Node in order to change the operation to a Quantize
        quant_node = lgf_pb2.LNF()
        quant_node.name = quantize_name
        quant_node.inputs.add().CopyFrom(input_edge)
        quant_node.control_inputs.extend(control_inputs)
        quant_node.outputs.add().CopyFrom(output_edge)
        quant_node.supported = True
        quant_node.quantize.SetInParent()

        # quantize attributes
        quant_node.quantize.scale = scale
        quant_node.quantize.precision = precision
        quant_node.quantize.bias = bias

        return [quant_node]
    def _create_phasify_node(self, opu_node, weights_edge, transpose_weights=False):
        # Get shape variables from the weights edge
        num_x, num_y, k, j = self.get_tiled_shape(weights_edge, transpose_weights,
                                                  self._hw_specs)

        # Create a phasify node
        phasify_node = lgf_pb2.LNF()
        phasify_node.name = opu_node.name + "_phasify"
        phasify_node.supported = True
        phasify_node.phasify.SetInParent()
        phasify_node.phasify.transpose = transpose_weights

        # Initialize inputs
        for _ in range(self.PHASIFY_NUM_INPUTS):
            phasify_node.inputs.add()

        # Quant params [quant_scale, quant_bias]
        quant_params = np.array([1, 0])
        quant_params_node = self.create_const_node(quant_params,
                                                   opu_node.name + "_quant_params",
                                                   self._sw_config.float_type,
                                                   lgf_pb2.ConstNode.GRAPH_CONST)
        phasify_node.inputs[lgf_pb2.PhasifyNode.QUANT_PARAMS_INPUT_INDEX].CopyFrom(
            quant_params_node.outputs[0])

        # Weights
        phasify_node.inputs[lgf_pb2.PhasifyNode.WEIGHTS_INPUT_INDEX].CopyFrom(
            weights_edge)
        phasify_node.inputs[lgf_pb2.PhasifyNode.WEIGHTS_INPUT_INDEX].dtype.CopyFrom(
            self._sw_config.float_type)

        # ADC scales
        adc_scales = np.ones(shape=[num_x, num_y, 1, j])
        adc_scales_node = self.create_const_node(adc_scales,
                                                 opu_node.name + "_adc_scales",
                                                 self._sw_config.float_type,
                                                 lgf_pb2.ConstNode.ADC_SCALE)
        phasify_node.inputs[lgf_pb2.PhasifyNode.ADC_SCALES_INPUT_INDEX].CopyFrom(
            adc_scales_node.outputs[0])

        # Initialize outputs
        for _ in range(self.PHASIFY_NUM_OUTPUTS):
            phasify_node.outputs.add()

        # Phases
        phases_edge = phasify_node.outputs[lgf_pb2.PhasifyNode.PHASES_OUTPUT_INDEX]
        phases_edge.name = phasify_node.name
        phases_edge.port = lgf_pb2.PhasifyNode.PHASES_OUTPUT_INDEX
        phases_edge.dtype.CopyFrom(self._phase_dtype)
        phases_edge.shape.d.extend([num_x, num_y, j // k, k, k])
        phases_edge.shape.batch_dim_indx = -1

        # Dequant scales
        dequant_scales_edge = phasify_node.outputs[
            lgf_pb2.PhasifyNode.DEQUANT_SCALES_OUTPUT_INDEX]
        dequant_scales_edge.name = phasify_node.name
        dequant_scales_edge.port = lgf_pb2.PhasifyNode.DEQUANT_SCALES_OUTPUT_INDEX
        dequant_scales_edge.dtype.CopyFrom(self._sw_config.float_type)
        dequant_scales_edge.shape.d.extend([num_x, num_y, 1, j])
        dequant_scales_edge.shape.batch_dim_indx = -1

        # ADC scales
        adc_scales_edge = phasify_node.outputs[
            lgf_pb2.PhasifyNode.ADC_SCALES_OUTPUT_INDEX]
        adc_scales_edge.CopyFrom(adc_scales_node.outputs[0])
        adc_scales_edge.name = phasify_node.name
        adc_scales_edge.port = lgf_pb2.PhasifyNode.ADC_SCALES_OUTPUT_INDEX

        # Initialize inputs of the opu node
        for _ in range(self.NUM_INPUTS):
            opu_node.inputs.add()

        # Add input edges from phasify
        opu_node.inputs[lgf_pb2.MatMulNode.QUANT_PARAMS_INDEX].CopyFrom(
            phasify_node.inputs[lgf_pb2.PhasifyNode.QUANT_PARAMS_INPUT_INDEX])
        opu_node.inputs[lgf_pb2.MatMulNode.PHASES_INDEX].CopyFrom(
            phasify_node.outputs[lgf_pb2.PhasifyNode.PHASES_OUTPUT_INDEX])
        opu_node.inputs[lgf_pb2.MatMulNode.DEQUANT_SCALES_INDEX].CopyFrom(
            phasify_node.outputs[lgf_pb2.PhasifyNode.DEQUANT_SCALES_OUTPUT_INDEX])
        opu_node.inputs[lgf_pb2.MatMulNode.ADC_SCALES_INDEX].CopyFrom(
            phasify_node.outputs[lgf_pb2.PhasifyNode.ADC_SCALES_OUTPUT_INDEX])

        # Default attributes
        self._set_default_attributes(self.get_matmul_from_opu_node(opu_node))

        return [phasify_node, quant_params_node, adc_scales_node]
    def matmul_graph(hw_spec,
                     sw_config,
                     sim_params,
                     weights,
                     inp_shape=(1, 4),
                     inp_dtype_t=dtypes_pb2.DT_BFLOAT,
                     inp_dtype_p=16,
                     add_activation=False):
        inp1 = lgf_pb2.EdgeInfo()
        inp1.name = "inp_ten1"
        inp1.port = 0
        inp1.dtype.t = inp_dtype_t
        inp1.dtype.p = inp_dtype_p
        inp1.shape.d.extend(list(inp_shape))

        weights_i = lgf_pb2.EdgeInfo()
        weights_i.name = "weights_ten"
        weights_i.port = 0
        weights_i.dtype.CopyFrom(inp1.dtype)
        weights_i.shape.d.extend(weights.shape)

        outp = lgf_pb2.EdgeInfo()
        outp.CopyFrom(inp1)
        outp.name = "out_ten"
        outp.shape.d[1] = weights.shape[1]
        outp.dtype.t = inp_dtype_t
        outp.dtype.p = inp_dtype_p

        wn = lgf_pb2.LNF()
        wn.name = "weights_ten"
        wn.const.SetInParent()
        wn.outputs.add().CopyFrom(weights_i)
        wn.const.value.CopyFrom(
            utils.array_to_tensor_pb(weights, weights_i.dtype))
        wn.const.const_type = lgf_pb2.ConstNode.GRAPH_CONST
        wn.supported = True

        mm_tx = matmul_transform.MatMulTransform(hw_spec, sw_config,
                                                 sim_params)
        mm_nodes = mm_tx.create_supported_nodes("out_ten", inp1, weights_i,
                                                outp, [])

        act_nodes = []
        if add_activation:
            bias = base_transform.BaseTransform.create_const_node(
                np.random.random(size=(1, inp_shape[1])), "add_bias",
                inp1.dtype, lgf_pb2.ConstNode.GRAPH_CONST)
            act_nodes.append(bias)

            act = lgf_pb2.LNF()
            act.name = "act"
            act.vv_add.SetInParent()
            act.supported = True
            act.inputs.add().CopyFrom(mm_nodes[0].outputs[0])
            act.inputs.add().CopyFrom(bias.outputs[0])
            act.outputs.add().CopyFrom(mm_nodes[0].outputs[0])
            act.outputs[0].name = "act"
            outp = act.outputs[0]
            act_nodes.append(act)

        lg = lgf_graph.LightGraph([wn] + mm_nodes + act_nodes,
                                  input_edges=[inp1],
                                  output_edges=[outp])

        folder = fold_phasify_constants.FoldPhasifyConstants(
            hw_spec, sw_config, sim_params)

        return folder.process_transforms(lg)
Beispiel #24
0
 def _copy_node(self, node):
     node_copy = lgf_pb2.LNF()
     node_copy.CopyFrom(node)
     return node_copy
    def transform(self, fully_connected_node, light_graph):
        """
        Converts unsupported TFLite FULLY_CONNECTED to supported standard MATMUL
        and VV_ADD
        """
        # Get the original sub_node
        sub_node = fully_connected_node.original

        # Assertions
        self.check_original_node(fully_connected_node)
        assert ("fused_activation_function" in sub_node.attr)
        assert ("weights_format" in sub_node.attr)
        assert (sub_node.attr["weights_format"].s == "DEFAULT")

        # Get the edges
        input_edge = fully_connected_node.inputs[0]
        weight_edge = fully_connected_node.inputs[1]
        bias_edge = fully_connected_node.inputs[2]
        output_edge = fully_connected_node.outputs[0]

        # Transforms
        to_add = []
        to_replace = []
        to_reroute = []
        edge_reroute = transform_result_pb2.ToReroute.edge_reroute.DESCRIPTOR.name

        # Matmul transform
        matmul_transforms = matmul_transform.MatMulTransform.do_generic_transform(
            self,
            fully_connected_node.name,
            input_edge,
            weight_edge,
            output_edge,
            fully_connected_node.control_inputs)
        to_add.extend([t.node for t in matmul_transforms.to_add])
        to_replace.extend([t.node for t in matmul_transforms.to_replace])
        matmul_node = matmul_transforms.to_replace[0].node

        # Create the CAST node to cast the bias to the type of the matmul
        cast_bias_node = lgf_pb2.LNF()
        cast_bias_node.name = fully_connected_node.name + "_cast_bias"
        cast_bias_node.supported = True
        cast_bias_node.cast.SetInParent()
        # Create the CAST input edge
        cast_bias_input_edge = cast_bias_node.inputs.add()
        cast_bias_input_edge.CopyFrom(bias_edge)
        cast_bias_input_edge.dtype.CopyFrom(self._get_dtype())
        # Create the CAST output edge
        cast_bias_edge = cast_bias_node.outputs.add()
        cast_bias_edge.name = cast_bias_node.name
        cast_bias_edge.port = 0
        cast_bias_edge.dtype.CopyFrom(matmul_node.outputs[0].dtype)
        cast_bias_edge.shape.CopyFrom(bias_edge.shape)
        # Append the node to add
        to_add.append(cast_bias_node)
        # Append the edges to be rerouted: BIAS>FC to BIAS>CAST_BIAS
        to_reroute.extend([(edge_reroute, [], bias_edge, cast_bias_edge)])

        # Create the ADD node
        add_node = lgf_pb2.LNF()
        add_node.name = fully_connected_node.name + "_add"
        add_node.supported = True
        add_node.vv_add.SetInParent()
        # Create the ADD input data edge
        add_node.inputs.add().CopyFrom(matmul_node.outputs[0])
        # Create the ADD input bias edge
        add_bias_edge = add_node.inputs.add()
        add_bias_edge.CopyFrom(cast_bias_edge)
        add_bias_edge.dtype.CopyFrom(self._sw_config.float_type)
        # Create the ADD output edge
        add_output_edge = add_node.outputs.add()
        add_output_edge.name = add_node.name
        add_output_edge.port = 0
        add_output_edge.dtype.CopyFrom(add_node.inputs[0].dtype)
        add_output_edge.shape.CopyFrom(add_node.inputs[0].shape)
        # Append the node to add
        to_add.append(add_node)
        to_reroute.extend([(edge_reroute, [], output_edge, add_output_edge)])

        # Create the CAST node to cast the bias to the type of the matmul
        cast_add_node = lgf_pb2.LNF()
        cast_add_node.name = fully_connected_node.name + "_cast_add"
        cast_add_node.supported = True
        cast_add_node.cast.SetInParent()
        # Create the CAST input edge
        cast_add_node.inputs.add().CopyFrom(add_output_edge)
        # Create the CAST output edge
        cast_add_edge = cast_add_node.outputs.add()
        cast_add_edge.name = cast_add_node.name
        cast_add_edge.port = 0
        cast_add_edge.dtype.CopyFrom(input_edge.dtype)
        cast_add_edge.shape.CopyFrom(add_output_edge.shape)
        # Append the node to add
        to_add.append(cast_add_node)
        # Append the edges to be rerouted: ADD>OUTPUT to CAST_ADD>OUTPUT
        to_reroute.extend([(edge_reroute, [], add_output_edge, cast_add_edge)])

        # Return the transforms
        return self.create_transform_result(to_add=to_add,
                                            to_replace=to_replace,
                                            to_reroute=to_reroute)
Beispiel #26
0
    def insert_collect_hist_node(edge, sw_config, hist_key, num_bins, hist_coll):
        to_add = []
        to_reroute = []
        edge_reroute = transform_result_pb2.ToReroute.edge_reroute.DESCRIPTOR.name

        # Cast to float if necessary
        insert_cast = (edge.dtype.p > sw_config.float_type.p)
        if insert_cast:
            # Cast to float
            cast_node = lgf_pb2.LNF()
            cast_node.name = "{}_{}_cast".format(edge.name, edge.port)
            cast_node.supported = True
            cast_node.cast.SetInParent()

            # Cast inputs and outputs
            cast_node.inputs.add().CopyFrom(edge)
            cast_output_edge = lgf_pb2.EdgeInfo()
            cast_output_edge.name = cast_node.name
            cast_output_edge.port = 0
            cast_output_edge.dtype.CopyFrom(sw_config.float_type)
            cast_output_edge.shape.CopyFrom(edge.shape)
            cast_node.outputs.add().CopyFrom(cast_output_edge)

            to_add.append(cast_node)
            to_reroute.append((edge_reroute, [], edge, cast_output_edge))
        else:
            cast_output_edge = edge

        # Collect hist node
        collect_hist_node = lgf_pb2.LNF()
        collect_hist_node.name = "{}_{}_collect_hist".format(edge.name, edge.port)
        collect_hist_node.supported = True
        collect_hist_node.collect_hist.SetInParent()
        collect_hist_node.collect_hist.hist_keys.keys.append(hist_key)
        collect_hist_node.collect_hist.hist_keys.quant_type = common_pb2.QT_SINGLE
        hist_coll.initialize_empty_histogram(hist_key, num_bins)

        # Calibration inputs and outputs
        collect_hist_node.inputs.add().CopyFrom(cast_output_edge)
        collect_hist_output_edge = lgf_pb2.EdgeInfo()
        collect_hist_output_edge.CopyFrom(cast_output_edge)
        collect_hist_output_edge.name = collect_hist_node.name
        collect_hist_output_edge.port = 0
        collect_hist_node.outputs.add().CopyFrom(collect_hist_output_edge)

        to_add.append(collect_hist_node)
        to_reroute.append((edge_reroute, [], cast_output_edge, collect_hist_output_edge))

        # Reverse cast if necessary
        if insert_cast:
            # Reverse cast
            reverse_cast_node = lgf_pb2.LNF()
            reverse_cast_node.name = "{}_{}_reverse_cast".format(edge.name, edge.port)
            reverse_cast_node.supported = True
            reverse_cast_node.cast.SetInParent()

            # Reverse cast inputs and outputs
            reverse_cast_node.inputs.add().CopyFrom(collect_hist_output_edge)
            reverse_cast_output_edge = lgf_pb2.EdgeInfo()
            reverse_cast_output_edge.CopyFrom(collect_hist_output_edge)
            reverse_cast_output_edge.name = reverse_cast_node.name
            reverse_cast_output_edge.dtype.CopyFrom(edge.dtype)
            reverse_cast_node.outputs.add().CopyFrom(reverse_cast_output_edge)

            to_add.append(reverse_cast_node)
            to_reroute.append((edge_reroute,
                               [],
                               collect_hist_output_edge,
                               reverse_cast_output_edge))

        return base_transform.BaseTransform.create_transform_result(
            to_add=to_add,
            to_reroute=to_reroute)