From f0b228a36dacaef00f7215df0d8ab3d3a84749a2 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Fri, 17 Apr 2020 16:15:38 -0700 Subject: [PATCH] TFL MCU: Move reference L2Normalization implementation into its own file. so that we won't need to import all the dependencies. This CL simply copies the existing code into the new file. PiperOrigin-RevId: 307134277 Change-Id: Idf7f9dffe6d6505337caefc736dce372aa014b14 --- tensorflow/lite/kernels/internal/BUILD | 2 + tensorflow/lite/kernels/internal/common.h | 2 + .../internal/reference/fully_connected.h | 2 - .../reference/integer_ops/l2normalization.h | 4 +- .../internal/reference/l2normalization.h | 88 +++++++++++++++++++ .../internal/reference/reference_ops.h | 57 +----------- 6 files changed, 95 insertions(+), 60 deletions(-) create mode 100644 tensorflow/lite/kernels/internal/reference/l2normalization.h diff --git a/tensorflow/lite/kernels/internal/BUILD b/tensorflow/lite/kernels/internal/BUILD index fcd5b712cdc..e838dc98da4 100644 --- a/tensorflow/lite/kernels/internal/BUILD +++ b/tensorflow/lite/kernels/internal/BUILD @@ -459,6 +459,7 @@ cc_library( "reference/integer_ops/pooling.h", "reference/integer_ops/tanh.h", "reference/integer_ops/transpose_conv.h", + "reference/l2normalization.h", "reference/logistic.h", "reference/maximum_minimum.h", "reference/mul.h", @@ -529,6 +530,7 @@ cc_library( "reference/dequantize.h", "reference/floor.h", "reference/fully_connected.h", + "reference/l2normalization.h", "reference/legacy_reference_ops.h", "reference/logistic.h", "reference/maximum_minimum.h", diff --git a/tensorflow/lite/kernels/internal/common.h b/tensorflow/lite/kernels/internal/common.h index a5d488d35f5..ff8cc6d45b3 100644 --- a/tensorflow/lite/kernels/internal/common.h +++ b/tensorflow/lite/kernels/internal/common.h @@ -29,6 +29,8 @@ limitations under the License. namespace tflite { +constexpr int kReverseShift = -1; + inline void GetActivationMinMax(FusedActivationFunctionType ac, float* output_activation_min, float* output_activation_max) { diff --git a/tensorflow/lite/kernels/internal/reference/fully_connected.h b/tensorflow/lite/kernels/internal/reference/fully_connected.h index fa59e1df370..204a0fa0afa 100644 --- a/tensorflow/lite/kernels/internal/reference/fully_connected.h +++ b/tensorflow/lite/kernels/internal/reference/fully_connected.h @@ -23,8 +23,6 @@ limitations under the License. namespace tflite { namespace reference_ops { -const int kReverseShift = -1; - inline void FullyConnected( const FullyConnectedParams& params, const RuntimeShape& input_shape, const float* input_data, const RuntimeShape& weights_shape, diff --git a/tensorflow/lite/kernels/internal/reference/integer_ops/l2normalization.h b/tensorflow/lite/kernels/internal/reference/integer_ops/l2normalization.h index 8e7c7f31760..7488a2147c4 100644 --- a/tensorflow/lite/kernels/internal/reference/integer_ops/l2normalization.h +++ b/tensorflow/lite/kernels/internal/reference/integer_ops/l2normalization.h @@ -41,8 +41,8 @@ inline void L2Normalization(int32_t input_zero_point, int32_t outer_size, } int32_t inv_l2norm_multiplier; int inv_l2norm_shift; - GetInvSqrtQuantizedMultiplierExp(acc, /*reverse_shift*/ -1, - &inv_l2norm_multiplier, &inv_l2norm_shift); + GetInvSqrtQuantizedMultiplierExp(acc, kReverseShift, &inv_l2norm_multiplier, + &inv_l2norm_shift); for (int inner_index = 0; inner_index < depth; ++inner_index) { int32_t input = diff --git a/tensorflow/lite/kernels/internal/reference/l2normalization.h b/tensorflow/lite/kernels/internal/reference/l2normalization.h new file mode 100644 index 00000000000..d93eb132fbf --- /dev/null +++ b/tensorflow/lite/kernels/internal/reference/l2normalization.h @@ -0,0 +1,88 @@ +/* Copyright 2020 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_L2NORMALIZATION_H_ +#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_L2NORMALIZATION_H_ + +#include + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/types.h" + +namespace tflite { + +namespace reference_ops { + +inline void L2Normalization(const tflite::L2NormalizationParams& op_params, + const RuntimeShape& input_shape, + const float* input_data, + const RuntimeShape& output_shape, + float* output_data, float epsilon = 1e-6) { + const int trailing_dim = input_shape.DimensionsCount() - 1; + const int outer_size = + MatchingFlatSizeSkipDim(input_shape, trailing_dim, output_shape); + const int depth = + MatchingDim(input_shape, trailing_dim, output_shape, trailing_dim); + for (int i = 0; i < outer_size; ++i) { + float squared_l2_norm = 0; + for (int c = 0; c < depth; ++c) { + const float val = input_data[depth * i + c]; + squared_l2_norm += val * val; + } + float l2_norm = std::sqrt(squared_l2_norm); + l2_norm = std::max(l2_norm, epsilon); + for (int c = 0; c < depth; ++c) { + output_data[depth * i + c] = input_data[depth * i + c] / l2_norm; + } + } +} + +inline void L2Normalization(const tflite::L2NormalizationParams& op_params, + const RuntimeShape& input_shape, + const uint8* input_data, + const RuntimeShape& output_shape, + uint8* output_data) { + const int trailing_dim = input_shape.DimensionsCount() - 1; + const int depth = + MatchingDim(input_shape, trailing_dim, output_shape, trailing_dim); + const int outer_size = + MatchingFlatSizeSkipDim(input_shape, trailing_dim, output_shape); + const int32 input_zero_point = op_params.input_zero_point; + + for (int i = 0; i < outer_size; ++i) { + int32 square_l2_norm = 0; + for (int c = 0; c < depth; c++) { + int32 diff = input_data[depth * i + c] - input_zero_point; + square_l2_norm += diff * diff; + } + int32 inv_l2norm_multiplier; + int inv_l2norm_shift; + GetInvSqrtQuantizedMultiplierExp(square_l2_norm, kReverseShift, + &inv_l2norm_multiplier, &inv_l2norm_shift); + for (int c = 0; c < depth; c++) { + int32 diff = input_data[depth * i + c] - input_zero_point; + int32 rescaled_diff = MultiplyByQuantizedMultiplierSmallerThanOneExp( + 128 * diff, inv_l2norm_multiplier, inv_l2norm_shift); + int32 unclamped_output_val = 128 + rescaled_diff; + int32 output_val = std::min(255, std::max(0, unclamped_output_val)); + output_data[depth * i + c] = static_cast(output_val); + } + } +} + + +} // namespace reference_ops +} // namespace tflite +#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_L2NORMALIZATION_H_ diff --git a/tensorflow/lite/kernels/internal/reference/reference_ops.h b/tensorflow/lite/kernels/internal/reference/reference_ops.h index 76064b4aca4..e991d4e758c 100644 --- a/tensorflow/lite/kernels/internal/reference/reference_ops.h +++ b/tensorflow/lite/kernels/internal/reference/reference_ops.h @@ -42,6 +42,7 @@ limitations under the License. #include "tensorflow/lite/kernels/internal/reference/dequantize.h" #include "tensorflow/lite/kernels/internal/reference/floor.h" #include "tensorflow/lite/kernels/internal/reference/fully_connected.h" +#include "tensorflow/lite/kernels/internal/reference/l2normalization.h" #include "tensorflow/lite/kernels/internal/reference/logistic.h" #include "tensorflow/lite/kernels/internal/reference/maximum_minimum.h" #include "tensorflow/lite/kernels/internal/reference/mul.h" @@ -294,62 +295,6 @@ inline void QuantizeLeakyRelu(const LeakyReluParams& params, } } -inline void L2Normalization(const tflite::L2NormalizationParams& op_params, - const RuntimeShape& input_shape, - const float* input_data, - const RuntimeShape& output_shape, - float* output_data, float epsilon = 1e-6) { - const int trailing_dim = input_shape.DimensionsCount() - 1; - const int outer_size = - MatchingFlatSizeSkipDim(input_shape, trailing_dim, output_shape); - const int depth = - MatchingDim(input_shape, trailing_dim, output_shape, trailing_dim); - for (int i = 0; i < outer_size; ++i) { - float squared_l2_norm = 0; - for (int c = 0; c < depth; ++c) { - const float val = input_data[depth * i + c]; - squared_l2_norm += val * val; - } - float l2_norm = std::sqrt(squared_l2_norm); - l2_norm = std::max(l2_norm, epsilon); - for (int c = 0; c < depth; ++c) { - output_data[depth * i + c] = input_data[depth * i + c] / l2_norm; - } - } -} - -inline void L2Normalization(const tflite::L2NormalizationParams& op_params, - const RuntimeShape& input_shape, - const uint8* input_data, - const RuntimeShape& output_shape, - uint8* output_data) { - const int trailing_dim = input_shape.DimensionsCount() - 1; - const int depth = - MatchingDim(input_shape, trailing_dim, output_shape, trailing_dim); - const int outer_size = - MatchingFlatSizeSkipDim(input_shape, trailing_dim, output_shape); - const int32 input_zero_point = op_params.input_zero_point; - for (int i = 0; i < outer_size; ++i) { - int32 square_l2_norm = 0; - for (int c = 0; c < depth; c++) { - int32 diff = input_data[depth * i + c] - input_zero_point; - square_l2_norm += diff * diff; - } - int32 inv_l2norm_multiplier; - int inv_l2norm_shift; - GetInvSqrtQuantizedMultiplierExp(square_l2_norm, kReverseShift, - &inv_l2norm_multiplier, &inv_l2norm_shift); - for (int c = 0; c < depth; c++) { - int32 diff = input_data[depth * i + c] - input_zero_point; - int32 rescaled_diff = MultiplyByQuantizedMultiplierSmallerThanOneExp( - 128 * diff, inv_l2norm_multiplier, inv_l2norm_shift); - int32 unclamped_output_val = 128 + rescaled_diff; - int32 output_val = std::min(255, std::max(0, unclamped_output_val)); - output_data[depth * i + c] = static_cast(output_val); - } - } -} - // T is expected to be either float or int. template inline void AddN(const RuntimeShape& input_shape, const size_t num_inputs,