Esempio n. 1
0
    def _common(cls, node, scales, sizes, nearest_mode='round_prefer_ceil', **kwargs):
        all_nodes = kwargs['all_nodes']
        G = kwargs['G']
        valid_name = kwargs['valid_name']
        inputs = [all_nodes[inp] if inp else None for inp in node.input]
        x = inputs[0]
        x_shape = x[2].shape
        x_rank = len(x_shape)
        spatial_size = x_rank - 2
        in_c = x_shape[1]
        in_w = x_shape[-1]
        if scales is not None:
            sizes = np.array(x_shape) * np.array(scales)
        sizes = [None if x_shape[idx] is None else dim
                 for idx, dim in enumerate(sizes)]
        if spatial_size == 1:
            sizes.insert(-1, 1)

        if nearest_mode != 'round_prefer_ceil':
            logger.warning('only round_prefer_ceil is supported for nearest mode')

        if spatial_size != 2 and spatial_size != 1:
            raise ValueError('resize only supports 4D tensor in NCHW mode or 3D tensor in NCF mode'
                             f' - input shape is {x_shape} sizes is {sizes}')

        if not all(x_dim == size_dim for x_dim, size_dim in zip(x_shape[:2:], sizes[:2:])):
            raise ValueError('resize only supports 4D tensor in NCHW mode or 3D tensor in NCF mode'
                             f' - input shape is {x_shape} sizes is {sizes}')

        mode = node.attrs.get('mode', 'nearest')
        if mode != 'nearest' and mode != 'linear':
            raise ValueError('resize only supports nearest and linear modes')

        params_class = BilinearResizerParameters if mode == 'linear' else NearestNeighborResizerParameters

        params = params_class(valid_name,
                              new_shape=tuple(sizes[2::]),
                              align_corners=False,
                              halfpixel_centers=False,
                              in_dims_hint=[['c', 'h', 'w']],
                              out_dims_hint=[['c', 'h', 'w']])

        if spatial_size == 1:
            r1_params = ReshapeParameters(f'{valid_name}_reshape2d',
                                          old_shape=Dim.unnamed([in_c, in_w]),
                                          shape=Dim.unnamed([in_c, 1, in_w]))
            r2_params = ReshapeParameters(f'{valid_name}_reshape1d',
                                          old_shape=Dim.unnamed([in_c, 1, sizes[-1]]),
                                          shape=Dim.unnamed([in_c, sizes[-1]]))
            G.add_edge(NNEdge(from_node=x[0], to_node=r1_params, from_idx=x[1], to_idx=0))
            G.add_edge(NNEdge(from_node=r1_params, to_node=params, from_idx=0, to_idx=0))
            G.add_edge(NNEdge(from_node=params, to_node=r2_params, from_idx=0, to_idx=0))
            pout_dims = ProvisionalDim(sizes[:-2:] + sizes[-1::])
            params = r2_params
        else:
            pout_dims = ProvisionalDim(sizes)
            G.add_edge(NNEdge(from_node=x[0], to_node=params, from_idx=x[1], to_idx=0))

        all_nodes[node.output[0]] = (params, 0, pout_dims)
        return params
Esempio n. 2
0
    def common_11_13(cls, node, **kwargs):
        all_nodes = kwargs['all_nodes']
        inputs = [all_nodes[inp] if inp else None for inp in node.input]
        x = inputs[0]
        x_shape = x[2].shape
        nearest_mode = node.attrs.get('nearest_mode', 'round_prefer_floor')
        coord_transmode = node.attrs.get(
            'coordinate_transformation_mode', 'half_pixel')
        if coord_transmode != 'align_corners':
            logger.warning(
                'only align_corners is supported as coordinate_transformation_mode')

        scales_inp = inputs[2]
        scales_shape = scales_inp[2].shape if scales_inp else None
        if scales_inp and len(scales_shape) > 0 and scales_shape[0] == len(x_shape):
            scales = cls.get_constant(inputs[2])
            return cls._common(node, scales, None, nearest_mode=nearest_mode, **kwargs)
        else:
            sizes_inp = inputs[2]
            sizes_shape = sizes_inp[2].shape if sizes_inp else None
            if not sizes_inp or len(sizes_shape) < 1 or sizes_shape[0] == len(x_shape):
                raise ValueError(
                    'neither sizes nor scales input is valid for reshape')
            sizes = cls.get_constant(inputs[3])
            return cls._common(node, None, sizes, nearest_mode=nearest_mode, **kwargs)
Esempio n. 3
0
    def _common(cls, node, **kwargs):
        all_nodes = kwargs['all_nodes']
        G = kwargs['G']
        valid_name = kwargs['valid_name']
        used_tensors = kwargs['used_tensors']
        inputs = [all_nodes[inp] if inp else None for inp in node.input]
        input_shapes = [inp[2].shape if inp else None for inp in inputs]
        x = inputs[0]

        seq_len = input_shapes[0][0]
        if seq_len is None:
            logger.warning("sequence length is variable in size. forcing to 20. "
                           "reexport your graph with sequence length set to the maxmimum sequence size")
            seq_len = 20
        input_size = input_shapes[0][2]
        hidden_size = node.attrs["hidden_size"]
        direction = node.attrs.get("direction", "forward")
        num_directions = 2 if direction == "bidirectional" else 1
        linear_before_reset = bool(node.attrs.get("linear_before_reset", 0))
        if not linear_before_reset:
            logger.warning("In {} linear_before_reset == 0 not supported by the Autotiler kernels".fromat(valid_name))
        # output_sequence = node.attrs.get("output_sequence", 0)

        i_weights = cls.get_constant(inputs[1])
        r_weights = cls.get_constant(inputs[2])
        biases = cls.get_constant(inputs[3]) if inputs[3] else np.zeros(
            [num_directions, 6 * hidden_size])
        tensors = {'forward': {}, 'backward': {}}
        # extract all the tensors in approriate format
        cls.deep_update(tensors, cls.extract_weights(
            i_weights, hidden_size,
            ('w_2_z_w', 'w_2_r_w', 'w_2_h_w'), num_directions))
        cls.deep_update(tensors, cls.extract_weights(
            r_weights, hidden_size,
            ('r_2_z_w', 'r_2_r_w', 'r_2_h_w'), num_directions))
        cls.deep_update(tensors, cls.extract_biases(
            biases, hidden_size,
            ("w_z_b", "w_r_b", "w_h_b", "r_z_b", "r_r_b", "r_h_b"), num_directions))
        cls.deep_update(tensors,
                        cls.get_state(inputs, 5, 'h_state', hidden_size, num_directions))
        cls.combine_biases_gru(tensors, ['z', 'r'], num_directions)
        extra_args = {
            'linear_before_reset': linear_before_reset
        }
        return cls.attach_rnn(G, x, GRUParameters, extra_args, valid_name, tensors,
                              used_tensors, hidden_size, input_size,
                              all_nodes, node, seq_len, num_directions)
Esempio n. 4
0
    def _common(cls,
                node,
                mode='constant',
                pads=None,
                constant_value=0,
                **kwargs):
        all_nodes = kwargs['all_nodes']
        G = kwargs['G']
        valid_name = kwargs['valid_name']
        inputs = [all_nodes[inp] for inp in node.input]
        x = inputs[0]
        x_shape = x[2].shape

        ndim = len(x_shape)
        npad = len(pads) // 2
        if npad != ndim:
            if all(not pad for pad in pads):
                logger.warning(
                    f'Pad {valid_name} has {npad} pad values and {ndim} input rank. '
                    'Since pad is zero this is ignored but it probably indicates a bug in the ONNX graph.'
                )
            else:
                raise ValueError(
                    f'Eroor in ONNX graph - pad {valid_name} has {npad} pad values and {ndim} input rank.'
                )
        apads = np.array([[pads[idx], pads[idx + ndim]]
                          for idx in range(ndim)])
        # apads = np.array(pads).reshape((-1, 2))
        if cls.is_constant(x):
            logger.info("reducing %s to a constant", valid_name)
            val = cls.get_constant(x)
            if mode == 'constant':
                val = np.pad(val,
                             apads,
                             mode=mode,
                             constant_values=constant_value)
            else:
                val = np.pad(val, apads, mode=mode)
            params = ConstantInputParameters(valid_name, value=val)
            pshape = [
                dim + sum(apads[idx]) if dim is not None else None
                for idx, dim in enumerate(x_shape)
            ]
            all_nodes[node.output[0]] = (params, 0, ProvisionalDim(pshape),
                                         x[3])
            return params

        if mode != 'constant':
            raise ValueError('%s - pad mode %s is not supported' %
                             (valid_name, mode))

        if any(
                sum(pad) > 0 and x_shape[idx] is None
                for idx, pad in enumerate(apads)):
            raise ValueError(
                f'unknown/batch axis is being padded in {valid_name}. Manipulation of '
                'unknown/batch axis is not supported')
        trimmed_pads = tuple(
            [pad for idx, pad in enumerate(apads) if x_shape[idx] is not None])

        if all(sum(trimmed_pad) == 0 for trimmed_pad in trimmed_pads):
            params = NoOPParameters(valid_name, desc="eliminated pad of 0")
            pshape = x_shape
        else:
            pshape = [
                dim + sum(apads[idx]) if dim is not None else None
                for idx, dim in enumerate(x_shape)
            ]
            # pshape = [None if dim is None else dim + sum(apads[idx]) for idx, dim in enumerate(x_shape)]
            padvals = [(constant_value, constant_value)] * len(trimmed_pads)
            params = PadParameters(valid_name,
                                   padding=trimmed_pads,
                                   pad_vals=padvals)
        G.add_edge(
            NNEdge(from_node=x[0], to_node=params, from_idx=x[1], to_idx=0))
        all_nodes[node.output[0]] = (params, 0, ProvisionalDim(pshape), x[3])
        return params
Esempio n. 5
0
    def conv(cls, node, quantized=False, **kwargs):
        all_nodes = kwargs['all_nodes']
        G = kwargs['G']
        valid_name = kwargs['valid_name']
        inputs = [all_nodes[inp] for inp in node.input]
        # input N x C x H x W
        x = inputs[0]
        x_rank = len(x[2].shape)
        x_shape = x[2].shape

        if x_shape[0] is not None:
            real_in_shape = tuple(x_shape.copy())
            if x_shape[0] > 1:
                # support for multi batch is very limited
                batch = x_shape[0]
                logger.warning(
                    f"{valid_name} has a non 1 batch dimension of {batch} -"
                    " this is not supported by nntool or autotiler kernels")
            else:
                # if the batch is specified but is 1 then the input will be reshaped
                # and the output will have the batch dim set as unknown.
                batch = None
        else:
            real_in_shape = tuple(x_shape[1:])
            batch = None

        spatial_size = x_rank - 2
        assert spatial_size == 2 or spatial_size == 1, "only 1D and 2D convolutions supported"

        # Input error checking
        undefined = []
        if x_shape[1] is None:
            # cope with swapped batch and channel due to bad initial reshape
            if x_shape[0] == 1:
                batch = None
                x_shape = [x_shape[1], x_shape[0]] + list(x_shape[2:])
                real_in_shape = x_shape[1:]
            else:
                undefined.append(f"input channel size of filter {valid_name} must be defined.")

        if not all(dim is not None for dim in x_shape[-spatial_size:]):
            undefined.append(f"input spatial size {x_shape} of filter {valid_name} must be defined.")
        if undefined:
            raise ValueError(f"{' '.join(undefined)}. You may need to override input dimensions.")

        # M x C/group x kH x kW
        weights_idx = 3 if quantized else 1
        weights_node = inputs[weights_idx][0]
        weights_node.name = f'{valid_name}_weights'
        weights = cls.get_constant(inputs[weights_idx])
        out_c = weights.shape[0]
        group = node.attrs.get("group", 1)
        in_c = x_shape[1]
        filt_in_c = in_c // group
        if in_c != weights.shape[1] * group:
            raise ValueError(f'node {valid_name} has incorrect input channel '
                             f'dimension {in_c} expecting {weights.shape[1] * group}')
        if spatial_size == 1:
            filt_w = weights.shape[-1]
            filt_h = h = 1
            w = x_shape[-1]
            # create a new constant node since we are changing the shape
            weights = np.reshape(weights, (out_c, filt_in_c, filt_h, filt_w))
            weights_node = ConstantInputParameters(f'{valid_name}_weights', value=weights,
                                                   dims=Dim.unnamed(
                                                       weights.shape))
            cls.record_constant_qrec(inputs[1], weights_node, **kwargs)
        else:
            filt_h = weights.shape[-2]
            filt_w = weights.shape[-1]
            h = x_shape[-2]
            w = x_shape[-1]

        conv_in_shape = (in_c, h, w)

        # h = 1 if spatial_size == 1 else (
        #     x_shape[-2] if x_shape[-2] is not None else 1)
        # w = x_shape[-1] if x_shape[-1] is not None else 1

        filt_dim = Conv2DFilterDim(filt_h, filt_w,
                                   out_c, in_c=filt_in_c)
        filt_dim = filt_dim.impose_order(cls.ONNX_FILTER_ORDER)

        biases_idx = 8 if quantized else 2
        if len(inputs) > biases_idx:
            biases_node = inputs[biases_idx][0]
            biases = cls.get_constant(inputs[biases_idx])
        else:
            biases = np.zeros([out_c], dtype=np.float32)
            biases_node = ConstantInputParameters(f'{valid_name}_biases', value=biases,
                                                  dims=Dim.unnamed(
                                                      biases.shape))

        dilations = cls.pad_start_with(node.attrs.get("dilations", []), [1], 2)
        strides = cls.pad_start_with(node.attrs.get("strides", []), [1], 2)
        pad_dim = cls.calc_pad_dim(node, 4)

        if batch is not None:
            in_hint = ['n', 'c', 'h', 'w']
            out_hint = ['n', 'c', 'h', 'w']
            in_dim = Dim.named_ordered(n=batch, c=in_c, h=h, w=w)
            ker_in_order = [
                ['n', 'c', 'h', 'w'],
                ['out_c', 'in_c', 'h', 'w'],
                ['out_c']]
            ker_out_order = [['n', 'c', 'h', 'w']]
        else:
            in_hint = ['c', 'h', 'w']
            out_hint = ['c', 'h', 'w']
            in_dim = Dim.named_ordered(c=in_c, h=h, w=w)
            ker_in_order = [
                ['c', 'h', 'w'],
                ['out_c', 'in_c', 'h', 'w'],
                ['out_c']]
            ker_out_order = [['c', 'h', 'w']]
        params = Conv2DParameters(valid_name,
                                  filt=filt_dim,
                                  stride=StrideDim(strides[0],
                                                   strides[1]),
                                  dilation=DilationDim(dilations[0],
                                                       dilations[1]),
                                  batch=batch,
                                  groups=group,
                                  padding=pad_dim,
                                  ker_in_order=ker_in_order,
                                  ker_out_order=ker_out_order,
                                  has_bias=True,
                                  in_dims_hint=[in_hint,
                                                cls.ONNX_FILTER_ORDER, ['c']],
                                  out_dims_hint=[out_hint])

        if quantized:
            qrecs = kwargs['qrecs']
            x_zp = cls.get_constant(inputs[2])
            x_scale = cls.get_constant(inputs[1])
            x_qtype = QType(dtype=x_zp.dtype, scale=x_scale, zero_point=x_zp)
            w_zp = cls.get_constant(inputs[5])
            w_scale = cls.get_constant(inputs[4])
            weights_node.qtype = w_qtype = QType(
                dtype=w_zp.dtype, scale=w_scale,
                zero_point=w_zp, quantized_dimension=0 if len(w_scale) > 1 else None)
            o_zp = cls.get_constant(inputs[7])
            o_scale = cls.get_constant(inputs[6])
            o_qtype = QType(dtype=o_zp.dtype, scale=o_scale, zero_point=o_zp)
            biases_node.qtype = b_qtype = QType(
                dtype=biases.dtype, scale=w_scale*x_scale)
            qrecs[NodeId(params)] = QRec.scaled(
                in_qs=[x_qtype, w_qtype, b_qtype],
                out_qs=[o_qtype],
            )
        else:
            o_qtype = None

        w_dim = Dim.named_ordered(
            out_c=out_c, in_c=filt_in_c, h=filt_h, w=filt_w)
        b_dim = Dim.named_ordered(c=out_c)
        out_dims = params.get_output_size([in_dim, w_dim, b_dim])
        G.add_edge(NNEdge(from_node=weights_node,
                          to_node=params, from_idx=0, to_idx=1))
        G.add_edge(NNEdge(from_node=biases_node,
                          to_node=params, from_idx=0, to_idx=2))

        # check if input needs a reshape
        if conv_in_shape != real_in_shape:
            r1_params = ReshapeParameters(f'{valid_name}_reshape_in',
                                          old_shape=Dim.unnamed(real_in_shape),
                                          shape=Dim.unnamed(conv_in_shape))
            G.add_edge(
                NNEdge(from_node=x[0], to_node=r1_params, from_idx=x[1], to_idx=0))
            G.add_edge(NNEdge(from_node=r1_params,
                              to_node=params, from_idx=0, to_idx=0))
        else:
            G.add_edge(
                NNEdge(from_node=x[0], to_node=params, from_idx=x[1], to_idx=0))

        # check if output needs a reshape
        if spatial_size == 1:
            if batch is not None:
                oned_out_shape = [batch, out_dims[0].c, out_dims[0].w]
                pout_dims = ProvisionalDim(oned_out_shape)
            else:
                oned_out_shape = [out_dims[0].c, out_dims[0].w]
                pout_dims = ProvisionalDim([None] + oned_out_shape)

            r2_params = ReshapeParameters(f'{valid_name}_reshape_out',
                                          old_shape=out_dims[0],
                                          shape=Dim.unnamed(oned_out_shape))
            G.add_edge(NNEdge(from_node=params,
                              to_node=r2_params, from_idx=0, to_idx=0))
            params = r2_params
        else:
            pout_dims = ProvisionalDim([batch] + out_dims[0].shape)

        all_nodes[node.output[0]] = (params, 0, pout_dims, o_qtype)
        return params