diff --git a/tensorflow/lite/experimental/micro/kernels/BUILD b/tensorflow/lite/experimental/micro/kernels/BUILD index 5121bc3d15b..c7562d6bbbd 100644 --- a/tensorflow/lite/experimental/micro/kernels/BUILD +++ b/tensorflow/lite/experimental/micro/kernels/BUILD @@ -17,6 +17,7 @@ cc_library( "conv.cc", "depthwise_conv.cc", "elementwise.cc", + "floor.cc", "fully_connected.cc", "pooling.cc", "prelu.cc", @@ -57,6 +58,7 @@ cc_library( srcs = [ "conv.cc", "elementwise.cc", + "floor.cc", "fully_connected.cc", "pooling.cc", "portable_optimized/depthwise_conv.cc", @@ -194,3 +196,16 @@ tflite_micro_cc_test( "//tensorflow/lite/experimental/micro/testing:micro_test", ], ) + +tflite_micro_cc_test( + name = "floor_test", + srcs = [ + "floor_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", + ], +) diff --git a/tensorflow/lite/experimental/micro/kernels/all_ops_resolver.cc b/tensorflow/lite/experimental/micro/kernels/all_ops_resolver.cc index c54cdf78f6c..e1afefc2867 100644 --- a/tensorflow/lite/experimental/micro/kernels/all_ops_resolver.cc +++ b/tensorflow/lite/experimental/micro/kernels/all_ops_resolver.cc @@ -24,6 +24,7 @@ TfLiteRegistration* Register_AVERAGE_POOL_2D(); TfLiteRegistration* Register_MAX_POOL_2D(); TfLiteRegistration* Register_ABS(); TfLiteRegistration* Register_PRELU(); +TfLiteRegistration* Register_FLOOR(); AllOpsResolver::AllOpsResolver() { AddBuiltin(BuiltinOperator_DEPTHWISE_CONV_2D, Register_DEPTHWISE_CONV_2D()); @@ -36,6 +37,7 @@ AllOpsResolver::AllOpsResolver() { AddBuiltin(BuiltinOperator_AVERAGE_POOL_2D, Register_AVERAGE_POOL_2D()); AddBuiltin(BuiltinOperator_ABS, Register_ABS()); AddBuiltin(BuiltinOperator_PRELU, Register_PRELU()); + AddBuiltin(BuiltinOperator_FLOOR, Register_FLOOR()); } } // namespace micro diff --git a/tensorflow/lite/experimental/micro/kernels/floor.cc b/tensorflow/lite/experimental/micro/kernels/floor.cc new file mode 100644 index 00000000000..7b55cff01a8 --- /dev/null +++ b/tensorflow/lite/experimental/micro/kernels/floor.cc @@ -0,0 +1,48 @@ +/* Copyright 2019 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/c_api_internal.h" +#include "tensorflow/lite/kernels/internal/reference/floor.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" + +namespace tflite { +namespace ops { +namespace micro { +namespace floor { + +constexpr int kInputTensor = 0; +constexpr int kOutputTensor = 0; + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + const TfLiteTensor* input = GetInput(context, node, kInputTensor); + TF_LITE_ENSURE_EQ(context, input->type, kTfLiteFloat32); + TfLiteTensor* output = GetOutput(context, node, kOutputTensor); + reference_ops::Floor(GetTensorShape(input), GetTensorData(input), + GetTensorShape(output), GetTensorData(output)); + return kTfLiteOk; +} +} // namespace floor + +TfLiteRegistration* Register_FLOOR() { + static TfLiteRegistration r = {/*init=*/nullptr, + /*free=*/nullptr, /*prepare=*/nullptr, + floor::Eval}; + return &r; +} + +} // namespace micro +} // namespace ops +} // namespace tflite diff --git a/tensorflow/lite/experimental/micro/kernels/floor_test.cc b/tensorflow/lite/experimental/micro/kernels/floor_test.cc new file mode 100644 index 00000000000..7b65a409fd7 --- /dev/null +++ b/tensorflow/lite/experimental/micro/kernels/floor_test.cc @@ -0,0 +1,99 @@ +/* Copyright 2019 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/simple_tensor_allocator.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 TestFloor(std::initializer_list input_dims_data, + std::initializer_list input_data, + std::initializer_list expected_output_data, + std::initializer_list output_dims_data, + float* output_data) { + TfLiteIntArray* input_dims = IntArrayFromInitializer(input_dims_data); + TfLiteIntArray* output_dims = IntArrayFromInitializer(output_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_FLOOR, 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(FloorOpSingleDimFloat32) { + float output_data[2]; + tflite::testing::TestFloor(/*input_dims_data=*/{1, 2}, + /*input_data=*/{8.5f, 0.0f}, + /*expected_output_data=*/{8, 0}, + /*output_dims_data*/ {1, 2}, + /*output_data=*/output_data); +} + +TF_LITE_MICRO_TEST(FloorOpMultiDimFloat32) { + float output_data[10]; + tflite::testing::TestFloor( + /*input_dims_data=*/{4, 2, 1, 1, 5}, + /*input_data=*/ + {0.0001f, 8.0001f, 0.9999f, 9.9999f, 0.5f, -0.0001f, -8.0001f, -0.9999f, + -9.9999f, -0.5f}, + /*expected_output_data=*/ + {0.0f, 8.0f, 0.0f, 9.0f, 0.0f, -1.0f, -9.0f, -1.0f, -10.0f, -1.0f}, + /*output_dims_data=*/{4, 2, 1, 1, 5}, + /*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 f3828928612..e37297c3c7f 100644 --- a/tensorflow/lite/experimental/micro/tools/make/Makefile +++ b/tensorflow/lite/experimental/micro/tools/make/Makefile @@ -110,6 +110,7 @@ tensorflow/lite/kernels/internal/optimized/neon_check.h \ tensorflow/lite/kernels/internal/reference/conv.h \ tensorflow/lite/kernels/internal/reference/depthwiseconv_float.h \ tensorflow/lite/kernels/internal/reference/depthwiseconv_uint8.h \ +tensorflow/lite/kernels/internal/reference/floor.h \ tensorflow/lite/kernels/internal/reference/fully_connected.h \ tensorflow/lite/kernels/internal/reference/pooling.h \ tensorflow/lite/kernels/internal/reference/prelu.h \ diff --git a/tensorflow/lite/kernels/floor.cc b/tensorflow/lite/kernels/floor.cc index b6ccce3b938..76074191797 100644 --- a/tensorflow/lite/kernels/floor.cc +++ b/tensorflow/lite/kernels/floor.cc @@ -13,9 +13,10 @@ See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ +#include "tensorflow/lite/kernels/internal/reference/floor.h" + #include "tensorflow/lite/c/c_api_internal.h" #include "tensorflow/lite/kernels/internal/optimized/optimized_ops.h" -#include "tensorflow/lite/kernels/internal/reference/reference_ops.h" #include "tensorflow/lite/kernels/internal/tensor.h" #include "tensorflow/lite/kernels/kernel_util.h" diff --git a/tensorflow/lite/kernels/internal/BUILD b/tensorflow/lite/kernels/internal/BUILD index 199909ccbf8..3caf2d5124d 100644 --- a/tensorflow/lite/kernels/internal/BUILD +++ b/tensorflow/lite/kernels/internal/BUILD @@ -350,6 +350,7 @@ cc_library( "reference/conv.h", "reference/depthwiseconv_float.h", "reference/depthwiseconv_uint8.h", + "reference/floor.h", "reference/fully_connected.h", "reference/integer_ops/add.h", "reference/integer_ops/conv.h", @@ -403,6 +404,7 @@ cc_library( "reference/conv.h", "reference/depthwiseconv_float.h", "reference/depthwiseconv_uint8.h", + "reference/floor.h", "reference/fully_connected.h", "reference/legacy_reference_ops.h", "reference/pooling.h", diff --git a/tensorflow/lite/kernels/internal/reference/floor.h b/tensorflow/lite/kernels/internal/reference/floor.h new file mode 100644 index 00000000000..0693fd42987 --- /dev/null +++ b/tensorflow/lite/kernels/internal/reference/floor.h @@ -0,0 +1,39 @@ +/* Copyright 2019 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_FLOOR_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_FLOOR_H_ + +#include + +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { + +namespace reference_ops { + +inline void Floor(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::floor(input_data[offset]); + } +} + +} // namespace reference_ops +} // namespace tflite + +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_FLOOR_H_ diff --git a/tensorflow/lite/kernels/internal/reference/reference_ops.h b/tensorflow/lite/kernels/internal/reference/reference_ops.h index 92b3b47fb04..31a337a71a3 100644 --- a/tensorflow/lite/kernels/internal/reference/reference_ops.h +++ b/tensorflow/lite/kernels/internal/reference/reference_ops.h @@ -33,6 +33,7 @@ limitations under the License. #include "tensorflow/lite/kernels/internal/common.h" #include "tensorflow/lite/kernels/internal/quantization_util.h" #include "tensorflow/lite/kernels/internal/reference/conv.h" +#include "tensorflow/lite/kernels/internal/reference/floor.h" #include "tensorflow/lite/kernels/internal/reference/fully_connected.h" #include "tensorflow/lite/kernels/internal/reference/pooling.h" #include "tensorflow/lite/kernels/internal/reference/prelu.h" @@ -2637,16 +2638,6 @@ T FloorMod(T input1, T input2) { : trunc_mod; } -inline void Floor(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::floor(input_data[offset]); - } -} - 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);