From e2e3525b15bfb0d09b4e0a7e0c00d3b7f82d28eb Mon Sep 17 00:00:00 2001 From: Balyshev Artem <43214667+BalyshevArtem@users.noreply.github.com> Date: Mon, 2 Oct 2023 13:29:54 +0300 Subject: [PATCH] [onert-micro] Add float LogSoftmax kernels (#11624) This commit adds float LogSoftmax kernels for onert-micro. ONE-DCO-1.0-Signed-off-by: Artem Balyshev Co-authored-by: Artem Balyshev --- .../log_softmax/FloatLogSoftmaxKernel.h | 89 ++++++++++++ .../log_softmax/NegLogSoftmaxKernel.h | 86 ++++++++++++ .../log_softmax/TestDataLogSoftmaxBase.h | 60 ++++++++ .../pal/cmsisnn/KernelsToBuild.lst | 1 + .../pal/common/PALLogSoftmax.h | 65 +++++++++ .../pal/mcu/KernelsToBuild.lst | 1 + .../src/kernels/LogSoftmax.cpp | 89 +++++------- .../luci-interpreter/src/kernels/LogSoftmax.h | 48 ------- .../src/kernels/LogSoftmax.test.cpp | 129 +++++++----------- 9 files changed, 379 insertions(+), 189 deletions(-) create mode 100644 onert-micro/luci-interpreter/include/luci_interpreter/test_models/log_softmax/FloatLogSoftmaxKernel.h create mode 100644 onert-micro/luci-interpreter/include/luci_interpreter/test_models/log_softmax/NegLogSoftmaxKernel.h create mode 100644 onert-micro/luci-interpreter/include/luci_interpreter/test_models/log_softmax/TestDataLogSoftmaxBase.h create mode 100644 onert-micro/luci-interpreter/pal/common/PALLogSoftmax.h delete mode 100644 onert-micro/luci-interpreter/src/kernels/LogSoftmax.h diff --git a/onert-micro/luci-interpreter/include/luci_interpreter/test_models/log_softmax/FloatLogSoftmaxKernel.h b/onert-micro/luci-interpreter/include/luci_interpreter/test_models/log_softmax/FloatLogSoftmaxKernel.h new file mode 100644 index 00000000000..cecf620fd50 --- /dev/null +++ b/onert-micro/luci-interpreter/include/luci_interpreter/test_models/log_softmax/FloatLogSoftmaxKernel.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2023 Samsung Electronics Co., Ltd. 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 LUCI_INTERPRETER_TEST_MODELS_FLOAT_LOG_SOFTMAX_KERNEL_H +#define LUCI_INTERPRETER_TEST_MODELS_FLOAT_LOG_SOFTMAX_KERNEL_H + +#include "TestDataLogSoftmaxBase.h" + +namespace luci_interpreter +{ +namespace test_kernel +{ +namespace log_softmax_float +{ +/* + * LogSoftmax Kernel: + * + * Input(1, 3, 3, 2) + * | + * LogSoftmax + * | + * Output(1, 3, 3, 2) + */ +const unsigned char test_kernel_model_circle[] = { + 0x18, 0x00, 0x00, 0x00, 0x43, 0x49, 0x52, 0x30, 0x00, 0x00, 0x0e, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x28, 0x00, 0x00, 0x00, 0x24, 0x01, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x8c, 0xff, 0xff, 0xff, + 0x90, 0xff, 0xff, 0xff, 0x94, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, + 0x60, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x08, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x24, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0xd4, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x6f, 0x66, 0x6d, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x69, 0x66, 0x6d, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x0c, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x11, 0x00, 0x00, 0x00, 0x4f, 0x4e, 0x45, 0x2d, + 0x74, 0x66, 0x6c, 0x69, 0x74, 0x65, 0x32, 0x63, 0x69, 0x72, 0x63, 0x6c, 0x65, 0x00, 0x00, 0x00}; + +const std::vector input_data = { + -98.99295, 67.388435, 48.43881, -61.26518, 35.86871, 22.69142, -61.265385, -87.11669, -20.316734, + 50.533947, -93.46988, 75.58928, -36.26448, 96.57878, 63.916878, -87.25623, 30.606735, 65.762665}; +const std::vector reference_output_data = { + -166.38138, 0.0, 0.0, -109.70399, -1.9073468e-06, -13.177292, + 0.0, -25.851307, -70.85068, 0.0, -169.05916, 0.0, + -132.84326, 0.0, 0.0, -151.17311, -35.15593, 0.0}; + +} // namespace log_softmax_float + +class TestDataFloatLogSoftmax : public TestDataLogSoftmaxBase +{ +public: + TestDataFloatLogSoftmax() + { + _input_data = log_softmax_float::input_data; + _reference_output_data = log_softmax_float::reference_output_data; + _test_kernel_model_circle = log_softmax_float::test_kernel_model_circle; + } + + ~TestDataFloatLogSoftmax() override = default; +}; + +} // namespace test_kernel +} // namespace luci_interpreter + +#endif // LUCI_INTERPRETER_TEST_MODELS_FLOAT_LOG_SOFTMAX_KERNEL_H diff --git a/onert-micro/luci-interpreter/include/luci_interpreter/test_models/log_softmax/NegLogSoftmaxKernel.h b/onert-micro/luci-interpreter/include/luci_interpreter/test_models/log_softmax/NegLogSoftmaxKernel.h new file mode 100644 index 00000000000..b15be46ed8b --- /dev/null +++ b/onert-micro/luci-interpreter/include/luci_interpreter/test_models/log_softmax/NegLogSoftmaxKernel.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2023 Samsung Electronics Co., Ltd. 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 LUCI_INTERPRETER_TEST_MODELS_NEG_LOG_SOFTMAX_KERNEL_H +#define LUCI_INTERPRETER_TEST_MODELS_NEG_LOG_SOFTMAX_KERNEL_H + +#include "luci_interpreter/test_models/TestDataBase.h" + +namespace luci_interpreter +{ +namespace test_kernel +{ +namespace neg_input_output_type_mismatch_log_softmax_kernel +{ +/* + * LogSoftmax Kernel with input output type mismatch: + * + * Input(1, 3, 3, 2) - Float32 + * | + * LogSoftmax + * | + * Output(1, 3, 3, 2) - Int32 + */ +const unsigned char test_kernel_model_circle[] = { + 0x18, 0x00, 0x00, 0x00, 0x43, 0x49, 0x52, 0x30, 0x00, 0x00, 0x0e, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x28, 0x00, 0x00, 0x00, 0x34, 0x01, 0x00, 0x00, 0x50, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x8c, 0xff, 0xff, 0xff, + 0x90, 0xff, 0xff, 0xff, 0x94, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, + 0x60, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x08, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x24, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x6f, 0x66, 0x6d, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x69, 0x66, 0x6d, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x0c, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x11, 0x00, 0x00, 0x00, 0x4f, 0x4e, 0x45, 0x2d, + 0x74, 0x66, 0x6c, 0x69, 0x74, 0x65, 0x32, 0x63, 0x69, 0x72, 0x63, 0x6c, 0x65, 0x00, 0x00, 0x00}; + +} // namespace neg_input_output_type_mismatch_log_softmax_kernel + +class NegTestDataInputOutputTypeMismatchLogSoftmaxKernel : public NegTestDataBase +{ +public: + NegTestDataInputOutputTypeMismatchLogSoftmaxKernel() + { + _test_kernel_model_circle = + neg_input_output_type_mismatch_log_softmax_kernel::test_kernel_model_circle; + } + + ~NegTestDataInputOutputTypeMismatchLogSoftmaxKernel() override = default; + + const unsigned char *get_model_ptr() override final { return _test_kernel_model_circle; } + +protected: + const unsigned char *_test_kernel_model_circle; +}; + +} // namespace test_kernel +} // namespace luci_interpreter + +#endif // LUCI_INTERPRETER_TEST_MODELS_NEG_LOG_SOFTMAX_KERNEL_H diff --git a/onert-micro/luci-interpreter/include/luci_interpreter/test_models/log_softmax/TestDataLogSoftmaxBase.h b/onert-micro/luci-interpreter/include/luci_interpreter/test_models/log_softmax/TestDataLogSoftmaxBase.h new file mode 100644 index 00000000000..07236cc5aed --- /dev/null +++ b/onert-micro/luci-interpreter/include/luci_interpreter/test_models/log_softmax/TestDataLogSoftmaxBase.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2023 Samsung Electronics Co., Ltd. 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 LUCI_INTERPRETER_TEST_MODELS_LOG_SOFTMAX_KERNEL_BASE_H +#define LUCI_INTERPRETER_TEST_MODELS_LOG_SOFTMAX_KERNEL_BASE_H + +#include "luci_interpreter/test_models/TestDataBase.h" + +namespace luci_interpreter +{ +namespace test_kernel +{ + +template class TestDataLogSoftmaxBase : public TestDataBase +{ +public: + TestDataLogSoftmaxBase() = default; + + const unsigned char *get_model_ptr() override final { return _test_kernel_model_circle; } + + const std::vector &get_input_data_by_index(int i) override final + { + switch (i) + { + case 0: + return _input_data; + default: + assert(false && "Wrong input index"); + } + } + + const std::vector &get_output_data_by_index(int i) override final + { + assert(i == 0); + return _reference_output_data; + } + +protected: + std::vector _input_data; + std::vector _reference_output_data; + const unsigned char *_test_kernel_model_circle; +}; + +} // namespace test_kernel +} // namespace luci_interpreter + +#endif // LUCI_INTERPRETER_TEST_MODELS_LOG_SOFTMAX_KERNEL_BASE_H diff --git a/onert-micro/luci-interpreter/pal/cmsisnn/KernelsToBuild.lst b/onert-micro/luci-interpreter/pal/cmsisnn/KernelsToBuild.lst index 0dbefa135cd..f9322ce6961 100644 --- a/onert-micro/luci-interpreter/pal/cmsisnn/KernelsToBuild.lst +++ b/onert-micro/luci-interpreter/pal/cmsisnn/KernelsToBuild.lst @@ -33,6 +33,7 @@ REGISTER_KERNEL(LESS_EQUAL, LessEqual) REGISTER_KERNEL(LOGICAL_AND, LogicalAnd) REGISTER_KERNEL(LOGICAL_OR, LogicalOr) REGISTER_KERNEL(LEAKY_RELU, LeakyRelu) +REGISTER_KERNEL(LOG_SOFTMAX, LogSoftmax) REGISTER_KERNEL(MUL, Mul) REGISTER_KERNEL(MAX_POOL_2D, MaxPool2D) REGISTER_KERNEL(CONCATENATION, Concatenation) diff --git a/onert-micro/luci-interpreter/pal/common/PALLogSoftmax.h b/onert-micro/luci-interpreter/pal/common/PALLogSoftmax.h new file mode 100644 index 00000000000..13bb0e5d000 --- /dev/null +++ b/onert-micro/luci-interpreter/pal/common/PALLogSoftmax.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2023 Samsung Electronics Co., Ltd. All Rights Reserved + * Copyright 2021 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 LUCI_INTERPRETER_PAL_LOG_SOFTMAX_COMMON_H +#define LUCI_INTERPRETER_PAL_LOG_SOFTMAX_COMMON_H + +#include "PALUtils.h" + +#include + +namespace luci_interpreter_pal +{ + +inline void LogSoftmax(const luci_interpreter::RuntimeShape &input_shape, const float *input_data, + const luci_interpreter::RuntimeShape &output_shape, float *output_data) +{ + const int trailing_dim = input_shape.dimensionsCount() - 1; + const int outer_size = + flatSizeSkipDim(input_shape.dimsData(), trailing_dim, input_shape.dimensionsCount()); + const int depth = MatchingDim(input_shape, trailing_dim, output_shape, trailing_dim); + + for (int i = 0; i < outer_size; ++i) + { + // Find max element value which we'll use to ensure numerical stability + // taking advantage of the following equality: + // log(exp(x[i])/sum(exp(x[i]))) == log(exp(x[i]+C)/sum(exp(x[i]+C))) + float max = std::numeric_limits::lowest(); + for (int c = 0; c < depth; ++c) + { + max = std::max(max, input_data[i * depth + c]); + } + + // Compute sum. + float sum = 0.f; + for (int c = 0; c < depth; ++c) + { + sum += std::exp(input_data[i * depth + c] - max); + } + + // Compute result. + const float log_sum = std::log(sum); + for (int c = 0; c < depth; ++c) + { + output_data[i * depth + c] = input_data[i * depth + c] - max - log_sum; + } + } +} + +} // namespace luci_interpreter_pal + +#endif // LUCI_INTERPRETER_PAL_LOG_SOFTMAX_COMMON_H diff --git a/onert-micro/luci-interpreter/pal/mcu/KernelsToBuild.lst b/onert-micro/luci-interpreter/pal/mcu/KernelsToBuild.lst index 18553b604e9..34b5f0f38e4 100644 --- a/onert-micro/luci-interpreter/pal/mcu/KernelsToBuild.lst +++ b/onert-micro/luci-interpreter/pal/mcu/KernelsToBuild.lst @@ -38,6 +38,7 @@ REGISTER_KERNEL(LESS_EQUAL, LessEqual) REGISTER_KERNEL(LOGICAL_AND, LogicalAnd) REGISTER_KERNEL(LOGICAL_OR, LogicalOr) REGISTER_KERNEL(LEAKY_RELU, LeakyRelu) +REGISTER_KERNEL(LOG_SOFTMAX, LogSoftmax) REGISTER_KERNEL(MUL, Mul) REGISTER_KERNEL(MAX_POOL_2D, MaxPool2D) REGISTER_KERNEL(MINIMUM, Minimum) diff --git a/onert-micro/luci-interpreter/src/kernels/LogSoftmax.cpp b/onert-micro/luci-interpreter/src/kernels/LogSoftmax.cpp index b467cb06b50..39f122637b9 100644 --- a/onert-micro/luci-interpreter/src/kernels/LogSoftmax.cpp +++ b/onert-micro/luci-interpreter/src/kernels/LogSoftmax.cpp @@ -14,80 +14,53 @@ * limitations under the License. */ -#include "kernels/LogSoftmax.h" - +#include "Builders.h" #include "kernels/Utils.h" - -#include +#include "SISOKernel.h" #include "PALLogSoftmax.h" namespace luci_interpreter { -namespace kernels -{ -LogSoftmax::LogSoftmax(const Tensor *input, Tensor *output) : Kernel({input}, {output}) {} - -void LogSoftmax::configure() +void configure_kernel_CircleLogSoftmax(const circle::Operator *cur_op, + BaseRuntimeGraph *runtime_graph) { - LUCI_INTERPRETER_CHECK(input()->element_type() == output()->element_type()); - if (input()->element_type() == DataType::U8) - { - LUCI_INTERPRETER_CHECK(output()->scale() == 16. / 256); - LUCI_INTERPRETER_CHECK(output()->zero_point() == 255); + kernels::SISOKernel kernel(cur_op, runtime_graph); - tflite::SoftmaxParams params{}; - - params.table = _table; - params.beta = 1.0; - luci_interpreter_pal::PopulateSoftmaxLookupTable(¶ms, input()->scale(), params.beta); - } - // TODO: enable it only if kernel with dynamic shapes - output()->resize(input()->shape()); + LUCI_INTERPRETER_CHECK(Tensor::element_type(kernel.input()) == + Tensor::element_type(kernel.output())); + LUCI_INTERPRETER_CHECK(Tensor::num_elements(kernel.input()) == + Tensor::num_elements(kernel.output())); + LUCI_INTERPRETER_CHECK(Tensor::num_dims(kernel.input()) == Tensor::num_dims(kernel.output())); } -void LogSoftmax::execute() const +void execute_kernel_CircleLogSoftmax(const circle::Operator *cur_op, + BaseRuntimeGraph *runtime_graph) { - switch (input()->element_type()) + kernels::SISOKernel kernel(cur_op, runtime_graph); + + const auto *input_data = runtime_graph->getDataByTensor(kernel.input()); + assert(input_data); + auto *output_data = runtime_graph->getDataByTensor(kernel.output()); + + switch (Tensor::element_type(kernel.input())) { +#ifndef DIS_FLOAT case DataType::FLOAT32: - evalFloat(); - break; - case DataType::U8: - evalQuantized(); + { + const float *input_data_float = kernels::getTensorData(input_data); + float *output_data_float = kernels::getTensorData(output_data); + assert(output_data_float); + + luci_interpreter_pal::LogSoftmax( + kernels::getTensorRuntimeShape(kernel.input(), runtime_graph), input_data_float, + kernels::getTensorRuntimeShape(kernel.output(), runtime_graph), output_data_float); break; + } +#endif // DIS_FLOAT default: - assert(false && "Unsupported type."); + assert(false && "Unsupported type"); } } - -void LogSoftmax::evalFloat() const -{ - tflite::SoftmaxParams params{}; - tflite::reference_ops::LogSoftmax(params, getTensorShape(input()), getTensorData(input()), - getTensorShape(output()), getTensorData(output())); -} - -void LogSoftmax::evalQuantized() const -{ - const auto input_shape = getTensorShape(input()); - const auto output_shape = getTensorShape(output()); - const auto input_scale = input()->scale(); - uint8_t *output_data = getTensorData(output()); - const uint8_t *input_data = getTensorData(input()); - const float beta = 1.0; - - tflite::SoftmaxParams params{}; - - params.table = const_cast(_table); - params.zero_point = output()->zero_point(); - params.scale = output()->scale(); - - luci_interpreter_pal::InitializeParams(¶ms, input_scale, beta); - luci_interpreter_pal::LogSoftmax(params, input_scale, input_shape, input_data, output_shape, - output_data); -} - -} // namespace kernels } // namespace luci_interpreter diff --git a/onert-micro/luci-interpreter/src/kernels/LogSoftmax.h b/onert-micro/luci-interpreter/src/kernels/LogSoftmax.h deleted file mode 100644 index 18477fbe327..00000000000 --- a/onert-micro/luci-interpreter/src/kernels/LogSoftmax.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. 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 LUCI_INTERPRETER_KERNELS_LOGSOFTMAX_H -#define LUCI_INTERPRETER_KERNELS_LOGSOFTMAX_H - -#include "core/Kernel.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class LogSoftmax : public Kernel -{ -public: - LogSoftmax(const Tensor *input, Tensor *output); - - const Tensor *input() const { return _inputs[0]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; - -private: - void evalFloat() const; - void evalQuantized() const; - - float _table[256]; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_LOGSOFTMAX_H diff --git a/onert-micro/luci-interpreter/src/kernels/LogSoftmax.test.cpp b/onert-micro/luci-interpreter/src/kernels/LogSoftmax.test.cpp index 50dcd5c28e6..423b603e511 100644 --- a/onert-micro/luci-interpreter/src/kernels/LogSoftmax.test.cpp +++ b/onert-micro/luci-interpreter/src/kernels/LogSoftmax.test.cpp @@ -1,6 +1,5 @@ /* * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2017 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. @@ -15,14 +14,14 @@ * limitations under the License. */ -#include "kernels/LogSoftmax.h" #include "kernels/TestUtils.h" -#include "luci_interpreter/TestMemoryManager.h" +#include "luci_interpreter/test_models/log_softmax/FloatLogSoftmaxKernel.h" +#include "luci_interpreter/test_models/log_softmax/NegLogSoftmaxKernel.h" + +#include "loader/ModuleLoader.h" namespace luci_interpreter { -namespace kernels -{ namespace { @@ -30,95 +29,59 @@ using namespace testing; class LogSoftmaxTest : public ::testing::Test { -protected: - void SetUp() override { _memory_manager = std::make_unique(); } - - std::unique_ptr _memory_manager; + // Do nothing }; -TEST_F(LogSoftmaxTest, Float) +template +std::vector checkLogSoftmaxKernel(test_kernel::TestDataBase *test_data_base) { - Shape input_shape{2, 4}; - std::vector input_data{ - 0, -6, 2, 4, // - 3, -2, 10, 1, // - }; - Tensor input_tensor = - makeInputTensor(input_shape, input_data, _memory_manager.get()); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - LogSoftmax kernel(&input_tensor, &output_tensor); - kernel.configure(); - _memory_manager->allocate_memory(output_tensor); - kernel.execute(); - - std::vector ref_output_data{ - -4.14297, -10.14297, -2.14297, -.142971, // - -7.00104, -12.00104, -.00104087, -9.00104, // - }; - EXPECT_THAT(extractTensorData(output_tensor), FloatArrayNear(ref_output_data)); -} + MemoryManager memory_manager{}; + RuntimeModule runtime_module{}; + bool dealloc_input = true; -TEST_F(LogSoftmaxTest, Uint8) -{ - float kMin = -10; - float kMax = 10; - float kLogSoftmaxQuantizedTolerance = 16. / 256; - std::pair quant_param = quantizationParams(kMin, kMax); - std::vector input_data{ - 0, -6, 2, 4, // - 3, -2, 10, 1, // - }; - Tensor input_tensor = makeInputTensor({2, 4}, quant_param.first, quant_param.second, - input_data, _memory_manager.get()); - Tensor output_tensor = makeOutputTensor(DataType::U8, 16. / 256, 255); - - LogSoftmax kernel(&input_tensor, &output_tensor); - kernel.configure(); - _memory_manager->allocate_memory(output_tensor); - kernel.execute(); - - std::vector ref_output_data{ - -4.14297, -10.14297, -2.14297, -.142971, // - -7.00104, -12.00104, -.00104087, -9.00104, // - }; - std::vector ref_output_shape{2, 4}; - EXPECT_THAT(dequantizeTensorData(output_tensor), - FloatArrayNear(ref_output_data, kLogSoftmaxQuantizedTolerance)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape)); - EXPECT_THAT(extractTensorData(output_tensor), - ::testing::ElementsAreArray({189, 93, 221, 253, 142, 63, 255, 111})); + // Load model with single op + auto *model_data_raw = reinterpret_cast(test_data_base->get_model_ptr()); + ModuleLoader::load(&runtime_module, &memory_manager, model_data_raw, dealloc_input); + + auto *main_runtime_graph = runtime_module.getMainGraph(); + assert(main_runtime_graph->getNumOfInputTensors() == 1); + + // Set input data + { + auto *input_tensor_data = reinterpret_cast(main_runtime_graph->configureGraphInput(0)); + std::copy(test_data_base->get_input_data_by_index(0).begin(), + test_data_base->get_input_data_by_index(0).end(), input_tensor_data); + } + + runtime_module.execute(); + + assert(main_runtime_graph->getNumOfOutputTensors() == 1); + + T *output_data = reinterpret_cast(main_runtime_graph->getOutputDataByIndex(0)); + const size_t num_elements = (main_runtime_graph->getOutputDataSizeByIndex(0) / sizeof(T)); + std::vector output_data_vector(output_data, output_data + num_elements); + return output_data_vector; } -TEST_F(LogSoftmaxTest, InvalidInputOutputType_NEG) +TEST_F(LogSoftmaxTest, Float_P) { - std::vector input_data{ - 0, -6, 2, 4, // - 3, -2, 10, 1, // - }; - Tensor input_tensor = - makeInputTensor({2, 4}, input_data, _memory_manager.get()); - Tensor output_tensor = makeOutputTensor(DataType::U8, 16. / 256, 255); - - LogSoftmax kernel(&input_tensor, &output_tensor); - EXPECT_ANY_THROW(kernel.configure()); + test_kernel::TestDataFloatLogSoftmax test_data_kernel; + std::vector output_data_vector = checkLogSoftmaxKernel(&test_data_kernel); + EXPECT_THAT(output_data_vector, test_data_kernel.get_output_data_by_index(0)); } -TEST_F(LogSoftmaxTest, InvalidOutputQuantParam_NEG) +TEST_F(LogSoftmaxTest, Input_output_type_mismatch_NEG) { - std::pair quant_param = quantizationParams(-10, 10); - std::vector input_data{ - 0, -6, 2, 4, // - 3, -2, 10, 1, // - }; - Tensor input_tensor = makeInputTensor({2, 4}, quant_param.first, quant_param.second, - input_data, _memory_manager.get()); - Tensor output_tensor = makeOutputTensor(DataType::U8, 20. / 256, 255); - - LogSoftmax kernel(&input_tensor, &output_tensor); - EXPECT_ANY_THROW(kernel.configure()); + test_kernel::NegTestDataInputOutputTypeMismatchLogSoftmaxKernel test_data_kernel; + + MemoryManager memory_manager{}; + RuntimeModule runtime_module{}; + bool dealloc_input = true; + // Load model with single op + auto *model_data_raw = reinterpret_cast(test_data_kernel.get_model_ptr()); + EXPECT_DEATH(ModuleLoader::load(&runtime_module, &memory_manager, model_data_raw, dealloc_input), + ""); } } // namespace -} // namespace kernels } // namespace luci_interpreter