From f70fab01544b2151746efe06cc63b6d743a4f1ca Mon Sep 17 00:00:00 2001 From: Balyshev Artem <43214667+BalyshevArtem@users.noreply.github.com> Date: Tue, 17 Oct 2023 13:46:02 +0300 Subject: [PATCH] [onert-micro] Add float Unpack kernel (#11715) This commit adds float Unpack kernel. ONE-DCO-1.0-Signed-off-by: Artem Balyshev Co-authored-by: Artem Balyshev --- .../test_models/unpack/FloatUnpackKernel.h | 103 ++++++++++++ .../test_models/unpack/NegUnpackKernel.h | 90 +++++++++++ .../test_models/unpack/TestDataUnpackBase.h | 68 ++++++++ .../pal/mcu/KernelsToBuild.lst | 1 + .../luci-interpreter/src/kernels/Unpack.cpp | 139 +++++++++++----- .../luci-interpreter/src/kernels/Unpack.h | 46 ------ .../src/kernels/Unpack.test.cpp | 150 ++++++------------ 7 files changed, 413 insertions(+), 184 deletions(-) create mode 100644 onert-micro/luci-interpreter/include/luci_interpreter/test_models/unpack/FloatUnpackKernel.h create mode 100644 onert-micro/luci-interpreter/include/luci_interpreter/test_models/unpack/NegUnpackKernel.h create mode 100644 onert-micro/luci-interpreter/include/luci_interpreter/test_models/unpack/TestDataUnpackBase.h delete mode 100644 onert-micro/luci-interpreter/src/kernels/Unpack.h diff --git a/onert-micro/luci-interpreter/include/luci_interpreter/test_models/unpack/FloatUnpackKernel.h b/onert-micro/luci-interpreter/include/luci_interpreter/test_models/unpack/FloatUnpackKernel.h new file mode 100644 index 00000000000..9098a952d9d --- /dev/null +++ b/onert-micro/luci-interpreter/include/luci_interpreter/test_models/unpack/FloatUnpackKernel.h @@ -0,0 +1,103 @@ +/* + * 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_UNPACK_KERNEL_H +#define LUCI_INTERPRETER_TEST_MODELS_FLOAT_UNPACK_KERNEL_H + +#include "TestDataUnpackBase.h" + +namespace luci_interpreter +{ +namespace test_kernel +{ +namespace unpack_float +{ +/* + * Unpack Kernel: + * + * Input(2, 2, 3, 4) + * | + * Unpack(num=2, axis=0) + * / \ + * Output1(2, 3, 4) Output1(2, 3, 4) + */ +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, + 0x34, 0x00, 0x00, 0x00, 0x6c, 0x01, 0x00, 0x00, 0x88, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0xf4, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0x04, 0x00, 0x04, 0x00, + 0x04, 0x00, 0x00, 0x00, 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, 0x68, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x74, 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, 0x16, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x08, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, + 0x14, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0xac, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x6f, 0x66, 0x6d, 0x3a, 0x31, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0xd8, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x6f, 0x66, 0x6d, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x04, 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, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 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, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, + 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 = { + 80.8925, -4.4767537, 38.051624, 69.14668, -23.124884, -8.138234, 79.53351, 40.877926, + -12.0593405, 41.621094, 69.482895, 7.9741273, 3.7500796, -80.87057, 10.576268, -16.321995, + -12.388415, -20.782156, 47.479202, -56.73159, 81.99104, 70.61185, 32.652695, -93.72114, + -75.67862, -70.78546, -42.199966, -12.66376, 21.785488, -7.168219, -19.772392, -17.600962, + 64.1301, -4.7490916, 76.81972, -41.70657, -83.13318, 45.003937, 85.05216, -29.184652, + 40.685417, -35.482887, -60.648735, -0.268777, -0.59301615, -19.212725, 87.67197, -37.269848}; +const std::vector reference_output_data_1 = { + 80.8925, -4.4767537, 38.051624, 69.14668, -23.124884, -8.138234, 79.53351, 40.877926, + -12.0593405, 41.621094, 69.482895, 7.9741273, 3.7500796, -80.87057, 10.576268, -16.321995, + -12.388415, -20.782156, 47.479202, -56.73159, 81.99104, 70.61185, 32.652695, -93.72114}; +const std::vector reference_output_data_2 = { + -75.67862, -70.78546, -42.199966, -12.66376, 21.785488, -7.168219, -19.772392, -17.600962, + 64.1301, -4.7490916, 76.81972, -41.70657, -83.13318, 45.003937, 85.05216, -29.184652, + 40.685417, -35.482887, -60.648735, -0.268777, -0.59301615, -19.212725, 87.67197, -37.269848}; + +} // namespace unpack_float + +class TestDataFloatUnpack : public TestDataUnpackBase +{ +public: + TestDataFloatUnpack() + { + _input_data = unpack_float::input_data; + _reference_output_data_1 = unpack_float::reference_output_data_1; + _reference_output_data_2 = unpack_float::reference_output_data_2; + _test_kernel_model_circle = unpack_float::test_kernel_model_circle; + } + + ~TestDataFloatUnpack() override = default; +}; + +} // namespace test_kernel +} // namespace luci_interpreter + +#endif // LUCI_INTERPRETER_TEST_MODELS_FLOAT_UNPACK_KERNEL_H diff --git a/onert-micro/luci-interpreter/include/luci_interpreter/test_models/unpack/NegUnpackKernel.h b/onert-micro/luci-interpreter/include/luci_interpreter/test_models/unpack/NegUnpackKernel.h new file mode 100644 index 00000000000..4da828eb972 --- /dev/null +++ b/onert-micro/luci-interpreter/include/luci_interpreter/test_models/unpack/NegUnpackKernel.h @@ -0,0 +1,90 @@ +/* + * 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_UNPACK_KERNEL_H +#define LUCI_INTERPRETER_TEST_MODELS_NEG_UNPACK_KERNEL_H + +#include "TestDataUnpackBase.h" + +namespace luci_interpreter +{ +namespace test_kernel +{ +namespace neg_unpack_input_type_mismatch +{ + +/* + * Unpack Kernel with input type mismatch (input_type should be equal to output_type): + * + * Input(2, 2, 3, 4) - Int32 + * | + * Unpack(num=2, axis=0) + * / \ + * Output1(2, 3, 4)-Float32 Output1(2, 3, 4) - Float32 + */ +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, + 0x34, 0x00, 0x00, 0x00, 0x7c, 0x01, 0x00, 0x00, 0x98, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0xf4, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0x04, 0x00, 0x04, 0x00, + 0x04, 0x00, 0x00, 0x00, 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, 0x68, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x74, 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, 0x16, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x08, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, + 0x14, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0xd4, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x6f, 0x66, 0x6d, 0x3a, 0x31, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x6f, 0x66, 0x6d, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x69, 0x66, 0x6d, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 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, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, + 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_unpack_input_type_mismatch + +class NegTestDataInputMismatchUnpackKernel : public NegTestDataBase +{ +public: + NegTestDataInputMismatchUnpackKernel() + { + _test_kernel_model_circle = neg_unpack_input_type_mismatch::test_kernel_model_circle; + } + + ~NegTestDataInputMismatchUnpackKernel() 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_UNPACK_KERNEL_H diff --git a/onert-micro/luci-interpreter/include/luci_interpreter/test_models/unpack/TestDataUnpackBase.h b/onert-micro/luci-interpreter/include/luci_interpreter/test_models/unpack/TestDataUnpackBase.h new file mode 100644 index 00000000000..65ad088011c --- /dev/null +++ b/onert-micro/luci-interpreter/include/luci_interpreter/test_models/unpack/TestDataUnpackBase.h @@ -0,0 +1,68 @@ +/* + * 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_UNPACK_KERNEL_BASE_H +#define LUCI_INTERPRETER_TEST_MODELS_UNPACK_KERNEL_BASE_H + +#include "luci_interpreter/test_models/TestDataBase.h" + +namespace luci_interpreter +{ +namespace test_kernel +{ + +template class TestDataUnpackBase : public TestDataBase +{ +public: + TestDataUnpackBase() = 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 + { + switch (i) + { + case 0: + return _reference_output_data_1; + case 1: + return _reference_output_data_2; + default: + assert(false && "Wrong input index"); + } + } + +protected: + std::vector _input_data; + std::vector _reference_output_data_1; + std::vector _reference_output_data_2; + const unsigned char *_test_kernel_model_circle; +}; + +} // namespace test_kernel +} // namespace luci_interpreter + +#endif // LUCI_INTERPRETER_TEST_MODELS_UNPACK_KERNEL_BASE_H diff --git a/onert-micro/luci-interpreter/pal/mcu/KernelsToBuild.lst b/onert-micro/luci-interpreter/pal/mcu/KernelsToBuild.lst index 5db59f4cfbc..4a4d20070b9 100644 --- a/onert-micro/luci-interpreter/pal/mcu/KernelsToBuild.lst +++ b/onert-micro/luci-interpreter/pal/mcu/KernelsToBuild.lst @@ -84,3 +84,4 @@ REGISTER_KERNEL(RSQRT, Rsqrt) REGISTER_KERNEL(NEG, Neg) REGISTER_KERNEL(ZEROS_LIKE, ZerosLike) REGISTER_KERNEL(SQUEEZE, Squeeze) +REGISTER_KERNEL(UNPACK, Unpack) diff --git a/onert-micro/luci-interpreter/src/kernels/Unpack.cpp b/onert-micro/luci-interpreter/src/kernels/Unpack.cpp index 80f4d1f2804..31f08a546b3 100644 --- a/onert-micro/luci-interpreter/src/kernels/Unpack.cpp +++ b/onert-micro/luci-interpreter/src/kernels/Unpack.cpp @@ -14,70 +14,131 @@ * limitations under the License. */ -#include "kernels/Unpack.h" - +#include "Builders.h" #include "kernels/Utils.h" -#include - namespace luci_interpreter { - -namespace kernels +namespace { -Unpack::Unpack(const Tensor *input, std::vector outputs, const UnpackParams ¶ms) - : KernelWithParams({input}, std::move(outputs), params) -{ -} +constexpr int kInputTensor = 0; -void Unpack::configure() +template +void UnpackImpl(const circle::Operator *cur_op, const circle::Tensor *input, int output_count, + int axis, RuntimeGraph *runtime_graph) { - const Shape &input_shape = input()->shape(); + const auto output0_index = cur_op->outputs()->operator[](0); + assert(output0_index != -1); + + const auto output0 = runtime_graph->getCircleTensorByIndex(output0_index); + assert(output0 != nullptr); + + const auto input_dims = Tensor::tensor_shape(input); + const auto output_dims = Tensor::tensor_shape(output0); + const int dimensions = input_dims.size(); - int axis = _params.axis; if (axis < 0) - axis += input()->shape().num_dims(); - assert(axis >= 0 && axis < input_shape.num_dims()); + { + axis += input_dims.size(); + } - Shape output_shape(input_shape.num_dims() - 1); - int out_index = 0; - for (int in_index = 0; in_index < input_shape.num_dims(); ++in_index) + int outer_size = 1; + for (int i = 0; i < axis; ++i) + { + outer_size *= input_dims[i]; + } + int copy_size = 1; + for (int i = axis + 1; i < dimensions; ++i) { - if (in_index != axis) - output_shape.dim(out_index++) = input_shape.dim(in_index); + copy_size *= input_dims[i]; } + int output_size = 1; + for (int i = 0; i < output_dims.size(); ++i) + { + output_size *= output_dims[i]; + } + + const T *input_data = kernels::getTensorData(runtime_graph->getDataByTensor(input)); - // TODO: enable it only if kernel with dynamic shapes - for (Tensor *output : _outputs) + for (int i = 0; i < output_count; ++i) { - assert(output->element_type() == input()->element_type()); - output->resize(output_shape); + const auto output_index = cur_op->outputs()->operator[](i); + assert(output_index != -1); + + const auto t = runtime_graph->getCircleTensorByIndex(output_index); + assert(output0 != nullptr); + T *output_data = kernels::getTensorData(runtime_graph->getDataByTensor(t)); + for (int k = 0; k < outer_size; ++k) + { + T *output_ptr = output_data + copy_size * k; + int loc = k * output_count * copy_size + i * copy_size; + const T *input_ptr = input_data + loc; + for (int j = 0; j < copy_size; ++j) + output_ptr[j] = input_ptr[j]; + } } } +} // namespace -template void Unpack::executeImpl() const +void configure_kernel_CircleUnpack(const circle::Operator *cur_op, BaseRuntimeGraph *runtime_graph) { - tflite::UnpackParams params{}; - params.axis = _params.axis; - params.num_split = _outputs.size(); - VectorOfTensors all_outputs(_outputs); - tflite::reference_ops::Unpack(params, getTensorShape(input()), getTensorData(input()), - **all_outputs.shapes(), all_outputs.data()); + const auto input_index = cur_op->inputs()->operator[](0); + const auto output_index = cur_op->outputs()->operator[](0); + + assert(input_index != -1); + assert(output_index != -1); + + const auto input = runtime_graph->getCircleTensorByIndex(input_index); + const auto output = runtime_graph->getCircleTensorByIndex(output_index); + + assert(input != nullptr); + assert(output != nullptr); + + const auto *options = cur_op->builtin_options_as_UnpackOptions(); + + LUCI_INTERPRETER_CHECK(cur_op->outputs()->size() == options->num()); + LUCI_INTERPRETER_CHECK(Tensor::element_type(input) == Tensor::element_type(output)); + + for (int i = 0; i < Tensor::num_dims(input); ++i) + { + if (i == options->axis()) + continue; + + if (i < options->axis()) + { + LUCI_INTERPRETER_CHECK(Tensor::dim(input, i) == Tensor::dim(output, i)); + } + else + { + LUCI_INTERPRETER_CHECK(Tensor::dim(input, i) == Tensor::dim(output, i - 1)); + } + } } -void Unpack::execute() const +void execute_kernel_CircleUnpack(const circle::Operator *cur_op, BaseRuntimeGraph *runtime_graph) { - switch (input()->element_type()) + const auto input_index = cur_op->inputs()->operator[](0); + assert(input_index != -1); + + const auto input = runtime_graph->getCircleTensorByIndex(input_index); + assert(input != nullptr); + + const auto type = Tensor::element_type(input); + + const auto *options = cur_op->builtin_options_as_UnpackOptions(); + + switch (type) { +#ifndef DIS_FLOAT case DataType::FLOAT32: - return executeImpl(); - case DataType::U8: - return executeImpl(); + { + UnpackImpl(cur_op, input, options->num(), options->axis(), runtime_graph); + break; + } +#endif // DIS_FLOAT default: - assert(false && "Unsupported type."); + assert(false && "Unsupported type"); } } - -} // namespace kernels } // namespace luci_interpreter diff --git a/onert-micro/luci-interpreter/src/kernels/Unpack.h b/onert-micro/luci-interpreter/src/kernels/Unpack.h deleted file mode 100644 index f4a44ecad0b..00000000000 --- a/onert-micro/luci-interpreter/src/kernels/Unpack.h +++ /dev/null @@ -1,46 +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_UNPACK_H -#define LUCI_INTERPRETER_KERNELS_UNPACK_H - -#include "core/Kernel.h" -#include "core/KernelParams.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class Unpack : public KernelWithParams -{ -public: - Unpack(const Tensor *input, std::vector outputs, const UnpackParams ¶ms); - - const Tensor *input() const { return _inputs[0]; } - Tensor *output(int index) const { return _outputs[index]; } - - void configure() override; - void execute() const override; - -private: - template void executeImpl() const; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_UNPACK_H diff --git a/onert-micro/luci-interpreter/src/kernels/Unpack.test.cpp b/onert-micro/luci-interpreter/src/kernels/Unpack.test.cpp index 9384ddc83a1..738051b2410 100644 --- a/onert-micro/luci-interpreter/src/kernels/Unpack.test.cpp +++ b/onert-micro/luci-interpreter/src/kernels/Unpack.test.cpp @@ -15,134 +15,86 @@ * limitations under the License. */ -#include "kernels/Unpack.h" #include "kernels/TestUtils.h" -#include "luci_interpreter/TestMemoryManager.h" +#include "luci_interpreter/test_models/unpack/FloatUnpackKernel.h" +#include "luci_interpreter/test_models/unpack/NegUnpackKernel.h" + +#include "loader/ModuleLoader.h" namespace luci_interpreter { -namespace kernels -{ namespace { using namespace testing; -template -void Check(int axis, Shape input_shape, std::initializer_list input_data, - const std::vector> &exp_output_shape, - std::vector> exp_output_data) +class UnpackTest : public ::testing::Test { - std::unique_ptr memory_manager = std::make_unique(); - constexpr DataType element_type = getElementType(); - const int num_outputs = input_shape.dim(axis < 0 ? axis + input_shape.num_dims() : axis); - - Tensor input_tensor = - makeInputTensor(input_shape, input_data, memory_manager.get()); - std::vector output_tensors; - output_tensors.reserve(num_outputs); - for (int i = 0; i < num_outputs; ++i) - { - output_tensors.push_back(makeOutputTensor(element_type)); - } + // Do nothing +}; - std::vector output_tensor_ptrs(num_outputs); - for (int i = 0; i < num_outputs; ++i) - { - output_tensor_ptrs[i] = &output_tensors[i]; - } +template +std::vector> checkUnpackKernel(test_kernel::TestDataBase *test_data_base) +{ + MemoryManager memory_manager{}; + RuntimeModule runtime_module{}; + bool dealloc_input = true; - UnpackParams params{}; - params.axis = axis; + // 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); - Unpack kernel(&input_tensor, std::move(output_tensor_ptrs), params); - kernel.configure(); - for (int i = 0; i < num_outputs; i++) - { - memory_manager->allocate_memory(output_tensors[i]); - } - kernel.execute(); + auto *main_runtime_graph = runtime_module.getMainGraph(); + assert(main_runtime_graph->getNumOfInputTensors() == 1); - for (int i = 0; i < num_outputs; ++i) + // set input data { - EXPECT_THAT(extractTensorData(output_tensors[i]), - ::testing::ElementsAreArray(exp_output_data[i])); + 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); } -} - -template class UnpackTest : public ::testing::Test -{ -}; -using DataTypes = ::testing::Types; -TYPED_TEST_SUITE(UnpackTest, DataTypes); + runtime_module.execute(); -TYPED_TEST(UnpackTest, ThreeOutputs) -{ - Check(/*axis=*/0, /*input_shape=*/{3, 2}, - /*input_data=*/{1, 2, 3, 4, 5, 6}, - /*exp_output_shape=*/{{2}, {2}, {2}}, - /*exp_output_data=*/{{1, 2}, {3, 4}, {5, 6}}); -} - -TYPED_TEST(UnpackTest, ThreeOutputsAxisOne) -{ - Check(/*axis=*/1, /*input_shape=*/{3, 2}, - /*input_data=*/{1, 2, 3, 4, 5, 6}, - /*exp_output_shape=*/{{3}, {3}}, - /*exp_output_data=*/{{1, 3, 5}, {2, 4, 6}}); -} + assert(main_runtime_graph->getNumOfOutputTensors() == 2); -TYPED_TEST(UnpackTest, ThreeOutputsNegativeAxisOne) -{ - Check(/*axis=*/-1, /*input_shape=*/{3, 2}, - /*input_data=*/{1, 2, 3, 4, 5, 6}, - /*exp_output_shape=*/{{3}, {3}}, - /*exp_output_data=*/{{1, 3, 5}, {2, 4, 6}}); -} + std::vector> res; -TYPED_TEST(UnpackTest, ThreeOutputsNegativeAxisTwo) -{ - Check(/*axis=*/-2, /*input_shape=*/{3, 2}, - /*input_data=*/{1, 2, 3, 4, 5, 6}, - /*exp_output_shape=*/{{2}, {2}, {2}}, - /*exp_output_data=*/{{1, 2}, {3, 4}, {5, 6}}); -} + T *output_data = reinterpret_cast(main_runtime_graph->getOutputDataByIndex(0)); + size_t num_elements = (main_runtime_graph->getOutputDataSizeByIndex(0) / sizeof(T)); + std::vector output_data_vector(output_data, output_data + num_elements); + res.push_back(output_data_vector); -TYPED_TEST(UnpackTest, OneOutput) -{ - Check(/*axis=*/0, /*input_shape=*/{1, 6}, - /*input_data=*/{1, 2, 3, 4, 5, 6}, - /*exp_output_shape=*/{{6}}, - /*exp_output_data=*/{{1, 2, 3, 4, 5, 6}}); -} + output_data = reinterpret_cast(main_runtime_graph->getOutputDataByIndex(1)); + num_elements = (main_runtime_graph->getOutputDataSizeByIndex(1) / sizeof(T)); + std::vector output_data_vector_1(output_data, output_data + num_elements); + res.push_back(output_data_vector_1); -TYPED_TEST(UnpackTest, ThreeDimensionsTwoOutputs) -{ - Check(/*axis=*/2, /*input_shape=*/{2, 2, 2}, - /*input_data=*/{1, 2, 3, 4, 5, 6, 7, 8}, - /*exp_output_shape=*/{{2, 2}, {2, 2}}, - /*exp_output_data=*/{{1, 3, 5, 7}, {2, 4, 6, 8}}); + return res; } -TYPED_TEST(UnpackTest, FiveDimensionsTwoOutputs) +TEST_F(UnpackTest, Float_P) { - Check( - /*axis=*/2, /*input_shape=*/{2, 2, 2, 2, 1}, - /*input_data=*/{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, - /*exp_output_shape=*/{{2, 2, 2, 1}, {2, 2, 2, 1}}, - /*exp_output_data=*/ - {{1, 2, 5, 6, 9, 10, 13, 14}, {3, 4, 7, 8, 11, 12, 15, 16}}); + test_kernel::TestDataFloatUnpack test_data_kernel; + std::vector> output_data_vector = checkUnpackKernel(&test_data_kernel); + EXPECT_THAT(output_data_vector[0], kernels::testing::FloatArrayNear( + test_data_kernel.get_output_data_by_index(0), 0.0001f)); + EXPECT_THAT(output_data_vector[1], kernels::testing::FloatArrayNear( + test_data_kernel.get_output_data_by_index(1), 0.0001f)); } -TYPED_TEST(UnpackTest, VectorToScalar) +TEST_F(UnpackTest, Input_type_mismatch_NEG) { - Check(/*axis=*/0, /*input_shape=*/{5}, - /*input_data=*/{1, 2, 3, 4, 5}, - /*exp_output_shape=*/{{}, {}, {}, {}, {}}, - /*exp_output_data=*/{{1}, {2}, {3}, {4}, {5}}); + test_kernel::NegTestDataInputMismatchUnpackKernel 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