Port NEG operation to micro
PiperOrigin-RevId: 263766684
This commit is contained in:
parent
33a5b7e52c
commit
8381bf1166
@ -24,6 +24,7 @@ cc_library(
|
||||
"fully_connected.cc",
|
||||
"logical.cc",
|
||||
"maximum_minimum.cc",
|
||||
"neg.cc",
|
||||
"pack.cc",
|
||||
"pooling.cc",
|
||||
"prelu.cc",
|
||||
@ -38,8 +39,8 @@ cc_library(
|
||||
],
|
||||
copts = tflite_copts(),
|
||||
deps = [
|
||||
":micro_utils",
|
||||
"//tensorflow/lite/c:c_api_internal",
|
||||
"//tensorflow/lite/experimental/micro/kernels:micro_utils",
|
||||
"//tensorflow/lite/kernels:kernel_util",
|
||||
"//tensorflow/lite/kernels:op_macros",
|
||||
"//tensorflow/lite/kernels:padding",
|
||||
@ -78,6 +79,7 @@ cc_library(
|
||||
"fully_connected.cc",
|
||||
"logical.cc",
|
||||
"maximum_minimum.cc",
|
||||
"neg.cc",
|
||||
"pack.cc",
|
||||
"pooling.cc",
|
||||
"portable_optimized/depthwise_conv.cc",
|
||||
@ -93,8 +95,8 @@ cc_library(
|
||||
],
|
||||
copts = tflite_copts(),
|
||||
deps = [
|
||||
":micro_utils",
|
||||
"//tensorflow/lite/c:c_api_internal",
|
||||
"//tensorflow/lite/experimental/micro/kernels:micro_utils",
|
||||
"//tensorflow/lite/kernels:kernel_util",
|
||||
"//tensorflow/lite/kernels:op_macros",
|
||||
"//tensorflow/lite/kernels:padding",
|
||||
@ -249,6 +251,19 @@ tflite_micro_cc_test(
|
||||
],
|
||||
)
|
||||
|
||||
tflite_micro_cc_test(
|
||||
name = "neg_test",
|
||||
srcs = [
|
||||
"neg_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",
|
||||
],
|
||||
)
|
||||
|
||||
tflite_micro_cc_test(
|
||||
name = "maximum_minimum_test",
|
||||
srcs = [
|
||||
@ -269,9 +284,9 @@ tflite_micro_cc_test(
|
||||
],
|
||||
deps = [
|
||||
":all_ops_resolver",
|
||||
":micro_utils",
|
||||
"//tensorflow/lite/c:c_api_internal",
|
||||
"//tensorflow/lite/experimental/micro:micro_framework",
|
||||
"//tensorflow/lite/experimental/micro/kernels:micro_utils",
|
||||
"//tensorflow/lite/experimental/micro/testing:micro_test",
|
||||
],
|
||||
)
|
||||
|
@ -51,6 +51,7 @@ TfLiteRegistration* Register_STRIDED_SLICE();
|
||||
TfLiteRegistration* Register_PACK();
|
||||
TfLiteRegistration* Register_SPLIT();
|
||||
TfLiteRegistration* Register_UNPACK();
|
||||
TfLiteRegistration* Register_NEG();
|
||||
|
||||
AllOpsResolver::AllOpsResolver() {
|
||||
AddBuiltin(BuiltinOperator_DEPTHWISE_CONV_2D, Register_DEPTHWISE_CONV_2D());
|
||||
@ -92,6 +93,7 @@ AllOpsResolver::AllOpsResolver() {
|
||||
/* min_version */ 1,
|
||||
/* max_version */ 3);
|
||||
AddBuiltin(BuiltinOperator_UNPACK, Register_UNPACK());
|
||||
AddBuiltin(BuiltinOperator_NEG, Register_NEG());
|
||||
}
|
||||
|
||||
} // namespace micro
|
||||
|
58
tensorflow/lite/experimental/micro/kernels/neg.cc
Normal file
58
tensorflow/lite/experimental/micro/kernels/neg.cc
Normal file
@ -0,0 +1,58 @@
|
||||
/* 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/kernels/internal/reference/neg.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 neg {
|
||||
|
||||
constexpr int kInputTensor = 0;
|
||||
constexpr int kOutputTensor = 0;
|
||||
|
||||
TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
|
||||
const TfLiteTensor* input = GetInput(context, node, kInputTensor);
|
||||
TfLiteTensor* output = GetOutput(context, node, kOutputTensor);
|
||||
switch (input->type) {
|
||||
// TODO(wangtz): handle for kTfLiteInt8
|
||||
case kTfLiteFloat32:
|
||||
reference_ops::Negate(GetTensorShape(input), GetTensorData<float>(input),
|
||||
GetTensorShape(output),
|
||||
GetTensorData<float>(output));
|
||||
break;
|
||||
default:
|
||||
context->ReportError(
|
||||
context, "Neg only currently supports float32, got %d.", input->type);
|
||||
return kTfLiteError;
|
||||
}
|
||||
return kTfLiteOk;
|
||||
}
|
||||
|
||||
} // namespace neg
|
||||
|
||||
TfLiteRegistration* Register_NEG() {
|
||||
static TfLiteRegistration r = {/*init=*/nullptr, /*free=*/nullptr,
|
||||
/*prepare=*/nullptr, neg::Eval};
|
||||
return &r;
|
||||
}
|
||||
|
||||
} // namespace micro
|
||||
} // namespace ops
|
||||
} // namespace tflite
|
101
tensorflow/lite/experimental/micro/kernels/neg_test.cc
Normal file
101
tensorflow/lite/experimental/micro/kernels/neg_test.cc
Normal file
@ -0,0 +1,101 @@
|
||||
/* 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 TestNegFloat(std::initializer_list<int> input_dims_data,
|
||||
std::initializer_list<float> input_data,
|
||||
std::initializer_list<float> expected_output_data,
|
||||
std::initializer_list<int> 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_NEG, 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));
|
||||
|
||||
TF_LITE_MICRO_EXPECT_EQ(expected_output_data.begin()[0], output_data[0]);
|
||||
for (int i = 0; i < output_dims_count; ++i) {
|
||||
TF_LITE_MICRO_EXPECT_EQ(expected_output_data.begin()[i], output_data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace testing
|
||||
} // namespace tflite
|
||||
|
||||
TF_LITE_MICRO_TESTS_BEGIN
|
||||
|
||||
TF_LITE_MICRO_TEST(NegOpSingleFloat) {
|
||||
float output_data[2];
|
||||
tflite::testing::TestNegFloat(/*input_dims_data=*/{1, 2},
|
||||
/*input_data=*/{8.5f, 0.0f},
|
||||
/*expected_output_data=*/{-8.5f, 0.0f},
|
||||
/*output_dims_data*/ {1, 2},
|
||||
/*output_data=*/output_data);
|
||||
}
|
||||
|
||||
TF_LITE_MICRO_TEST(NegOpFloat) {
|
||||
float output_data[6];
|
||||
tflite::testing::TestNegFloat(/*input_dims_data=*/{2, 2, 3},
|
||||
/*input_data=*/
|
||||
{-2.0f, -1.0f, 0.f, 1.0f, 2.0f, 3.0f},
|
||||
/*expected_output_data=*/
|
||||
{2.0f, 1.0f, -0.f, -1.0f, -2.0f, -3.0f},
|
||||
/*output_dims_data=*/{2, 2, 3},
|
||||
/*output_data=*/output_data);
|
||||
}
|
||||
|
||||
TF_LITE_MICRO_TESTS_END
|
@ -123,6 +123,7 @@ tensorflow/lite/kernels/internal/reference/round.h \
|
||||
tensorflow/lite/kernels/internal/reference/softmax.h \
|
||||
tensorflow/lite/kernels/internal/reference/strided_slice.h \
|
||||
tensorflow/lite/kernels/internal/reference/arg_min_max.h \
|
||||
tensorflow/lite/kernels/internal/reference/neg.h \
|
||||
tensorflow/lite/kernels/internal/round.h \
|
||||
tensorflow/lite/kernels/internal/strided_slice_logic.h \
|
||||
tensorflow/lite/kernels/internal/tensor_ctypes.h \
|
||||
|
@ -382,6 +382,7 @@ cc_library(
|
||||
"reference/integer_ops/softmax.h",
|
||||
"reference/integer_ops/tanh.h",
|
||||
"reference/maximum_minimum.h",
|
||||
"reference/neg.h",
|
||||
"reference/pooling.h",
|
||||
"reference/prelu.h",
|
||||
"reference/process_broadcast_shapes.h",
|
||||
@ -434,6 +435,7 @@ cc_library(
|
||||
"reference/fully_connected.h",
|
||||
"reference/legacy_reference_ops.h",
|
||||
"reference/maximum_minimum.h",
|
||||
"reference/neg.h",
|
||||
"reference/pooling.h",
|
||||
"reference/prelu.h",
|
||||
"reference/process_broadcast_shapes.h",
|
||||
|
37
tensorflow/lite/kernels/internal/reference/neg.h
Normal file
37
tensorflow/lite/kernels/internal/reference/neg.h
Normal file
@ -0,0 +1,37 @@
|
||||
/* 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_NEG_H_
|
||||
#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_NEG_H_
|
||||
|
||||
#include "tensorflow/lite/kernels/internal/types.h"
|
||||
|
||||
namespace tflite {
|
||||
|
||||
namespace reference_ops {
|
||||
|
||||
template <typename T>
|
||||
inline void Negate(const RuntimeShape& input_shape, const T* input_data,
|
||||
const RuntimeShape& output_shape, T* output_data) {
|
||||
const int flat_size = MatchingFlatSize(input_shape, output_shape);
|
||||
|
||||
for (int i = 0; i < flat_size; ++i) {
|
||||
output_data[i] = -input_data[i];
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace reference_ops
|
||||
} // namespace tflite
|
||||
|
||||
#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_NEG_H_
|
@ -41,6 +41,7 @@ limitations under the License.
|
||||
#include "tensorflow/lite/kernels/internal/reference/floor.h"
|
||||
#include "tensorflow/lite/kernels/internal/reference/fully_connected.h"
|
||||
#include "tensorflow/lite/kernels/internal/reference/maximum_minimum.h"
|
||||
#include "tensorflow/lite/kernels/internal/reference/neg.h"
|
||||
#include "tensorflow/lite/kernels/internal/reference/pooling.h"
|
||||
#include "tensorflow/lite/kernels/internal/reference/prelu.h"
|
||||
#include "tensorflow/lite/kernels/internal/reference/process_broadcast_shapes.h"
|
||||
|
@ -13,7 +13,11 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==============================================================================*/
|
||||
|
||||
#include "tensorflow/lite/kernels/internal/reference/neg.h"
|
||||
|
||||
#include "tensorflow/lite/c/c_api_internal.h"
|
||||
#include "tensorflow/lite/kernels/internal/optimized/optimized_ops.h"
|
||||
#include "tensorflow/lite/kernels/internal/tensor.h"
|
||||
#include "tensorflow/lite/kernels/kernel_util.h"
|
||||
|
||||
namespace tflite {
|
||||
@ -35,27 +39,24 @@ TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) {
|
||||
TfLiteIntArrayCopy(input->dims));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Negate(const T* in_data, int num_elements, T* out_data) {
|
||||
// TODO(alanchiao): add vectorized version.
|
||||
for (int i = 0; i < num_elements; ++i) {
|
||||
out_data[i] = -in_data[i];
|
||||
}
|
||||
}
|
||||
|
||||
TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
|
||||
const TfLiteTensor* input = GetInput(context, node, kInputTensor);
|
||||
TfLiteTensor* output = GetOutput(context, node, kOutputTensor);
|
||||
const int num_elements = NumElements(input);
|
||||
switch (input->type) {
|
||||
case kTfLiteInt64:
|
||||
Negate(input->data.i64, num_elements, output->data.i64);
|
||||
reference_ops::Negate(
|
||||
GetTensorShape(input), GetTensorData<int64_t>(input),
|
||||
GetTensorShape(output), GetTensorData<int64_t>(output));
|
||||
break;
|
||||
case kTfLiteInt32:
|
||||
Negate(input->data.i32, num_elements, output->data.i32);
|
||||
reference_ops::Negate(
|
||||
GetTensorShape(input), GetTensorData<int32_t>(input),
|
||||
GetTensorShape(output), GetTensorData<int32_t>(output));
|
||||
break;
|
||||
case kTfLiteFloat32:
|
||||
Negate(input->data.f, num_elements, output->data.f);
|
||||
reference_ops::Negate(GetTensorShape(input), GetTensorData<float>(input),
|
||||
GetTensorShape(output),
|
||||
GetTensorData<float>(output));
|
||||
break;
|
||||
default:
|
||||
context->ReportError(
|
||||
|
Loading…
x
Reference in New Issue
Block a user