From c382d71b68a58a0c790d1a65f7b0e0e4477d7ed9 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Tue, 20 Aug 2019 18:44:28 -0700 Subject: [PATCH] add int8 test to reshape PiperOrigin-RevId: 264515407 --- .../lite/experimental/micro/kernels/BUILD | 1 + .../micro/kernels/reshape_test.cc | 292 +++++++----------- 2 files changed, 112 insertions(+), 181 deletions(-) diff --git a/tensorflow/lite/experimental/micro/kernels/BUILD b/tensorflow/lite/experimental/micro/kernels/BUILD index 3023ed0181d..fd5cea18b52 100644 --- a/tensorflow/lite/experimental/micro/kernels/BUILD +++ b/tensorflow/lite/experimental/micro/kernels/BUILD @@ -398,5 +398,6 @@ tflite_micro_cc_test( "//tensorflow/lite/c:c_api_internal", "//tensorflow/lite/experimental/micro:micro_framework", "//tensorflow/lite/experimental/micro/testing:micro_test", + "//tensorflow/lite/kernels/internal:tensor", ], ) diff --git a/tensorflow/lite/experimental/micro/kernels/reshape_test.cc b/tensorflow/lite/experimental/micro/kernels/reshape_test.cc index 9a629430ddd..2e48eaa896b 100644 --- a/tensorflow/lite/experimental/micro/kernels/reshape_test.cc +++ b/tensorflow/lite/experimental/micro/kernels/reshape_test.cc @@ -19,34 +19,12 @@ limitations under the License. #include "tensorflow/lite/experimental/micro/simple_tensor_allocator.h" #include "tensorflow/lite/experimental/micro/testing/micro_test.h" #include "tensorflow/lite/experimental/micro/testing/test_utils.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" namespace tflite { namespace testing { namespace { -inline TfLiteTensor CreateInt32Tensor(std::initializer_list data, - TfLiteIntArray* dims, const char* name) { - TfLiteTensor result; - result.type = kTfLiteInt32; - result.data.i32 = const_cast(data.begin()); - result.dims = dims; - result.params = {}; - result.allocation_type = kTfLiteMemNone; - result.bytes = ElementCount(*dims) * sizeof(int32_t); - result.allocation = nullptr; - result.name = name; - result.is_variable = true; - return result; -} - -inline TfLiteTensor CreateInt32ConstTensor(std::initializer_list data, - TfLiteIntArray* dims, - const char* name) { - auto result = CreateInt32Tensor(data, dims, name); - result.is_variable = false; - return result; -} - TfLiteReshapeParams create_params(int* shape_data) { TfLiteReshapeParams op_params = {}; op_params.num_dimensions = shape_data[0]; @@ -56,12 +34,14 @@ TfLiteReshapeParams create_params(int* shape_data) { } // If expected output is empty, the test is expected to fail. +template void TestReshapeImpl(TfLiteTensor* input_tensor, TfLiteTensor* shape_tensor, - TfLiteTensor* output_tensor, int expected_output_size, - const float* expected_output, + TfLiteTensor* output_tensor, + std::initializer_list expected_output, std::initializer_list expected_dims) { TfLiteContext context; TfLiteTensor tensors[3]; + TfLiteNode node; if (shape_tensor == nullptr) { constexpr int inputs_size = 1; constexpr int outputs_size = 1; @@ -69,6 +49,8 @@ void TestReshapeImpl(TfLiteTensor* input_tensor, TfLiteTensor* shape_tensor, tensors[0] = *input_tensor; tensors[1] = *output_tensor, PopulateContext(tensors, tensors_size, &context); + node.inputs = IntArrayFromInitializer({1, 0}); + node.outputs = IntArrayFromInitializer({1, 1}); } else { constexpr int inputs_size = 2; constexpr int outputs_size = 1; @@ -77,6 +59,8 @@ void TestReshapeImpl(TfLiteTensor* input_tensor, TfLiteTensor* shape_tensor, tensors[1] = *shape_tensor; tensors[2] = *output_tensor; PopulateContext(tensors, tensors_size, &context); + node.inputs = IntArrayFromInitializer({2, 0, 1}); + node.outputs = IntArrayFromInitializer({1, 2}); } ::tflite::ops::micro::AllOpsResolver resolver; @@ -88,29 +72,21 @@ void TestReshapeImpl(TfLiteTensor* input_tensor, TfLiteTensor* shape_tensor, const char* init_data = reinterpret_cast(&builtin_data); size_t init_data_size = 0; void* user_data = nullptr; - if (registration->init) { - user_data = registration->init(&context, init_data, init_data_size); - } - TfLiteIntArray* temporaries_array = IntArrayFromInitializer({0}); - TfLiteNode node; - if (shape_tensor == nullptr) { - node.inputs = IntArrayFromInitializer({1, 0}); - node.outputs = IntArrayFromInitializer({1, 1}); - } else { - node.inputs = IntArrayFromInitializer({2, 0, 1}); - node.outputs = IntArrayFromInitializer({1, 2}); - } - node.temporaries = temporaries_array; + node.temporaries = nullptr; node.user_data = user_data; node.builtin_data = reinterpret_cast(&builtin_data); node.custom_initial_data = nullptr; node.custom_initial_data_size = 0; node.delegate = nullptr; + + if (registration->init) { + user_data = registration->init(&context, init_data, init_data_size); + } if (registration->prepare) { TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, registration->prepare(&context, &node)); } TF_LITE_MICRO_EXPECT_NE(nullptr, registration->invoke); - if (expected_output_size == 0) { + if (expected_output.size() == 0) { TF_LITE_MICRO_EXPECT_EQ(kTfLiteError, registration->invoke(&context, &node)); return; @@ -119,28 +95,12 @@ void TestReshapeImpl(TfLiteTensor* input_tensor, TfLiteTensor* shape_tensor, if (registration->free) { registration->free(&context, user_data); } + const int output_dims_count = ElementCount(*output_tensor->dims); - switch (output_tensor->type) { - case kTfLiteFloat32: - for (int i = 0; i < expected_output_size; ++i) { - TF_LITE_MICRO_EXPECT_NEAR(expected_output[i], output_tensor->data.f[i], - 1e-5f); - } - break; - case kTfLiteUInt8: - for (int i = 0; i < expected_output_size; ++i) { - TF_LITE_MICRO_EXPECT_NEAR(expected_output[i], - output_tensor->data.uint8[i], 1e-5f); - } - break; - case kTfLiteInt8: - for (int i = 0; i < expected_output_size; ++i) { - TF_LITE_MICRO_EXPECT_NEAR(expected_output[i], - output_tensor->data.int8[i], 1e-5f); - } - break; - default: - break; + const T* output_data = GetTensorData(output_tensor); + for (int i = 0; i < expected_output.size(); ++i) { + TF_LITE_MICRO_EXPECT_NEAR(expected_output.begin()[i], output_data[i], + 1e-5f); } TF_LITE_MICRO_EXPECT_EQ(expected_dims.size(), output_tensor->dims->size); for (int i = 0; i < expected_dims.size(); ++i) { @@ -149,60 +109,30 @@ void TestReshapeImpl(TfLiteTensor* input_tensor, TfLiteTensor* shape_tensor, } } -void TestReshapeTyped(TfLiteTensor* input_tensor, - std::initializer_list shape_dims_data, - std::initializer_list shape_data, - int* output_dims_data, TfLiteTensor* output_tensor, - int expected_output_size, const float* expected_output, - std::initializer_list expected_dims) { - TestReshapeImpl(input_tensor, nullptr, output_tensor, expected_output_size, - expected_output, expected_dims); - TfLiteIntArray* shape_dims = IntArrayFromInitializer(shape_dims_data); - auto shape_tensor = CreateInt32Tensor(shape_data, shape_dims, "shape_tensor"); - TestReshapeImpl(input_tensor, &shape_tensor, output_tensor, - expected_output_size, expected_output, expected_dims); - auto shape_const_tensor = - CreateInt32ConstTensor(shape_data, shape_dims, "shape_tensor"); - TestReshapeImpl(input_tensor, &shape_const_tensor, output_tensor, - expected_output_size, expected_output, expected_dims); -} - +template void TestReshape(std::initializer_list input_dims_data, - std::initializer_list input_data, + std::initializer_list input_data, std::initializer_list shape_dims_data, std::initializer_list shape_data, - int* output_dims_data, float* output_data, - std::initializer_list expected_output, + int* output_dims_data, uint8_t* output_data_raw, + std::initializer_list expected_output, std::initializer_list expected_dims) { TfLiteIntArray* input_dims = IntArrayFromInitializer(input_dims_data); TfLiteIntArray* output_dims = IntArrayFromInts(output_dims_data); - int expected_output_size = expected_output.size(); - // Testing float input. - auto input_tensor = CreateFloatTensor(input_data, input_dims, "input_tensor"); - auto output_tensor = - CreateFloatTensor(output_data, output_dims, "input_tensor"); - TestReshapeTyped(&input_tensor, shape_dims_data, shape_data, output_dims_data, - &output_tensor, expected_output_size, - expected_output.begin(), expected_dims); - // Testing uint8 input. - float expected_uint8[16], expected_int8[16]; - uint8_t input_uint8[16], output_uint8[16]; - int8_t input_int8[16], output_int8[16]; - float input_min = 0; - float input_max = 15.9375; - for (int i = 0; i < input_data.size(); ++i) { - input_uint8[i] = F2Q(input_data.begin()[i], input_min, input_max); - } - for (int i = 0; i < expected_output.size(); ++i) { - expected_uint8[i] = F2Q(expected_output.begin()[i], input_min, input_max); - } - input_tensor = CreateQuantizedTensor(input_uint8, input_dims, "input_tensor", - input_min, input_max); - output_tensor = CreateQuantizedTensor(output_uint8, output_dims, - "input_tensor", input_min, input_max); - TestReshapeTyped(&input_tensor, shape_dims_data, shape_data, output_dims_data, - &output_tensor, expected_output_size, expected_uint8, - expected_dims); + TfLiteTensor input_tensor = CreateTensor( + input_data, input_dims, "input_tensor"); + T* output_data = reinterpret_cast(output_data_raw); + TfLiteTensor output_tensor = CreateTensor( + output_data, output_dims, "input_tensor"); + // Reshape param is passed as op's param. + TestReshapeImpl(&input_tensor, nullptr, &output_tensor, expected_output, + expected_dims); + // Reshape param is passed as a tensor. + TfLiteIntArray* shape_dims = IntArrayFromInitializer(shape_dims_data); + auto shape_tensor = CreateTensor( + shape_data, shape_dims, "shape_tensor"); + TestReshapeImpl(&input_tensor, &shape_tensor, &output_tensor, + expected_output, expected_dims); } } // namespace } // namespace testing @@ -210,44 +140,50 @@ void TestReshape(std::initializer_list input_dims_data, TF_LITE_MICRO_TESTS_BEGIN +#define TEST_RESHAPE(...) \ + using tflite::testing::TestReshape; \ + tflite::testing::TestReshape(__VA_ARGS__); \ + tflite::testing::TestReshape(__VA_ARGS__); \ + tflite::testing::TestReshape(__VA_ARGS__); + TF_LITE_MICRO_TEST(MismatchedDimensions) { - float output_data[8]; + uint8_t output_data[32]; int output_dims[3] = {2, 2, 1}; - tflite::testing::TestReshape({4, 1, 2, 4, 1}, // input_dims - {3}, // input_data - {1, 2}, // shape_dims - {2, 1}, // shape_data - output_dims, // output_dims - output_data, {}, // expected_output - {} // expected_dims + TEST_RESHAPE({4, 1, 2, 4, 1}, // input_dims + {3}, // input_data + {1, 2}, // shape_dims + {2, 1}, // shape_data + output_dims, // output_dims + output_data, {}, // expected_output + {} // expected_dims ); } TF_LITE_MICRO_TEST(TooManyDimensions) { - float output_data[2]; + uint8_t output_data[32]; int output_dims[10] = {9, 1, 1, 1, 1, 1, 1, 1, 1, 2}; - tflite::testing::TestReshape({9, 1, 1, 2, 1, 1, 1, 1, 1, 1}, // input_dims - {3, 2}, // input_data - {1, 9}, // shape_dims - {1, 1, 1, 1, 1, 1, 1, 1, 2}, // shape_data - output_dims, // output_dims - output_data, {3, 2}, // expected_output - {1, 1, 1, 1, 1, 1, 1, 1, 2} // expected_dims + TEST_RESHAPE({9, 1, 1, 2, 1, 1, 1, 1, 1, 1}, // input_dims + {3, 2}, // input_data + {1, 9}, // shape_dims + {1, 1, 1, 1, 1, 1, 1, 1, 2}, // shape_data + output_dims, // output_dims + output_data, {3, 2}, // expected_output + {1, 1, 1, 1, 1, 1, 1, 1, 2} // expected_dims ); } // Number of dimensions > 8 is accepted in micro since it does not use // TfLiteReshapeParams. TF_LITE_MICRO_TEST(TooManySpecialDimensions) { - float output_data[8]; + uint8_t output_data[32]; int output_dims[5] = {4, -1, -1, 2, 4}; - tflite::testing::TestReshape({4, 1, 2, 4, 1}, // input_dims - {3}, // input_data - {1, 4}, // shape_dims - {-1, -1, 2, 4}, // shape_data - output_dims, // output_dims - output_data, {}, // expected_output - {} // expected_dims + TEST_RESHAPE({4, 1, 2, 4, 1}, // input_dims + {3}, // input_data + {1, 4}, // shape_dims + {-1, -1, 2, 4}, // shape_data + output_dims, // output_dims + output_data, {}, // expected_output + {} // expected_dims ); } @@ -265,53 +201,52 @@ TF_LITE_MICRO_TEST(InvalidShape) { TfLiteIntArray* output_dims = IntArrayFromInts(output_dims_data); auto output_tensor = CreateFloatTensor(output_data, output_dims, "input_tensor"); - tflite::testing::TestReshapeImpl(&input_tensor, // input_tensor - nullptr, // shape_tensor - &output_tensor, 0, {}, // expected_output - {} // expected_dims + tflite::testing::TestReshapeImpl(&input_tensor, // input_tensor + nullptr, // shape_tensor + &output_tensor, // output_tensor + {}, // expected_output + {} // expected_dims ); } TF_LITE_MICRO_TEST(RegularShapes) { - float output_data[8]; + uint8_t output_data[32]; int output_dims[4] = {3, 2, 2, 2}; - tflite::testing::TestReshape({4, 1, 2, 4, 1}, // input_dims - {1, 2, 3, 4, 5, 6, 7, 8}, // input_data - {1, 3}, // shape_dims - {2, 2, 2}, // shape_data - output_dims, // output_dims - output_data, - {1, 2, 3, 4, 5, 6, 7, 8}, // expected_output - {2, 2, 2} // expected_dims + TEST_RESHAPE({4, 1, 2, 4, 1}, // input_dims + {1, 2, 3, 4, 5, 6, 7, 8}, // input_data + {1, 3}, // shape_dims + {2, 2, 2}, // shape_data + output_dims, // output_dims + output_data, {1, 2, 3, 4, 5, 6, 7, 8}, // expected_output + {2, 2, 2} // expected_dims ); } TF_LITE_MICRO_TEST(WithStretchDimension) { - float output_data[8]; + uint8_t output_data[32]; int output_dims[4] = {3, 2, 1, -1}; - tflite::testing::TestReshape({4, 1, 2, 4, 1}, // input_dims - {1, 2, 3, 4, 5, 6, 7, 8}, // input_data - {1, 3}, // shape_dims - {2, 1, -1}, // shape_data - output_dims, // output_dims - output_data, - {1, 2, 3, 4, 5, 6, 7, 8}, // expected_output - {2, 1, 4} // expected_dims + TEST_RESHAPE({4, 1, 2, 4, 1}, // input_dims + {1, 2, 3, 4, 5, 6, 7, 8}, // input_data + {1, 3}, // shape_dims + {2, 1, -1}, // shape_data + output_dims, // output_dims + output_data, {1, 2, 3, 4, 5, 6, 7, 8}, // expected_output + {2, 1, 4} // expected_dims ); } // Shape is specified as '[]', which is the modern way to represent scalar // input and output. TF_LITE_MICRO_TEST(ScalarOutput) { - float output_data[1]; + uint8_t output_data[4]; int output_dims[1] = {0}; - tflite::testing::TestReshape({1, 1}, // input_dims - {3}, // input_data - {0}, // shape_dims - {}, // shape_data - output_dims, // output_dims - output_data, {3}, // expected_output - {} // expected_dims + TEST_RESHAPE({1, 1}, // input_dims + {3}, // input_data + {0}, // shape_dims + {}, // shape_data + output_dims, // output_dims + output_data, {3}, // expected_output + {} // expected_dims ); } @@ -330,27 +265,22 @@ TF_LITE_MICRO_TEST(LegacyScalarOutput) { auto output_tensor = CreateFloatTensor(output_data, output_dims, "input_tensor"); TfLiteIntArray* shape_dims = tflite::testing::IntArrayFromInitializer({1, 0}); - auto shape_tensor = - tflite::testing::CreateInt32Tensor({0}, shape_dims, "shape_tensor"); - tflite::testing::TestReshapeImpl(&input_tensor, // input_tensor - &shape_tensor, // shape_tensor - &output_tensor, 0, {}, // expected_output - {} // expected_dims + auto shape_tensor = tflite::testing::CreateTensor( + {0}, shape_dims, "shape_tensor"); + tflite::testing::TestReshapeImpl(&input_tensor, // input_tensor + &shape_tensor, // shape_tensor + &output_tensor, // output_tensor + {}, // expected_output + {} // expected_dims ); - auto shape_const_tensor = - tflite::testing::CreateInt32ConstTensor({0}, shape_dims, "shape_tensor"); - tflite::testing::TestReshapeImpl(&input_tensor, // input_tensor - &shape_const_tensor, // shape_tensor - &output_tensor, 0, {}, // expected_output - {} // expected_dims - ); - float expected_ouput[1] = {3}; - tflite::testing::TestReshapeImpl(&input_tensor, // input_tensor - nullptr, // shape_tensor - &output_tensor, 1, - expected_ouput, // expected_output - {} // expected_dims + tflite::testing::TestReshapeImpl(&input_tensor, // input_tensor + nullptr, // shape_tensor + &output_tensor, // output_tensor + {3}, // expected_output + {} // expected_dims ); } +#undef TEST_RESHAPE + TF_LITE_MICRO_TESTS_END