From fa5fd01612d454a4c374e6bc4fd7cdf999e1c9c4 Mon Sep 17 00:00:00 2001 From: Ramesh Kunasi Date: Mon, 16 Jun 2025 04:52:39 +0000 Subject: [PATCH 1/7] Sync files related to Reverse_V2 from TFLite #3110 --- ci/tflite_files.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/ci/tflite_files.txt b/ci/tflite_files.txt index 83bd58fc0a6..a95475ec9e0 100644 --- a/ci/tflite_files.txt +++ b/ci/tflite_files.txt @@ -88,6 +88,7 @@ tensorflow/lite/kernels/internal/reference/reduce.h tensorflow/lite/kernels/internal/reference/requantize.h tensorflow/lite/kernels/internal/reference/resize_bilinear.h tensorflow/lite/kernels/internal/reference/resize_nearest_neighbor.h +tensorflow/lite/kernels/internal/reference/reverse.h tensorflow/lite/kernels/internal/reference/round.h tensorflow/lite/kernels/internal/reference/softmax.h tensorflow/lite/kernels/internal/reference/space_to_batch_nd.h From 1cb414cca29280ad3f1ea634fae53703dfa6b5ea Mon Sep 17 00:00:00 2001 From: Ramesh Kunasi Date: Fri, 20 Jun 2025 13:23:44 +0000 Subject: [PATCH 2/7] Added Reverse_V2 changes BUG=fixes #3110 --- python/tflite_micro/python_ops_resolver.cc | 1 + tensorflow/lite/micro/kernels/BUILD | 14 + tensorflow/lite/micro/kernels/Makefile.inc | 1 + tensorflow/lite/micro/kernels/micro_ops.h | 1 + tensorflow/lite/micro/kernels/reverse.cc | 202 +++++++++ tensorflow/lite/micro/kernels/reverse_test.cc | 408 ++++++++++++++++++ .../lite/micro/micro_mutable_op_resolver.h | 5 + .../micro/tools/benchmarking/op_resolver.h | 1 + tensorflow/lite/micro/tools/make/Makefile | 1 + 9 files changed, 634 insertions(+) create mode 100644 tensorflow/lite/micro/kernels/reverse.cc create mode 100644 tensorflow/lite/micro/kernels/reverse_test.cc diff --git a/python/tflite_micro/python_ops_resolver.cc b/python/tflite_micro/python_ops_resolver.cc index f5d6e636c16..f7171d7e0f7 100644 --- a/python/tflite_micro/python_ops_resolver.cc +++ b/python/tflite_micro/python_ops_resolver.cc @@ -104,6 +104,7 @@ PythonOpsResolver::PythonOpsResolver() { AddReshape(); AddResizeBilinear(); AddResizeNearestNeighbor(); + AddReverseV2(); AddRfft(); AddRound(); AddRsqrt(); diff --git a/tensorflow/lite/micro/kernels/BUILD b/tensorflow/lite/micro/kernels/BUILD index 7b5ddc7b306..babdb7b6406 100644 --- a/tensorflow/lite/micro/kernels/BUILD +++ b/tensorflow/lite/micro/kernels/BUILD @@ -292,6 +292,7 @@ tflm_kernel_cc_library( "reshape_common.cc", "resize_bilinear.cc", "resize_nearest_neighbor.cc", + "reverse.cc", "round.cc", "select.cc", "shape.cc", @@ -1224,6 +1225,19 @@ tflm_cc_test( ], ) +tflm_cc_test( + name = "reverse_test", + srcs = [ + "reverse_test.cc", + ], + deps = [ + ":kernel_runner", + "//tensorflow/lite/c:common", + "//tensorflow/lite/micro:test_helpers", + "//tensorflow/lite/micro/testing:micro_test", + ], +) + tflm_cc_test( name = "round_test", srcs = [ diff --git a/tensorflow/lite/micro/kernels/Makefile.inc b/tensorflow/lite/micro/kernels/Makefile.inc index f4456242fef..a62432daa1b 100644 --- a/tensorflow/lite/micro/kernels/Makefile.inc +++ b/tensorflow/lite/micro/kernels/Makefile.inc @@ -160,6 +160,7 @@ $(TENSORFLOW_ROOT)tensorflow/lite/micro/kernels/reduce_test.cc \ $(TENSORFLOW_ROOT)tensorflow/lite/micro/kernels/reshape_test.cc \ $(TENSORFLOW_ROOT)tensorflow/lite/micro/kernels/resize_bilinear_test.cc \ $(TENSORFLOW_ROOT)tensorflow/lite/micro/kernels/resize_nearest_neighbor_test.cc \ +$(TENSORFLOW_ROOT)tensorflow/lite/micro/kernels/reverse_test.cc \ $(TENSORFLOW_ROOT)tensorflow/lite/micro/kernels/round_test.cc \ $(TENSORFLOW_ROOT)tensorflow/lite/micro/kernels/select_test.cc \ $(TENSORFLOW_ROOT)tensorflow/lite/micro/kernels/shape_test.cc \ diff --git a/tensorflow/lite/micro/kernels/micro_ops.h b/tensorflow/lite/micro/kernels/micro_ops.h index 2e33a6730bd..13a0798b159 100644 --- a/tensorflow/lite/micro/kernels/micro_ops.h +++ b/tensorflow/lite/micro/kernels/micro_ops.h @@ -105,6 +105,7 @@ TFLMRegistration Register_RELU6(); TFLMRegistration Register_RESHAPE(); TFLMRegistration Register_RESIZE_BILINEAR(); TFLMRegistration Register_RESIZE_NEAREST_NEIGHBOR(); +TFLMRegistration Register_REVERSE_V2(); TFLMRegistration Register_ROUND(); TFLMRegistration Register_RSQRT(); TFLMRegistration Register_SELECT_V2(); diff --git a/tensorflow/lite/micro/kernels/reverse.cc b/tensorflow/lite/micro/kernels/reverse.cc new file mode 100644 index 00000000000..3010fa0cf4a --- /dev/null +++ b/tensorflow/lite/micro/kernels/reverse.cc @@ -0,0 +1,202 @@ +/* Copyright 2025 The TensorFlow Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ + +#include + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/micro_log.h" +#include "tensorflow/lite/micro/micro_utils.h" + +namespace tflite { + +constexpr int kMaxDimensions = 8; + +namespace { + +constexpr int kInputTensor = 0; +constexpr int kAxisTensor = 1; +constexpr int kOutputTensor = 0; + +TfLiteStatus ReverseV2Prepare(TfLiteContext* context, TfLiteNode* node) { + MicroContext* micro_context = GetMicroContext(context); + + TF_LITE_ENSURE_EQ(context, NumInputs(node), 2); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + + // Ensure inputs and outputs exist. + TfLiteTensor* input = + micro_context->AllocateTempInputTensor(node, kInputTensor); + TF_LITE_ENSURE(context, input != nullptr); + TfLiteTensor* axis = + micro_context->AllocateTempInputTensor(node, kAxisTensor); + TF_LITE_ENSURE(context, axis != nullptr); + TfLiteTensor* output = + micro_context->AllocateTempOutputTensor(node, kOutputTensor); + TF_LITE_ENSURE(context, output != nullptr); + TF_LITE_ENSURE_EQ(context, NumDimensions(axis), 1); + TF_LITE_ENSURE(context, NumDimensions(input) <= 8); + TF_LITE_ENSURE(context, NumDimensions(input) >= NumElements(axis)); + + if (input->type != kTfLiteInt32 && input->type != kTfLiteFloat32 && + input->type != kTfLiteUInt8 && input->type != kTfLiteInt8 && + input->type != kTfLiteInt16) { + MicroPrintf("Type '%s' is not supported by reverse.", + TfLiteTypeGetName(input->type)); + return kTfLiteError; + } + + if (axis->type != kTfLiteInt32) { + MicroPrintf("Axis Type '%s' is not supported by reverse.", + TfLiteTypeGetName(axis->type)); + return kTfLiteError; + } + // The value type and output type must match. + TF_LITE_ENSURE_EQ(context, input->type, output->type); + + micro_context->DeallocateTempTfLiteTensor(input); + micro_context->DeallocateTempTfLiteTensor(axis); + micro_context->DeallocateTempTfLiteTensor(output); + return kTfLiteOk; +} + +template +void ReverseImpl(int32_t* axes, int num_axes, + const RuntimeShape& input_shape, const T* input_data, + T* output_data) { + bool is_upper = (axes[num_axes - 1] == input_shape.DimensionsCount() - 1); + bool is_lower = (axes[0] == 0); + int rank = input_shape.DimensionsCount(); + if (is_upper && is_lower) { + std::reverse_copy(input_data, input_data + input_shape.FlatSize(), + output_data); + return; + } else { + int32_t min_dim = axes[0]; + int32_t max_dim = axes[num_axes - 1]; + int upper_size = 1; + for (int i = 0; i < min_dim; ++i) { + upper_size *= input_shape.Dims(i); + } + int lower_size = 1; + for (int i = max_dim + 1; i < rank; ++i) { + lower_size *= input_shape.Dims(i); + } + int middle_size = 1; + for (int i = min_dim; i <= max_dim; ++i) { + middle_size *= input_shape.Dims(i); + } + + if (lower_size > 1) { + for (int i = 0; i < upper_size; ++i) { + for (int j = 0; j < middle_size; ++j) { + T* src = + (T*)input_data + (i * (middle_size) + j) * lower_size; + T* dst = + (T*)output_data + + (i * (middle_size) + (middle_size - j - 1)) * lower_size; + memcpy(dst, src, lower_size * sizeof(T)); + } + } + } else { + for (int i = 0; i < upper_size; ++i) { + std::reverse_copy(input_data + i * (middle_size), + input_data + i * middle_size + middle_size, + output_data + i * (middle_size)); + } + } + } +} + +TfLiteStatus ReverseV2Eval(TfLiteContext* context, TfLiteNode* node) { + const TfLiteEvalTensor* input = + micro::GetEvalInput(context, node, kInputTensor); + const TfLiteEvalTensor* axis = + micro::GetEvalInput(context, node, kAxisTensor); + TfLiteEvalTensor* output = micro::GetEvalOutput(context, node, kOutputTensor); + + TF_LITE_ENSURE_EQ(context, axis->type, kTfLiteInt32); + const int num_axes = static_cast(ElementCount(*axis->dims)); + TF_LITE_ENSURE(context, num_axes <= 8); + + int32_t axes_data[kMaxDimensions]; + std::memcpy(axes_data, axis->data.i32, sizeof(int32_t) * num_axes); + const int rank = tflite::micro::GetTensorShape(input).DimensionsCount(); + for (int i = 0; i < num_axes; ++i) { + if (axes_data[i] < 0) { + axes_data[i] += rank; + } + TF_LITE_ENSURE(context, axes_data[i] >= 0 && axes_data[i] < rank); + } + std::sort(axes_data, axes_data + num_axes); + + bool is_contiguous = true; + for (int i = 1; i < num_axes; ++i) { + if (axes_data[i - 1] + 1 != axes_data[i]) { + is_contiguous = false; + break; + } + } + if (!is_contiguous) { + MicroPrintf("Non-contiguous `axes` not supported"); + return kTfLiteError; + } + + switch (output->type) { + case kTfLiteFloat32: + ReverseImpl(axes_data, num_axes, + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorData(output)); + break; + case kTfLiteInt32: + ReverseImpl(axes_data, num_axes, + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorData(output)); + break; + case kTfLiteInt16: + ReverseImpl(axes_data, num_axes, + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorData(output)); + break; + case kTfLiteInt8: + case kTfLiteUInt8: + ReverseImpl(axes_data, num_axes, + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorData(output)); + break; + default: + MicroPrintf( + "Reverse currently supports float32, int16, " + "int8 and uint8 for output, got %d.", + TfLiteTypeGetName(output->type)); + return kTfLiteError; + } + + return kTfLiteOk; +} + +} // namespace + +TFLMRegistration Register_REVERSE_V2() { + return tflite::micro::RegisterOp(nullptr, ReverseV2Prepare, ReverseV2Eval); +} + +} // namespace tflite diff --git a/tensorflow/lite/micro/kernels/reverse_test.cc b/tensorflow/lite/micro/kernels/reverse_test.cc new file mode 100644 index 00000000000..19d0b483097 --- /dev/null +++ b/tensorflow/lite/micro/kernels/reverse_test.cc @@ -0,0 +1,408 @@ +/* Copyright 2025 The TensorFlow Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ + +#include + +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/micro/kernels/kernel_runner.h" +#include "tensorflow/lite/micro/test_helpers.h" +#include "tensorflow/lite/micro/testing/micro_test.h" + +namespace tflite { +namespace testing { +namespace { + +constexpr int kNumInputs = 2; +constexpr int kNumOutputs = 1; +constexpr int kInputTensorIndex_0 = 0; +constexpr int kInputTensorIndex_1 = 1; +constexpr int kOutputTensorIndex = 2; + +void ExecuteReverseTest(TfLiteTensor* tensors, int tensors_count) { + int kInputArrayData[] = {kNumInputs, kInputTensorIndex_0, + kInputTensorIndex_1}; + TfLiteIntArray* inputs_array = IntArrayFromInts(kInputArrayData); + int kOutputArrayData[] = {kNumOutputs, kOutputTensorIndex}; + TfLiteIntArray* outputs_array = IntArrayFromInts(kOutputArrayData); + + const TFLMRegistration registration = tflite::Register_REVERSE_V2(); + micro::KernelRunner runner(registration, tensors, tensors_count, inputs_array, + outputs_array, nullptr); + + TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, runner.InitAndPrepare()); + TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, runner.Invoke()); +} + +template +void TestReverse(int* input_dims_data[kNumInputs], + const T* input_data_0, const int32_t* input_data_1, + int* expected_dims, const T* expected_data, + T* output_data) { + TfLiteIntArray* input_dims_0 = IntArrayFromInts(input_dims_data[0]); + TfLiteIntArray* input_dims_1 = IntArrayFromInts(input_dims_data[1]); + TfLiteIntArray* output_dims = IntArrayFromInts(expected_dims); + const int output_count = ElementCount(*output_dims); + + TfLiteTensor tensors[] = { + CreateTensor(input_data_0, input_dims_0), + CreateTensor(input_data_1, input_dims_1), + CreateTensor(output_data, output_dims), + }; + constexpr int tensors_count = std::extent::value; + ExecuteReverseTest(tensors, tensors_count); + + // check output data against expected + for (int i = 0; i < output_count; i++) { + TF_LITE_MICRO_EXPECT_NEAR(expected_data[i], output_data[i], 0); + } + + // check output dimensions (relocated) against original dimensions + TF_LITE_MICRO_EXPECT_EQ(output_dims->size, + tensors[kOutputTensorIndex].dims->size); + for (int i = 0; i < output_dims->size; i++) { + TF_LITE_MICRO_EXPECT_EQ(output_dims->data[i], + tensors[kOutputTensorIndex].dims->data[i]); + } +} + +} // namespace +} // namespace testing +} // namespace tflite + +TF_LITE_MICRO_TESTS_BEGIN + +// float32 tests. +TF_LITE_MICRO_TEST(ReverseOpTestFloatOneDimension) { + int kInputDims_0[] = {1, 4}; + int kInputDims_1[] = {1, 1}; + int* kInputDims[tflite::testing::kNumInputs] = {kInputDims_0, kInputDims_1}; + int kOutputDims[] = {1, 4}; + + const float kInput_0[] = {1, 2, 3, 4}; + const int32_t kInput_1[] = {0}; + const float kExpect[] = {4, 3, 2, 1}; + const int kOutputCount = std::extent::value; + float output_data[kOutputCount]; + + tflite::testing::TestReverse(kInputDims, kInput_0, kInput_1, kOutputDims, + kExpect, output_data); +} + +TF_LITE_MICRO_TEST(ReverseOpTestFloatMultiDimensions) { + int kInputDims_0[] = {3, 4, 3, 2}; + int kInputDims_1[] = {1, 1}; + int* kInputDims[tflite::testing::kNumInputs] = {kInputDims_0, kInputDims_1}; + int kOutputDims[] = {3, 4, 3, 2}; + + const float kInput_0[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}; + const int32_t kInput_1[] = {1}; + const float kExpect[] = {5, 6, 3, 4, 1, 2, 11, 12, 9, 10, 7, 8, + 17, 18, 15, 16, 13, 14, 23, 24, 21, 22, 19, 20}; + const int kOutputCount = std::extent::value; + float output_data[kOutputCount]; + + tflite::testing::TestReverse(kInputDims, kInput_0, kInput_1, kOutputDims, + kExpect, output_data); +} + +// int32 tests +TF_LITE_MICRO_TEST(ReverseOpTestInt32OneDimension) { + int kInputDims_0[] = {1, 4}; + int kInputDims_1[] = {1, 1}; + int* kInputDims[tflite::testing::kNumInputs] = {kInputDims_0, kInputDims_1}; + int kOutputDims[] = {1, 4}; + + const int32_t kInput_0[] = {1, 2, 3, 4}; + const int32_t kInput_1[] = {0}; + const int32_t kExpect[] = {4, 3, 2, 1}; + const int kOutputCount = std::extent::value; + int32_t output_data[kOutputCount]; + + tflite::testing::TestReverse(kInputDims, kInput_0, kInput_1, kOutputDims, + kExpect, output_data); +} + +TF_LITE_MICRO_TEST(ReverseOpTestInt32MultiDimensions) { + int kInputDims_0[] = {3, 4, 3, 2}; + int kInputDims_1[] = {1, 1}; + int* kInputDims[tflite::testing::kNumInputs] = {kInputDims_0, kInputDims_1}; + int kOutputDims[] = {3, 4, 3, 2}; + + const int32_t kInput_0[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}; + const int32_t kInput_1[] = {1}; + const int32_t kExpect[] = {5, 6, 3, 4, 1, 2, 11, 12, 9, 10, 7, 8, + 17, 18, 15, 16, 13, 14, 23, 24, 21, 22, 19, 20}; + const int kOutputCount = std::extent::value; + int32_t output_data[kOutputCount]; + + tflite::testing::TestReverse(kInputDims, kInput_0, kInput_1, kOutputDims, + kExpect, output_data); +} + +TF_LITE_MICRO_TEST(ReverseOpTestInt32MultiDimensionsFirst) { + int kInputDims_0[] = {3, 3, 3, 3}; + int kInputDims_1[] = {1, 1}; + int* kInputDims[tflite::testing::kNumInputs] = {kInputDims_0, kInputDims_1}; + int kOutputDims[] = {3, 3, 3, 3}; + + const int32_t kInput_0[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27}; + const int32_t kInput_1[] = {0}; + const int32_t kExpect[] = {19, 20, 21, 22, 23, 24, 25, 26, 27, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 1, 2, 3, 4, 5, 6, + 7, 8, 9}; + const int kOutputCount = std::extent::value; + int32_t output_data[kOutputCount]; + + tflite::testing::TestReverse(kInputDims, kInput_0, kInput_1, kOutputDims, + kExpect, output_data); +} + +TF_LITE_MICRO_TEST(ReverseOpTestInt32MultiDimensionsSecond) { + int kInputDims_0[] = {3, 3, 3, 3}; + int kInputDims_1[] = {1, 1}; + int* kInputDims[tflite::testing::kNumInputs] = {kInputDims_0, kInputDims_1}; + int kOutputDims[] = {3, 3, 3, 3}; + + const int32_t kInput_0[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27}; + const int32_t kInput_1[] = {1}; + const int32_t kExpect[] = {7, 8, 9, 4, 5, 6, 1, 2, 3, 16, 17, 18, + 13, 14, 15, 10, 11, 12, 25, 26, 27, 22, 23, 24, + 19, 20, 21}; + const int kOutputCount = std::extent::value; + int32_t output_data[kOutputCount]; + + tflite::testing::TestReverse(kInputDims, kInput_0, kInput_1, kOutputDims, + kExpect, output_data); +} + +TF_LITE_MICRO_TEST(ReverseOpTestInt32MultiDimensionsThird) { + int kInputDims_0[] = {3, 3, 3, 3}; + int kInputDims_1[] = {1, 1}; + int* kInputDims[tflite::testing::kNumInputs] = {kInputDims_0, kInputDims_1}; + int kOutputDims[] = {3, 3, 3, 3}; + + const int32_t kInput_0[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27}; + const int32_t kInput_1[] = {2}; + const int32_t kExpect[] = {3, 2, 1, 6, 5, 4, 9, 8, 7, 12, 11, 10, + 15, 14, 13, 18, 17, 16, 21, 20, 19, 24, 23, 22, + 27, 26, 25}; + const int kOutputCount = std::extent::value; + int32_t output_data[kOutputCount]; + + tflite::testing::TestReverse(kInputDims, kInput_0, kInput_1, kOutputDims, + kExpect, output_data); +} + +TF_LITE_MICRO_TEST(ReverseOpTestInt32MultiDimensionsFirstSecond) { + int kInputDims_0[] = {3, 3, 3, 3}; + int kInputDims_1[] = {1, 2}; + int* kInputDims[tflite::testing::kNumInputs] = {kInputDims_0, kInputDims_1}; + int kOutputDims[] = {3, 3, 3, 3}; + + const int32_t kInput_0[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27}; + const int32_t kInput_1[] = {0, 1}; + + const int32_t kExpect[] = {25, 26, 27, 22, 23, 24, 19, 20, 21, 16, 17, 18, + 13, 14, 15, 10, 11, 12, 7, 8, 9, 4, 5, 6, + 1, 2, 3}; + + const int kOutputCount = std::extent::value; + int32_t output_data[kOutputCount]; + + tflite::testing::TestReverse(kInputDims, kInput_0, kInput_1, kOutputDims, + kExpect, output_data); +} + +TF_LITE_MICRO_TEST(ReverseOpTestInt32MultiDimensionsSecondThird) { + int kInputDims_0[] = {3, 3, 3, 3}; + int kInputDims_1[] = {1, 2}; + int* kInputDims[tflite::testing::kNumInputs] = {kInputDims_0, kInputDims_1}; + int kOutputDims[] = {3, 3, 3, 3}; + + const int32_t kInput_0[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27}; + const int32_t kInput_1[] = {1, 2}; + + const int32_t kExpect[] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 18, 17, 16, + 15, 14, 13, 12, 11, 10, 27, 26, 25, 24, 23, 22, + 21, 20, 19}; + const int kOutputCount = std::extent::value; + int32_t output_data[kOutputCount]; + + tflite::testing::TestReverse(kInputDims, kInput_0, kInput_1, kOutputDims, + kExpect, output_data); +} + +TF_LITE_MICRO_TEST(ReverseOpTestInt32MultiDimensionsSecondFirst) { + int kInputDims_0[] = {3, 3, 3, 3}; + int kInputDims_1[] = {1, 2}; + int* kInputDims[tflite::testing::kNumInputs] = {kInputDims_0, kInputDims_1}; + int kOutputDims[] = {3, 3, 3, 3}; + + const int32_t kInput_0[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27}; + const int32_t kInput_1[] = {1, 0}; + + const int32_t kExpect[] = {25, 26, 27, 22, 23, 24, 19, 20, 21, 16, 17, 18, + 13, 14, 15, 10, 11, 12, 7, 8, 9, 4, 5, 6, + 1, 2, 3}; + + const int kOutputCount = std::extent::value; + int32_t output_data[kOutputCount]; + + tflite::testing::TestReverse(kInputDims, kInput_0, kInput_1, kOutputDims, + kExpect, output_data); +} + +TF_LITE_MICRO_TEST(ReverseOpTestInt32MultiDimensionsAll) { + int kInputDims_0[] = {3, 3, 3, 3}; + int kInputDims_1[] = {1, 3}; + int* kInputDims[tflite::testing::kNumInputs] = {kInputDims_0, kInputDims_1}; + int kOutputDims[] = {3, 3, 3, 3}; + + const int32_t kInput_0[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27}; + const int32_t kInput_1[] = {0, 1, 2}; + const int32_t kExpect[] = {27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, + 3, 2, 1}; + const int kOutputCount = std::extent::value; + int32_t output_data[kOutputCount]; + + tflite::testing::TestReverse(kInputDims, kInput_0, kInput_1, kOutputDims, + kExpect, output_data); +} + +// uint8 tests +TF_LITE_MICRO_TEST(ReverseOpTestUint8OneDimension) { + int kInputDims_0[] = {1, 4}; + int kInputDims_1[] = {1, 1}; + int* kInputDims[tflite::testing::kNumInputs] = {kInputDims_0, kInputDims_1}; + int kOutputDims[] = {1, 4}; + + const uint8_t kInput_0[] = {1, 2, 3, 4}; + const int32_t kInput_1[] = {0}; + const uint8_t kExpect[] = {4, 3, 2, 1}; + + const int kOutputCount = std::extent::value; + uint8_t output_data[kOutputCount]; + + tflite::testing::TestReverse(kInputDims, kInput_0, kInput_1, kOutputDims, + kExpect, output_data); +} + +TF_LITE_MICRO_TEST(ReverseOpTestUint8MultiDimensions) { + int kInputDims_0[] = {3, 4, 3, 2}; + int kInputDims_1[] = {1, 1}; + int* kInputDims[tflite::testing::kNumInputs] = {kInputDims_0, kInputDims_1}; + int kOutputDims[] = {3, 4, 3, 2}; + + const uint8_t kInput_0[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}; + const int32_t kInput_1[] = {1}; + const uint8_t kExpect[] = {5, 6, 3, 4, 1, 2, 11, 12, 9, 10, 7, 8, + 17, 18, 15, 16, 13, 14, 23, 24, 21, 22, 19, 20}; + const int kOutputCount = std::extent::value; + uint8_t output_data[kOutputCount]; + + tflite::testing::TestReverse(kInputDims, kInput_0, kInput_1, kOutputDims, + kExpect, output_data); +} + +// int8 tests +TF_LITE_MICRO_TEST(ReverseOpTestInt8OneDimension) { + int kInputDims_0[] = {1, 4}; + int kInputDims_1[] = {1, 1}; + int* kInputDims[tflite::testing::kNumInputs] = {kInputDims_0, kInputDims_1}; + int kOutputDims[] = {1, 4}; + + const int8_t kInput_0[] = {1, 2, -1, -2}; + const int32_t kInput_1[] = {0}; + const int8_t kExpect[] = {-2, -1, 2, 1}; + const int kOutputCount = std::extent::value; + int8_t output_data[kOutputCount]; + + tflite::testing::TestReverse(kInputDims, kInput_0, kInput_1, kOutputDims, + kExpect, output_data); +} + +TF_LITE_MICRO_TEST(ReverseOpTestInt8MultiDimensions) { + int kInputDims_0[] = {3, 4, 3, 2}; + int kInputDims_1[] = {1, 1}; + int* kInputDims[tflite::testing::kNumInputs] = {kInputDims_0, kInputDims_1}; + int kOutputDims[] = {3, 4, 3, 2}; + + const int8_t kInput_0[] = {-1, -2, -3, -4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, -21, -22, -23, -24}; + const int32_t kInput_1[] = {1}; + const int8_t kExpect[] = {5, 6, -3, -4, -1, -2, 11, 12, 9, 10, 7, 8, + 17, 18, 15, 16, 13, 14, -23, -24, -21, -22, 19, 20}; + const int kOutputCount = std::extent::value; + int8_t output_data[kOutputCount]; + + tflite::testing::TestReverse(kInputDims, kInput_0, kInput_1, kOutputDims, + kExpect, output_data); +} + +// int16 tests +TF_LITE_MICRO_TEST(ReverseOpTestInt16OneDimension) { + int kInputDims_0[] = {1, 4}; + int kInputDims_1[] = {1, 1}; + int* kInputDims[tflite::testing::kNumInputs] = {kInputDims_0, kInputDims_1}; + int kOutputDims[] = {1, 4}; + + const int16_t kInput_0[] = {1, 2, 3, 4}; + const int32_t kInput_1[] = {0}; + const int16_t kExpect[] = {4, 3, 2, 1}; + const int kOutputCount = std::extent::value; + int16_t output_data[kOutputCount]; + + tflite::testing::TestReverse(kInputDims, kInput_0, kInput_1, kOutputDims, + kExpect, output_data); +} + +TF_LITE_MICRO_TEST(ReverseOpTestInt16MultiDimensions) { + int kInputDims_0[] = {3, 4, 3, 2}; + int kInputDims_1[] = {1, 1}; + int* kInputDims[tflite::testing::kNumInputs] = {kInputDims_0, kInputDims_1}; + int kOutputDims[] = {3, 4, 3, 2}; + + const int16_t kInput_0[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}; + const int32_t kInput_1[] = {1}; + const int16_t kExpect[] = {5, 6, 3, 4, 1, 2, 11, 12, 9, 10, 7, 8, + 17, 18, 15, 16, 13, 14, 23, 24, 21, 22, 19, 20}; + const int kOutputCount = std::extent::value; + int16_t output_data[kOutputCount]; + + tflite::testing::TestReverse(kInputDims, kInput_0, kInput_1, kOutputDims, + kExpect, output_data); +} + +TF_LITE_MICRO_TESTS_END diff --git a/tensorflow/lite/micro/micro_mutable_op_resolver.h b/tensorflow/lite/micro/micro_mutable_op_resolver.h index f3f2080f0aa..e6af3b0a7dd 100644 --- a/tensorflow/lite/micro/micro_mutable_op_resolver.h +++ b/tensorflow/lite/micro/micro_mutable_op_resolver.h @@ -525,6 +525,11 @@ class MicroMutableOpResolver : public MicroOpResolver { ParseResizeNearestNeighbor); } + TfLiteStatus AddReverseV2() { + return AddBuiltin(BuiltinOperator_REVERSE_V2, Register_REVERSE_V2(), + ParseReverseV2); + } + TfLiteStatus AddRfft(const TFLMRegistration* registration = tflite::tflm_signal::Register_RFFT()) { // TODO(b/286250473): change back name and remove namespace diff --git a/tensorflow/lite/micro/tools/benchmarking/op_resolver.h b/tensorflow/lite/micro/tools/benchmarking/op_resolver.h index 9b98849c472..03aa5890ef0 100644 --- a/tensorflow/lite/micro/tools/benchmarking/op_resolver.h +++ b/tensorflow/lite/micro/tools/benchmarking/op_resolver.h @@ -109,6 +109,7 @@ inline TfLiteStatus CreateOpResolver(TflmOpResolver& op_resolver) { TF_LITE_ENSURE_STATUS(op_resolver.AddReshape()); TF_LITE_ENSURE_STATUS(op_resolver.AddResizeBilinear()); TF_LITE_ENSURE_STATUS(op_resolver.AddResizeNearestNeighbor()); + TF_LITE_ENSURE_STATUS(op_resolver.AddReverseV2()); TF_LITE_ENSURE_STATUS(op_resolver.AddRfft()); TF_LITE_ENSURE_STATUS(op_resolver.AddRound()); TF_LITE_ENSURE_STATUS(op_resolver.AddRsqrt()); diff --git a/tensorflow/lite/micro/tools/make/Makefile b/tensorflow/lite/micro/tools/make/Makefile index 0bf5532badf..a21765b3454 100644 --- a/tensorflow/lite/micro/tools/make/Makefile +++ b/tensorflow/lite/micro/tools/make/Makefile @@ -447,6 +447,7 @@ $(TENSORFLOW_ROOT)tensorflow/lite/micro/kernels/reshape.cc \ $(TENSORFLOW_ROOT)tensorflow/lite/micro/kernels/reshape_common.cc \ $(TENSORFLOW_ROOT)tensorflow/lite/micro/kernels/resize_bilinear.cc \ $(TENSORFLOW_ROOT)tensorflow/lite/micro/kernels/resize_nearest_neighbor.cc \ +$(TENSORFLOW_ROOT)tensorflow/lite/micro/kernels/reverse.cc \ $(TENSORFLOW_ROOT)tensorflow/lite/micro/kernels/round.cc \ $(TENSORFLOW_ROOT)tensorflow/lite/micro/kernels/select.cc \ $(TENSORFLOW_ROOT)tensorflow/lite/micro/kernels/shape.cc \ From e13be667777214f6bc62cbda687907f05504b594 Mon Sep 17 00:00:00 2001 From: Ramesh Kunasi Date: Wed, 25 Jun 2025 16:56:06 +0000 Subject: [PATCH 3/7] Using stable_sort instead of sort & format fixes --- tensorflow/lite/micro/kernels/reverse.cc | 19 ++-- tensorflow/lite/micro/kernels/reverse_test.cc | 102 +++++++++--------- 2 files changed, 59 insertions(+), 62 deletions(-) diff --git a/tensorflow/lite/micro/kernels/reverse.cc b/tensorflow/lite/micro/kernels/reverse.cc index 3010fa0cf4a..e05cb7d0263 100644 --- a/tensorflow/lite/micro/kernels/reverse.cc +++ b/tensorflow/lite/micro/kernels/reverse.cc @@ -75,9 +75,8 @@ TfLiteStatus ReverseV2Prepare(TfLiteContext* context, TfLiteNode* node) { } template -void ReverseImpl(int32_t* axes, int num_axes, - const RuntimeShape& input_shape, const T* input_data, - T* output_data) { +void ReverseImpl(int32_t* axes, int num_axes, const RuntimeShape& input_shape, + const T* input_data, T* output_data) { bool is_upper = (axes[num_axes - 1] == input_shape.DimensionsCount() - 1); bool is_lower = (axes[0] == 0); int rank = input_shape.DimensionsCount(); @@ -104,11 +103,9 @@ void ReverseImpl(int32_t* axes, int num_axes, if (lower_size > 1) { for (int i = 0; i < upper_size; ++i) { for (int j = 0; j < middle_size; ++j) { - T* src = - (T*)input_data + (i * (middle_size) + j) * lower_size; - T* dst = - (T*)output_data + - (i * (middle_size) + (middle_size - j - 1)) * lower_size; + T* src = (T*)input_data + (i * (middle_size) + j) * lower_size; + T* dst = (T*)output_data + + (i * (middle_size) + (middle_size - j - 1)) * lower_size; memcpy(dst, src, lower_size * sizeof(T)); } } @@ -132,7 +129,7 @@ TfLiteStatus ReverseV2Eval(TfLiteContext* context, TfLiteNode* node) { TF_LITE_ENSURE_EQ(context, axis->type, kTfLiteInt32); const int num_axes = static_cast(ElementCount(*axis->dims)); TF_LITE_ENSURE(context, num_axes <= 8); - + int32_t axes_data[kMaxDimensions]; std::memcpy(axes_data, axis->data.i32, sizeof(int32_t) * num_axes); const int rank = tflite::micro::GetTensorShape(input).DimensionsCount(); @@ -142,7 +139,7 @@ TfLiteStatus ReverseV2Eval(TfLiteContext* context, TfLiteNode* node) { } TF_LITE_ENSURE(context, axes_data[i] >= 0 && axes_data[i] < rank); } - std::sort(axes_data, axes_data + num_axes); + std::stable_sort(axes_data, axes_data + num_axes); bool is_contiguous = true; for (int i = 1; i < num_axes; ++i) { @@ -169,7 +166,7 @@ TfLiteStatus ReverseV2Eval(TfLiteContext* context, TfLiteNode* node) { tflite::micro::GetTensorData(input), tflite::micro::GetTensorData(output)); break; - case kTfLiteInt16: + case kTfLiteInt16: ReverseImpl(axes_data, num_axes, tflite::micro::GetTensorShape(input), tflite::micro::GetTensorData(input), diff --git a/tensorflow/lite/micro/kernels/reverse_test.cc b/tensorflow/lite/micro/kernels/reverse_test.cc index 19d0b483097..a5c69d33a08 100644 --- a/tensorflow/lite/micro/kernels/reverse_test.cc +++ b/tensorflow/lite/micro/kernels/reverse_test.cc @@ -47,10 +47,9 @@ void ExecuteReverseTest(TfLiteTensor* tensors, int tensors_count) { } template -void TestReverse(int* input_dims_data[kNumInputs], - const T* input_data_0, const int32_t* input_data_1, - int* expected_dims, const T* expected_data, - T* output_data) { +void TestReverse(int* input_dims_data[kNumInputs], const T* input_data_0, + const int32_t* input_data_1, int* expected_dims, + const T* expected_data, T* output_data) { TfLiteIntArray* input_dims_0 = IntArrayFromInts(input_dims_data[0]); TfLiteIntArray* input_dims_1 = IntArrayFromInts(input_dims_data[1]); TfLiteIntArray* output_dims = IntArrayFromInts(expected_dims); @@ -66,7 +65,7 @@ void TestReverse(int* input_dims_data[kNumInputs], // check output data against expected for (int i = 0; i < output_count; i++) { - TF_LITE_MICRO_EXPECT_NEAR(expected_data[i], output_data[i], 0); + TF_LITE_MICRO_EXPECT_NEAR(expected_data[i], output_data[i], 0); } // check output dimensions (relocated) against original dimensions @@ -160,13 +159,13 @@ TF_LITE_MICRO_TEST(ReverseOpTestInt32MultiDimensionsFirst) { int* kInputDims[tflite::testing::kNumInputs] = {kInputDims_0, kInputDims_1}; int kOutputDims[] = {3, 3, 3, 3}; - const int32_t kInput_0[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, - 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27}; + const int32_t kInput_0[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27}; const int32_t kInput_1[] = {0}; - const int32_t kExpect[] = {19, 20, 21, 22, 23, 24, 25, 26, 27, 10, 11, 12, - 13, 14, 15, 16, 17, 18, 1, 2, 3, 4, 5, 6, - 7, 8, 9}; + const int32_t kExpect[] = {19, 20, 21, 22, 23, 24, 25, 26, 27, + 10, 11, 12, 13, 14, 15, 16, 17, 18, + 1, 2, 3, 4, 5, 6, 7, 8, 9}; const int kOutputCount = std::extent::value; int32_t output_data[kOutputCount]; @@ -180,13 +179,13 @@ TF_LITE_MICRO_TEST(ReverseOpTestInt32MultiDimensionsSecond) { int* kInputDims[tflite::testing::kNumInputs] = {kInputDims_0, kInputDims_1}; int kOutputDims[] = {3, 3, 3, 3}; - const int32_t kInput_0[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, - 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27}; + const int32_t kInput_0[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27}; const int32_t kInput_1[] = {1}; - const int32_t kExpect[] = {7, 8, 9, 4, 5, 6, 1, 2, 3, 16, 17, 18, - 13, 14, 15, 10, 11, 12, 25, 26, 27, 22, 23, 24, - 19, 20, 21}; + const int32_t kExpect[] = {7, 8, 9, 4, 5, 6, 1, 2, 3, + 16, 17, 18, 13, 14, 15, 10, 11, 12, + 25, 26, 27, 22, 23, 24, 19, 20, 21}; const int kOutputCount = std::extent::value; int32_t output_data[kOutputCount]; @@ -200,13 +199,13 @@ TF_LITE_MICRO_TEST(ReverseOpTestInt32MultiDimensionsThird) { int* kInputDims[tflite::testing::kNumInputs] = {kInputDims_0, kInputDims_1}; int kOutputDims[] = {3, 3, 3, 3}; - const int32_t kInput_0[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, - 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27}; + const int32_t kInput_0[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27}; const int32_t kInput_1[] = {2}; - const int32_t kExpect[] = {3, 2, 1, 6, 5, 4, 9, 8, 7, 12, 11, 10, - 15, 14, 13, 18, 17, 16, 21, 20, 19, 24, 23, 22, - 27, 26, 25}; + const int32_t kExpect[] = {3, 2, 1, 6, 5, 4, 9, 8, 7, + 12, 11, 10, 15, 14, 13, 18, 17, 16, + 21, 20, 19, 24, 23, 22, 27, 26, 25}; const int kOutputCount = std::extent::value; int32_t output_data[kOutputCount]; @@ -220,14 +219,14 @@ TF_LITE_MICRO_TEST(ReverseOpTestInt32MultiDimensionsFirstSecond) { int* kInputDims[tflite::testing::kNumInputs] = {kInputDims_0, kInputDims_1}; int kOutputDims[] = {3, 3, 3, 3}; - const int32_t kInput_0[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, - 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27}; + const int32_t kInput_0[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27}; const int32_t kInput_1[] = {0, 1}; - const int32_t kExpect[] = {25, 26, 27, 22, 23, 24, 19, 20, 21, 16, 17, 18, - 13, 14, 15, 10, 11, 12, 7, 8, 9, 4, 5, 6, - 1, 2, 3}; + const int32_t kExpect[] = {25, 26, 27, 22, 23, 24, 19, 20, 21, + 16, 17, 18, 13, 14, 15, 10, 11, 12, + 7, 8, 9, 4, 5, 6, 1, 2, 3}; const int kOutputCount = std::extent::value; int32_t output_data[kOutputCount]; @@ -242,14 +241,14 @@ TF_LITE_MICRO_TEST(ReverseOpTestInt32MultiDimensionsSecondThird) { int* kInputDims[tflite::testing::kNumInputs] = {kInputDims_0, kInputDims_1}; int kOutputDims[] = {3, 3, 3, 3}; - const int32_t kInput_0[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, - 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27}; + const int32_t kInput_0[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27}; const int32_t kInput_1[] = {1, 2}; - const int32_t kExpect[] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 18, 17, 16, - 15, 14, 13, 12, 11, 10, 27, 26, 25, 24, 23, 22, - 21, 20, 19}; + const int32_t kExpect[] = {9, 8, 7, 6, 5, 4, 3, 2, 1, + 18, 17, 16, 15, 14, 13, 12, 11, 10, + 27, 26, 25, 24, 23, 22, 21, 20, 19}; const int kOutputCount = std::extent::value; int32_t output_data[kOutputCount]; @@ -263,14 +262,14 @@ TF_LITE_MICRO_TEST(ReverseOpTestInt32MultiDimensionsSecondFirst) { int* kInputDims[tflite::testing::kNumInputs] = {kInputDims_0, kInputDims_1}; int kOutputDims[] = {3, 3, 3, 3}; - const int32_t kInput_0[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, - 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27}; + const int32_t kInput_0[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27}; const int32_t kInput_1[] = {1, 0}; - const int32_t kExpect[] = {25, 26, 27, 22, 23, 24, 19, 20, 21, 16, 17, 18, - 13, 14, 15, 10, 11, 12, 7, 8, 9, 4, 5, 6, - 1, 2, 3}; + const int32_t kExpect[] = {25, 26, 27, 22, 23, 24, 19, 20, 21, + 16, 17, 18, 13, 14, 15, 10, 11, 12, + 7, 8, 9, 4, 5, 6, 1, 2, 3}; const int kOutputCount = std::extent::value; int32_t output_data[kOutputCount]; @@ -285,13 +284,13 @@ TF_LITE_MICRO_TEST(ReverseOpTestInt32MultiDimensionsAll) { int* kInputDims[tflite::testing::kNumInputs] = {kInputDims_0, kInputDims_1}; int kOutputDims[] = {3, 3, 3, 3}; - const int32_t kInput_0[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, - 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27}; + const int32_t kInput_0[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 26, 27}; const int32_t kInput_1[] = {0, 1, 2}; - const int32_t kExpect[] = {27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, - 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, - 3, 2, 1}; + const int32_t kExpect[] = {27, 26, 25, 24, 23, 22, 21, 20, 19, + 18, 17, 16, 15, 14, 13, 12, 11, 10, + 9, 8, 7, 6, 5, 4, 3, 2, 1}; const int kOutputCount = std::extent::value; int32_t output_data[kOutputCount]; @@ -358,8 +357,9 @@ TF_LITE_MICRO_TEST(ReverseOpTestInt8MultiDimensions) { int* kInputDims[tflite::testing::kNumInputs] = {kInputDims_0, kInputDims_1}; int kOutputDims[] = {3, 4, 3, 2}; - const int8_t kInput_0[] = {-1, -2, -3, -4, 5, 6, 7, 8, 9, 10, 11, 12, 13, - 14, 15, 16, 17, 18, 19, 20, -21, -22, -23, -24}; + const int8_t kInput_0[] = {-1, -2, -3, -4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, -21, -22, -23, -24}; const int32_t kInput_1[] = {1}; const int8_t kExpect[] = {5, 6, -3, -4, -1, -2, 11, 12, 9, 10, 7, 8, 17, 18, 15, 16, 13, 14, -23, -24, -21, -22, 19, 20}; @@ -393,8 +393,8 @@ TF_LITE_MICRO_TEST(ReverseOpTestInt16MultiDimensions) { int* kInputDims[tflite::testing::kNumInputs] = {kInputDims_0, kInputDims_1}; int kOutputDims[] = {3, 4, 3, 2}; - const int16_t kInput_0[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, - 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}; + const int16_t kInput_0[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}; const int32_t kInput_1[] = {1}; const int16_t kExpect[] = {5, 6, 3, 4, 1, 2, 11, 12, 9, 10, 7, 8, 17, 18, 15, 16, 13, 14, 23, 24, 21, 22, 19, 20}; From 2da9fc8a9928a9e4a937ec8566d1361822ed119d Mon Sep 17 00:00:00 2001 From: Ramesh Kunasi Date: Thu, 26 Jun 2025 08:53:20 +0000 Subject: [PATCH 4/7] Replace std::stable_sort with qsort --- tensorflow/lite/micro/kernels/reverse.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tensorflow/lite/micro/kernels/reverse.cc b/tensorflow/lite/micro/kernels/reverse.cc index e05cb7d0263..cf42248b471 100644 --- a/tensorflow/lite/micro/kernels/reverse.cc +++ b/tensorflow/lite/micro/kernels/reverse.cc @@ -32,6 +32,10 @@ constexpr int kInputTensor = 0; constexpr int kAxisTensor = 1; constexpr int kOutputTensor = 0; +int comp(const void *a, const void *b) { + return (*(int *)a - *(int *)b); +} + TfLiteStatus ReverseV2Prepare(TfLiteContext* context, TfLiteNode* node) { MicroContext* micro_context = GetMicroContext(context); @@ -139,7 +143,7 @@ TfLiteStatus ReverseV2Eval(TfLiteContext* context, TfLiteNode* node) { } TF_LITE_ENSURE(context, axes_data[i] >= 0 && axes_data[i] < rank); } - std::stable_sort(axes_data, axes_data + num_axes); + qsort(axes_data, num_axes, sizeof(int32_t), comp); bool is_contiguous = true; for (int i = 1; i < num_axes; ++i) { From 77408018318305b180fdb282717a2d37e980f27e Mon Sep 17 00:00:00 2001 From: Ramesh Kunasi Date: Thu, 26 Jun 2025 09:04:54 +0000 Subject: [PATCH 5/7] fix format issues --- tensorflow/lite/micro/kernels/reverse.cc | 4 +--- tensorflow/lite/micro/kernels/reverse_test.cc | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/tensorflow/lite/micro/kernels/reverse.cc b/tensorflow/lite/micro/kernels/reverse.cc index cf42248b471..81f30c2490d 100644 --- a/tensorflow/lite/micro/kernels/reverse.cc +++ b/tensorflow/lite/micro/kernels/reverse.cc @@ -32,9 +32,7 @@ constexpr int kInputTensor = 0; constexpr int kAxisTensor = 1; constexpr int kOutputTensor = 0; -int comp(const void *a, const void *b) { - return (*(int *)a - *(int *)b); -} +int comp(const void *a, const void *b) { return (*(int *)a - *(int *)b); } TfLiteStatus ReverseV2Prepare(TfLiteContext* context, TfLiteNode* node) { MicroContext* micro_context = GetMicroContext(context); diff --git a/tensorflow/lite/micro/kernels/reverse_test.cc b/tensorflow/lite/micro/kernels/reverse_test.cc index a5c69d33a08..3a2c54929cd 100644 --- a/tensorflow/lite/micro/kernels/reverse_test.cc +++ b/tensorflow/lite/micro/kernels/reverse_test.cc @@ -361,7 +361,7 @@ TF_LITE_MICRO_TEST(ReverseOpTestInt8MultiDimensions) { 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, -21, -22, -23, -24}; const int32_t kInput_1[] = {1}; - const int8_t kExpect[] = {5, 6, -3, -4, -1, -2, 11, 12, 9, 10, 7, 8, + const int8_t kExpect[] = {5, 6, -3, -4, -1, -2, 11, 12, 9, 10, 7, 8, 17, 18, 15, 16, 13, 14, -23, -24, -21, -22, 19, 20}; const int kOutputCount = std::extent::value; int8_t output_data[kOutputCount]; From 5851edce7cc8f84c3784c6b74910a2fa2eb55bce Mon Sep 17 00:00:00 2001 From: Ramesh Kunasi Date: Thu, 26 Jun 2025 09:15:58 +0000 Subject: [PATCH 6/7] fix format issues --- tensorflow/lite/micro/kernels/reverse.cc | 2 +- tensorflow/lite/micro/kernels/reverse_test.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tensorflow/lite/micro/kernels/reverse.cc b/tensorflow/lite/micro/kernels/reverse.cc index 81f30c2490d..c83bcf4c67f 100644 --- a/tensorflow/lite/micro/kernels/reverse.cc +++ b/tensorflow/lite/micro/kernels/reverse.cc @@ -32,7 +32,7 @@ constexpr int kInputTensor = 0; constexpr int kAxisTensor = 1; constexpr int kOutputTensor = 0; -int comp(const void *a, const void *b) { return (*(int *)a - *(int *)b); } +int comp(const void *a, const void *b) { return (*(int*)a - *(int*)b); } TfLiteStatus ReverseV2Prepare(TfLiteContext* context, TfLiteNode* node) { MicroContext* micro_context = GetMicroContext(context); diff --git a/tensorflow/lite/micro/kernels/reverse_test.cc b/tensorflow/lite/micro/kernels/reverse_test.cc index 3a2c54929cd..d92bf3156aa 100644 --- a/tensorflow/lite/micro/kernels/reverse_test.cc +++ b/tensorflow/lite/micro/kernels/reverse_test.cc @@ -361,7 +361,7 @@ TF_LITE_MICRO_TEST(ReverseOpTestInt8MultiDimensions) { 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, -21, -22, -23, -24}; const int32_t kInput_1[] = {1}; - const int8_t kExpect[] = {5, 6, -3, -4, -1, -2, 11, 12, 9, 10, 7, 8, + const int8_t kExpect[] = {5, 6, -3, -4, -1, -2, 11, 12, 9, 10, 7, 8, 17, 18, 15, 16, 13, 14, -23, -24, -21, -22, 19, 20}; const int kOutputCount = std::extent::value; int8_t output_data[kOutputCount]; From 523b294e43ccae902fd6899043fb991674924b18 Mon Sep 17 00:00:00 2001 From: Ramesh Kunasi Date: Thu, 26 Jun 2025 09:24:01 +0000 Subject: [PATCH 7/7] fix format issues --- tensorflow/lite/micro/kernels/reverse.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/lite/micro/kernels/reverse.cc b/tensorflow/lite/micro/kernels/reverse.cc index c83bcf4c67f..17bf444346f 100644 --- a/tensorflow/lite/micro/kernels/reverse.cc +++ b/tensorflow/lite/micro/kernels/reverse.cc @@ -32,7 +32,7 @@ constexpr int kInputTensor = 0; constexpr int kAxisTensor = 1; constexpr int kOutputTensor = 0; -int comp(const void *a, const void *b) { return (*(int*)a - *(int*)b); } +int comp(const void* a, const void* b) { return (*(int*)a - *(int*)b); } TfLiteStatus ReverseV2Prepare(TfLiteContext* context, TfLiteNode* node) { MicroContext* micro_context = GetMicroContext(context);