From 7ad7977d75c3862f1603dc2137b7ec26e8c462ea Mon Sep 17 00:00:00 2001 From: 0xjah Date: Wed, 8 Apr 2026 19:38:29 +0300 Subject: [PATCH 1/5] [relax][frontend][tflite] add tests for fully_connected/depthwise_conv2d/transpose_conv/l2_pool2d --- tests/python/relax/test_frontend_tflite.py | 66 ++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/tests/python/relax/test_frontend_tflite.py b/tests/python/relax/test_frontend_tflite.py index 275e162b818b..aa9c7598d4ed 100644 --- a/tests/python/relax/test_frontend_tflite.py +++ b/tests/python/relax/test_frontend_tflite.py @@ -707,6 +707,72 @@ def main(x: R.Tensor((5, 30), dtype="float32")) -> R.Tensor(out_shape, dtype="in verify(TfInput, Expected) +def test_fully_connected(): + class FullyConnected(tf.Module): + @tf.function(input_signature=[tf.TensorSpec(shape=(1, 8), dtype=tf.float32)]) + def func(self, x): + weight = tf.constant(np.arange(24, dtype=np.float32).reshape((3, 8))) + bias = tf.constant(np.array([0.5, 1.0, -1.0], dtype=np.float32)) + out = tf.matmul(x, weight, transpose_b=True) + return tf.nn.bias_add(out, bias) + + verify(FullyConnected) + + +def test_depthwise_conv2d(): + class DepthwiseConv2D(tf.Module): + @tf.function( + input_signature=[ + tf.TensorSpec(shape=(1, 8, 8, 2), dtype=tf.float32), + tf.TensorSpec(shape=(3, 3, 2, 2), dtype=tf.float32), + ] + ) + def func(self, data, kernel): + return tf.nn.depthwise_conv2d( + input=data, + filter=kernel, + strides=[1, 1, 1, 1], + padding="SAME", + ) + + verify(DepthwiseConv2D) + + +def test_transpose_conv(): + class TransposeConv(tf.Module): + @tf.function( + input_signature=[ + tf.TensorSpec(shape=(1, 8, 8, 2), dtype=tf.float32), + tf.TensorSpec(shape=(3, 3, 3, 2), dtype=tf.float32), + ] + ) + def func(self, data, kernel): + output_shape = tf.constant([1, 8, 8, 3], dtype=tf.int32) + return tf.nn.conv2d_transpose( + input=data, + filters=kernel, + output_shape=output_shape, + strides=[1, 1, 1, 1], + padding="SAME", + ) + + verify(TransposeConv) + + +def test_l2_pool2d(): + class L2Pool2D(tf.Module): + @tf.function(input_signature=[tf.TensorSpec(shape=(1, 8, 8, 2), dtype=tf.float32)]) + def func(self, data): + return tf.compat.v1.nn.l2_pool( + input=data, + ksize=[1, 2, 2, 1], + strides=[1, 1, 1, 1], + padding="SAME", + ) + + verify(L2Pool2D) + + def _make_conv2d_module(data_shape, kernel_shape, data_format, strides, padding): class Conv2DModule(tf.Module): @tf.function( From 42859531e40745eeac1969215c3d4b1aa0634d4d Mon Sep 17 00:00:00 2001 From: 0xjah Date: Thu, 9 Apr 2026 11:37:21 +0300 Subject: [PATCH 2/5] Fix: Correct depthwise_conv2d kernel shape and l2_pool2d API compatibility - Fix test_depthwise_conv2d: Correct kernel shape from (3,3,2,2) to (3,3,1,2) - For depthwise convolution with 2 input channels and grouping, kernel should have shape (height, width, input_channels_per_group, depth_multiplier) = (3, 3, 1, 2) - This matches the format required by tf.nn.depthwise_conv2d - Fix test_l2_pool2d: Replace deprecated tf.compat.v1.nn.l2_pool with tf.nn.pool - tf.compat.v1.nn.l2_pool is no longer available in current TensorFlow versions - Use tf.nn.pool with AVG pooling type and appropriate window shape and strides --- tests/python/relax/test_frontend_tflite.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/python/relax/test_frontend_tflite.py b/tests/python/relax/test_frontend_tflite.py index aa9c7598d4ed..a37ec387c14a 100644 --- a/tests/python/relax/test_frontend_tflite.py +++ b/tests/python/relax/test_frontend_tflite.py @@ -724,7 +724,7 @@ class DepthwiseConv2D(tf.Module): @tf.function( input_signature=[ tf.TensorSpec(shape=(1, 8, 8, 2), dtype=tf.float32), - tf.TensorSpec(shape=(3, 3, 2, 2), dtype=tf.float32), + tf.TensorSpec(shape=(3, 3, 1, 2), dtype=tf.float32), ] ) def func(self, data, kernel): @@ -763,10 +763,11 @@ def test_l2_pool2d(): class L2Pool2D(tf.Module): @tf.function(input_signature=[tf.TensorSpec(shape=(1, 8, 8, 2), dtype=tf.float32)]) def func(self, data): - return tf.compat.v1.nn.l2_pool( + return tf.nn.pool( input=data, - ksize=[1, 2, 2, 1], - strides=[1, 1, 1, 1], + window_shape=[2, 2], + pooling_type="AVG", + strides=[1, 1], padding="SAME", ) From 343d055ea2d823f915240ee183ac272b3b382f48 Mon Sep 17 00:00:00 2001 From: 0xjah Date: Thu, 9 Apr 2026 21:45:44 +0300 Subject: [PATCH 3/5] Fix: Correct depthwise_conv2d kernel shape to match input channels Changed kernel shape from (3,3,1,2) to (3,3,2,1) because: - Input shape is (1,8,8,2) with 2 channels - depthwise_conv2d filter format: [height, width, in_channels, depth_multiplier] - With 2 input channels, third dimension must be 2 (not 1) - Using (3,3,2,1) means 2 output channels (one multiplier per input channel) --- tests/python/relax/test_frontend_tflite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/python/relax/test_frontend_tflite.py b/tests/python/relax/test_frontend_tflite.py index a37ec387c14a..a3730e8a0c0f 100644 --- a/tests/python/relax/test_frontend_tflite.py +++ b/tests/python/relax/test_frontend_tflite.py @@ -724,7 +724,7 @@ class DepthwiseConv2D(tf.Module): @tf.function( input_signature=[ tf.TensorSpec(shape=(1, 8, 8, 2), dtype=tf.float32), - tf.TensorSpec(shape=(3, 3, 1, 2), dtype=tf.float32), + tf.TensorSpec(shape=(3, 3, 2, 1), dtype=tf.float32), ] ) def func(self, data, kernel): From f14c4fd06b40a2561c7653ca00f56e938493fa45 Mon Sep 17 00:00:00 2001 From: 0xjah Date: Sat, 11 Apr 2026 13:17:14 +0300 Subject: [PATCH 4/5] Update tflite frontend and tests for conv/linear/pooling support --- .../relax/frontend/tflite/tflite_frontend.py | 2 -- tests/python/relax/test_frontend_tflite.py | 33 ++++++++++++++----- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/python/tvm/relax/frontend/tflite/tflite_frontend.py b/python/tvm/relax/frontend/tflite/tflite_frontend.py index 1a437093a718..eece6be15224 100644 --- a/python/tvm/relax/frontend/tflite/tflite_frontend.py +++ b/python/tvm/relax/frontend/tflite/tflite_frontend.py @@ -3089,8 +3089,6 @@ def convert_transpose_conv(self, op): weight_expr_iohw, strides=(stride_h, stride_w), padding=padding, - channels=int(out_channels), - kernel_size=(int(kernel_h), int(kernel_w)), data_layout="NHWC", kernel_layout="IOHW", out_dtype=output_tensor_type_str, diff --git a/tests/python/relax/test_frontend_tflite.py b/tests/python/relax/test_frontend_tflite.py index a3730e8a0c0f..252bd3e04e16 100644 --- a/tests/python/relax/test_frontend_tflite.py +++ b/tests/python/relax/test_frontend_tflite.py @@ -758,20 +758,35 @@ def func(self, data, kernel): verify(TransposeConv) - def test_l2_pool2d(): class L2Pool2D(tf.Module): @tf.function(input_signature=[tf.TensorSpec(shape=(1, 8, 8, 2), dtype=tf.float32)]) def func(self, data): - return tf.nn.pool( - input=data, - window_shape=[2, 2], - pooling_type="AVG", - strides=[1, 1], - padding="SAME", - ) + squared = tf.math.square(data) + pooled = tf.nn.avg_pool2d(squared, ksize=[2, 2], strides=[1, 1], padding="SAME") + return tf.math.sqrt(pooled) + + @I.ir_module + class Expected: + @R.function + def main( + data: R.Tensor((1, 8, 8, 2), dtype="float32") + ) -> R.Tensor((1, 8, 8, 2), dtype="float32"): + R.func_attr({"num_input": 1}) + with R.dataflow(): + squared = R.power(data, R.const(2.0, "float32")) + pooled = R.nn.avg_pool2d( + squared, + pool_size=[2, 2], + strides=[1, 1], + padding=[0, 0, 1, 1], + layout="NHWC", + ) + gv = R.sqrt(pooled) + R.output(gv) + return gv - verify(L2Pool2D) + verify(L2Pool2D, Expected) def _make_conv2d_module(data_shape, kernel_shape, data_format, strides, padding): From c2d6545320f36c8ec24e16bd58c958bbf12259c1 Mon Sep 17 00:00:00 2001 From: 0xjah Date: Sat, 11 Apr 2026 22:14:16 +0300 Subject: [PATCH 5/5] Update TFLite frontend tests after merge Sync test_frontend_tflite.py with latest changes from main branch --- tests/python/relax/test_frontend_tflite.py | 43 ++++++++++++---------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/tests/python/relax/test_frontend_tflite.py b/tests/python/relax/test_frontend_tflite.py index 2dd9b2461ae2..c766b806c764 100644 --- a/tests/python/relax/test_frontend_tflite.py +++ b/tests/python/relax/test_frontend_tflite.py @@ -767,6 +767,30 @@ def func(self, data): squared = tf.math.square(data) pooled = tf.nn.avg_pool2d(squared, ksize=[2, 2], strides=[1, 1], padding="SAME") return tf.math.sqrt(pooled) + + @I.ir_module + class Expected: + @R.function + def main( + data: R.Tensor((1, 8, 8, 2), dtype="float32") + ) -> R.Tensor((1, 8, 8, 2), dtype="float32"): + R.func_attr({"num_input": 1}) + with R.dataflow(): + squared = R.power(data, R.const(2.0, "float32")) + pooled = R.nn.avg_pool2d( + squared, + pool_size=[2, 2], + strides=[1, 1], + padding=[0, 0, 1, 1], + layout="NHWC", + ) + gv = R.sqrt(pooled) + R.output(gv) + return gv + + verify(L2Pool2D, Expected) + + def test_l2_normalization(): class L2Normalization(tf.Module): @tf.function(input_signature=[tf.TensorSpec(shape=(2, 4), dtype=tf.float32)]) @@ -806,24 +830,6 @@ def func(self, x): @I.ir_module class Expected: @R.function - def main( - data: R.Tensor((1, 8, 8, 2), dtype="float32") - ) -> R.Tensor((1, 8, 8, 2), dtype="float32"): - R.func_attr({"num_input": 1}) - with R.dataflow(): - squared = R.power(data, R.const(2.0, "float32")) - pooled = R.nn.avg_pool2d( - squared, - pool_size=[2, 2], - strides=[1, 1], - padding=[0, 0, 1, 1], - layout="NHWC", - ) - gv = R.sqrt(pooled) - R.output(gv) - return gv - - verify(L2Pool2D, Expected) def main(x: R.Tensor((2, 3), dtype="float32")) -> R.Tensor((2, 3), dtype="float32"): R.func_attr({"num_input": 1}) with R.dataflow(): @@ -833,7 +839,6 @@ def main(x: R.Tensor((2, 3), dtype="float32")) -> R.Tensor((2, 3), dtype="float3 verify(ReverseV2, Expected) - def _make_conv2d_module(data_shape, kernel_shape, data_format, strides, padding): class Conv2DModule(tf.Module): @tf.function(