diff options
author | Sergei Barannikov <s.barannikov@samsung.com> | 2020-10-14 11:39:47 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-10-14 11:39:47 +0300 |
commit | 37a313805fd72f471f2d0d78b1aee59c22388858 (patch) | |
tree | eba85b380382056b67475b99cac995f6fb9f41cb | |
parent | 9c34e2d57f44697615f6df50f6f54fd83241fad3 (diff) | |
download | nnfw-37a313805fd72f471f2d0d78b1aee59c22388858.tar.gz nnfw-37a313805fd72f471f2d0d78b1aee59c22388858.tar.bz2 nnfw-37a313805fd72f471f2d0d78b1aee59c22388858.zip |
[luci-interpreter] Support S16 Prelu op (#4570)
Add support for S16 `Prelu` operator.
Signed-off-by: Sergei Barannikov <s.barannikov@samsung.com>
-rw-r--r-- | compiler/luci-interpreter/src/kernels/Prelu.cpp | 33 | ||||
-rw-r--r-- | compiler/luci-interpreter/src/kernels/Prelu.h | 1 | ||||
-rw-r--r-- | compiler/luci-interpreter/src/kernels/Prelu.test.cpp | 46 |
3 files changed, 79 insertions, 1 deletions
diff --git a/compiler/luci-interpreter/src/kernels/Prelu.cpp b/compiler/luci-interpreter/src/kernels/Prelu.cpp index 01655e721..e658d87b5 100644 --- a/compiler/luci-interpreter/src/kernels/Prelu.cpp +++ b/compiler/luci-interpreter/src/kernels/Prelu.cpp @@ -15,6 +15,8 @@ */ #include "kernels/Prelu.h" + +#include "kernels/BinaryOpCommon.h" #include "kernels/Utils.h" #include <tensorflow/lite/kernels/internal/reference/reference_ops.h> @@ -37,8 +39,13 @@ void Prelu::configure() LUCI_INTERPRETER_CHECK(input()->element_type() == output()->element_type()); LUCI_INTERPRETER_CHECK(alpha()->element_type() == output()->element_type()); - if (input()->element_type() == DataType::U8) + if (input()->element_type() == DataType::U8 || input()->element_type() == DataType::S16) { + if (input()->element_type() == DataType::S16) + { + LUCI_INTERPRETER_CHECK(input()->zero_point() == 0 && alpha()->zero_point() == 0 && + output()->zero_point() == 0); + } double alpha_multiplier = input()->scale() * alpha()->scale() / output()->scale(); quantizeMultiplier(alpha_multiplier, &_output_multiplier_alpha, &_output_shift_alpha); double identity_multiplier = input()->scale() / output()->scale(); @@ -57,6 +64,9 @@ void Prelu::execute() const case DataType::U8: evalQuantized(); break; + case DataType::S16: + evalQuantizedS16(); + break; default: throw std::runtime_error("Unsupported type."); } @@ -118,5 +128,26 @@ void Prelu::evalQuantized() const } } +void Prelu::evalQuantizedS16() const +{ + constexpr int32_t quantized_min = std::numeric_limits<int16_t>::min(); + constexpr int32_t quantized_max = std::numeric_limits<int16_t>::max(); + + auto fn = [this, quantized_min, quantized_max](int16_t input_val, int16_t alpha_val) { + const int32_t output_val = + input_val >= 0 + ? tflite::MultiplyByQuantizedMultiplier(input_val, _output_multiplier_identity, + _output_shift_identity) + : tflite::MultiplyByQuantizedMultiplier(input_val * alpha_val, _output_multiplier_alpha, + _output_shift_alpha); + const int32_t clamped_output = std::min(quantized_max, std::max(quantized_min, output_val)); + return static_cast<int16_t>(clamped_output); + }; + + BinaryOpBroadcastSlow(getTensorShape(input()), getTensorData<int16_t>(input()), + getTensorShape(alpha()), getTensorData<int16_t>(alpha()), + getTensorShape(output()), getTensorData<int16_t>(output()), fn); +} + } // namespace kernels } // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/Prelu.h b/compiler/luci-interpreter/src/kernels/Prelu.h index 25c27a315..c7911a63f 100644 --- a/compiler/luci-interpreter/src/kernels/Prelu.h +++ b/compiler/luci-interpreter/src/kernels/Prelu.h @@ -39,6 +39,7 @@ public: private: void evalFloat() const; void evalQuantized() const; + void evalQuantizedS16() const; private: int32_t _output_multiplier_alpha = 0; diff --git a/compiler/luci-interpreter/src/kernels/Prelu.test.cpp b/compiler/luci-interpreter/src/kernels/Prelu.test.cpp index 1e67caf1a..30702c826 100644 --- a/compiler/luci-interpreter/src/kernels/Prelu.test.cpp +++ b/compiler/luci-interpreter/src/kernels/Prelu.test.cpp @@ -164,6 +164,52 @@ TEST(PreluTest, Uint8Broadcast) ::testing::ElementsAreArray(ref_quant_output_data)); } +TEST(PreluTest, SInt16Simple) +{ + std::vector<float> input_data{-0.8f, 0.2f, 0.9f, 0.7f, 0.1f, -0.4f}; + std::vector<float> alpha_data{0.5f, 0.5f, 0.5f, 0.25f, 1.0f, 0.25f}; + std::vector<float> ref_output_data{-0.4f, 0.2f, 0.9f, 0.7f, 0.1f, -0.1f}; + + Tensor input_tensor = makeInputTensor<DataType::S16>({1, 2, 3, 1}, 0.1, 0, input_data); + Tensor alpha_tensor = makeInputTensor<DataType::S16>({1, 2, 3, 1}, 0.1, 0, alpha_data); + Tensor output_tensor = makeOutputTensor(DataType::S16, 0.1, 0); + + Prelu kernel(&input_tensor, &alpha_tensor, &output_tensor); + kernel.configure(); + kernel.execute(); + + EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({1, 2, 3, 1})); + EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data)); +} + +TEST(PreluTest, SInt16Broadcast) +{ + std::vector<float> input_data{ + 0.0f, 0.0f, 0.0f, // Row 1, Column 1 + 0.5f, 0.5f, 0.5f, // Row 1, Column 2 + -1.0f, -1.0f, -1.0f, // Row 2, Column 1 + -0.25f, -0.25f, -0.25f, // Row 2, Column 2 + }; + std::vector<float> alpha_data{0.0f, 0.5f, -0.5f}; + std::vector<float> ref_output_data{ + 0.0f, 0.0f, 0.0f, // Row 1, Column 1 + 0.5f, 0.5f, 0.5f, // Row 1, Column 2 + 0.0f, -0.5f, 0.5f, // Row 2, Column 1 + 0.0f, -0.125f, 0.125f // Row 2, Column 2 + }; + + Tensor input_tensor = makeInputTensor<DataType::S16>({1, 2, 2, 3}, 0.01, 0, input_data); + Tensor alpha_tensor = makeInputTensor<DataType::S16>({1, 1, 3}, 0.1, 0, alpha_data); + Tensor output_tensor = makeOutputTensor(DataType::S16, 0.001, 0); + + Prelu kernel(&input_tensor, &alpha_tensor, &output_tensor); + kernel.configure(); + kernel.execute(); + + EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({1, 2, 2, 3})); + EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data)); +} + TEST(PreluTest, Input_Output_Type_NEG) { Tensor input_tensor = makeInputTensor<DataType::FLOAT32>({1}, {1.f}); |