summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergei Barannikov <s.barannikov@samsung.com>2020-10-14 11:39:47 +0300
committerGitHub <noreply@github.com>2020-10-14 11:39:47 +0300
commit37a313805fd72f471f2d0d78b1aee59c22388858 (patch)
treeeba85b380382056b67475b99cac995f6fb9f41cb
parent9c34e2d57f44697615f6df50f6f54fd83241fad3 (diff)
downloadnnfw-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.cpp33
-rw-r--r--compiler/luci-interpreter/src/kernels/Prelu.h1
-rw-r--r--compiler/luci-interpreter/src/kernels/Prelu.test.cpp46
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});