This is an automated email from the ASF dual-hosted git repository. zhaowu pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-tvm.git
The following commit(s) were added to refs/heads/master by this push: new ab83993 [TFLITE]Activation functions support (#4978) ab83993 is described below commit ab839933093b37e4ee455e49a31e6a57b6156c5d Author: Samuel <siju.sam...@huawei.com> AuthorDate: Wed Mar 11 08:38:48 2020 +0530 [TFLITE]Activation functions support (#4978) * [TFLITE]elu, leaky_relu, lrn, log_softmax activation functions * removed ops present in pr 4805 * review_comments updated --- python/tvm/relay/frontend/tflite.py | 162 ++++++++++++++++++--------- tests/python/frontend/tflite/test_forward.py | 54 +++++++-- 2 files changed, 154 insertions(+), 62 deletions(-) diff --git a/python/tvm/relay/frontend/tflite.py b/python/tvm/relay/frontend/tflite.py index c2ec4d4..c820713 100644 --- a/python/tvm/relay/frontend/tflite.py +++ b/python/tvm/relay/frontend/tflite.py @@ -62,70 +62,72 @@ class OperatorConverter(object): # Add more operators self.convert_map = { 'ABS': self.convert_abs, + 'ADD': self.convert_add, + 'AVERAGE_POOL_2D': self.convert_average_pool2d, + 'BATCH_TO_SPACE_ND': self.convert_batch_to_space_nd, + 'CAST': self.convert_cast, + 'CEIL': self.convert_ceil, + 'CONCATENATION': self.convert_concatenation, + 'CONV_2D': self.convert_conv2d, + 'COS': self.convert_cos, + 'DEPTHWISE_CONV_2D': self.convert_depthwise_conv2d, + 'DETECTION_POSTPROCESS': self.convert_detection_postprocess, + 'DIV': self.convert_div, + 'ELU': self.convert_elu, + 'EQUAL': self.convert_equal, 'EXP': self.convert_exp, + 'FLOOR_DIV': self.convert_floor_div, + 'FLOOR_MOD': self.convert_floor_mod, 'FLOOR': self.convert_floor, - 'CEIL': self.convert_ceil, + 'FULLY_CONNECTED': self.convert_fully_connected, + 'GREATER_EQUAL': self.convert_greater_equal, + 'GREATER': self.convert_greater, + 'L2_NORMALIZATION': self.convert_l2_normalization, + 'LESS_EQUAL': self.convert_less_equal, + 'LESS': self.convert_less, + 'LOCAL_RESPONSE_NORMALIZATION': self.convert_lrn, 'LOG': self.convert_log, - 'SIN': self.convert_sin, - 'COS': self.convert_cos, - 'TAN': self.convert_tan, - 'SQRT': self.convert_sqrt, - 'RSQRT': self.convert_rsqrt, + 'LOGICAL_AND': self.convert_logical_and, + 'LOGICAL_OR': self.convert_logical_or, + 'LOGISTIC': self.convert_logistic, + 'MAX_POOL_2D': self.convert_max_pool2d, + 'MAXIMUM': self.convert_maximum, + 'MEAN': self._convert_reduce_mean, + 'MINIMUM': self.convert_minimum, + 'MIRROR_PAD': self.convert_mirror_pad, + 'MUL': self.convert_mul, 'NEG': self.convert_neg, - 'CONV_2D': self.convert_conv2d, - 'DEPTHWISE_CONV_2D': self.convert_depthwise_conv2d, - 'AVERAGE_POOL_2D': self.convert_average_pool2d, + 'NOT_EQUAL': self.convert_not_equal, + 'PACK': self.convert_pack, + 'PAD': self.convert_pad, + 'POW': self.convert_pow, + 'PRELU': self.convert_prelu, + 'REDUCE_MAX': self._convert_reduce_max, + 'REDUCE_MIN': self._convert_reduce_min, + 'REDUCE_PROD': self._convert_reduce_prod, + 'RELU':self.convert_relu, 'RESHAPE': self.convert_reshape, 'RESIZE_BILINEAR': self.convert_resize_bilinear, 'RESIZE_NEAREST_NEIGHBOR': self.convert_resize_nearest_neighbor, + 'RSQRT': self.convert_rsqrt, + 'SIN': self.convert_sin, + 'SLICE': self.convert_slice, 'SOFTMAX': self.convert_softmax, + 'SPACE_TO_BATCH_ND': self.convert_space_to_batch_nd, + 'SPLIT': self.convert_split, + 'SQRT': self.convert_sqrt, + 'SQUARE': self.convert_square, + 'SQUARED_DIFFERENCE': self.convert_squared_difference, 'SQUEEZE': self.convert_squeeze, - 'MAX_POOL_2D': self.convert_max_pool2d, - 'CONCATENATION': self.convert_concatenation, - 'ADD': self.convert_add, 'SUB': self.convert_sub, - 'MUL': self.convert_mul, - 'DIV': self.convert_div, - 'POW': self.convert_pow, - 'MAXIMUM': self.convert_maximum, - 'MINIMUM': self.convert_minimum, - 'GREATER': self.convert_greater, - 'GREATER_EQUAL': self.convert_greater_equal, - 'LESS': self.convert_less, - 'LESS_EQUAL': self.convert_less_equal, - 'EQUAL': self.convert_equal, - 'NOT_EQUAL': self.convert_not_equal, - 'ZEROS_LIKE': self.convert_zeros_like, - 'REDUCE_MIN': self._convert_reduce_min, - 'REDUCE_MAX': self._convert_reduce_max, - 'MEAN': self._convert_reduce_mean, - 'REDUCE_PROD': self._convert_reduce_prod, 'SUM': self._convert_reduce_sum, - 'FULLY_CONNECTED': self.convert_fully_connected, - 'PAD': self.convert_pad, - 'MIRROR_PAD': self.convert_mirror_pad, - 'PACK': self.convert_pack, - 'UNPACK': self.convert_unpack, - 'LOGISTIC': self.convert_logistic, + 'TAN': self.convert_tan, 'TANH':self.convert_tanh, - 'RELU':self.convert_relu, - 'SPLIT': self.convert_split, - 'SLICE': self.convert_slice, - 'TRANSPOSE': self.convert_transpose, - 'CAST': self.convert_cast, 'TILE': self.convert_tile, - 'BATCH_TO_SPACE_ND': self.convert_batch_to_space_nd, - 'SPACE_TO_BATCH_ND': self.convert_space_to_batch_nd, - 'PRELU': self.convert_prelu, 'TRANSPOSE_CONV': self.convert_transpose_conv, - 'SQUARED_DIFFERENCE': self.convert_squared_difference, - 'LOGICAL_AND': self.convert_logical_and, - 'LOGICAL_OR': self.convert_logical_or, - 'DETECTION_POSTPROCESS': self.convert_detection_postprocess, - 'SQUARE': self.convert_square, - 'L2_NORMALIZATION': self.convert_l2_normalization, - 'FLOOR_DIV': self.convert_floor_div, - 'FLOOR_MOD': self.convert_floor_mod, + 'TRANSPOSE': self.convert_transpose, + 'UNPACK': self.convert_unpack, + 'ZEROS_LIKE': self.convert_zeros_like, } def check_unsupported_ops(self): @@ -455,6 +457,43 @@ class OperatorConverter(object): return out + def convert_lrn(self, op): + """Convert TFLite LOCAL_RESPONSE_NORMALIZATION """ + try: + from tflite.Operator import Operator + from tflite.BuiltinOptions import BuiltinOptions + from tflite.LocalResponseNormalizationOptions import LocalResponseNormalizationOptions + except ImportError: + raise ImportError("The tflite package must be installed") + + assert isinstance(op, Operator) + if self.is_quantized(op): + raise tvm.error.OpNotImplemented( + 'TFlite quantized LRN operator is not supported yet.') + + input_tensors = self.get_input_tensors(op) + assert len(input_tensors) == 1, "input tensors length should be 1" + input_tensor = input_tensors[0] + in_expr = self.get_expr(input_tensor.tensor_idx) + + output_tensors = self.get_output_tensors(op) + assert len(output_tensors) == 1, "output tensors length should be 1" + + assert op.BuiltinOptionsType() == BuiltinOptions.LocalResponseNormalizationOptions + op_options = op.BuiltinOptions() + lrn_options = LocalResponseNormalizationOptions() + lrn_options.Init(op_options.Bytes, op_options.Pos) + radius = lrn_options.Radius() + bias = lrn_options.Bias() + alpha = lrn_options.Alpha() + beta = lrn_options.Beta() + size = (radius * 2) + 1 + alpha = alpha * size + axis = 3 # NHWC format + out = _op.nn.lrn(in_expr, size=size, axis=axis, bias=bias, alpha=alpha, beta=beta) + + return out + def convert_logistic(self, op): """Convert TFLite LOGISTIC""" try: @@ -693,6 +732,29 @@ class OperatorConverter(object): 'TFlite quantized NEG operator is not supported yet.') return self._convert_unary_elemwise(_op.negative, op) + def convert_elu(self, op): + """Convert TFLite ELU""" + try: + from tflite.Operator import Operator + except ImportError: + raise ImportError("The tflite package must be installed") + assert isinstance(op, Operator) + + if self.is_quantized(op): + raise tvm.error.OpNotImplemented( + 'TFlite quantized ELU operator is not supported yet.') + input_tensors = self.get_input_tensors(op) + assert len(input_tensors) == 1, "input tensors length should be 1" + + input_tensor = input_tensors[0] + in_expr = self.get_expr(input_tensor.tensor_idx) + exp_type = self.get_tensor_type_str(input_tensor.tensor.Type()) + out = relay.const(-1.0, exp_type) * \ + _op.nn.relu(relay.const(1., exp_type) - _op.exp(in_expr)) + \ + _op.nn.relu(in_expr) + + return out + def convert_square(self, op): """Convert TFLite SQUARE""" try: diff --git a/tests/python/frontend/tflite/test_forward.py b/tests/python/frontend/tflite/test_forward.py index 28216fc..78d6c3e 100644 --- a/tests/python/frontend/tflite/test_forward.py +++ b/tests/python/frontend/tflite/test_forward.py @@ -57,8 +57,8 @@ def convert_to_list(x): ####################################################################### -# Get a real image for e2e testing. -# -------------------------------------- +# Get a real image for e2e testing +# -------------------------------- def get_real_image(im_height, im_width): repo_base = 'https://github.com/dmlc/web-data/raw/master/tensorflow/models/InceptionV1/' img_name = 'elephant-299.jpg' @@ -299,7 +299,7 @@ def test_forward_transpose(): ####################################################################### # Cast -# -------- +# ---- def _test_cast(data, cast_dtype): """ One iteration of CAST """ @@ -316,8 +316,8 @@ def test_forward_cast(): _test_cast(np.arange(6.0, dtype=np.int32).reshape((1, 6)), cast_dtype=tf.int64) ####################################################################### -# tile -# --------- +# Tile +# ---- def _test_forward_tile(in_shape, reps, dtype): @@ -758,6 +758,14 @@ def _test_square(data): """ One iteration of square """ return _test_unary_elemwise(math_ops.square, data) +####################################################################### +# Elu +# --- + +def _test_elu(data): + """ One iteration of elu """ + return _test_unary_elemwise(nn_ops.elu, data) + def _test_forward_unary_elemwise(test_op): # functions that need positive input if test_op.__name__ in {'_test_log', '_test_sqrt', '_test_rsqrt'}: @@ -780,10 +788,11 @@ def test_all_unary_elemwise(): _test_forward_unary_elemwise(_test_ceil) _test_forward_unary_elemwise(_test_cos) _test_forward_unary_elemwise(_test_tan) + _test_forward_unary_elemwise(_test_elu) ####################################################################### # Element-wise -# --- +# ------------ def _test_elemwise(math_op, data, fused_activation_function=None, quantized=False, qnn_op=None): """ One iteration of elemwise """ @@ -1049,7 +1058,7 @@ def test_all_logical(): ####################################################################### # Zeros like -# -------- +# ---------- def _test_zeros_like(data): """ One iteration of ZEROS LIKE """ @@ -1237,7 +1246,7 @@ def test_forward_pad(): ####################################################################### # Pack -# ------------- +# ---- def _test_pack(data, axis): """ One iteration of pack """ @@ -1291,6 +1300,26 @@ def test_forward_unpack(): _test_unpack(np.array(np.random.uniform(0, 5, (3, 6)), dtype=np.int32), axis=-2, num_unpacks=3) _test_unpack(np.array(np.random.uniform(0, 5, (2, 3, 4)), dtype=np.int32), axis=-3, num_unpacks=2) + +####################################################################### +# Local response normalization +# ---------------------------- + +def _test_local_response_normalization(data, depth_radius, bias, alpha, beta): + """ One iteration of LOCAL_RESPONSE_NORMALIZATION """ + with tf.Graph().as_default(): + in_data = array_ops.placeholder(shape=data.shape, dtype='float32', name='in_0') + out = nn_ops.local_response_normalization(in_data, depth_radius=depth_radius, bias=bias, alpha=alpha, beta=beta) + compare_tflite_with_tvm(data, 'in_0:0', [in_data], [out]) + +def test_forward_local_response_normalization(): + """ LOCAL_RESPONSE_NORMALIZATION """ + data = np.random.uniform(size=(1, 6, 4, 3)).astype('float32') + # LOCAL_RESPONSE_NORMALIZATION come with TFLite >= 1.14.0 fbs schema + if package_version.parse(tf.VERSION) >= package_version.parse('1.14.0'): + _test_local_response_normalization(data, depth_radius=5, bias=1, alpha=1, beta=0.5) + + ####################################################################### # L2 normalization # ---------------- @@ -1350,7 +1379,7 @@ def test_forward_softmax(): ####################################################################### # Tanh -# -------- +# ---- def _test_tanh(data): """ One iteration of TANH """ @@ -1365,7 +1394,7 @@ def test_forward_tanh(): ####################################################################### # ReLu -# -------- +# ---- def _test_relu(data): """ One iteration of ReLU """ @@ -1393,7 +1422,7 @@ def test_forward_prelu(): ####################################################################### # Fully Connected -# ------- +# --------------- def _test_fully_connected(tensor_in_sizes, filter_in_sizes, bias_in_size=None): """ One iteration of fully connected """ @@ -1518,7 +1547,7 @@ def test_forward_mobilenet_v2(): ####################################################################### # Inception -# ------------ +# --------- def test_forward_inception_v3_net(): """Test the Inception V3 TF Lite model.""" @@ -1696,6 +1725,7 @@ if __name__ == '__main__': test_forward_prelu() test_forward_fully_connected() test_forward_l2_normalization() + test_forward_local_response_normalization() # Elemwise test_all_elemwise()