From f9233a58974095e9ee711ca7c5de9fa60ede742a Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Sun, 11 Aug 2019 23:59:49 -0700 Subject: [PATCH] Add ceil op for micro PiperOrigin-RevId: 262866402 --- .../lite/experimental/micro/kernels/BUILD | 15 +++ .../micro/kernels/all_ops_resolver.cc | 2 + .../lite/experimental/micro/kernels/ceil.cc | 64 +++++++++++ .../experimental/micro/kernels/ceil_test.cc | 103 ++++++++++++++++++ .../experimental/micro/tools/make/Makefile | 1 + tensorflow/lite/kernels/internal/BUILD | 2 + .../lite/kernels/internal/reference/ceil.h | 37 +++++++ .../internal/reference/reference_ops.h | 11 +- 8 files changed, 225 insertions(+), 10 deletions(-) create mode 100644 tensorflow/lite/experimental/micro/kernels/ceil.cc create mode 100644 tensorflow/lite/experimental/micro/kernels/ceil_test.cc create mode 100644 tensorflow/lite/kernels/internal/reference/ceil.h diff --git a/tensorflow/lite/experimental/micro/kernels/BUILD b/tensorflow/lite/experimental/micro/kernels/BUILD index b1d2fd70c37..2f9b046f4b8 100644 --- a/tensorflow/lite/experimental/micro/kernels/BUILD +++ b/tensorflow/lite/experimental/micro/kernels/BUILD @@ -15,6 +15,7 @@ cc_library( name = "micro_ops", srcs = [ "arg_min_max.cc", + "ceil.cc", "comparisons.cc", "conv.cc", "depthwise_conv.cc", @@ -63,6 +64,7 @@ cc_library( name = "portable_optimized_micro_ops", srcs = [ "arg_min_max.cc", + "ceil.cc", "comparisons.cc", "conv.cc", "elementwise.cc", @@ -276,6 +278,19 @@ tflite_micro_cc_test( ], ) +tflite_micro_cc_test( + name = "ceil_test", + srcs = [ + "ceil_test.cc", + ], + deps = [ + ":all_ops_resolver", + "//tensorflow/lite/c:c_api_internal", + "//tensorflow/lite/experimental/micro:micro_framework", + "//tensorflow/lite/experimental/micro/testing:micro_test", + ], +) + cc_library( name = "micro_utils", hdrs = ["micro_utils.h"], diff --git a/tensorflow/lite/experimental/micro/kernels/all_ops_resolver.cc b/tensorflow/lite/experimental/micro/kernels/all_ops_resolver.cc index 6bc10dffc15..712eb57e7ad 100644 --- a/tensorflow/lite/experimental/micro/kernels/all_ops_resolver.cc +++ b/tensorflow/lite/experimental/micro/kernels/all_ops_resolver.cc @@ -45,6 +45,7 @@ TfLiteRegistration* Register_GREATER(); TfLiteRegistration* Register_GREATER_EQUAL(); TfLiteRegistration* Register_LESS(); TfLiteRegistration* Register_LESS_EQUAL(); +TfLiteRegistration* Register_CEIL(); AllOpsResolver::AllOpsResolver() { AddBuiltin(BuiltinOperator_DEPTHWISE_CONV_2D, Register_DEPTHWISE_CONV_2D()); @@ -78,6 +79,7 @@ AllOpsResolver::AllOpsResolver() { AddBuiltin(BuiltinOperator_GREATER_EQUAL, Register_GREATER_EQUAL()); AddBuiltin(BuiltinOperator_LESS, Register_LESS()); AddBuiltin(BuiltinOperator_LESS_EQUAL, Register_LESS_EQUAL()); + AddBuiltin(BuiltinOperator_CEIL, Register_CEIL()); } } // namespace micro diff --git a/tensorflow/lite/experimental/micro/kernels/ceil.cc b/tensorflow/lite/experimental/micro/kernels/ceil.cc new file mode 100644 index 00000000000..41f7331726d --- /dev/null +++ b/tensorflow/lite/experimental/micro/kernels/ceil.cc @@ -0,0 +1,64 @@ +/* Copyright 2018 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 "tensorflow/lite/kernels/internal/reference/ceil.h" + +#include "tensorflow/lite/c/c_api_internal.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" + +namespace tflite { +namespace ops { +namespace micro { +namespace ceil { + +constexpr int kInputTensor = 0; +constexpr int kOutputTensor = 0; + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + const TfLiteTensor* input = GetInput(context, node, kInputTensor); + TfLiteTensor* output = GetOutput(context, node, kOutputTensor); + TF_LITE_ENSURE_EQ(context, NumInputs(node), 1); + TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); + TF_LITE_ENSURE_EQ(context, input->type, kTfLiteFloat32); + TF_LITE_ENSURE_EQ(context, output->type, input->type); + TF_LITE_ENSURE_EQ(context, output->bytes, input->bytes); + TF_LITE_ENSURE_EQ(context, output->dims->size, input->dims->size); + for (int i = 0; i < output->dims->size; ++i) { + TF_LITE_ENSURE_EQ(context, output->dims->data[i], input->dims->data[i]); + } + return kTfLiteOk; +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + const TfLiteTensor* input = GetInput(context, node, kInputTensor); + TfLiteTensor* output = GetOutput(context, node, kOutputTensor); + + reference_ops::Ceil(GetTensorShape(input), GetTensorData(input), + GetTensorShape(output), GetTensorData(output)); + + return kTfLiteOk; +} +} // namespace ceil + +TfLiteRegistration* Register_CEIL() { + static TfLiteRegistration r = {/*init=*/nullptr, + /*free=*/nullptr, ceil::Prepare, ceil::Eval}; + return &r; +} + +} // namespace micro +} // namespace ops +} // namespace tflite diff --git a/tensorflow/lite/experimental/micro/kernels/ceil_test.cc b/tensorflow/lite/experimental/micro/kernels/ceil_test.cc new file mode 100644 index 00000000000..a57fc70b8ce --- /dev/null +++ b/tensorflow/lite/experimental/micro/kernels/ceil_test.cc @@ -0,0 +1,103 @@ +/* Copyright 2018 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 "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/c_api_internal.h" +#include "tensorflow/lite/experimental/micro/kernels/all_ops_resolver.h" +#include "tensorflow/lite/experimental/micro/testing/micro_test.h" +#include "tensorflow/lite/experimental/micro/testing/test_utils.h" + +namespace tflite { +namespace testing { +namespace { + +void TestCeil(std::initializer_list input_dims_data, + std::initializer_list input_data, + std::initializer_list expected_output_data, + float* output_data) { + TfLiteIntArray* input_dims = IntArrayFromInitializer(input_dims_data); + TfLiteIntArray* output_dims = IntArrayFromInitializer(input_dims_data); + const int output_dims_count = ElementCount(*output_dims); + constexpr int inputs_size = 1; + constexpr int outputs_size = 1; + constexpr int tensors_size = inputs_size + outputs_size; + TfLiteTensor tensors[tensors_size] = { + CreateFloatTensor(input_data, input_dims, "input_tensor"), + CreateFloatTensor(output_data, output_dims, "output_tensor"), + }; + TfLiteContext context; + PopulateContext(tensors, tensors_size, &context); + ::tflite::ops::micro::AllOpsResolver resolver; + const TfLiteRegistration* registration = + resolver.FindOp(tflite::BuiltinOperator_CEIL, 1); + TF_LITE_MICRO_EXPECT_NE(nullptr, registration); + + int inputs_array_data[] = {1, 0}; + TfLiteIntArray* inputs_array = IntArrayFromInts(inputs_array_data); + int outputs_array_data[] = {1, 1}; + TfLiteIntArray* outputs_array = IntArrayFromInts(outputs_array_data); + TfLiteIntArray* temporaries_array = IntArrayFromInitializer({0}); + TfLiteNode node; + node.inputs = inputs_array; + node.outputs = outputs_array; + node.temporaries = temporaries_array; + node.user_data = nullptr; + node.builtin_data = nullptr; + node.custom_initial_data = nullptr; + node.custom_initial_data_size = 0; + node.delegate = nullptr; + TF_LITE_MICRO_EXPECT_NE(nullptr, registration->invoke); + TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, registration->invoke(&context, &node)); + for (int i = 0; i < output_dims_count; ++i) { + TF_LITE_MICRO_EXPECT_NEAR(expected_output_data.begin()[i], output_data[i], + 1e-5f); + } +} + +} // namespace +} // namespace testing +} // namespace tflite + +TF_LITE_MICRO_TESTS_BEGIN + +TF_LITE_MICRO_TEST(SingleDim) { + float output_data[2]; + tflite::testing::TestCeil({1, 2}, // input_dims_data + {8.5, 0.0}, // input_data + {9, 0}, // expected_output_data + output_data); +} + +TF_LITE_MICRO_TEST(MultiDims) { + float output_data[10]; + tflite::testing::TestCeil( + {4, 2, 1, 1, 5}, // input_dims_data + { + 0.0001, + 8.0001, + 0.9999, + 9.9999, + 0.5, + -0.0001, + -8.0001, + -0.9999, + -9.9999, + -0.5, + }, // input_data + {1, 9, 1, 10, 1, 0, -8, 0, -9, 0}, // expected_output_data + output_data); +} + +TF_LITE_MICRO_TESTS_END diff --git a/tensorflow/lite/experimental/micro/tools/make/Makefile b/tensorflow/lite/experimental/micro/tools/make/Makefile index f52452c63af..12c168052cf 100644 --- a/tensorflow/lite/experimental/micro/tools/make/Makefile +++ b/tensorflow/lite/experimental/micro/tools/make/Makefile @@ -109,6 +109,7 @@ tensorflow/lite/kernels/internal/compatibility.h \ tensorflow/lite/kernels/internal/optimized/neon_check.h \ tensorflow/lite/kernels/internal/reference/binary_function.h \ tensorflow/lite/kernels/internal/reference/comparisons.h \ +tensorflow/lite/kernels/internal/reference/ceil.h \ tensorflow/lite/kernels/internal/reference/conv.h \ tensorflow/lite/kernels/internal/reference/depthwiseconv_float.h \ tensorflow/lite/kernels/internal/reference/depthwiseconv_uint8.h \ diff --git a/tensorflow/lite/kernels/internal/BUILD b/tensorflow/lite/kernels/internal/BUILD index 43a3927d564..80b866c3def 100644 --- a/tensorflow/lite/kernels/internal/BUILD +++ b/tensorflow/lite/kernels/internal/BUILD @@ -361,6 +361,7 @@ cc_library( "reference/add.h", "reference/arg_min_max.h", "reference/binary_function.h", + "reference/ceil.h", "reference/comparisons.h", "reference/conv.h", "reference/depthwiseconv_float.h", @@ -423,6 +424,7 @@ cc_library( "reference/add.h", "reference/arg_min_max.h", "reference/binary_function.h", + "reference/ceil.h", "reference/comparisons.h", "reference/conv.h", "reference/depthwiseconv_float.h", diff --git a/tensorflow/lite/kernels/internal/reference/ceil.h b/tensorflow/lite/kernels/internal/reference/ceil.h new file mode 100644 index 00000000000..66d1dc3599c --- /dev/null +++ b/tensorflow/lite/kernels/internal/reference/ceil.h @@ -0,0 +1,37 @@ +/* Copyright 2018 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. +==============================================================================*/ +#ifndef TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_CEIL_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_CEIL_H_ + +#include + +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { + +namespace reference_ops { + +inline void Ceil(const RuntimeShape& input_shape, const float* input_data, + const RuntimeShape& output_shape, float* output_data) { + const int flat_size = MatchingFlatSize(input_shape, output_shape); + + for (int i = 0; i < flat_size; ++i) { + output_data[i] = std::ceil(input_data[i]); + } +} + +} // namespace reference_ops +} // namespace tflite +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_CEIL_H_ diff --git a/tensorflow/lite/kernels/internal/reference/reference_ops.h b/tensorflow/lite/kernels/internal/reference/reference_ops.h index 91fd8d9c36a..923872908d4 100644 --- a/tensorflow/lite/kernels/internal/reference/reference_ops.h +++ b/tensorflow/lite/kernels/internal/reference/reference_ops.h @@ -35,6 +35,7 @@ limitations under the License. #include "tensorflow/lite/kernels/internal/reference/add.h" #include "tensorflow/lite/kernels/internal/reference/arg_min_max.h" #include "tensorflow/lite/kernels/internal/reference/binary_function.h" +#include "tensorflow/lite/kernels/internal/reference/ceil.h" #include "tensorflow/lite/kernels/internal/reference/comparisons.h" #include "tensorflow/lite/kernels/internal/reference/conv.h" #include "tensorflow/lite/kernels/internal/reference/floor.h" @@ -2158,16 +2159,6 @@ T FloorMod(T input1, T input2) { : trunc_mod; } -inline void Ceil(const RuntimeShape& input_shape, const float* input_data, - const RuntimeShape& output_shape, float* output_data) { - const int flat_size = MatchingFlatSize(input_shape, output_shape); - - for (int i = 0; i < flat_size; i++) { - int offset = i; - output_data[offset] = std::ceil(input_data[offset]); - } -} - inline float RoundToNearest(float value) { auto floor_val = std::floor(value); auto diff = value - floor_val;