Port the circular buffer kernel to the new TfLiteEvalTensor API.
PiperOrigin-RevId: 322701794
Change-Id: Ib3d39f12747791760ed03d9ad39694660d05522d
diff --git a/tensorflow/lite/micro/kernels/BUILD b/tensorflow/lite/micro/kernels/BUILD
index a9b371b..c98e23a 100644
--- a/tensorflow/lite/micro/kernels/BUILD
+++ b/tensorflow/lite/micro/kernels/BUILD
@@ -585,6 +585,7 @@
"circular_buffer_test.cc",
],
deps = [
+ ":kernel_runner",
":micro_ops",
"//tensorflow/lite/c:common",
"//tensorflow/lite/micro:op_resolvers",
diff --git a/tensorflow/lite/micro/kernels/circular_buffer.cc b/tensorflow/lite/micro/kernels/circular_buffer.cc
index f588d64..876ea56 100644
--- a/tensorflow/lite/micro/kernels/circular_buffer.cc
+++ b/tensorflow/lite/micro/kernels/circular_buffer.cc
@@ -22,6 +22,7 @@
#include "tensorflow/lite/kernels/internal/tensor_ctypes.h"
#include "tensorflow/lite/kernels/kernel_util.h"
#include "tensorflow/lite/kernels/op_macros.h"
+#include "tensorflow/lite/micro/kernels/kernel_util.h"
/*
* The circular buffer custom operator is used to implement strided streaming
@@ -121,8 +122,10 @@
}
TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
- const TfLiteTensor* input = GetInput(context, node, kInputTensor);
- TfLiteTensor* output = GetOutput(context, node, kOutputTensor);
+ const TfLiteEvalTensor* input =
+ tflite::micro::GetEvalInput(context, node, kInputTensor);
+ TfLiteEvalTensor* output =
+ tflite::micro::GetEvalOutput(context, node, kOutputTensor);
OpData* data = reinterpret_cast<OpData*>(node->user_data);
@@ -130,8 +133,8 @@
int depth = output->dims->data[3];
if (input->type == kTfLiteInt8) {
- EvalInt8(GetTensorData<int8_t>(input), num_slots, depth,
- GetTensorData<int8_t>(output));
+ EvalInt8(tflite::micro::GetTensorData<int8_t>(input), num_slots, depth,
+ tflite::micro::GetTensorData<int8_t>(output));
} else {
TF_LITE_KERNEL_LOG(context, "Type %s (%d) not supported.",
TfLiteTypeGetName(input->type), input->type);
diff --git a/tensorflow/lite/micro/kernels/circular_buffer_test.cc b/tensorflow/lite/micro/kernels/circular_buffer_test.cc
index 4c48060..770f456 100644
--- a/tensorflow/lite/micro/kernels/circular_buffer_test.cc
+++ b/tensorflow/lite/micro/kernels/circular_buffer_test.cc
@@ -16,6 +16,7 @@
#include "tensorflow/lite/c/builtin_op_data.h"
#include "tensorflow/lite/c/common.h"
#include "tensorflow/lite/micro/all_ops_resolver.h"
+#include "tensorflow/lite/micro/kernels/kernel_runner.h"
#include "tensorflow/lite/micro/kernels/micro_ops.h"
#include "tensorflow/lite/micro/testing/micro_test.h"
#include "tensorflow/lite/micro/testing/test_utils.h"
@@ -29,93 +30,6 @@
// TODO(b/149795762): Add this to TfLiteStatus enum.
constexpr int kTfLiteAbort = -9;
-TfLiteNode PrepareCircularBufferInt8(const int* input_dims_data,
- const int8_t* input_data,
- const int* output_dims_data,
- const int8_t* expected_output_data,
- int8_t* output_data) {
- const TfLiteRegistration* registration =
- ops::micro::Register_CIRCULAR_BUFFER();
-
- TfLiteNode node;
- TfLiteIntArray* input_dims = IntArrayFromInts(input_dims_data);
- TfLiteIntArray* output_dims = IntArrayFromInts(output_dims_data);
- constexpr int inputs_size = 2;
- constexpr int outputs_size = 1;
- constexpr int tensors_size = inputs_size + outputs_size;
- TfLiteTensor tensors[tensors_size] = {
- CreateQuantizedTensor(input_data, input_dims, 1, 0),
- CreateQuantizedTensor(output_data, output_dims, 1, 0),
- };
- TfLiteContext context;
- PopulateContext(tensors, tensors_size, micro_test::reporter, &context);
-
- // There is one input - tensor 0.
- const int inputs_array_data[] = {1, 0};
- TfLiteIntArray* inputs_array = IntArrayFromInts(inputs_array_data);
- // There is one output - tensor 1.
- const int outputs_array_data[] = {1, 1};
- TfLiteIntArray* outputs_array = IntArrayFromInts(outputs_array_data);
-
- node.inputs = inputs_array;
- node.outputs = outputs_array;
- node.builtin_data = nullptr;
- node.custom_initial_data = nullptr;
- node.custom_initial_data_size = 0;
-
- TF_LITE_MICRO_EXPECT_NE(nullptr, registration->prepare);
- TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, registration->prepare(&context, &node));
- return node;
-}
-
-// Run invoke cycles_until_output times with the supplied input, expecting
-// invoke to return kTfLiteAbort until the last iteration, at which point the
-// output should match expected_output_data.
-TfLiteStatus InvokeCircularBufferInt8(const int* input_dims_data,
- const int8_t* input_data,
- const int* output_dims_data,
- const int8_t* expected_output_data,
- int8_t* output_data, TfLiteNode* node) {
- TfLiteIntArray* output_dims = IntArrayFromInts(output_dims_data);
- TfLiteIntArray* input_dims = IntArrayFromInts(input_dims_data);
-
- const int output_dims_count = ElementCount(*output_dims);
- const TfLiteRegistration* registration =
- ops::micro::Register_CIRCULAR_BUFFER();
-
- constexpr int inputs_size = 2;
- constexpr int outputs_size = 1;
- constexpr int tensors_size = inputs_size + outputs_size;
- TfLiteTensor tensors[tensors_size] = {
- CreateQuantizedTensor(input_data, input_dims, 1, 0),
- CreateQuantizedTensor(output_data, output_dims, 1, 0),
- };
- TfLiteContext context;
- PopulateContext(tensors, tensors_size, micro_test::reporter, &context);
-
- // There is one input - tensor 0.
- const int inputs_array_data[] = {1, 0};
- TfLiteIntArray* inputs_array = IntArrayFromInts(inputs_array_data);
- // There is one output - tensor 1.
- const int outputs_array_data[] = {1, 1};
- TfLiteIntArray* outputs_array = IntArrayFromInts(outputs_array_data);
-
- node->inputs = inputs_array;
- node->outputs = outputs_array;
- node->builtin_data = nullptr;
- node->custom_initial_data = nullptr;
- node->custom_initial_data_size = 0;
-
- TF_LITE_MICRO_EXPECT_NE(nullptr, registration->invoke);
-
- TfLiteStatus status = registration->invoke(&context, node);
-
- for (int i = 0; i < output_dims_count; ++i) {
- TF_LITE_MICRO_EXPECT_EQ(expected_output_data[i], output_data[i]);
- }
- return status;
-}
-
} // namespace
} // namespace testing
} // namespace tflite
@@ -125,30 +39,65 @@
TF_LITE_MICRO_TEST(OutputTensorLength4) {
constexpr int depth = 3;
constexpr int num_slots = 4;
+ int8_t input_data[depth];
int8_t output_data[depth * num_slots];
memset(output_data, 0, sizeof(output_data));
+
// There are four input dimensions - [1, 1, 1, depth].
const int input_dims[] = {4, 1, 1, 1, depth};
// There are four output dimensions - [1, num_slots, 1, depth].
const int output_dims[] = {4, 1, num_slots, 1, depth};
+ TfLiteIntArray* input_tensor_dims =
+ tflite::testing::IntArrayFromInts(input_dims);
+ TfLiteIntArray* output_tensor_dims =
+ tflite::testing::IntArrayFromInts(output_dims);
+
+ const int output_dims_count = tflite::ElementCount(*output_tensor_dims);
+
+ constexpr int inputs_size = 2;
+ constexpr int outputs_size = 1;
+ constexpr int tensors_size = inputs_size + outputs_size;
+ TfLiteTensor tensors[tensors_size] = {
+ tflite::testing::CreateQuantizedTensor(input_data, input_tensor_dims, 1,
+ 0),
+ tflite::testing::CreateQuantizedTensor(output_data, output_tensor_dims, 1,
+ 0),
+ };
+
+ // There is one input - tensor 0.
+ const int inputs_array_data[] = {1, 0};
+ TfLiteIntArray* inputs_array =
+ tflite::testing::IntArrayFromInts(inputs_array_data);
+ // There is one output - tensor 1.
+ const int outputs_array_data[] = {1, 1};
+ TfLiteIntArray* outputs_array =
+ tflite::testing::IntArrayFromInts(outputs_array_data);
+
+ const TfLiteRegistration* registration =
+ tflite::ops::micro::Register_CIRCULAR_BUFFER();
+ tflite::micro::KernelRunner runner = tflite::micro::KernelRunner(
+ *registration, tensors, tensors_size, inputs_array, outputs_array,
+ /*builtin_data=*/nullptr, micro_test::reporter);
+ TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, runner.InitAndPrepare());
+
const int8_t goldens[5][16] = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3},
{0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6},
{0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12},
{4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}};
- int8_t input[depth];
- TfLiteNode node = tflite::testing::PrepareCircularBufferInt8(
- input_dims, input, output_dims, goldens[0], output_data);
// Expect the circular buffer to run every other invoke for 4xN output.
for (int i = 0; i < 5; i++) {
for (int j = 0; j < depth; j++) {
- input[j] = i * depth + j + 1;
+ input_data[j] = i * depth + j + 1;
}
- TfLiteStatus status = tflite::testing::InvokeCircularBufferInt8(
- input_dims, input, output_dims, goldens[i], output_data, &node);
+ TfLiteStatus status = runner.Invoke();
+
+ for (int j = 0; j < output_dims_count; ++j) {
+ TF_LITE_MICRO_EXPECT_EQ(goldens[i][j], output_data[j]);
+ }
// Every kRunPeriod iterations, the circular buffer should return kTfLiteOk.
if (i % tflite::testing::kRunPeriod == tflite::testing::kRunPeriod - 1) {
@@ -162,11 +111,44 @@
TF_LITE_MICRO_TEST(OutputTensorLength5) {
constexpr int depth = 4;
constexpr int num_slots = 5;
+ int8_t input_data[depth];
int8_t output_data[depth * num_slots];
memset(output_data, 0, sizeof(output_data));
const int input_dims[] = {4, 1, 1, 1, depth};
const int output_dims[] = {4, 1, num_slots, 1, depth};
+ TfLiteIntArray* input_tensor_dims =
+ tflite::testing::IntArrayFromInts(input_dims);
+ TfLiteIntArray* output_tensor_dims =
+ tflite::testing::IntArrayFromInts(output_dims);
+
+ const int output_dims_count = tflite::ElementCount(*output_tensor_dims);
+
+ constexpr int inputs_size = 2;
+ constexpr int outputs_size = 1;
+ constexpr int tensors_size = inputs_size + outputs_size;
+ TfLiteTensor tensors[tensors_size] = {
+ tflite::testing::CreateQuantizedTensor(input_data, input_tensor_dims, 1,
+ 0),
+ tflite::testing::CreateQuantizedTensor(output_data, output_tensor_dims, 1,
+ 0),
+ };
+
+ // There is one input - tensor 0.
+ const int inputs_array_data[] = {1, 0};
+ TfLiteIntArray* inputs_array =
+ tflite::testing::IntArrayFromInts(inputs_array_data);
+ // There is one output - tensor 1.
+ const int outputs_array_data[] = {1, 1};
+ TfLiteIntArray* outputs_array =
+ tflite::testing::IntArrayFromInts(outputs_array_data);
+
+ const TfLiteRegistration* registration =
+ tflite::ops::micro::Register_CIRCULAR_BUFFER();
+ tflite::micro::KernelRunner runner = tflite::micro::KernelRunner(
+ *registration, tensors, tensors_size, inputs_array, outputs_array,
+ /*builtin_data=*/nullptr, micro_test::reporter);
+ TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, runner.InitAndPrepare());
const int8_t goldens[6][20] = {
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4},
@@ -177,18 +159,16 @@
{5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24}};
- int8_t input[depth];
- TfLiteNode node = tflite::testing::PrepareCircularBufferInt8(
- input_dims, input, output_dims, goldens[0], output_data);
// Expect circular buffer to run every cycle for 5xN output.
for (int i = 0; i < 6; i++) {
for (int j = 0; j < depth; j++) {
- input[j] = i * depth + j + 1;
+ input_data[j] = i * depth + j + 1;
}
- TF_LITE_MICRO_EXPECT_EQ(
- kTfLiteOk,
- tflite::testing::InvokeCircularBufferInt8(
- input_dims, input, output_dims, goldens[i], output_data, &node));
+ TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, runner.Invoke());
+
+ for (int j = 0; j < output_dims_count; ++j) {
+ TF_LITE_MICRO_EXPECT_EQ(goldens[i][j], output_data[j]);
+ }
}
}