diff --git a/onert-micro/luci-interpreter/include/luci_interpreter/test_models/mirror_pad/FloatMirrorPadKernel.h b/onert-micro/luci-interpreter/include/luci_interpreter/test_models/mirror_pad/FloatMirrorPadKernel.h new file mode 100644 index 00000000000..a62c4219adf --- /dev/null +++ b/onert-micro/luci-interpreter/include/luci_interpreter/test_models/mirror_pad/FloatMirrorPadKernel.h @@ -0,0 +1,104 @@ +/* + * 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_MIRROR_PAD_KERNEL_H +#define LUCI_INTERPRETER_TEST_MODELS_FLOAT_MIRROR_PAD_KERNEL_H + +#include "TestDataMirrorPadBase.h" + +namespace luci_interpreter +{ +namespace test_kernel +{ +namespace mirror_pad_float +{ +/* + * MirrorPad Kernel: + * + * Input(1, 3, 3, 2) + * | + * MirrorPad + * | + * Output(1, 5, 7, 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, + 0x60, 0x00, 0x00, 0x00, 0x9c, 0x01, 0x00, 0x00, 0xb8, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 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, 0x60, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x68, 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, 0x4d, 0x10, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x9c, 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, 0x05, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x04, 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, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, + 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 = {-91.67193, 92.42922, -34.20932, 31.049513, 82.94563, + -71.50903, 73.466835, 6.7792625, -94.79867, -62.1785, + 95.14197, -7.264842, -76.86396, 58.690563, -12.9692545, + 77.169426, 52.5776, 62.414425}; +const std::vector reference_output_data = { + 95.14197, -7.264842, -94.79867, -62.1785, 73.466835, 6.7792625, -94.79867, -62.1785, + 95.14197, -7.264842, -94.79867, -62.1785, 73.466835, 6.7792625, 82.94563, -71.50903, + -34.20932, 31.049513, -91.67193, 92.42922, -34.20932, 31.049513, 82.94563, -71.50903, + -34.20932, 31.049513, -91.67193, 92.42922, 95.14197, -7.264842, -94.79867, -62.1785, + 73.466835, 6.7792625, -94.79867, -62.1785, 95.14197, -7.264842, -94.79867, -62.1785, + 73.466835, 6.7792625, 52.5776, 62.414425, -12.9692545, 77.169426, -76.86396, 58.690563, + -12.9692545, 77.169426, 52.5776, 62.414425, -12.9692545, 77.169426, -76.86396, 58.690563, + 95.14197, -7.264842, -94.79867, -62.1785, 73.466835, 6.7792625, -94.79867, -62.1785, + 95.14197, -7.264842, -94.79867, -62.1785, 73.466835, 6.7792625}; + +} // namespace mirror_pad_float + +class TestDataFloatMirrorPad : public TestDataMirrorPadBase +{ +public: + TestDataFloatMirrorPad() + { + _input_data = mirror_pad_float::input_data; + _reference_output_data = mirror_pad_float::reference_output_data; + _test_kernel_model_circle = mirror_pad_float::test_kernel_model_circle; + } + + ~TestDataFloatMirrorPad() override = default; +}; + +} // namespace test_kernel +} // namespace luci_interpreter + +#endif // LUCI_INTERPRETER_TEST_MODELS_FLOAT_MIRROR_PAD_KERNEL_H diff --git a/onert-micro/luci-interpreter/include/luci_interpreter/test_models/mirror_pad/NegMirrorPadKernel.h b/onert-micro/luci-interpreter/include/luci_interpreter/test_models/mirror_pad/NegMirrorPadKernel.h new file mode 100644 index 00000000000..557134947db --- /dev/null +++ b/onert-micro/luci-interpreter/include/luci_interpreter/test_models/mirror_pad/NegMirrorPadKernel.h @@ -0,0 +1,92 @@ +/* + * 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_MIRROR_PAD_KERNEL_H +#define LUCI_INTERPRETER_TEST_MODELS_NEG_MIRROR_PAD_KERNEL_H + +#include "luci_interpreter/test_models/TestDataBase.h" + +namespace luci_interpreter +{ +namespace test_kernel +{ +namespace neg_input_output_type_mismatch_mirror_pad_kernel +{ +/* + * MirrorPad Kernel with input output type mismatch: + * + * Input(1, 3, 3, 2) - Float32 + * | + * MirrorPad + * | + * Output(1, 5, 7, 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, + 0x60, 0x00, 0x00, 0x00, 0xa0, 0x01, 0x00, 0x00, 0xbc, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 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, 0x60, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x68, 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, 0x4d, 0x10, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0xd0, 0xff, 0xff, 0xff, 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, 0x05, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x10, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x04, 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, 0x64, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x64, 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_mirror_pad_kernel + +class NegTestDataInputOutputTypeMismatchMirrorPadKernel : public NegTestDataBase +{ +public: + NegTestDataInputOutputTypeMismatchMirrorPadKernel() + { + _test_kernel_model_circle = + neg_input_output_type_mismatch_mirror_pad_kernel::test_kernel_model_circle; + } + + ~NegTestDataInputOutputTypeMismatchMirrorPadKernel() 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_MIRROR_PAD_KERNEL_H diff --git a/onert-micro/luci-interpreter/include/luci_interpreter/test_models/mirror_pad/TestDataMirrorPadBase.h b/onert-micro/luci-interpreter/include/luci_interpreter/test_models/mirror_pad/TestDataMirrorPadBase.h new file mode 100644 index 00000000000..e7260970519 --- /dev/null +++ b/onert-micro/luci-interpreter/include/luci_interpreter/test_models/mirror_pad/TestDataMirrorPadBase.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_MIRROR_PAD_KERNEL_BASE_H +#define LUCI_INTERPRETER_TEST_MODELS_MIRROR_PAD_KERNEL_BASE_H + +#include "luci_interpreter/test_models/TestDataBase.h" + +namespace luci_interpreter +{ +namespace test_kernel +{ + +template class TestDataMirrorPadBase : public TestDataBase +{ +public: + TestDataMirrorPadBase() = 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_MIRROR_PAD_KERNEL_BASE_H diff --git a/onert-micro/luci-interpreter/pal/cmsisnn/KernelsToBuild.lst b/onert-micro/luci-interpreter/pal/cmsisnn/KernelsToBuild.lst index 30ec35ff7f3..8c25c05c7fb 100644 --- a/onert-micro/luci-interpreter/pal/cmsisnn/KernelsToBuild.lst +++ b/onert-micro/luci-interpreter/pal/cmsisnn/KernelsToBuild.lst @@ -42,6 +42,7 @@ REGISTER_KERNEL(LOGICAL_OR, LogicalOr) REGISTER_KERNEL(LEAKY_RELU, LeakyRelu) REGISTER_KERNEL(LOG_SOFTMAX, LogSoftmax) REGISTER_KERNEL(MUL, Mul) +REGISTER_KERNEL(MIRROR_PAD, MirrorPad) REGISTER_KERNEL(MAX_POOL_2D, MaxPool2D) REGISTER_KERNEL(MEAN, Mean) REGISTER_KERNEL(CONCATENATION, Concatenation) diff --git a/onert-micro/luci-interpreter/pal/common/PALMirrorPad.h b/onert-micro/luci-interpreter/pal/common/PALMirrorPad.h new file mode 100644 index 00000000000..80fd48496cf --- /dev/null +++ b/onert-micro/luci-interpreter/pal/common/PALMirrorPad.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2023 Samsung Electronics Co., Ltd. All Rights Reserved + * Copyright 2019 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_MIRROR_PAD_COMMON_H +#define LUCI_INTERPRETER_PAL_MIRROR_PAD_COMMON_H + +#include "PALUtils.h" +#include "Params.h" + +namespace luci_interpreter_pal +{ +namespace +{ + +// Helper method that fills the left and right pads. +template +inline void getPadding(const T *data, int offset, int64_t *left_pad, int64_t *right_pad) +{ + *left_pad = static_cast(*(data + offset * 2)); + *right_pad = static_cast(*(data + offset * 2 + 1)); +} + +// Given dimension index and the left/right padding. +// Returns the corresponding dimension in the input array. +inline int getInputDimension(int padded_dimension, int left_pad, int right_pad, int input_dim_size, + int offset) +{ + if (padded_dimension < left_pad) + { + const int original_ind = left_pad + offset - 1; + return original_ind - (std::min(padded_dimension, original_ind - offset)); + } + padded_dimension -= left_pad; + if (padded_dimension >= input_dim_size) + { + padded_dimension -= input_dim_size; + const int original_ind = input_dim_size - (1 + offset); + return original_ind - std::min(padded_dimension, original_ind); + } + return padded_dimension; +} + +// Given and index in output array, returns the index of the value +// in input array. +int getFlatIndex(int index, int num_dims, const luci_interpreter::DataType padding_matrix_type, + const uint8_t *padding_matrix_data, const int32_t *input_dims, + int *output_dims_num_elements, int *input_dims_num_elements, const int offset) +{ + int flat_index = 0; + int64_t left_pad = 0, right_pad = 0, dimension_index, index_in_input; + + for (int i = 0; i < num_dims; ++i) + { + switch (padding_matrix_type) + { + case luci_interpreter::DataType::S32: + getPadding(luci_interpreter::kernels::getTensorData(padding_matrix_data), i, + &left_pad, &right_pad); + break; + case luci_interpreter::DataType::S64: + getPadding(luci_interpreter::kernels::getTensorData(padding_matrix_data), i, + &left_pad, &right_pad); + break; + default: + break; + } + dimension_index = index / output_dims_num_elements[i]; + + index_in_input = getInputDimension(dimension_index, left_pad, right_pad, input_dims[i], offset); + + flat_index += index_in_input * (input_dims_num_elements)[i]; + index %= output_dims_num_elements[i]; + } + + return flat_index; +} + +} // namespace + +template +void MirrorPad(const luci_interpreter::DataType padding_matrix_type, + const uint8_t *padding_matrix_data, const int32_t *input_dims, + int *output_dims_num_elements, int *input_dims_num_elements, const T *input_data, + T *output_data, const int offset, const int num_dims, const int output_size) +{ + for (int i = 0; i < output_size; ++i) + { + output_data[i] = + input_data[getFlatIndex(i, num_dims, padding_matrix_type, padding_matrix_data, input_dims, + output_dims_num_elements, input_dims_num_elements, offset)]; + } +} + +} // namespace luci_interpreter_pal + +#endif // LUCI_INTERPRETER_PAL_MIRROR_PAD_COMMON_H diff --git a/onert-micro/luci-interpreter/pal/mcu/KernelsToBuild.lst b/onert-micro/luci-interpreter/pal/mcu/KernelsToBuild.lst index d8a152cdcb6..51b00a4796f 100644 --- a/onert-micro/luci-interpreter/pal/mcu/KernelsToBuild.lst +++ b/onert-micro/luci-interpreter/pal/mcu/KernelsToBuild.lst @@ -48,6 +48,7 @@ REGISTER_KERNEL(LOGICAL_OR, LogicalOr) REGISTER_KERNEL(LEAKY_RELU, LeakyRelu) REGISTER_KERNEL(LOG_SOFTMAX, LogSoftmax) REGISTER_KERNEL(MUL, Mul) +REGISTER_KERNEL(MIRROR_PAD, MirrorPad) REGISTER_KERNEL(MAXIMUM, Maximum) REGISTER_KERNEL(MEAN, Mean) REGISTER_KERNEL(MAX_POOL_2D, MaxPool2D) diff --git a/onert-micro/luci-interpreter/src/kernels/MirrorPad.cpp b/onert-micro/luci-interpreter/src/kernels/MirrorPad.cpp index d9e60b060a1..fa12c903546 100644 --- a/onert-micro/luci-interpreter/src/kernels/MirrorPad.cpp +++ b/onert-micro/luci-interpreter/src/kernels/MirrorPad.cpp @@ -15,158 +15,77 @@ * limitations under the License. */ -#include "kernels/MirrorPad.h" - +#include "Builders.h" #include "kernels/Utils.h" +#include "TISOKernel.h" -#include +#include "PALMirrorPad.h" namespace luci_interpreter { -namespace kernels +namespace { +constexpr int maxInputSize = 5; +} -MirrorPad::MirrorPad(const Tensor *input, const Tensor *paddings, Tensor *output, - const MirrorPadParams ¶ms) - : KernelWithParams({input, paddings}, {output}, params) +void configure_kernel_CircleMirrorPad(const circle::Operator *cur_op, + BaseRuntimeGraph *runtime_graph) { + kernels::TISOKernel kernel(cur_op, runtime_graph); + + LUCI_INTERPRETER_CHECK(Tensor::element_type(kernel.input1()) == + Tensor::element_type(kernel.output())); + LUCI_INTERPRETER_CHECK(Tensor::num_dims(kernel.input2()) == 2); + LUCI_INTERPRETER_CHECK(Tensor::dim(kernel.input2(), 0) == Tensor::num_dims(kernel.input1())); } -void MirrorPad::configure() +void execute_kernel_CircleMirrorPad(const circle::Operator *cur_op, BaseRuntimeGraph *runtime_graph) { - const Shape &input_shape = input()->shape(); - const int num_dims = input_shape.num_dims(); - - if (num_dims > 4) - assert(false && "Unsupported number of dimensions."); - - assert(output()->element_type() == input()->element_type()); - assert(paddings()->element_type() == DataType::S32); - // Paddings shape should be [N, 2]. - assert(paddings()->shape().num_dims() == 2); - assert(paddings()->shape().dim(0) == num_dims); - assert(paddings()->shape().dim(1) == 2); - - Shape output_shape(num_dims); - const auto *paddings_data = getTensorData(paddings()); - for (int i = 0; i < num_dims; ++i) + kernels::TISOKernel kernel(cur_op, runtime_graph); + + kernels::TISOData data = kernel.readData(); + + const auto *options = cur_op->builtin_options_as_MirrorPadOptions(); + + const auto offset = options->mode() != circle::MirrorPadMode_REFLECT ? 0 : 1; + const auto input_dims = Tensor::num_dims(kernel.input1()); + const auto output_size = Tensor::num_elements(kernel.output()); + + int output_dims_num_elements[5]; + int input_dims_num_elements[5]; + + for (int i = 0; i < input_dims; i++) { - const int32_t padding_before = paddings_data[i * 2]; - const int32_t padding_after = paddings_data[i * 2 + 1]; - assert(padding_before >= 0 && padding_after >= 0); - output_shape.dim(i) = input_shape.dim(i) + padding_before + padding_after; + output_dims_num_elements[i] = 1; + input_dims_num_elements[i] = 1; } - // TODO: enable it only if kernel with dynamic shapes - output()->resize(output_shape); -} -template -inline void MirrorPadImpl(const Tensor &input, const Tensor &paddings, MirrorPadMode mode, - Tensor &output); + for (int i = input_dims - 2; i >= 0; i--) + { + output_dims_num_elements[i] = + output_dims_num_elements[i + 1] * Tensor::dim(kernel.output(), i + 1); -void MirrorPad::execute() const -{ - switch (input()->element_type()) + input_dims_num_elements[i] = + input_dims_num_elements[i + 1] * Tensor::dim(kernel.input1(), i + 1); + } + + switch (Tensor::element_type(kernel.input1())) { +#ifndef DIS_FLOAT case DataType::FLOAT32: { - MirrorPadImpl(*input(), *paddings(), params().mode, *output()); - break; - } - case DataType::U8: - { - assert(output()->zero_point() >= std::numeric_limits::min()); - assert(output()->zero_point() <= std::numeric_limits::max()); + luci_interpreter_pal::MirrorPad( + Tensor::element_type(kernel.input2()), data.input2_data, + wrap(kernel.input1()->shape()).data(), output_dims_num_elements, input_dims_num_elements, + kernels::getTensorData(data.input1_data), + kernels::getTensorData(data.output_data), offset, input_dims, output_size); - MirrorPadImpl(*input(), *paddings(), params().mode, *output()); break; } +#endif // DIS_FLOAT default: - assert(false && "Unsupported type."); - } -} - -template -inline void MirrorPadImpl(const Tensor &input, const Tensor &paddings, MirrorPadMode mode, - Tensor &output) -{ - auto const input_dims = input.shape().num_dims(); - auto const input_data = input.data(); - auto const paddings_data = paddings.data(); - auto const output_data = output.data(); - - auto const input_b = input_dims > 3 ? input.shape().dim(input_dims - 4) : 1; - auto const input_h = input_dims > 2 ? input.shape().dim(input_dims - 3) : 1; - auto const input_w = input_dims > 1 ? input.shape().dim(input_dims - 2) : 1; - auto const input_d = input.shape().dim(input_dims - 1); - - auto const input_h_offset = input_d * input_w; - auto const input_b_offset = input_h_offset * input_h; - - auto const output_b = input_dims > 3 ? output.shape().dim(input_dims - 4) : 1; - auto const output_h = input_dims > 2 ? output.shape().dim(input_dims - 3) : 1; - auto const output_w = input_dims > 1 ? output.shape().dim(input_dims - 2) : 1; - auto const output_d = output.shape().dim(input_dims - 1); - - auto const left_b_pad = paddings_data[2 * (input_dims - 4)]; - auto const left_h_pad = paddings_data[2 * (input_dims - 3)]; - auto const left_w_pad = paddings_data[2 * (input_dims - 2)]; - auto const left_d_pad = paddings_data[2 * (input_dims - 1)]; - - auto const right_b_pad = paddings_data[2 * (input_dims - 4) + 1]; - auto const right_h_pad = paddings_data[2 * (input_dims - 3) + 1]; - auto const right_w_pad = paddings_data[2 * (input_dims - 2) + 1]; - auto const right_d_pad = paddings_data[2 * (input_dims - 1) + 1]; - - const auto positive_mod = [](auto a, auto b) { return (a % b + b) % b; }; - const auto offset_index = [input_d, input_h_offset, input_b_offset](auto d, auto w, auto h, - auto b) { - return d + w * input_d + h * input_h_offset + b * input_b_offset; - }; - - const auto symmetric_dim = [&positive_mod](auto i, auto left_pad, auto input) { - bool reflected = (((i < left_pad ? i + 1 - input : i) - left_pad) / input & 1) == 1; - return positive_mod(reflected ? input + left_pad - i - 1 : i - left_pad, input); - }; - - const T *in_ptr = input_data; - T *out_ptr = output_data; - - for (int32_t b = 0; b < output_b; ++b) - { - for (int32_t h = 0; h < output_h; ++h) - { - for (int32_t w = 0; w < output_w; ++w) - { - for (int32_t d = 0; d < output_d; ++d) - { - if (b < left_b_pad || b >= output_b - right_b_pad || // - h < left_h_pad || h >= output_h - right_h_pad || // - w < left_w_pad || w >= output_w - right_w_pad || // - d < left_d_pad || d >= output_d - right_d_pad) - { - if (mode == MirrorPadMode::REFLECT) - { - *out_ptr++ = input_data[offset_index( - positive_mod(d - left_d_pad, input_d), positive_mod(w - left_w_pad, input_w), - positive_mod(h - left_h_pad, input_h), positive_mod(b - left_b_pad, input_b))]; - } - else - { - *out_ptr++ = input_data[offset_index( - symmetric_dim(d, left_d_pad, input_d), symmetric_dim(w, left_w_pad, input_w), - symmetric_dim(h, left_h_pad, input_h), symmetric_dim(b, left_b_pad, input_b))]; - } - } - else - { - *out_ptr++ = *in_ptr++; - } - } - } - } + assert(false && "Unsupported type"); } } -} // namespace kernels } // namespace luci_interpreter diff --git a/onert-micro/luci-interpreter/src/kernels/MirrorPad.h b/onert-micro/luci-interpreter/src/kernels/MirrorPad.h deleted file mode 100644 index d3e6e858a89..00000000000 --- a/onert-micro/luci-interpreter/src/kernels/MirrorPad.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2021 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_MIRROR_PAD_H -#define LUCI_INTERPRETER_KERNELS_MIRROR_PAD_H - -#include "core/Kernel.h" -#include "core/KernelParams.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class MirrorPad : public KernelWithParams -{ -public: - MirrorPad(const Tensor *input, const Tensor *paddings, Tensor *output, - const MirrorPadParams ¶ms); - - const Tensor *input() const { return _inputs[0]; } - const Tensor *paddings() const { return _inputs[1]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_MIRROR_PAD_H diff --git a/onert-micro/luci-interpreter/src/kernels/MirrorPad.test.cpp b/onert-micro/luci-interpreter/src/kernels/MirrorPad.test.cpp index 740d8cb2272..ed207e5206c 100644 --- a/onert-micro/luci-interpreter/src/kernels/MirrorPad.test.cpp +++ b/onert-micro/luci-interpreter/src/kernels/MirrorPad.test.cpp @@ -14,14 +14,14 @@ * limitations under the License. */ -#include "kernels/MirrorPad.h" #include "kernels/TestUtils.h" -#include "luci_interpreter/TestMemoryManager.h" +#include "luci_interpreter/test_models/mirror_pad/FloatMirrorPadKernel.h" +#include "luci_interpreter/test_models/mirror_pad/NegMirrorPadKernel.h" + +#include "loader/ModuleLoader.h" namespace luci_interpreter { -namespace kernels -{ namespace { @@ -29,197 +29,59 @@ using namespace testing; class MirrorPadTest : public ::testing::Test { -protected: - void SetUp() override { _memory_manager = std::make_unique(); } - - void Execute(const Tensor &input, const Tensor &padding, Tensor &output, MirrorPadMode mode) - { - MirrorPadParams params{}; - params.mode = mode; - - MirrorPad kernel(&input, &padding, &output, params); - kernel.configure(); - _memory_manager->allocate_memory(output); - kernel.execute(); - } - - std::unique_ptr _memory_manager; + // Do nothing }; -TEST_F(MirrorPadTest, FloatReflect) -{ - Shape input_shape = {1, 2, 2, 1}; - Shape padding_shape = {4, 2}; - - std::vector input_data{1.0f, 2.0f, // - 3.0f, 4.0f}; // - std::vector padding_data{0, 0, 2, 1, 1, 2, 0, 0}; - - Tensor input_tensor = - makeInputTensor(input_shape, input_data, _memory_manager.get()); - Tensor padding_tensor = - makeInputTensor(padding_shape, padding_data, _memory_manager.get()); - - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - Execute(input_tensor, padding_tensor, output_tensor, MirrorPadMode::REFLECT); - - std::vector ref_output_data{2.0f, 1.0f, 2.0f, 1.0f, 2.0f, // - 4.0f, 3.0f, 4.0f, 3.0f, 4.0f, // - 2.0f, 1.0f, 2.0f, 1.0f, 2.0f, // - 4.0f, 3.0f, 4.0f, 3.0f, 4.0f, // - 2.0f, 1.0f, 2.0f, 1.0f, 2.0f}; // - std::initializer_list ref_output_shape{1, 5, 5, 1}; - - EXPECT_THAT(extractTensorData(output_tensor), FloatArrayNear(ref_output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape)); -} - -TEST_F(MirrorPadTest, FloatSymmetric) +template +std::vector checkMirrorPadKernel(test_kernel::TestDataBase *test_data_base) { - Shape input_shape = {1, 2, 2, 1}; - Shape padding_shape = {4, 2}; - - std::vector input_data{1.0f, 2.0f, // - 3.0f, 4.0f}; // - std::vector padding_data{0, 0, 2, 1, 1, 2, 0, 0}; - - Tensor input_tensor = - makeInputTensor(input_shape, input_data, _memory_manager.get()); - Tensor padding_tensor = - makeInputTensor(padding_shape, padding_data, _memory_manager.get()); - - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - Execute(input_tensor, padding_tensor, output_tensor, MirrorPadMode::SYMMETRIC); - - std::vector ref_output_data{3.0, 3.0, 4.0, 4.0, 3.0, // - 1.0, 1.0, 2.0, 2.0, 1.0, // - 1.0, 1.0, 2.0, 2.0, 1.0, // - 3.0, 3.0, 4.0, 4.0, 3.0, // - 3.0, 3.0, 4.0, 4.0, 3.0}; // - std::initializer_list ref_output_shape{1, 5, 5, 1}; - - EXPECT_THAT(extractTensorData(output_tensor), FloatArrayNear(ref_output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape)); -} - -TEST_F(MirrorPadTest, FloatSymmetric2Dim) -{ - Shape input_shape = {3, 1}; - Shape padding_shape = {2, 2}; - - std::vector input_data{1.0f, 2.0f, 3.0f}; - std::vector padding_data{1, 2, 0, 0}; + MemoryManager memory_manager{}; + RuntimeModule runtime_module{}; + bool dealloc_input = true; - Tensor input_tensor = - makeInputTensor(input_shape, input_data, _memory_manager.get()); - Tensor padding_tensor = - makeInputTensor(padding_shape, padding_data, _memory_manager.get()); + // 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); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); + auto *main_runtime_graph = runtime_module.getMainGraph(); + assert(main_runtime_graph->getNumOfInputTensors() == 1); - Execute(input_tensor, padding_tensor, output_tensor, MirrorPadMode::SYMMETRIC); - - std::vector ref_output_data{1.0, 1.0, 2.0, 3.0, 3.0, 2.0}; - std::initializer_list ref_output_shape{6, 1}; - - EXPECT_THAT(extractTensorData(output_tensor), FloatArrayNear(ref_output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape)); -} - -TEST_F(MirrorPadTest, Uint8Reflect) -{ - Shape input_shape = {1, 2, 3, 1}; - Shape padding_shape = {4, 2}; - - float quant_tolerance = getTolerance(0.0f, 6.0f, 255); - std::pair quant_param = quantizationParams(0.0f, 6.0f); - - std::vector input_data{1.0f, 2.0f, 3.0f, // - 4.0f, 5.0f, 6.0f}; // - std::vector padding_data{0, 0, 2, 1, 1, 3, 0, 0}; - - Tensor input_tensor = makeInputTensor( - input_shape, quant_param.first, quant_param.second, input_data, _memory_manager.get()); - - Tensor padding_tensor = - makeInputTensor(padding_shape, padding_data, _memory_manager.get()); - - Tensor output_tensor = makeOutputTensor(DataType::U8, quant_param.first, quant_param.second); - - Execute(input_tensor, padding_tensor, output_tensor, MirrorPadMode::REFLECT); - - std::vector ref_output_data{ - 3.0f, 1.0f, 2.0f, 3.0f, 1.0f, 2.0f, 3.0f, // - 6.0f, 4.0f, 5.0f, 6.0f, 4.0f, 5.0f, 6.0f, // - 3.0f, 1.0f, 2.0f, 3.0f, 1.0f, 2.0f, 3.0f, // - 6.0f, 4.0f, 5.0f, 6.0f, 4.0f, 5.0f, 6.0f, // - 3.0f, 1.0f, 2.0f, 3.0f, 1.0f, 2.0f, 3.0f, // - }; - std::initializer_list ref_output_shape{1, 5, 7, 1}; - - EXPECT_THAT(dequantizeTensorData(output_tensor), - FloatArrayNear(ref_output_data, quant_tolerance)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape)); -} - -TEST_F(MirrorPadTest, Uint8Symmetric) -{ - Shape input_shape = {1, 2, 3, 1}; - Shape padding_shape = {4, 2}; - - float quant_tolerance = getTolerance(0.0f, 6.0f, 255); - std::pair quant_param = quantizationParams(0.0f, 6.0f); - - std::vector input_data{1.0f, 2.0f, 3.0f, // - 4.0f, 5.0f, 6.0f}; // - std::vector padding_data{0, 0, 2, 1, 1, 3, 0, 0}; - - Tensor input_tensor = makeInputTensor( - input_shape, quant_param.first, quant_param.second, input_data, _memory_manager.get()); - - Tensor padding_tensor = - makeInputTensor(padding_shape, padding_data, _memory_manager.get()); - - Tensor output_tensor = makeOutputTensor(DataType::U8, quant_param.first, quant_param.second); + // 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); + } - Execute(input_tensor, padding_tensor, output_tensor, MirrorPadMode::SYMMETRIC); + runtime_module.execute(); - std::vector ref_output_data{ - 4.0f, 4.0f, 5.0f, 6.0f, 6.0f, 5.0f, 4.0f, // - 1.0f, 1.0f, 2.0f, 3.0f, 3.0f, 2.0f, 1.0f, // - 1.0f, 1.0f, 2.0f, 3.0f, 3.0f, 2.0f, 1.0f, // - 4.0f, 4.0f, 5.0f, 6.0f, 6.0f, 5.0f, 4.0f, // - 4.0f, 4.0f, 5.0f, 6.0f, 6.0f, 5.0f, 4.0f, // - }; - std::initializer_list ref_output_shape{1, 5, 7, 1}; + assert(main_runtime_graph->getNumOfOutputTensors() == 1); - EXPECT_THAT(dequantizeTensorData(output_tensor), - FloatArrayNear(ref_output_data, quant_tolerance)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape)); + 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(MirrorPadTest, UnsupportedDim_NEG) +TEST_F(MirrorPadTest, Float_P) { - Tensor input_tensor = - makeInputTensor({1, 1, 1, 1, 1}, {1.0f}, _memory_manager.get()); - Tensor padding_tensor = - makeInputTensor({5, 2}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, _memory_manager.get()); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - EXPECT_ANY_THROW(Execute(input_tensor, padding_tensor, output_tensor, MirrorPadMode::REFLECT)); + test_kernel::TestDataFloatMirrorPad test_data_kernel; + std::vector output_data_vector = checkMirrorPadKernel(&test_data_kernel); + EXPECT_THAT(output_data_vector, kernels::testing::FloatArrayNear( + test_data_kernel.get_output_data_by_index(0), 0.0001f)); } -TEST_F(MirrorPadTest, InvalidInputType_NEG) +TEST_F(MirrorPadTest, Input_output_type_mismatch_NEG) { - Tensor input_tensor = makeInputTensor({1}, {1}, _memory_manager.get()); - Tensor padding_tensor = makeInputTensor({1, 2}, {0, 0}, _memory_manager.get()); - Tensor output_tensor = makeOutputTensor(DataType::S64); - - EXPECT_ANY_THROW(Execute(input_tensor, padding_tensor, output_tensor, MirrorPadMode::REFLECT)); + test_kernel::NegTestDataInputOutputTypeMismatchMirrorPadKernel 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