From 68e6df25f71a6695b96c04d245fb623333de1d40 Mon Sep 17 00:00:00 2001 From: Lianmin Zheng Date: Thu, 3 Dec 2020 18:55:39 -0800 Subject: [PATCH 1/2] [Frontend] Prevent tflite frontend from producing int64 shape and parameters --- python/tvm/relay/frontend/common.py | 10 ++++++++++ python/tvm/relay/frontend/tflite.py | 30 +++++++++++++++-------------- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/python/tvm/relay/frontend/common.py b/python/tvm/relay/frontend/common.py index ae51f2155402..a8c3f2f74aac 100644 --- a/python/tvm/relay/frontend/common.py +++ b/python/tvm/relay/frontend/common.py @@ -601,3 +601,13 @@ def __call__(self, inputs, attrs, *args): if "tvm_custom" in attrs: attrs.pop("tvm_custom") return get_relay_op(self._new_name)(*inputs, **attrs) + +def to_int_list(np_array): + """Convert a np array to a python int list. + + Note: This function converts np.int32 to python's int. + If we don't do this conversion, numpy's automatic upcast will make + the shape / parameters be converted to int64 IntImm in relay and + cause problems in relay/TOPI. + """ + return [int(x) for x in np_array] diff --git a/python/tvm/relay/frontend/tflite.py b/python/tvm/relay/frontend/tflite.py index 3572d35c6e3b..9c1eb0282e37 100644 --- a/python/tvm/relay/frontend/tflite.py +++ b/python/tvm/relay/frontend/tflite.py @@ -30,7 +30,7 @@ from .. import qnn as _qnn from ... import nd as _nd from .common import ExprTable -from .common import infer_shape as _infer_shape +from .common import infer_shape as _infer_shape, to_int_list from .tflite_flexbuffer import FlexBufferDecoder @@ -345,7 +345,7 @@ def get_tensor_value(self, tensor_wrapper): data = tensor_wrapper.buffer.DataAsNumpy() if tensor_wrapper.tensor.ShapeLength() != 0: - shape = tensor_wrapper.tensor.ShapeAsNumpy() + shape = to_int_list(tensor_wrapper.tensor.ShapeAsNumpy()) else: shape = [] @@ -503,7 +503,7 @@ def convert_reshape(self, op): op_options = op.BuiltinOptions() reshape_options = ReshapeOptions() reshape_options.Init(op_options.Bytes, op_options.Pos) - target_shape = tuple(reshape_options.NewShapeAsNumpy()) + target_shape = to_int_list(reshape_options.NewShapeAsNumpy()) in_expr = self.get_expr(input_tensor_idx) @@ -1387,7 +1387,7 @@ def convert_gather(self, op): axis = gather_options.Axis() # Check the indices are with in bounds. - data_shape = list(input_tensors[0].tensor.ShapeAsNumpy()) + data_shape = to_int_list(input_tensors[0].tensor.ShapeAsNumpy()) data_dim = len(data_shape) axis = data_dim + axis if axis < 0 else axis @@ -1505,7 +1505,7 @@ def convert_strided_slice(self, op): new_axis_mask = options.NewAxisMask() shrink_axis_mask = options.ShrinkAxisMask() - data_shape = list(input_tensors[0].tensor.ShapeAsNumpy()) + data_shape = to_int_list(input_tensors[0].tensor.ShapeAsNumpy()) data_dim = len(data_shape) stride_dim = len(stride) @@ -1757,7 +1757,7 @@ def convert_fully_connected(self, op): output_tensor_type = output_tensor.tensor.Type() output_tensor_type_str = self.get_tensor_type_str(output_tensor_type) - weight_tensor_shape = weight_tensor.tensor.ShapeAsNumpy() + weight_tensor_shape = to_int_list(weight_tensor.tensor.ShapeAsNumpy()) # Weight should have only 2 dimensions(TFLite convention) assert len(weight_tensor_shape) == 2, "Weight should be only 2-dim" @@ -1951,15 +1951,15 @@ def convert_conv(self, op, conv_type): padding = conv_options.Padding() fused_activation_fn = conv_options.FusedActivationFunction() - _, input_h, input_w, input_c = input_tensor.tensor.ShapeAsNumpy() + _, input_h, input_w, input_c = to_int_list(input_tensor.tensor.ShapeAsNumpy()) if is_depthwise_conv: # TFLite depthwise convolution kernel layout is: # 1 KH KW C(input_c * depth_multiplier) - _, kernel_h, kernel_w, in_channels = weight_tensor.tensor.ShapeAsNumpy() + _, kernel_h, kernel_w, in_channels = to_int_list(weight_tensor.tensor.ShapeAsNumpy()) assert in_channels == input_c * depth_multiplier else: - output_channels, kernel_h, kernel_w, _ = weight_tensor.tensor.ShapeAsNumpy() + output_channels, kernel_h, kernel_w, _ = to_int_list(weight_tensor.tensor.ShapeAsNumpy()) dilated_kernel_h = dilation_h * (kernel_h - 1) + 1 dilated_kernel_w = dilation_w * (kernel_w - 1) + 1 @@ -2007,6 +2007,8 @@ def convert_conv(self, op, conv_type): pass elif padding == Padding.SAME: pad_top, pad_bottom = get_pad_value(input_h, dilated_kernel_h, stride_h) + + pad_left, pad_right = get_pad_value(input_w, dilated_kernel_w, stride_w) do_pad = not (pad_top == 0 and pad_bottom == 0 and pad_left == 0 and pad_right == 0) if do_pad: @@ -2160,7 +2162,7 @@ def convert_slice(self, op): size = list(self.get_tensor_value(input_tensors[2])) # strided_slice(Relay) needs the slice's end indices, not the size end = size - input_tensor_shape = input_tensor.tensor.ShapeAsNumpy() + input_tensor_shape = to_int_list(input_tensor.tensor.ShapeAsNumpy()) input_tensor_rank = len(input_tensor_shape) for i in range(input_tensor_rank): if size[i] == -1: @@ -2322,7 +2324,7 @@ def convert_pool2d(self, op, pool_type): in_expr = self.get_expr(input_tensor_idx) - _, input_h, input_w, _ = input_tensor.tensor.ShapeAsNumpy() + _, input_h, input_w, _ = to_int_list(input_tensor.tensor.ShapeAsNumpy()) if padding == Padding.VALID: pass elif padding == Padding.SAME: @@ -2701,10 +2703,10 @@ def convert_transpose_conv(self, op): # Input (data) Tensor. NHWC layout input_tensor = input_tensors[2] - _, input_h, input_w, input_c = input_tensor.tensor.ShapeAsNumpy() + _, input_h, input_w, input_c = to_int_list(input_tensor.tensor.ShapeAsNumpy()) # Weights tensor. TFLite uses OHWI layout weights_tensor = input_tensors[1] - out_channels, kernel_h, kernel_w, in_channels = weights_tensor.tensor.ShapeAsNumpy() + out_channels, kernel_h, kernel_w, in_channels = to_int_list(weights_tensor.tensor.ShapeAsNumpy()) assert ( input_c == in_channels ), "Input channel in the filter should match to channel in the input" @@ -3120,7 +3122,7 @@ def convert_matrix_diag(self, op): ), "TFLite MATRIX_DIAG requires diagonal and output tensors' \ scale and zero points to be equal" - shape = diagonal.tensor.ShapeAsNumpy() + shape = to_int_list(diagonal.tensor.ShapeAsNumpy()) shape = np.append(shape, shape[-1]) dtype = self.get_tensor_type_str(diagonal.tensor.Type()) From 24329625998c022a6ef777467c7b4d8b13e503a3 Mon Sep 17 00:00:00 2001 From: Lianmin Zheng Date: Thu, 3 Dec 2020 19:04:42 -0800 Subject: [PATCH 2/2] fix lint --- python/tvm/relay/frontend/common.py | 3 ++- python/tvm/relay/frontend/tflite.py | 9 ++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/python/tvm/relay/frontend/common.py b/python/tvm/relay/frontend/common.py index a8c3f2f74aac..8c74f3a54138 100644 --- a/python/tvm/relay/frontend/common.py +++ b/python/tvm/relay/frontend/common.py @@ -602,9 +602,10 @@ def __call__(self, inputs, attrs, *args): attrs.pop("tvm_custom") return get_relay_op(self._new_name)(*inputs, **attrs) + def to_int_list(np_array): """Convert a np array to a python int list. - + Note: This function converts np.int32 to python's int. If we don't do this conversion, numpy's automatic upcast will make the shape / parameters be converted to int64 IntImm in relay and diff --git a/python/tvm/relay/frontend/tflite.py b/python/tvm/relay/frontend/tflite.py index 9c1eb0282e37..3f0140d19b1f 100644 --- a/python/tvm/relay/frontend/tflite.py +++ b/python/tvm/relay/frontend/tflite.py @@ -1959,7 +1959,9 @@ def convert_conv(self, op, conv_type): _, kernel_h, kernel_w, in_channels = to_int_list(weight_tensor.tensor.ShapeAsNumpy()) assert in_channels == input_c * depth_multiplier else: - output_channels, kernel_h, kernel_w, _ = to_int_list(weight_tensor.tensor.ShapeAsNumpy()) + output_channels, kernel_h, kernel_w, _ = to_int_list( + weight_tensor.tensor.ShapeAsNumpy() + ) dilated_kernel_h = dilation_h * (kernel_h - 1) + 1 dilated_kernel_w = dilation_w * (kernel_w - 1) + 1 @@ -2008,7 +2010,6 @@ def convert_conv(self, op, conv_type): elif padding == Padding.SAME: pad_top, pad_bottom = get_pad_value(input_h, dilated_kernel_h, stride_h) - pad_left, pad_right = get_pad_value(input_w, dilated_kernel_w, stride_w) do_pad = not (pad_top == 0 and pad_bottom == 0 and pad_left == 0 and pad_right == 0) if do_pad: @@ -2706,7 +2707,9 @@ def convert_transpose_conv(self, op): _, input_h, input_w, input_c = to_int_list(input_tensor.tensor.ShapeAsNumpy()) # Weights tensor. TFLite uses OHWI layout weights_tensor = input_tensors[1] - out_channels, kernel_h, kernel_w, in_channels = to_int_list(weights_tensor.tensor.ShapeAsNumpy()) + out_channels, kernel_h, kernel_w, in_channels = to_int_list( + weights_tensor.tensor.ShapeAsNumpy() + ) assert ( input_c == in_channels ), "Input channel in the filter should match to channel in the input"