From 9d8c7477bc63bbabf40c55de1446b94e211abd7a Mon Sep 17 00:00:00 2001 From: Balyshev Artem <43214667+BalyshevArtem@users.noreply.github.com> Date: Thu, 6 Jul 2023 06:43:27 +0300 Subject: [PATCH] [onert-micro] Support AveragePool2D kernel (#10961) This PR adds supporting of AveragePool2D kernel. ONE-DCO-1.0-Signed-off-by: Artem Balyshev Co-authored-by: Artem Balyshev --- .../FloatAveragePool2DKernel.h | 103 +++++++ .../average_pool_2d/NegAveragePool2DKernel.h | 88 ++++++ .../TestDataAveragePool2DBase.h | 60 ++++ .../pal/mcu/KernelsToBuild.lst | 1 + .../pal/mcu/PALAveragePool2D.h | 93 ++++++ .../pal/mcu/PALAveragePool2d.h | 73 ----- .../src/kernels/AveragePool2D.cpp | 217 ++++---------- .../src/kernels/AveragePool2D.h | 54 ---- .../src/kernels/AveragePool2D.test.cpp | 279 +++--------------- 9 files changed, 449 insertions(+), 519 deletions(-) create mode 100644 onert-micro/luci-interpreter/include/luci_interpreter/test_models/average_pool_2d/FloatAveragePool2DKernel.h create mode 100644 onert-micro/luci-interpreter/include/luci_interpreter/test_models/average_pool_2d/NegAveragePool2DKernel.h create mode 100644 onert-micro/luci-interpreter/include/luci_interpreter/test_models/average_pool_2d/TestDataAveragePool2DBase.h create mode 100644 onert-micro/luci-interpreter/pal/mcu/PALAveragePool2D.h delete mode 100644 onert-micro/luci-interpreter/pal/mcu/PALAveragePool2d.h delete mode 100644 onert-micro/luci-interpreter/src/kernels/AveragePool2D.h diff --git a/onert-micro/luci-interpreter/include/luci_interpreter/test_models/average_pool_2d/FloatAveragePool2DKernel.h b/onert-micro/luci-interpreter/include/luci_interpreter/test_models/average_pool_2d/FloatAveragePool2DKernel.h new file mode 100644 index 00000000000..58790e94baf --- /dev/null +++ b/onert-micro/luci-interpreter/include/luci_interpreter/test_models/average_pool_2d/FloatAveragePool2DKernel.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_AVERAGE_POOL2D_KERNEL_H +#define LUCI_INTERPRETER_TEST_MODELS_FLOAT_AVERAGE_POOL2D_KERNEL_H + +#include "TestDataAveragePool2DBase.h" + +namespace luci_interpreter +{ +namespace test_kernel +{ +namespace average_pool2d_float +{ +/* + * AveragePool2D Kernel: + * + * Input(1, 8, 8, 1) + * | + * AveragePool2D + * | + * Output(1, 7, 7, 1) + */ +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, + 0x2c, 0x00, 0x00, 0x00, 0x48, 0x01, 0x00, 0x00, 0x64, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 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, + 0x7c, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x84, 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, 0x05, 0x1c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x17, 0x00, 0x10, 0x00, 0x0c, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 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, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x01, 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, + 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 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, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 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 = { + -10.829727, -5.0753784, -0.46581638, 1.1337309, -12.983028, -1.7739874, -3.8115792, -1.470794, + 0.8652655, 3.5751436, 3.142009, -2.881177, 0.21681504, -0.6201232, -1.168152, -5.972758, + 6.4394593, 0.60464424, -1.8141485, -17.769108, -13.40761, 6.139243, -2.3543136, -2.5557704, + 15.057343, 7.4924536, -20.035614, 4.250232, 5.9063106, 10.382995, -7.45354, 3.7568998, + 5.0376787, 2.825182, -7.3617344, -3.2233214, 2.2610564, -6.776909, -2.56466, 17.584259, + 15.771288, 5.9487047, -0.11435696, 8.510494, 9.547339, 11.753286, 12.103353, -14.300014, + 4.453389, 11.3001, -7.494295, 9.240987, -2.8403296, -1.9216467, 8.1578245, -7.334697, + 1.2287734, 0.7231084, 9.715425, -7.466359, -15.67608, 6.574766, 4.489766, -1.6495954}; + +const std::vector reference_output_data{ + -2.866174, 0.29398948, 0.23218668, -3.6284149, -3.790081, -1.8434604, -3.1058207, + 2.871128, 1.376912, -4.830606, -8.46027, -1.9179188, 0.4991635, -3.0127485, + 7.3984747, -3.4381661, -8.842159, -5.2550435, 2.2552347, 1.678596, -2.151681, + 7.6031637, -4.269928, -6.5926094, 2.2985694, 2.9433632, -1.6030285, 2.83074, + 7.395714, 0.32444882, -0.54722965, 4.273892, 4.196193, 3.6287675, 3.2057345, + 9.368371, 2.4100385, 2.535707, 6.1146226, 4.134662, 7.523204, -0.3433833, + 4.426343, 3.5610845, 0.9989393, -4.1854453, -3.4658222, 4.3251777, 0.91582465}; + +} // namespace average_pool2d_float + +class TestDataFloatAveragePool2D : public TestDataAveragePool2DBase +{ +public: + TestDataFloatAveragePool2D() + { + _input_data = average_pool2d_float::input_data; + _reference_output_data = average_pool2d_float::reference_output_data; + _test_kernel_model_circle = average_pool2d_float::test_kernel_model_circle; + } + + ~TestDataFloatAveragePool2D() override = default; +}; + +} // namespace test_kernel +} // namespace luci_interpreter + +#endif // LUCI_INTERPRETER_TEST_MODELS_FLOAT_AVERAGE_POOL2D_KERNEL_H diff --git a/onert-micro/luci-interpreter/include/luci_interpreter/test_models/average_pool_2d/NegAveragePool2DKernel.h b/onert-micro/luci-interpreter/include/luci_interpreter/test_models/average_pool_2d/NegAveragePool2DKernel.h new file mode 100644 index 00000000000..0c1c5a29bc6 --- /dev/null +++ b/onert-micro/luci-interpreter/include/luci_interpreter/test_models/average_pool_2d/NegAveragePool2DKernel.h @@ -0,0 +1,88 @@ +/* + * 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_AVERAGE_POOL2D_KERNEL_H +#define LUCI_INTERPRETER_TEST_MODELS_NEG_AVERAGE_POOL2D_KERNEL_H + +#include "TestDataAveragePool2DBase.h" + +namespace luci_interpreter +{ +namespace test_kernel +{ +namespace neg_average_pool2d_kernel +{ +/* + * AveragePool2D Kernel with input_type != output_type: + * + * Input(1, 8, 8, 1) = Float32 + * | + * AveragePool2D + * | + * Output(1, 7, 7, 1) = 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, + 0x2c, 0x00, 0x00, 0x00, 0x58, 0x01, 0x00, 0x00, 0x74, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 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, + 0x7c, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x84, 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, 0x05, 0x1c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x17, 0x00, 0x10, 0x00, 0x0c, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 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, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x01, 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, + 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 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, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 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_average_pool2d_kernel + +class NegTestDataInputOutputTypeMismatchAveragePool2DKernel : public NegTestDataBase +{ +public: + NegTestDataInputOutputTypeMismatchAveragePool2DKernel() + { + _test_kernel_model_circle = neg_average_pool2d_kernel::test_kernel_model_circle; + } + + ~NegTestDataInputOutputTypeMismatchAveragePool2DKernel() 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_AVERAGE_POOL2D_KERNEL_H diff --git a/onert-micro/luci-interpreter/include/luci_interpreter/test_models/average_pool_2d/TestDataAveragePool2DBase.h b/onert-micro/luci-interpreter/include/luci_interpreter/test_models/average_pool_2d/TestDataAveragePool2DBase.h new file mode 100644 index 00000000000..c7de059cd4f --- /dev/null +++ b/onert-micro/luci-interpreter/include/luci_interpreter/test_models/average_pool_2d/TestDataAveragePool2DBase.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_AVERAGE_POOL_2D_KERNEL_BASE_H +#define LUCI_INTERPRETER_TEST_MODELS_AVERAGE_POOL_2D_KERNEL_BASE_H + +#include "luci_interpreter/test_models/TestDataBase.h" + +namespace luci_interpreter +{ +namespace test_kernel +{ + +template class TestDataAveragePool2DBase : public TestDataBase +{ +public: + TestDataAveragePool2DBase() = 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_AVERAGE_POOL_2D_KERNEL_BASE_H diff --git a/onert-micro/luci-interpreter/pal/mcu/KernelsToBuild.lst b/onert-micro/luci-interpreter/pal/mcu/KernelsToBuild.lst index 82cc887ecbf..53142b658d2 100644 --- a/onert-micro/luci-interpreter/pal/mcu/KernelsToBuild.lst +++ b/onert-micro/luci-interpreter/pal/mcu/KernelsToBuild.lst @@ -1,4 +1,5 @@ REGISTER_KERNEL(ADD, Add) +REGISTER_KERNEL(AVERAGE_POOL_2D, AveragePool2D) REGISTER_KERNEL(FULLY_CONNECTED, FullyConnected) REGISTER_KERNEL(CONV_2D, Conv2D) REGISTER_KERNEL(LOGISTIC, Logistic) diff --git a/onert-micro/luci-interpreter/pal/mcu/PALAveragePool2D.h b/onert-micro/luci-interpreter/pal/mcu/PALAveragePool2D.h new file mode 100644 index 00000000000..e111abbb572 --- /dev/null +++ b/onert-micro/luci-interpreter/pal/mcu/PALAveragePool2D.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2023 Samsung Electronics Co., Ltd. All Rights Reserved + * Copyright 2020 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_AVERAGE_POOL_2D_H +#define LUCI_INTERPRETER_PAL_AVERAGE_POOL_2D_H + +#include "Params.h" +#include "PALUtils.h" + +namespace luci_interpreter_pal +{ + +// TODO: reduce code duplication with MaxPool +inline void AveragePool(const PoolParams ¶ms, const luci_interpreter::RuntimeShape &input_shape, + const float *input_data, const luci_interpreter::RuntimeShape &output_shape, + float *output_data) +{ + const int batches = input_shape.dims(0); + const int depth = output_shape.dims(3); + const int input_height = input_shape.dims(1); + const int input_width = input_shape.dims(2); + const int output_height = output_shape.dims(1); + const int output_width = output_shape.dims(2); + const int stride_height = params.stride_height; + const int stride_width = params.stride_width; + for (int batch = 0; batch < batches; ++batch) + { + for (int out_y = 0; out_y < output_height; ++out_y) + { + for (int out_x = 0; out_x < output_width; ++out_x) + { + for (int channel = 0; channel < depth; ++channel) + { + const int in_x_origin = (out_x * stride_width) - params.padding_values.width; + const int in_y_origin = (out_y * stride_height) - params.padding_values.height; + // Compute the boundaries of the filter region clamped so as to + // ensure that the filter window fits in the input array. + const int filter_x_start = std::max(0, -in_x_origin); + const int filter_x_end = std::min(params.filter_width, input_width - in_x_origin); + const int filter_y_start = std::max(0, -in_y_origin); + const int filter_y_end = std::min(params.filter_height, input_height - in_y_origin); + + float total = 0.f; + float filter_count = 0; + + for (int filter_y = filter_y_start; filter_y < filter_y_end; ++filter_y) + { + for (int filter_x = filter_x_start; filter_x < filter_x_end; ++filter_x) + { + const int in_x = in_x_origin + filter_x; + const int in_y = in_y_origin + filter_y; + + const int input_data_offset = + ((batch * input_shape.dims(1) + in_y) * input_shape.dims(2) + in_x) * + input_shape.dims(3) + + channel; + + total += input_data[input_data_offset]; + filter_count++; + } + } + const int output_data_offset = + ((batch * output_shape.dims(1) + out_y) * output_shape.dims(2) + out_x) * + output_shape.dims(3) + + channel; + + assert(filter_count != 0); + const float average = total / filter_count; + + output_data[output_data_offset] = + std::min(std::max(average, params.float_activation_min), params.float_activation_max); + } + } + } + } +} +} // namespace luci_interpreter_pal + +#endif // LUCI_INTERPRETER_PAL_AVERAGE_POOL_2D_H diff --git a/onert-micro/luci-interpreter/pal/mcu/PALAveragePool2d.h b/onert-micro/luci-interpreter/pal/mcu/PALAveragePool2d.h deleted file mode 100644 index cce30601f7a..00000000000 --- a/onert-micro/luci-interpreter/pal/mcu/PALAveragePool2d.h +++ /dev/null @@ -1,73 +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_PAL_AVERAGEPOOL2D_H -#define LUCI_INTERPRETER_PAL_AVERAGEPOOL2D_H - -#include -#include - -namespace luci_interpreter_pal -{ -template -static inline void AveragePool(const tflite::PoolParams ¶ms, - const tflite::RuntimeShape &input_shape, const T *input_data, - const tflite::RuntimeShape &output_shape, T *output_data, - const tflite::RuntimeShape &scratchpad_shape, T *scratchpad_data) -{ - { - // MARK: At this moment this operation doesn't support - assert(false && "AveragePool NYI"); - (void)params; - (void)input_shape; - (void)input_data; - (void)output_shape; - (void)output_data; - (void)scratchpad_shape; - (void)scratchpad_data; - } -} - -template <> -inline void AveragePool(const tflite::PoolParams ¶ms, - const tflite::RuntimeShape &input_shape, const int8_t *input_data, - const tflite::RuntimeShape &output_shape, int8_t *output_data, - const tflite::RuntimeShape &scratchpad_shape, - int8_t *scratchpad_data) -{ - (void)scratchpad_shape; - (void)scratchpad_data; - - tflite::reference_integer_ops::AveragePool(params, input_shape, input_data, output_shape, - output_data); -} - -static inline void SetupScratchpadTensor(luci_interpreter::Tensor *scratchpad, - const luci_interpreter::DataType &input_data_type, - const tflite::RuntimeShape &input_shape, - const tflite::RuntimeShape &output_shape) - -{ - (void)input_data_type; - (void)input_shape; - (void)output_shape; - - scratchpad->set_allocatable(false); -} - -} // namespace luci_interpreter_pal - -#endif // LUCI_INTERPRETER_PAL_AVERAGEPOOL2D_H diff --git a/onert-micro/luci-interpreter/src/kernels/AveragePool2D.cpp b/onert-micro/luci-interpreter/src/kernels/AveragePool2D.cpp index 498334c27c6..ccdda8406e5 100644 --- a/onert-micro/luci-interpreter/src/kernels/AveragePool2D.cpp +++ b/onert-micro/luci-interpreter/src/kernels/AveragePool2D.cpp @@ -14,180 +14,87 @@ * limitations under the License. */ -#include "kernels/AveragePool2D.h" +#include "Builders.h" #include "kernels/Utils.h" - -#include "PALAveragePool2d.h" +#include "PALAveragePool2D.h" namespace luci_interpreter { -namespace kernels +// TODO: reduce code duplication with MaxPool2D +void configure_kernel_CircleAveragePool2D(const circle::Operator *cur_op, + BaseRuntimeGraph *runtime_graph) { + const auto input_index = cur_op->inputs()->operator[](0); + const auto output_index = cur_op->outputs()->operator[](0); -AveragePool2D::AveragePool2D(const Tensor *input, Tensor *output, Tensor *scratchpad, - const Pool2DParams ¶ms) - : KernelWithParams({input}, {output, scratchpad}, params) -{ -} + assert(input_index != -1); + assert(output_index != -1); -void AveragePool2D::configure() -{ - if (input()->element_type() != output()->element_type()) - { - assert(false && "Input Tensor and Output Tensor Type must be same"); - } - if (input()->shape().num_dims() != 4) - { - assert(false && "Input Tensor Shape must be 4-D"); - } - const Shape &input_shape = input()->shape(); - - const int32_t batches = input_shape.dim(0); - const int32_t input_height = input_shape.dim(1); - const int32_t input_width = input_shape.dim(2); - const int32_t depth = input_shape.dim(3); - - const int32_t output_height = - computeOutputSize(_params.padding, input_height, _params.filter_height, _params.stride_height); - const int32_t output_width = - computeOutputSize(_params.padding, input_width, _params.filter_width, _params.stride_width); - - _padding_height = - computePadding(_params.stride_height, 1, input_height, _params.filter_height, output_height); - _padding_width = - computePadding(_params.stride_width, 1, input_width, _params.filter_width, output_width); - if (input()->element_type() == DataType::U8) - { - LUCI_INTERPRETER_CHECK(std::abs(output()->scale() - input()->scale()) <= 1.0e-6); - LUCI_INTERPRETER_CHECK(output()->zero_point() == input()->zero_point()); - } - else if (input()->element_type() == DataType::S16) - { - LUCI_INTERPRETER_CHECK(std::abs(output()->scale() - input()->scale()) <= 1.0e-6); - LUCI_INTERPRETER_CHECK(input()->zero_point() == 0 && output()->zero_point() == 0); - } - else if (input()->element_type() == DataType::S8) - { - LUCI_INTERPRETER_CHECK(std::abs(output()->scale() - input()->scale()) <= 1.0e-6); - LUCI_INTERPRETER_CHECK(output()->zero_point() == input()->zero_point()); - } - // TODO: enable it only if kernel with dynamic shapes - output()->resize({batches, output_height, output_width, depth}); + const auto input = runtime_graph->getCircleTensorByIndex(input_index); + const auto output = runtime_graph->getCircleTensorByIndex(output_index); - auto scratchpad = getOutputTensors()[1]; - luci_interpreter_pal::SetupScratchpadTensor(scratchpad, input()->element_type(), - getTensorShape(input()), getTensorShape(output())); + LUCI_INTERPRETER_CHECK(Tensor::element_type(input) == Tensor::element_type(output)); + assert(Tensor::num_dims(input) == 4); } -void AveragePool2D::execute() const +void execute_kernel_CircleAveragePool2D(const circle::Operator *cur_op, + BaseRuntimeGraph *runtime_graph) { - switch (input()->element_type()) - { - case DataType::FLOAT32: - evalFloat(); - break; - case DataType::U8: - evalQuantized(); - break; - case DataType::S16: - evalSInt16(); - break; - case DataType::S8: - evalSInt8(); - break; - default: - assert(false && "Unsupported type."); - } -} + 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); + auto output = runtime_graph->getCircleTensorByIndex(output_index); + + const auto *options = cur_op->builtin_options_as_Pool2DOptions(); + + const int32_t input_height = Tensor::dim(input, 1); + const int32_t input_width = Tensor::dim(input, 2); + + const int32_t output_height = kernels::computeOutputSize( + luci_padding(options->padding()), input_height, options->filter_height(), options->stride_h()); + const int32_t output_width = kernels::computeOutputSize( + luci_padding(options->padding()), input_width, options->filter_width(), options->stride_w()); + + const auto padding_height = kernels::computePadding(options->stride_h(), 1, input_height, + options->filter_height(), output_height); + const auto padding_width = kernels::computePadding(options->stride_w(), 1, input_width, + options->filter_width(), output_width); + + const auto *input_data = runtime_graph->getDataByTensor(input); + auto *output_data = runtime_graph->getDataByTensor(output); -void AveragePool2D::evalFloat() const -{ float activation_min{}; float activation_max{}; - calculateActivationRange(_params.activation, &activation_min, &activation_max); - - tflite::PoolParams params{}; - params.padding_values.height = _padding_height; - params.padding_values.width = _padding_width; - params.stride_height = _params.stride_height; - params.stride_width = _params.stride_width; - params.filter_height = _params.filter_height; - params.filter_width = _params.filter_width; + kernels::calculateActivationRange(luci_actfunc(options->fused_activation_function()), + &activation_min, &activation_max); + luci_interpreter_pal::PoolParams params{}; + params.padding_values.height = padding_height; + params.padding_values.width = padding_width; + params.stride_height = options->stride_h(); + params.stride_width = options->stride_w(); + params.filter_height = options->filter_height(); + params.filter_width = options->filter_width(); params.float_activation_min = activation_min; params.float_activation_max = activation_max; - tflite::reference_ops::AveragePool(params, getTensorShape(input()), getTensorData(input()), - getTensorShape(output()), getTensorData(output())); -} - -void AveragePool2D::evalQuantized() const -{ - int32_t activation_min{}; - int32_t activation_max{}; - calculateActivationRangeQuantized(_params.activation, output(), &activation_min, &activation_max); - - tflite::PoolParams params{}; - params.padding_values.height = _padding_height; - params.padding_values.width = _padding_width; - params.stride_height = _params.stride_height; - params.stride_width = _params.stride_width; - params.filter_height = _params.filter_height; - params.filter_width = _params.filter_width; - params.quantized_activation_min = activation_min; - params.quantized_activation_max = activation_max; - - tflite::reference_ops::AveragePool(params, getTensorShape(input()), - getTensorData(input()), getTensorShape(output()), - getTensorData(output())); -} - -void AveragePool2D::evalSInt8() const -{ - int32_t activation_min{}; - int32_t activation_max{}; - calculateActivationRangeQuantized(_params.activation, output(), &activation_min, &activation_max); - tflite::PoolParams params{}; - params.padding_values.height = _padding_height; - params.padding_values.width = _padding_width; - params.stride_height = _params.stride_height; - params.stride_width = _params.stride_width; - params.filter_height = _params.filter_height; - params.filter_width = _params.filter_width; - params.quantized_activation_min = activation_min; - params.quantized_activation_max = activation_max; - - auto scratchpad = getOutputTensors()[1]; - int8_t *scratchpad_data = nullptr; - if (scratchpad->is_allocatable()) - scratchpad_data = scratchpad->data(); - - luci_interpreter_pal::AveragePool( - params, getTensorShape(input()), getTensorData(input()), getTensorShape(output()), - getTensorData(output()), getTensorShape(scratchpad), scratchpad_data); -} - -void AveragePool2D::evalSInt16() const -{ - int32_t activation_min{}; - int32_t activation_max{}; - calculateActivationRangeQuantized(_params.activation, output(), &activation_min, &activation_max); - - tflite::PoolParams params{}; - params.padding_values.height = _padding_height; - params.padding_values.width = _padding_width; - params.stride_height = _params.stride_height; - params.stride_width = _params.stride_width; - params.filter_height = _params.filter_height; - params.filter_width = _params.filter_width; - params.quantized_activation_min = activation_min; - params.quantized_activation_max = activation_max; - - tflite::reference_integer_ops::AveragePool( - params, getTensorShape(input()), getTensorData(input()), // - getTensorShape(output()), getTensorData(output())); + switch (Tensor::element_type(input)) + { +#ifndef DIS_FLOAT + case DataType::FLOAT32: + luci_interpreter_pal::AveragePool( + params, kernels::getTensorShape(input), kernels::getTensorData(input_data), + kernels::getTensorShape(output), kernels::getTensorData(output_data)); + break; +#endif // DIS_FLOAT + default: + assert(false && "Unsupported type."); + } } -} // namespace kernels } // namespace luci_interpreter diff --git a/onert-micro/luci-interpreter/src/kernels/AveragePool2D.h b/onert-micro/luci-interpreter/src/kernels/AveragePool2D.h deleted file mode 100644 index 2c8fe16e764..00000000000 --- a/onert-micro/luci-interpreter/src/kernels/AveragePool2D.h +++ /dev/null @@ -1,54 +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_AVERAGEPOOL2D_H -#define LUCI_INTERPRETER_KERNELS_AVERAGEPOOL2D_H - -#include "core/Kernel.h" -#include "core/KernelParams.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class AveragePool2D : public KernelWithParams -{ -public: - AveragePool2D(const Tensor *input, Tensor *output, Tensor *scratchpad, - const Pool2DParams ¶ms); - - 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; - void evalSInt16() const; - void evalSInt8() const; - -private: - int32_t _padding_height{}; - int32_t _padding_width{}; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_AVERAGEPOOL2D_H diff --git a/onert-micro/luci-interpreter/src/kernels/AveragePool2D.test.cpp b/onert-micro/luci-interpreter/src/kernels/AveragePool2D.test.cpp index 478bfa68ecb..6bc32645351 100644 --- a/onert-micro/luci-interpreter/src/kernels/AveragePool2D.test.cpp +++ b/onert-micro/luci-interpreter/src/kernels/AveragePool2D.test.cpp @@ -14,14 +14,14 @@ * limitations under the License. */ -#include "kernels/AveragePool2D.h" #include "kernels/TestUtils.h" -#include "luci_interpreter/TestMemoryManager.h" +#include "luci_interpreter/test_models/average_pool_2d/FloatAveragePool2DKernel.h" +#include "luci_interpreter/test_models/average_pool_2d/NegAveragePool2DKernel.h" + +#include "loader/ModuleLoader.h" namespace luci_interpreter { -namespace kernels -{ namespace { @@ -29,255 +29,60 @@ using namespace testing; class AveragePool2DTest : public ::testing::Test { -protected: - void SetUp() override { _memory_manager = std::make_unique(); } - - std::unique_ptr _memory_manager; + // Do nothing }; -TEST_F(AveragePool2DTest, Float) -{ - Shape input_shape{1, 3, 5, 1}; - std::vector input_data{ - -4, -3, -2, -1, 0, // - 1, 2, 3, 4, 5, // - 6, 7, 8, 9, 10, // - }; - Tensor input_tensor = - makeInputTensor(input_shape, input_data, _memory_manager.get()); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - Tensor scratchpad(DataType::FLOAT32, Shape({}), {}, ""); - - Pool2DParams params{}; - params.padding = Padding::VALID; - params.filter_height = 2; - params.filter_width = 3; - params.stride_height = 1; - params.stride_width = 2; - params.activation = Activation::RELU6; - - AveragePool2D kernel(&input_tensor, &output_tensor, &scratchpad, params); - kernel.configure(); - _memory_manager->allocate_memory(scratchpad); - _memory_manager->allocate_memory(output_tensor); - kernel.execute(); - - std::vector ref_output_data{ - 0, 1.5, // - 4.5, 6, // - }; - EXPECT_THAT(extractTensorData(output_tensor), FloatArrayNear(ref_output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({1, 2, 2, 1})); -} - -TEST_F(AveragePool2DTest, Uint8_0) -{ - std::vector input_data{ - 0, -6, 12, 4, // - -3, -2, 10, 7, // - }; - std::pair quant_param = quantizationParams(-15.9375f, 15.9375f); - Tensor input_tensor = makeInputTensor( - {1, 2, 4, 1}, quant_param.first, quant_param.second, input_data, _memory_manager.get()); - Tensor output_tensor = makeOutputTensor(DataType::U8, quant_param.first, quant_param.second); - Tensor scratchpad(DataType::U8, Shape({}), {}, ""); - - Pool2DParams params{}; - params.padding = Padding::VALID; - params.filter_height = 2; - params.filter_width = 2; - params.stride_height = 2; - params.stride_width = 2; - params.activation = Activation::RELU6; - - AveragePool2D kernel(&input_tensor, &output_tensor, &scratchpad, params); - kernel.configure(); - _memory_manager->allocate_memory(scratchpad); - _memory_manager->allocate_memory(output_tensor); - kernel.execute(); - - EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear({0.0, 6.0})); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({1, 1, 2, 1})); -} - -TEST_F(AveragePool2DTest, Uint8_1) -{ - std::vector input_data{ - 0, 6, 12, 4, // - 3, 2, 10, 7, // - }; - - std::pair quant_param = quantizationParams(-15.9375f, 15.9375f); - Tensor input_tensor = makeInputTensor( - {1, 2, 4, 1}, quant_param.first, quant_param.second, input_data, _memory_manager.get()); - Tensor output_tensor = makeOutputTensor(DataType::U8, quant_param.first, quant_param.second); - Tensor scratchpad(DataType::U8, Shape({}), {}, ""); - - Pool2DParams params{}; - params.padding = Padding::VALID; - params.filter_height = 2; - params.filter_width = 2; - params.stride_height = 2; - params.stride_width = 2; - params.activation = Activation::RELU6; - - AveragePool2D kernel(&input_tensor, &output_tensor, &scratchpad, params); - kernel.configure(); - _memory_manager->allocate_memory(output_tensor); - _memory_manager->allocate_memory(scratchpad); - kernel.execute(); - - EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear({2.75, 6.0})); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({1, 1, 2, 1})); -} - -TEST_F(AveragePool2DTest, SInt16) -{ - Shape input_shape{1, 3, 5, 1}; - std::vector ref_output_shape{1, 2, 2, 1}; - std::vector input_data{ - -4, -3, -2, -1, 0, // - 1, 2, 3, 4, 5, // - 6, 7, 8, 9, 10, // - }; - std::vector ref_output_data{ - 0, 1.5, // - 4.5, 6, // - }; - Tensor input_tensor = - makeInputTensor(input_shape, 0.5, 0, input_data, _memory_manager.get()); - Tensor output_tensor = makeOutputTensor(DataType::S16, 0.5, 0); - Tensor scratchpad(DataType::S16, Shape({}), {}, ""); - - Pool2DParams params{}; - params.padding = Padding::VALID; - params.filter_height = 2; - params.filter_width = 3; - params.stride_height = 1; - params.stride_width = 2; - params.activation = Activation::RELU6; - - AveragePool2D kernel(&input_tensor, &output_tensor, &scratchpad, params); - kernel.configure(); - _memory_manager->allocate_memory(scratchpad); - _memory_manager->allocate_memory(output_tensor); - kernel.execute(); - - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape)); - EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data)); -} - -TEST_F(AveragePool2DTest, SInt8) +template +std::vector checkAveragePool2DKernel(test_kernel::TestDataBase *test_data_base) { - Shape input_shape{1, 4, 5, 1}; - std::vector ref_output_shape{1, 2, 2, 1}; - std::vector input_data{-7, -3, 0, 2, -5, 12, -15, 3, 10, 5, - 7, -6, -1, 9, -2, 0, -5, 11, -1, -7}; - std::vector ref_output_data{ - 0, 2.5, // - 1, 1.5, // - }; + MemoryManager memory_manager{}; + RuntimeModule runtime_module{}; + bool dealloc_input = true; - std::pair quant_param = quantizationParams(-15.9375f, 15.9375f); - Tensor input_tensor = makeInputTensor( - input_shape, quant_param.first, quant_param.second, input_data, _memory_manager.get()); - Tensor output_tensor = makeOutputTensor(DataType::S8, quant_param.first, quant_param.second); - Tensor scratchpad(DataType::S8, Shape({}), {}, ""); + // 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); - Pool2DParams params{}; - params.padding = Padding::VALID; - params.filter_height = 2; - params.filter_width = 3; - params.stride_height = 2; - params.stride_width = 2; - params.activation = Activation::RELU6; + auto *main_runtime_graph = runtime_module.getMainGraph(); + assert(main_runtime_graph->getNumOfInputTensors() == 1); - AveragePool2D kernel(&input_tensor, &output_tensor, &scratchpad, params); - kernel.configure(); - _memory_manager->allocate_memory(scratchpad); - _memory_manager->allocate_memory(output_tensor); - kernel.execute(); + // 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); + } - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape)); - EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data)); -} + runtime_module.execute(); -TEST_F(AveragePool2DTest, Invalid_Input_Shape_NEG) -{ - Shape input_shape{1, 3, 5}; - std::vector input_data{ - -4, -3, -2, -1, 0, // - 1, 2, 3, 4, 5, // - 6, 7, 8, 9, 10, // - }; - Tensor input_tensor = - makeInputTensor(input_shape, input_data, _memory_manager.get()); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - Tensor scratchpad(DataType::FLOAT32, Shape({}), {}, ""); + assert(main_runtime_graph->getNumOfOutputTensors() == 1); - Pool2DParams params{}; - params.padding = Padding::VALID; - params.filter_height = 2; - params.filter_width = 3; - params.stride_height = 1; - params.stride_width = 2; - params.activation = Activation::RELU6; - - AveragePool2D kernel(&input_tensor, &output_tensor, &scratchpad, params); - EXPECT_ANY_THROW(kernel.configure()); + 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(AveragePool2DTest, In_Out_Type_NEG) +TEST_F(AveragePool2DTest, Float_P) { - Shape input_shape{1, 3, 5, 1}; - std::vector input_data{ - -4, -3, -2, -1, 0, // - 1, 2, 3, 4, 5, // - 6, 7, 8, 9, 10, // - }; - Tensor input_tensor = - makeInputTensor(input_shape, input_data, _memory_manager.get()); - Tensor output_tensor = makeOutputTensor(DataType::U8); - Tensor scratchpad(DataType::FLOAT32, Shape({}), {}, ""); - - Pool2DParams params{}; - params.padding = Padding::VALID; - params.filter_height = 2; - params.filter_width = 3; - params.stride_height = 1; - params.stride_width = 2; - params.activation = Activation::RELU6; - - AveragePool2D kernel(&input_tensor, &output_tensor, &scratchpad, params); - EXPECT_ANY_THROW(kernel.configure()); + test_kernel::TestDataFloatAveragePool2D test_data_kernel; + std::vector output_data_vector = checkAveragePool2DKernel(&test_data_kernel); + EXPECT_THAT(output_data_vector, kernels::testing::FloatArrayNear( + test_data_kernel.get_output_data_by_index(0), 0.001f)); } -TEST_F(AveragePool2DTest, Quant_Param_NEG) +TEST_F(AveragePool2DTest, InputOutputTypeMismatch_NEG) { - std::vector input_data{ - 0, -6, 12, 4, // - -3, -2, 10, 7, // - }; - - std::pair quant_param1 = quantizationParams(-15.9375f, 15.9375f); - std::pair quant_param2 = quantizationParams(-7.875f, 7.875f); - Tensor input_tensor = makeInputTensor( - {1, 2, 4, 1}, quant_param1.first, quant_param1.second, input_data, _memory_manager.get()); - Tensor output_tensor = makeOutputTensor(DataType::U8, quant_param2.first, quant_param2.second); - Tensor scratchpad(DataType::U8, Shape({}), {}, ""); - - Pool2DParams params{}; - params.padding = Padding::VALID; - params.filter_height = 2; - params.filter_width = 2; - params.stride_height = 2; - params.stride_width = 2; - params.activation = Activation::RELU6; - - AveragePool2D kernel(&input_tensor, &output_tensor, &scratchpad, params); - EXPECT_ANY_THROW(kernel.configure()); + test_kernel::NegTestDataInputOutputTypeMismatchAveragePool2DKernel 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