From 242662c191b5e32deb3ded22337a0fd5b465cf47 Mon Sep 17 00:00:00 2001 From: Artem Balyshev Date: Wed, 20 Sep 2023 15:42:29 +0300 Subject: [PATCH] [onert-micro] Add float TransposeConv kernel This commit adds float TransposeConv kernel. ONE-DCO-1.0-Signed-off-by: Artem Balyshev --- .../test_models/conv2d/NegConv2DKernel.h | 8 +- .../transpose_conv/FloatTransposeConvKernel.h | 107 +++++ .../transpose_conv/NegTransposeConvKernel.h | 174 +++++++ .../TestDataTransposeConvBase.h | 60 +++ .../pal/common/PALTransposeConv.h | 127 ++++++ .../luci-interpreter/pal/common/PALUtils.h | 18 + .../pal/mcu/KernelsToBuild.lst | 1 + .../src/kernels/Conv2D.test.cpp | 4 +- .../src/kernels/TransposeConv.cpp | 430 ++++++------------ .../src/kernels/TransposeConv.h | 65 --- .../src/kernels/TransposeConv.test.cpp | 358 +++------------ 11 files changed, 673 insertions(+), 679 deletions(-) create mode 100644 onert-micro/luci-interpreter/include/luci_interpreter/test_models/transpose_conv/FloatTransposeConvKernel.h create mode 100644 onert-micro/luci-interpreter/include/luci_interpreter/test_models/transpose_conv/NegTransposeConvKernel.h create mode 100644 onert-micro/luci-interpreter/include/luci_interpreter/test_models/transpose_conv/TestDataTransposeConvBase.h create mode 100644 onert-micro/luci-interpreter/pal/common/PALTransposeConv.h delete mode 100644 onert-micro/luci-interpreter/src/kernels/TransposeConv.h diff --git a/onert-micro/luci-interpreter/include/luci_interpreter/test_models/conv2d/NegConv2DKernel.h b/onert-micro/luci-interpreter/include/luci_interpreter/test_models/conv2d/NegConv2DKernel.h index 52baf89db20..25a199099fd 100644 --- a/onert-micro/luci-interpreter/include/luci_interpreter/test_models/conv2d/NegConv2DKernel.h +++ b/onert-micro/luci-interpreter/include/luci_interpreter/test_models/conv2d/NegConv2DKernel.h @@ -209,15 +209,15 @@ class NegTestDataWrongBiasTypeConv2DKernel : public NegTestDataBase const unsigned char *_test_kernel_model_circle; }; -class NegTestDataInvalidInputTypeConv2DKernel : public NegTestDataBase +class NegTestDataInvalidInputShapeConv2DKernel : public NegTestDataBase { public: - NegTestDataInvalidInputTypeConv2DKernel() + NegTestDataInvalidInputShapeConv2DKernel() { - _test_kernel_model_circle = neg_conv2d_bias_wrong_type::test_kernel_model_circle; + _test_kernel_model_circle = neg_conv2d_invalid_input_shape::test_kernel_model_circle; } - ~NegTestDataInvalidInputTypeConv2DKernel() override = default; + ~NegTestDataInvalidInputShapeConv2DKernel() override = default; const unsigned char *get_model_ptr() override final { return _test_kernel_model_circle; } diff --git a/onert-micro/luci-interpreter/include/luci_interpreter/test_models/transpose_conv/FloatTransposeConvKernel.h b/onert-micro/luci-interpreter/include/luci_interpreter/test_models/transpose_conv/FloatTransposeConvKernel.h new file mode 100644 index 00000000000..a74a1a4fb32 --- /dev/null +++ b/onert-micro/luci-interpreter/include/luci_interpreter/test_models/transpose_conv/FloatTransposeConvKernel.h @@ -0,0 +1,107 @@ +/* + * 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_TRANSPOSE_CONV_KERNEL_H +#define LUCI_INTERPRETER_TEST_MODELS_FLOAT_TRANSPOSE_CONV_KERNEL_H + +#include "TestDataTransposeConvBase.h" + +namespace luci_interpreter +{ +namespace test_kernel +{ +namespace transpose_conv_float +{ +/* + * TransposeConv Kernel: + * + * Input(1, 4, 4, 2) Weights(1, 3, 3, 2) + * | | + * TransposeConv + * | + * Output(1, 4, 4, 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, + 0xac, 0x00, 0x00, 0x00, 0x2c, 0x02, 0x00, 0x00, 0x48, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x98, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0xaa, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0xc0, 0x00, 0x00, 0x80, 0xc0, + 0x00, 0x00, 0xa0, 0x40, 0x00, 0x00, 0xc0, 0xc0, 0x00, 0x00, 0xe0, 0x40, 0x00, 0x00, 0x00, 0x41, + 0x00, 0x00, 0x10, 0xc1, 0x00, 0x00, 0x20, 0xc1, 0x00, 0x00, 0x30, 0x41, 0x00, 0x00, 0x40, 0xc1, + 0x00, 0x00, 0x50, 0x41, 0x00, 0x00, 0x60, 0x41, 0x00, 0x00, 0x70, 0xc1, 0x00, 0x00, 0x80, 0xc1, + 0x00, 0x00, 0x88, 0x41, 0x00, 0x00, 0x90, 0xc1, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 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, + 0x74, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x7c, 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, 0x31, 0x18, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x34, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xa8, 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, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0xd4, 0xff, 0xff, 0xff, 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, 0x04, 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, 0x04, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x6b, 0x65, 0x72, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x03, 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, 0x14, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x6f, 0x75, 0x74, 0x5f, + 0x73, 0x68, 0x61, 0x70, 0x65, 0x00, 0x00, 0x00, 0x01, 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, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, + 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 = { + 9.050506, 24.50502, -2.1620092, -10.667578, -6.026517, 0.45524502, -9.493163, 11.918655, + 0.89637375, 4.3721895, 15.263344, 4.124815, -0.085579395, 12.434898, 8.761413, -0.016460419, + 14.467015, 7.194871, 8.063942, -1.125905, -3.0618992, 7.227646, 9.65494, -7.4324093, + 1.7922368, 2.179245, 2.5192776, -8.438859, 5.4460173, 3.9627461, 5.714366, -0.14670324}; +const std::vector reference_output_data = { + -423.64435, -166.1708, 193.6256, -206.75839, -683.60583, -257.56488, 359.98495, -445.70508, + -10.393387, -102.10723, 203.30502, -502.5265, -330.8531, 199.97214, 188.26364, -245.66447}; + +} // namespace transpose_conv_float + +class TestDataFloatTransposeConv : public TestDataTransposeConvBase +{ +public: + TestDataFloatTransposeConv() + { + _input_data = transpose_conv_float::input_data; + _reference_output_data = transpose_conv_float::reference_output_data; + _test_kernel_model_circle = transpose_conv_float::test_kernel_model_circle; + } + + ~TestDataFloatTransposeConv() override = default; +}; + +} // namespace test_kernel +} // namespace luci_interpreter + +#endif // LUCI_INTERPRETER_TEST_MODELS_FLOAT_TRANSPOSE_CONV_KERNEL_H diff --git a/onert-micro/luci-interpreter/include/luci_interpreter/test_models/transpose_conv/NegTransposeConvKernel.h b/onert-micro/luci-interpreter/include/luci_interpreter/test_models/transpose_conv/NegTransposeConvKernel.h new file mode 100644 index 00000000000..b2d85e8edb6 --- /dev/null +++ b/onert-micro/luci-interpreter/include/luci_interpreter/test_models/transpose_conv/NegTransposeConvKernel.h @@ -0,0 +1,174 @@ +/* + * 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_TRANSPOSE_CONV_KERNEL_H +#define LUCI_INTERPRETER_TEST_MODELS_NEG_TRANSPOSE_CONV_KERNEL_H + +#include "TestDataTransposeConvBase.h" + +namespace luci_interpreter +{ +namespace test_kernel +{ +namespace neg_transpose_conv_input_type_mismatch +{ + +/* + * TransposeConv Kernel with input type mismatch (input_type should be equal to weight_type): + * + * Input(1, 4, 4, 2) - Float32 Weight(1, 3, 3, 2) - Int32 + * \ / + * \ / + * TransposeConv + * | + * Output(1, 4, 4, 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, + 0xac, 0x00, 0x00, 0x00, 0x30, 0x02, 0x00, 0x00, 0x4c, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x98, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0xaa, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, + 0x05, 0x00, 0x00, 0x00, 0xfa, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0xf7, 0xff, 0xff, 0xff, 0xf6, 0xff, 0xff, 0xff, 0x0b, 0x00, 0x00, 0x00, 0xf4, 0xff, 0xff, 0xff, + 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0xf1, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, + 0x11, 0x00, 0x00, 0x00, 0xee, 0xff, 0xff, 0xff, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 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, + 0x74, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x7c, 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, 0x31, 0x18, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x70, 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, 0x04, 0x00, 0x00, 0x00, 0x04, 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, + 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xd0, 0xff, 0xff, 0xff, + 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0c, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x6b, 0x65, 0x72, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x03, 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, 0x14, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x6f, 0x75, 0x74, 0x5f, 0x73, 0x68, 0x61, 0x70, 0x65, 0x00, 0x00, 0x00, 0x01, 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, 0x43, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x43, 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_transpose_conv_input_type_mismatch + +namespace neg_transpose_conv_invalid_input_shape +{ +/* + * TransposeConv Kernel with input type mismatch (input_type should be equal to weight_type): + * + * Input(1, 1, 4, 4, 2) - Float32 Weight(1, 3, 3, 2) - Float32 + * \ / + * \ / + * TransposeConv + * | + * Output(1, 4, 4, 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, + 0xac, 0x00, 0x00, 0x00, 0x30, 0x02, 0x00, 0x00, 0x4c, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x98, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0xaa, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0xc0, 0x00, 0x00, 0x80, 0xc0, + 0x00, 0x00, 0xa0, 0x40, 0x00, 0x00, 0xc0, 0xc0, 0x00, 0x00, 0xe0, 0x40, 0x00, 0x00, 0x00, 0x41, + 0x00, 0x00, 0x10, 0xc1, 0x00, 0x00, 0x20, 0xc1, 0x00, 0x00, 0x30, 0x41, 0x00, 0x00, 0x40, 0xc1, + 0x00, 0x00, 0x50, 0x41, 0x00, 0x00, 0x60, 0x41, 0x00, 0x00, 0x70, 0xc1, 0x00, 0x00, 0x80, 0xc1, + 0x00, 0x00, 0x88, 0x41, 0x00, 0x00, 0x90, 0xc1, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 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, + 0x74, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x7c, 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, 0x31, 0x18, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, + 0x34, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xa4, 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, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0xd0, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x69, 0x66, 0x6d, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 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, 0x04, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x6b, 0x65, 0x72, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x03, 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, 0x14, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x6f, 0x75, 0x74, 0x5f, 0x73, 0x68, 0x61, 0x70, 0x65, 0x00, 0x00, 0x00, 0x01, 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, 0x43, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x43, 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_transpose_conv_invalid_input_shape + +class NegTestDataInputMismatchTransposeConvKernel : public NegTestDataBase +{ +public: + NegTestDataInputMismatchTransposeConvKernel() + { + _test_kernel_model_circle = neg_transpose_conv_input_type_mismatch::test_kernel_model_circle; + } + + ~NegTestDataInputMismatchTransposeConvKernel() override = default; + + const unsigned char *get_model_ptr() override final { return _test_kernel_model_circle; } + +protected: + const unsigned char *_test_kernel_model_circle; +}; + +class NegTestDataInvalidInputShapeTransposeConvKernel : public NegTestDataBase +{ +public: + NegTestDataInvalidInputShapeTransposeConvKernel() + { + _test_kernel_model_circle = neg_transpose_conv_invalid_input_shape::test_kernel_model_circle; + } + + ~NegTestDataInvalidInputShapeTransposeConvKernel() 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_TRANSPOSE_CONV_KERNEL_H diff --git a/onert-micro/luci-interpreter/include/luci_interpreter/test_models/transpose_conv/TestDataTransposeConvBase.h b/onert-micro/luci-interpreter/include/luci_interpreter/test_models/transpose_conv/TestDataTransposeConvBase.h new file mode 100644 index 00000000000..504fa80effa --- /dev/null +++ b/onert-micro/luci-interpreter/include/luci_interpreter/test_models/transpose_conv/TestDataTransposeConvBase.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_TRANSPOSE_CONV_KERNEL_BASE_H +#define LUCI_INTERPRETER_TEST_MODELS_TRANSPOSE_CONV_KERNEL_BASE_H + +#include "luci_interpreter/test_models/TestDataBase.h" + +namespace luci_interpreter +{ +namespace test_kernel +{ + +template class TestDataTransposeConvBase : public TestDataBase +{ +public: + TestDataTransposeConvBase() = 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_TRANSPOSE_CONV_KERNEL_BASE_H diff --git a/onert-micro/luci-interpreter/pal/common/PALTransposeConv.h b/onert-micro/luci-interpreter/pal/common/PALTransposeConv.h new file mode 100644 index 00000000000..7aad34ed879 --- /dev/null +++ b/onert-micro/luci-interpreter/pal/common/PALTransposeConv.h @@ -0,0 +1,127 @@ +/* + * 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_TRANSPOSE_CONV_H +#define LUCI_INTERPRETER_PAL_TRANSPOSE_CONV_H + +#include "PALUtils.h" + +namespace luci_interpreter_pal +{ + +inline void TransposeConv(const ConvParams ¶ms, + const luci_interpreter::RuntimeShape &input_shape, + const float *input_data, + const luci_interpreter::RuntimeShape &filter_shape, + const float *filter_data, + const luci_interpreter::RuntimeShape &bias_shape, const float *bias_data, + const luci_interpreter::RuntimeShape &output_shape, float *output_data) +{ + const int stride_width = params.stride_width; + const int stride_height = params.stride_height; + const int pad_width = params.padding_values.width; + const int pad_height = params.padding_values.height; + + const int batches = input_shape.dims(0); + const int input_depth = input_shape.dims(3); + const int output_depth = filter_shape.dims(0); + const int input_height = input_shape.dims(1); + const int input_width = input_shape.dims(2); + const int filter_height = filter_shape.dims(1); + const int filter_width = filter_shape.dims(2); + const int output_height = output_shape.dims(1); + const int output_width = output_shape.dims(2); + const float output_activation_min = params.float_activation_min; + const float output_activation_max = params.float_activation_max; + + // Although transpose convolution simplifies to convolution with transposed + // weights for strides of 1, non-unitary striding complicates matters. To + // keep this reference implementation as clear as possible, we use a + // "scatter" access pattern, where we loop through all the input elements, + // computing their influence on the output, rather than looping through the + // output elements in the typical "gather" access pattern of a conv. We + // therefore must initialize the output array to zero. + const int num_elements = output_shape.flatSize(); + for (int i = 0; i < num_elements; i++) + { + output_data[i] = 0.0f; + } + + // Loop through input elements one at a time. + for (int batch = 0; batch < batches; ++batch) + { + for (int in_y = 0; in_y < input_height; ++in_y) + { + for (int in_x = 0; in_x < input_width; ++in_x) + { + for (int in_channel = 0; in_channel < input_depth; ++in_channel) + { + // Loop through the output elements it will influence + const int out_x_origin = (in_x * stride_width) - pad_width; + const int out_y_origin = (in_y * stride_height) - pad_height; + for (int filter_y = 0; filter_y < filter_height; ++filter_y) + { + for (int filter_x = 0; filter_x < filter_width; ++filter_x) + { + for (int out_channel = 0; out_channel < output_depth; ++out_channel) + { + // Compute output element location + const int out_x = out_x_origin + filter_x; + const int out_y = out_y_origin + filter_y; + // We cannot accumulate out of bounds + if ((out_x >= 0) && (out_x < output_width) && (out_y >= 0) && + (out_y < output_height)) + { + float input_value = + input_data[offset(input_shape.dimsData(), batch, in_y, in_x, in_channel)]; + float filter_value = filter_data[offset(filter_shape.dimsData(), out_channel, + filter_y, filter_x, in_channel)]; + output_data[offset(output_shape.dimsData(), batch, out_y, out_x, out_channel)] += + input_value * filter_value; + } + } + } + } + } + } + } + } + + 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 out_channel = 0; out_channel < output_depth; ++out_channel) + { + float acc = + output_data[offset(output_shape.dimsData(), batch, out_y, out_x, out_channel)]; + if (bias_data) + acc += bias_data[out_channel]; + + output_data[offset(output_shape.dimsData(), batch, out_y, out_x, out_channel)] = + activationFunctionWithMinMax(acc, output_activation_min, output_activation_max); + } + } + } + } +} + +} // namespace luci_interpreter_pal + +#endif // LUCI_INTERPRETER_PAL_TRANSPOSE_CONV_H diff --git a/onert-micro/luci-interpreter/pal/common/PALUtils.h b/onert-micro/luci-interpreter/pal/common/PALUtils.h index 1e05bfc7b06..7205bc2c6b7 100644 --- a/onert-micro/luci-interpreter/pal/common/PALUtils.h +++ b/onert-micro/luci-interpreter/pal/common/PALUtils.h @@ -177,6 +177,24 @@ inline int MatchingDim(const luci_interpreter::RuntimeShape &shape1, int index1, return shape1.dims(index1); } +inline int offset(const int32_t *dims_data, int i0, int i1, int i2, int i3) +{ + return ((i0 * dims_data[1] + i1) * dims_data[2] + i2) * dims_data[3] + i3; +} + +inline int offset(const int32_t *dims_data, int i0, int i1, int i2, int i3, int i4) +{ + return (((i0 * dims_data[1] + i1) * dims_data[2] + i2) * dims_data[3] + i3) * dims_data[4] + i4; +} + +template +inline T activationFunctionWithMinMax(T x, T output_activation_min, T output_activation_max) +{ + using std::max; + using std::min; + return min(max(x, output_activation_min), output_activation_max); +} + } // namespace luci_interpreter_pal #endif // LUCI_INTERPRETER_PAL_UTILS_H diff --git a/onert-micro/luci-interpreter/pal/mcu/KernelsToBuild.lst b/onert-micro/luci-interpreter/pal/mcu/KernelsToBuild.lst index 42883192ebe..4b15b65b6b8 100644 --- a/onert-micro/luci-interpreter/pal/mcu/KernelsToBuild.lst +++ b/onert-micro/luci-interpreter/pal/mcu/KernelsToBuild.lst @@ -40,6 +40,7 @@ REGISTER_KERNEL(STRIDED_SLICE, StridedSlice) REGISTER_KERNEL(SPLIT_V, SplitV) REGISTER_KERNEL(TANH, Tanh) REGISTER_KERNEL(TRANSPOSE, Transpose) +REGISTER_KERNEL(TRANSPOSE_CONV, TransposeConv) REGISTER_KERNEL(SOFTMAX, Softmax) REGISTER_KERNEL(WHILE, While) REGISTER_KERNEL(UNIDIRECTIONAL_SEQUENCE_LSTM, UnidirectionalSequenceLSTM) diff --git a/onert-micro/luci-interpreter/src/kernels/Conv2D.test.cpp b/onert-micro/luci-interpreter/src/kernels/Conv2D.test.cpp index c373bd28f12..d05bd0a2cad 100644 --- a/onert-micro/luci-interpreter/src/kernels/Conv2D.test.cpp +++ b/onert-micro/luci-interpreter/src/kernels/Conv2D.test.cpp @@ -104,9 +104,9 @@ TEST_F(Conv2DTest, Wrong_bias_type_NEG) ""); } -TEST_F(Conv2DTest, Invalid_input_type_NEG) +TEST_F(Conv2DTest, Invalid_input_shape_NEG) { - test_kernel::NegTestDataInvalidInputTypeConv2DKernel test_data_kernel; + test_kernel::NegTestDataInvalidInputShapeConv2DKernel test_data_kernel; MemoryManager memory_manager{}; RuntimeModule runtime_module{}; diff --git a/onert-micro/luci-interpreter/src/kernels/TransposeConv.cpp b/onert-micro/luci-interpreter/src/kernels/TransposeConv.cpp index f8483ea361a..82c6aef03f2 100644 --- a/onert-micro/luci-interpreter/src/kernels/TransposeConv.cpp +++ b/onert-micro/luci-interpreter/src/kernels/TransposeConv.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * Copyright 2017 The TensorFlow Authors. 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. @@ -15,337 +15,161 @@ * limitations under the License. */ -#include "kernels/TransposeConv.h" - +#include "Builders.h" #include "kernels/Utils.h" -#include +#include "PALTransposeConv.h" namespace luci_interpreter { -namespace kernels +namespace { -TransposeConv::TransposeConv(const Tensor *output_shape, const Tensor *filter, const Tensor *input, - const Tensor *bias, Tensor *output, Tensor *scratch_tensor, - const TransposeConvParams ¶ms) - : KernelWithParams({output_shape, filter, input, bias}, - {output, scratch_tensor}, params) +// For the TfLite transpose_conv implementation, input tensor 0 corresponds to +// the OutputShapeTensor. However, since TFLM does not support dynamic tensors, +// the TFLM implementation ignores input tensor 0 and the only inputs we care +// about are kFilterTensor, kInputTensor and kBiasTensor. +constexpr int kFilterTensor = 1; +constexpr int kInputTensor = 2; +constexpr int kBiasTensor = 3; +constexpr int kOutputTensor = 0; + +// TODO: reduce code duplication with Conv +int32_t compute_padding_h(const circle::Tensor *input, const circle::Tensor *filter, + const circle::TransposeConvOptions *options) { + // Note: Dilation height and width are always 1 for transpose_conv + const int32_t input_height = Tensor::dim(input, 1); + const int32_t filter_height = Tensor::dim(filter, 1); + const int32_t output_height = kernels::computeOutputSize( + luci_padding(options->padding()), input_height, filter_height, options->stride_h(), 1); + + const auto padding_height = + kernels::computePadding(options->stride_h(), 1, input_height, filter_height, output_height); + return padding_height; } -TransposeConv::~TransposeConv() +int32_t compute_padding_w(const circle::Tensor *input, const circle::Tensor *filter, + const circle::TransposeConvOptions *options) { - // Define destructor here, to delete vector of qunatized multipliers properly -} + // Note: Dilation height and width are always 1 for transpose_conv + const int32_t input_width = Tensor::dim(input, 2); + const int32_t filter_width = Tensor::dim(filter, 2); + const int32_t output_width = kernels::computeOutputSize( + luci_padding(options->padding()), input_width, filter_width, options->stride_w(), 1); -void TransposeConv::configure() -{ - assert(output_shape()->shape().num_dims() == 1); - assert(input()->shape().num_dims() == 4); - assert(filter()->shape().num_dims() == 4); - assert(input()->element_type() == DataType::FLOAT32 || input()->element_type() == DataType::U8 || - input()->element_type() == DataType::S16); - assert(input()->element_type() == output()->element_type()); - assert(input()->shape().dim(3) == filter()->shape().dim(3)); - - const int num_dims = output_shape()->shape().dim(0); - Shape out_shape(num_dims); - const auto *shape_data = getTensorData(output_shape()); - for (int i = 0; i < num_dims; i++) - out_shape.dim(i) = shape_data[i]; - // TODO: enable it only if kernel with dynamic shapes - output()->resize(out_shape); - - const int32_t filter_height = filter()->shape().dim(1); - const int32_t filter_width = filter()->shape().dim(2); - const int32_t output_height = out_shape.dim(1); - const int32_t output_width = out_shape.dim(2); - - const int32_t unused_output_height = - computeOutputSize(params().padding, output_height, filter_height, params().stride_height, 1); - const int32_t unused_output_width = - computeOutputSize(params().padding, output_width, filter_width, params().stride_width, 1); - - _padding_height = - computePadding(params().stride_height, 1, output_height, filter_height, unused_output_height); - _padding_width = - computePadding(params().stride_width, 1, output_width, filter_width, unused_output_width); - - if (input()->element_type() == DataType::U8 || input()->element_type() == DataType::S16) - { - auto scratch_tensor = getOutputTensors()[1]; - scratch_tensor->resize(output()->shape()); - const std::vector real_multipliers = - getQuantizedConvolutionMultiplers(input()->scale(), filter()->scales(), output()->scale()); + const auto padding_width = + kernels::computePadding(options->stride_w(), 1, input_width, filter_width, output_width); - _quant_multipliers = quantizeMultipliers(real_multipliers); - } - else - { - auto scratch_tensor = getOutputTensors()[1]; - scratch_tensor->set_allocatable(false); - } + return padding_width; } -void TransposeConv::execute() const -{ - switch (input()->element_type()) - { - case DataType::FLOAT32: - evalFloat(); - break; - case DataType::U8: - if (filter()->scales().size() == 1) - { - evalQuantized(); - } - else if (filter()->scales().size() > 1) - { - LUCI_INTERPRETER_CHECK(filter()->shape().num_dims() == 4); - LUCI_INTERPRETER_CHECK(filter()->scales().size() == - static_cast(filter()->shape().dim(0))); - evalQuantizedPerChannel(); - } - break; - case DataType::S16: - evalQuantizedS16(); - break; - default: - assert(false && "Unsupported type."); - } -} +#ifndef DIS_FLOAT -void TransposeConv::evalFloat() const +void evalFloat(const circle::Tensor *input, const circle::Tensor *filter, + const circle::Tensor *bias, const circle::Tensor *output, + const circle::TransposeConvOptions *options, BaseRuntimeGraph *runtime_graph) { - tflite::ConvParams op_params{}; - op_params.padding_type = tflite::PaddingType::kSame; - op_params.padding_values.height = _padding_height; - op_params.padding_values.width = _padding_width; - op_params.stride_height = params().stride_height; - op_params.stride_width = params().stride_width; - tflite::reference_ops::TransposeConv(op_params, // - getTensorShape(input()), getTensorData(input()), // - getTensorShape(filter()), getTensorData(filter()), // - getTensorShape(bias()), getTensorData(bias()), // - getTensorShape(output()), getTensorData(output()), // - tflite::RuntimeShape(), nullptr); + float activation_min{}; + float activation_max{}; + kernels::calculateActivationRange(FusedActFunc::NONE, &activation_min, &activation_max); + + luci_interpreter_pal::ConvParams params{}; + params.padding_values.height = compute_padding_h(input, filter, options); + params.padding_values.width = compute_padding_w(input, filter, options); + params.stride_height = options->stride_h(); + params.stride_width = options->stride_w(); + params.dilation_height_factor = 1; + params.dilation_width_factor = 1; + params.float_activation_min = activation_min; + params.float_activation_max = activation_max; + + auto *input_data = runtime_graph->getDataByTensor(input); + auto *output_data = runtime_graph->getDataByTensor(output); + + auto *filter_data = runtime_graph->getConstDataByTensor(filter); + auto *bias_data = runtime_graph->getConstDataByTensor(bias); + + luci_interpreter_pal::TransposeConv( + params, kernels::getTensorRuntimeShape(input, runtime_graph), + kernels::getTensorData(input_data), + kernels::getTensorRuntimeShape(filter, runtime_graph), + kernels::getTensorData(filter_data), kernels::getTensorRuntimeShape(bias, runtime_graph), + kernels::getTensorData(bias_data), kernels::getTensorRuntimeShape(output, runtime_graph), + kernels::getTensorData(output_data)); } -void TransposeConv::evalQuantized() const -{ - tflite::ConvParams op_params{}; - op_params.padding_type = tflite::PaddingType::kSame; - op_params.padding_values.height = _padding_height; - op_params.padding_values.width = _padding_width; - op_params.stride_height = params().stride_height; - op_params.stride_width = params().stride_width; - // The kernel expects input and filter zero points to be negated. - op_params.input_offset = -input()->zero_point(); // Note the '-'. - op_params.weights_offset = -filter()->zero_point(); // Note the '-'. - op_params.output_offset = output()->zero_point(); - op_params.output_multiplier = _quant_multipliers[0].multiplier; - op_params.output_shift = _quant_multipliers[0].shift; - op_params.quantized_activation_min = std::numeric_limits::min(); - op_params.quantized_activation_max = std::numeric_limits::max(); - - auto scratch_tensor = getOutputTensors()[1]; - - tflite::reference_ops::TransposeConv( - op_params, // - getTensorShape(input()), getTensorData(input()), // - getTensorShape(filter()), getTensorData(filter()), // - getTensorShape(bias()), getTensorData(bias()), // - getTensorShape(output()), getTensorData(output()), // - tflite::RuntimeShape(), nullptr, // - getTensorData(scratch_tensor)); -} +#endif // DIS_FLOAT -void TransposeConv::evalQuantizedPerChannel() const +} // namespace + +void configure_kernel_CircleTransposeConv(const circle::Operator *cur_op, + BaseRuntimeGraph *runtime_graph) { - const auto *input_data = getTensorData(input()); - const auto *filter_data = getTensorData(filter()); - const auto *bias_data = getTensorData(bias()); - auto *output_data = getTensorData(output()); - - auto scratch_tensor = getOutputTensors()[1]; - auto *scratch_data = getTensorData(scratch_tensor); - - const Shape &input_shape = input()->shape(); - const Shape &filter_shape = filter()->shape(); - const Shape &output_shape = output()->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 input_depth = input_shape.dim(3); - const int32_t output_depth = filter_shape.dim(0); - const int32_t filter_height = filter_shape.dim(1); - const int32_t filter_width = filter_shape.dim(2); - const int32_t output_height = output_shape.dim(1); - const int32_t output_width = output_shape.dim(2); - - const int32_t stride_height = _params.stride_height; - const int32_t stride_width = _params.stride_width; - - int32_t activation_min{}; - int32_t activation_max{}; - calculateActivationRangeQuantized(Activation::NONE, output(), &activation_min, &activation_max); - - std::memset(scratch_data, 0, scratch_tensor->shape().num_elements() * sizeof(int32_t)); - - BroadcastableWrapper output_multipliers(_quant_multipliers); - for (int32_t batch = 0; batch < batches; ++batch) - { - for (int32_t in_y = 0; in_y < input_height; ++in_y) - { - for (int32_t in_x = 0; in_x < input_width; ++in_x) - { - for (int32_t in_c = 0; in_c < input_depth; ++in_c) - { - const int32_t out_y_origin = in_y * stride_height - _padding_height; - const int32_t out_x_origin = in_x * stride_width - _padding_width; - for (int32_t filter_y = 0; filter_y < filter_height; ++filter_y) - { - for (int32_t filter_x = 0; filter_x < filter_width; ++filter_x) - { - const int32_t out_x = out_x_origin + filter_x; - const int32_t out_y = out_y_origin + filter_y; - if ((out_y >= 0 && out_y < output_height) && (out_x >= 0 && out_x < output_width)) - { - for (int32_t out_c = 0; out_c < output_depth; ++out_c) - { - const uint8_t input_val = - input_data[calcOffset(input_shape, batch, in_y, in_x, in_c)]; - const uint8_t filter_val = - filter_data[calcOffset(filter_shape, out_c, filter_y, filter_x, in_c)]; - scratch_data[calcOffset(output_shape, batch, out_y, out_x, out_c)] += - static_cast(input_val - input()->zero_point()) * - static_cast(filter_val - filter()->zero_points()[out_c]); - } - } - } - } - } - } - } - for (int32_t out_y = 0; out_y < output_height; ++out_y) - { - for (int32_t out_x = 0; out_x < output_width; ++out_x) - { - for (int32_t out_c = 0; out_c < output_depth; ++out_c) - { - int32_t acc = scratch_data[calcOffset(output_shape, batch, out_y, out_x, out_c)]; - if (bias_data) - { - acc += bias_data[out_c]; - } - - int32_t scaled_acc = tflite::MultiplyByQuantizedMultiplier( - acc, output_multipliers[out_c].multiplier, output_multipliers[out_c].shift); - - scaled_acc += output()->zero_point(); - scaled_acc = std::max(scaled_acc, activation_min); - scaled_acc = std::min(scaled_acc, activation_max); - - output_data[calcOffset(output_shape, batch, out_y, out_x, out_c)] = scaled_acc; - } - } - } - } + const auto input_index = cur_op->inputs()->operator[](kInputTensor); + const auto filter_index = cur_op->inputs()->operator[](kFilterTensor); + const auto output_index = cur_op->outputs()->operator[](kOutputTensor); + + assert(input_index != -1); + assert(filter_index != -1); + assert(output_index != -1); + + const auto input = runtime_graph->getCircleTensorByIndex(input_index); + const auto filter = runtime_graph->getCircleTensorByIndex(filter_index); + const auto output = runtime_graph->getCircleTensorByIndex(output_index); + + assert(input != nullptr); + assert(filter != nullptr); + + auto filter_data = runtime_graph->getConstDataByTensor(filter); + + assert(filter_data != nullptr); + + LUCI_INTERPRETER_CHECK(Tensor::element_type(output) == Tensor::element_type(input)); + LUCI_INTERPRETER_CHECK(Tensor::element_type(filter) == Tensor::element_type(input)); + + LUCI_INTERPRETER_CHECK(Tensor::num_dims(input) == 4 && Tensor::num_dims(filter) == 4); } -void TransposeConv::evalQuantizedS16() const +void execute_kernel_CircleTransposeConv(const circle::Operator *cur_op, + BaseRuntimeGraph *runtime_graph) { - const auto *input_data = getTensorData(input()); - const auto *filter_data = getTensorData(filter()); - const auto *bias_data = getTensorData(bias()); - auto *output_data = getTensorData(output()); - - auto scratch_tensor = getOutputTensors()[1]; - auto *scratch_data = getTensorData(scratch_tensor); - - const Shape &input_shape = input()->shape(); - const Shape &filter_shape = filter()->shape(); - const Shape &output_shape = output()->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 input_depth = input_shape.dim(3); - const int32_t output_depth = filter_shape.dim(0); - const int32_t filter_height = filter_shape.dim(1); - const int32_t filter_width = filter_shape.dim(2); - const int32_t output_height = output_shape.dim(1); - const int32_t output_width = output_shape.dim(2); - - const int32_t stride_height = _params.stride_height; - const int32_t stride_width = _params.stride_width; - - int32_t activation_min{}; - int32_t activation_max{}; - calculateActivationRangeQuantized(Activation::NONE, output(), &activation_min, &activation_max); - - std::memset(scratch_data, 0, scratch_tensor->shape().num_elements() * sizeof(int64_t)); - - BroadcastableWrapper output_multipliers(_quant_multipliers); - for (int32_t batch = 0; batch < batches; ++batch) + const auto input_index = cur_op->inputs()->operator[](kInputTensor); + const auto weight_index = cur_op->inputs()->operator[](kFilterTensor); + const auto bias_index = + cur_op->inputs()->size() == 4 ? cur_op->inputs()->operator[](kBiasTensor) : -1; + const auto output_index = cur_op->outputs()->operator[](kOutputTensor); + + assert(input_index != -1); + assert(weight_index != -1); + assert(output_index != -1); + + const auto input = runtime_graph->getCircleTensorByIndex(input_index); + const auto weights = runtime_graph->getCircleTensorByIndex(weight_index); + const auto bias = runtime_graph->getCircleTensorByIndex(bias_index); + const auto output = runtime_graph->getCircleTensorByIndex(output_index); + + assert(input != nullptr); + assert(weights != nullptr); + assert(output != nullptr); + + const auto *options = cur_op->builtin_options_as_TransposeConvOptions(); + + const auto type = Tensor::element_type(input); + switch (type) { - for (int32_t in_y = 0; in_y < input_height; ++in_y) - { - for (int32_t in_x = 0; in_x < input_width; ++in_x) - { - for (int32_t in_c = 0; in_c < input_depth; ++in_c) - { - const int32_t out_y_origin = in_y * stride_height - _padding_height; - const int32_t out_x_origin = in_x * stride_width - _padding_width; - for (int32_t filter_y = 0; filter_y < filter_height; ++filter_y) - { - for (int32_t filter_x = 0; filter_x < filter_width; ++filter_x) - { - const int32_t out_x = out_x_origin + filter_x; - const int32_t out_y = out_y_origin + filter_y; - if ((out_y >= 0 && out_y < output_height) && (out_x >= 0 && out_x < output_width)) - { - for (int32_t out_c = 0; out_c < output_depth; ++out_c) - { - const int16_t input_val = - input_data[calcOffset(input_shape, batch, in_y, in_x, in_c)]; - const int16_t filter_val = - filter_data[calcOffset(filter_shape, out_c, filter_y, filter_x, in_c)]; - scratch_data[calcOffset(output_shape, batch, out_y, out_x, out_c)] += - static_cast(input_val) * static_cast(filter_val); - } - } - } - } - } - } - } - for (int32_t out_y = 0; out_y < output_height; ++out_y) - { - for (int32_t out_x = 0; out_x < output_width; ++out_x) +#ifndef DIS_FLOAT + case DataType::FLOAT32: + if (Tensor::element_type(weights) == DataType::FLOAT32) { - for (int32_t out_c = 0; out_c < output_depth; ++out_c) - { - int64_t acc = scratch_data[calcOffset(output_shape, batch, out_y, out_x, out_c)]; - if (bias_data) - { - acc += bias_data[out_c]; - } - int32_t scaled_acc = tflite::MultiplyByQuantizedMultiplier( - acc, output_multipliers[out_c].multiplier, output_multipliers[out_c].shift); - - scaled_acc = std::max(scaled_acc, activation_min); - scaled_acc = std::min(scaled_acc, activation_max); - - output_data[calcOffset(output_shape, batch, out_y, out_x, out_c)] = scaled_acc; - } + evalFloat(input, weights, bias, output, options, runtime_graph); + break; } - } +#endif // DIS_FLOAT + default: + assert(false && "Unsupported type."); } } -} // namespace kernels } // namespace luci_interpreter diff --git a/onert-micro/luci-interpreter/src/kernels/TransposeConv.h b/onert-micro/luci-interpreter/src/kernels/TransposeConv.h deleted file mode 100644 index cea0cf3c7dd..00000000000 --- a/onert-micro/luci-interpreter/src/kernels/TransposeConv.h +++ /dev/null @@ -1,65 +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_TRANSPOSECONV_H -#define LUCI_INTERPRETER_KERNELS_TRANSPOSECONV_H - -#include "core/Kernel.h" -#include "core/KernelParams.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class ChannelQuantMultipliers; - -class TransposeConv : public KernelWithParams -{ -public: - TransposeConv(const Tensor *output_shape, const Tensor *filter, const Tensor *input, - const Tensor *bias, Tensor *output, Tensor *scratch_tensor, - const TransposeConvParams ¶ms); - - ~TransposeConv(); - - const Tensor *output_shape() const { return _inputs[0]; } - const Tensor *filter() const { return _inputs[1]; } - const Tensor *input() const { return _inputs[2]; } - const Tensor *bias() const { return _inputs[3]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; - -private: - void evalFloat() const; - void evalQuantized() const; - void evalQuantizedPerChannel() const; - void evalQuantizedS16() const; - -private: - int32_t _padding_height{}; - int32_t _padding_width{}; - // The scaling factor from input to output (aka the 'real multiplier') can - // be represented as a fixed point multiplier plus a left shift. - std::vector _quant_multipliers; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_TRANSPOSECONV_H diff --git a/onert-micro/luci-interpreter/src/kernels/TransposeConv.test.cpp b/onert-micro/luci-interpreter/src/kernels/TransposeConv.test.cpp index 4856e1b87d2..fa81a83a5c4 100644 --- a/onert-micro/luci-interpreter/src/kernels/TransposeConv.test.cpp +++ b/onert-micro/luci-interpreter/src/kernels/TransposeConv.test.cpp @@ -14,340 +14,88 @@ * limitations under the License. */ -#include "kernels/TransposeConv.h" #include "kernels/TestUtils.h" -#include "luci_interpreter/TestMemoryManager.h" +#include "luci_interpreter/test_models/transpose_conv/FloatTransposeConvKernel.h" +#include "luci_interpreter/test_models/transpose_conv/NegTransposeConvKernel.h" + +#include "loader/ModuleLoader.h" namespace luci_interpreter { -namespace kernels -{ namespace { using namespace testing; -template -void Check(std::initializer_list output_shape_shape, - std::initializer_list weight_shape, std::initializer_list input_shape, - std::initializer_list bias_shape, std::initializer_list output_shape, - std::initializer_list output_shape_data, std::initializer_list weight_data, - std::initializer_list input_data, std::initializer_list bias_data, - std::initializer_list output_data, luci::Padding padding, int32_t stride_height, - int32_t stride_width) +class TransposeConvTest : public ::testing::Test { - std::unique_ptr memory_manager = std::make_unique(); + // Do nothing +}; - constexpr DataType element_type = getElementType(); - Tensor output_shape_tensor = - makeInputTensor(output_shape_shape, output_shape_data, memory_manager.get()); - Tensor weight_tensor = - makeInputTensor(weight_shape, weight_data, memory_manager.get()); - Tensor input_data_tensor = - makeInputTensor(input_shape, input_data, memory_manager.get()); +template +std::vector checkTransposeConvKernel(test_kernel::TestDataBase *test_data_base) +{ + MemoryManager memory_manager{}; + RuntimeModule runtime_module{}; + bool dealloc_input = true; - DataType scratch_data_type = element_type == DataType::S16 ? DataType::S64 : DataType::S32; - Tensor scratch_tensor(scratch_data_type, Shape({}), {}, ""); - Tensor output_tensor = makeOutputTensor(element_type); + // 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); - TransposeConvParams params{}; - params.padding = padding; - params.stride_height = stride_height; - params.stride_width = stride_width; + auto *main_runtime_graph = runtime_module.getMainGraph(); + assert(main_runtime_graph->getNumOfInputTensors() == 1); - if (bias_data.size() != 0) + // set input data { - Tensor bias_tensor = - makeInputTensor()>(bias_shape, bias_data, memory_manager.get()); - TransposeConv kernel(&output_shape_tensor, &weight_tensor, &input_data_tensor, &bias_tensor, - &output_tensor, &scratch_tensor, params); - kernel.configure(); - memory_manager->allocate_memory(output_tensor); - memory_manager->allocate_memory(scratch_tensor); - kernel.execute(); + 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); } - else - { - TransposeConv kernel(&output_shape_tensor, &weight_tensor, &input_data_tensor, nullptr, - &output_tensor, &scratch_tensor, params); - kernel.configure(); - memory_manager->allocate_memory(output_tensor); - memory_manager->allocate_memory(scratch_tensor); - kernel.execute(); - } - EXPECT_THAT(extractTensorData(output_tensor), ::testing::ElementsAreArray(output_data)); -} -TEST(TransposeConvTest, FloatSimple) -{ - Check( - /*output_shape_shape=*/{4}, /*weight_shape=*/{1, 3, 3, 1}, /*input_shape=*/{1, 4, 4, 1}, - /*bias_shape=*/{}, /*output_shape=*/{1, 4, 4, 1}, /*output_shape_data=*/{1, 4, 4, 1}, - /*weight_data=*/{1, 2, 3, 4, 5, 6, 7, 8, 9}, - /*input_data=*/{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, - /*bias_data=*/{}, - /*output_data=*/{29, 62, 83, 75, 99, 192, 237, 198, 207, 372, 417, 330, 263, 446, 485, 365}, - /*params.padding=*/luci::Padding::SAME, /*stride_height=*/1, /*stride_width=*/1); + runtime_module.execute(); - SUCCEED(); -} - -TEST(TransposeConvTest, FloatTwoFiltersTest) -{ - Check( - /*output_shape_shape=*/{4}, /*weight_shape=*/{1, 3, 3, 2}, /*input_shape=*/{1, 4, 4, 2}, - /*bias_shape=*/{}, /*output_shape=*/{1, 4, 4, 1}, /*output_shape_data=*/{1, 4, 4, 1}, - /*weight_data=*/{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18}, - /*input_data=*/{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32}, - /*bias_data=*/{}, - /*output_data=*/ - {184, 412, 568, 528, 678, 1347, 1689, 1434, 1494, 2715, 3057, 2442, 1968, 3352, 3652, 2760}, - /*params.padding=*/luci::Padding::SAME, /*stride_height=*/1, /*stride_width=*/1); + assert(main_runtime_graph->getNumOfOutputTensors() == 1); - SUCCEED(); + 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(TransposeConvTest, SimpleBiasTest) +TEST_F(TransposeConvTest, Float_P) { - Check( - /*output_shape_shape=*/{4}, /*weight_shape=*/{2, 3, 3, 1}, - /*input_shape=*/{1, 2, 2, 1}, - /*bias_shape=*/{2}, /*output_shape=*/{1, 4, 4, 1}, /*output_shape_data=*/{1, 5, 5, 2}, - /*weight_data=*/{1, 3, 5, 7, 9, 11, 13, 15, 17, 2, 4, 6, 8, 10, 12, 14, 16, 18}, - /*input_data=*/{1, 2, 3, 4}, - /*bias_data=*/{3, 4}, - /*output_data=*/{4, 6, 6, 8, 10, 14, 9, 12, 13, 16, 10, 12, 12, 14, 28, 32, 21, - 24, 25, 28, 19, 24, 27, 32, 65, 76, 45, 52, 57, 64, 24, 28, 30, 34, - 64, 72, 39, 44, 47, 52, 42, 46, 48, 52, 106, 114, 63, 68, 71, 76}, - /*params.padding=*/luci::Padding::VALID, /*stride_height=*/2, /*stride_width=*/2); - - SUCCEED(); + test_kernel::TestDataFloatTransposeConv test_data_kernel; + std::vector output_data_vector = checkTransposeConvKernel(&test_data_kernel); + EXPECT_THAT(output_data_vector, kernels::testing::FloatArrayNear( + test_data_kernel.get_output_data_by_index(0), 0.0001f)); } -TEST(TransposeConvTest, UInt8) +TEST_F(TransposeConvTest, Input_type_mismatch_NEG) { - std::unique_ptr memory_manager = std::make_unique(); - - std::vector input_data{1, 2, 3, 4}; - std::vector filter_data{1, 3, 5, 7, 9, 11, 13, 15, 17, 2, 4, 6, 8, 10, 12, 14, 16, 18}; - std::vector bias_data{3, 4}; - std::vector output_shape_data{1, 5, 5, 2}; - std::vector ref_output_data{ - 4, 6, 6, 8, 10, 14, 9, 12, 13, 16, // - 10, 12, 12, 14, 28, 32, 21, 24, 25, 28, // - 19, 24, 27, 32, 65, 76, 45, 52, 57, 64, // - 24, 28, 30, 34, 64, 72, 39, 44, 47, 52, // - 42, 46, 48, 52, 106, 114, 63, 68, 71, 76, // - }; - - // Choose quantization parameters carefully. - auto input_quant = quantizationParams(-8.0, 7.9375); // s = 1 / 16, zp = 128 - auto filter_quant = quantizationParams(-24.0, 39.75); // s = 1 / 4, zp = 96 - auto output_quant = quantizationParams(-64.0, 191.0); // s = 1, zp = 64 - - Tensor input_tensor = makeInputTensor( - {1, 2, 2, 1}, input_quant.first, input_quant.second, input_data, memory_manager.get()); - Tensor filter_tensor = makeInputTensor( - {2, 3, 3, 1}, filter_quant.first, filter_quant.second, filter_data, memory_manager.get()); - Tensor bias_tensor = makeInputTensor({2}, input_quant.first * filter_quant.first, - 0, bias_data, memory_manager.get()); - Tensor output_shape_tensor = - makeInputTensor({4}, output_shape_data, memory_manager.get()); - Tensor output_tensor = makeOutputTensor(DataType::U8, output_quant.first, output_quant.second); - - DataType scratch_data_type = - input_tensor.element_type() == DataType::S16 ? DataType::S64 : DataType::S32; - Tensor scratch_tensor(scratch_data_type, Shape({}), {}, ""); - - TransposeConvParams params{}; - params.padding = Padding::VALID; - params.stride_height = 2; - params.stride_width = 2; - - TransposeConv kernel(&output_shape_tensor, &filter_tensor, &input_tensor, &bias_tensor, - &output_tensor, &scratch_tensor, params); - kernel.configure(); - memory_manager->allocate_memory(output_tensor); - memory_manager->allocate_memory(scratch_tensor); - kernel.execute(); - - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape_data)); - EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data)); + test_kernel::NegTestDataInputMismatchTransposeConvKernel 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), + ""); } -TEST(TransposeConvTest, UInt8_CWQ) +TEST_F(TransposeConvTest, Invalid_input_shape_NEG) { - std::unique_ptr memory_manager = std::make_unique(); - - const int32_t output_channels = 2; - std::vector input_data{1, 2, 3, 4}; - std::vector filter_data{1, 3, 5, 7, 9, 11, 13, 15, 17, 2, 4, 6, 8, 10, 12, 14, 16, 18}; - std::vector bias_data{3, 4}; - std::vector output_shape_data{1, 5, 5, 2}; - std::vector ref_output_data{ - 4, 6, 6, 8, 10, 14, 9, 12, 13, 16, // - 10, 12, 12, 14, 28, 32, 21, 24, 25, 28, // - 19, 24, 27, 32, 65, 76, 45, 52, 57, 64, // - 24, 28, 30, 34, 64, 72, 39, 44, 47, 52, // - 42, 46, 48, 52, 106, 114, 63, 68, 71, 76, // - }; - - // Choose quantization parameters carefully. - auto input_quant = quantizationParams(-8.0, 7.9375); // s = 1 / 16, zp = 128 - auto output_quant = quantizationParams(-64.0, 191.0); // s = 1, zp = 64 - - std::vector> filter_quant_params; - filter_quant_params.push_back(quantizationParams(0, 17)); - filter_quant_params.push_back(quantizationParams(0, 18)); - - std::vector filter_scales; - std::vector filter_zerops; - for (auto iter : filter_quant_params) - { - filter_scales.push_back(iter.first); - filter_zerops.push_back(iter.second); - } - - std::vector bias_scales; - for (int i = 0; i < output_channels; ++i) - bias_scales.push_back(filter_quant_params[i].first * input_quant.first); - std::vector zerop(output_channels, 0); - - Tensor input_tensor = makeInputTensor( - {1, 2, 2, 1}, input_quant.first, input_quant.second, input_data, memory_manager.get()); - Tensor filter_tensor = makeInputTensor( - {output_channels, 3, 3, 1}, filter_scales, filter_zerops, 0, filter_data, memory_manager.get()); - Tensor bias_tensor = makeInputTensor({output_channels}, bias_scales, zerop, 0, - bias_data, memory_manager.get()); - Tensor output_shape_tensor = - makeInputTensor({4}, output_shape_data, memory_manager.get()); - Tensor output_tensor = makeOutputTensor(DataType::U8, output_quant.first, output_quant.second); - - DataType scratch_data_type = - input_tensor.element_type() == DataType::S16 ? DataType::S64 : DataType::S32; - Tensor scratch_tensor(scratch_data_type, Shape({}), {}, ""); - - TransposeConvParams params{}; - params.padding = Padding::VALID; - params.stride_height = 2; - params.stride_width = 2; - - TransposeConv kernel(&output_shape_tensor, &filter_tensor, &input_tensor, &bias_tensor, - &output_tensor, &scratch_tensor, params); - kernel.configure(); - memory_manager->allocate_memory(output_tensor); - memory_manager->allocate_memory(scratch_tensor); - kernel.execute(); - - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape_data)); - EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data)); -} - -TEST(TransposeConvTest, SInt16) -{ - std::unique_ptr memory_manager = std::make_unique(); - - std::vector input_data{1, 2, 3, 4}; - std::vector filter_data{1, 3, 5, 7, 9, 11, 13, 15, 17, 2, 4, 6, 8, 10, 12, 14, 16, 18}; - std::vector bias_data{3, 4}; - std::vector output_shape_data{1, 5, 5, 2}; - std::vector ref_output_data{ - 4, 6, 6, 8, 10, 14, 9, 12, 13, 16, // - 10, 12, 12, 14, 28, 32, 21, 24, 25, 28, // - 19, 24, 27, 32, 65, 76, 45, 52, 57, 64, // - 24, 28, 30, 34, 64, 72, 39, 44, 47, 52, // - 42, 46, 48, 52, 106, 114, 63, 68, 71, 76, // - }; - - Tensor input_tensor = - makeInputTensor({1, 2, 2, 1}, 0.25, 0, input_data, memory_manager.get()); - Tensor filter_tensor = - makeInputTensor({2, 3, 3, 1}, 0.2, 0, filter_data, memory_manager.get()); - Tensor bias_tensor = - makeInputTensor({2}, 0.25 * 0.2, 0, bias_data, memory_manager.get()); - Tensor output_shape_tensor = - makeInputTensor({4}, output_shape_data, memory_manager.get()); - Tensor output_tensor = makeOutputTensor(DataType::S16, 0.5, 0); - - DataType scratch_data_type = - input_tensor.element_type() == DataType::S16 ? DataType::S64 : DataType::S32; - Tensor scratch_tensor(scratch_data_type, Shape({}), {}, ""); - - TransposeConvParams params{}; - params.padding = Padding::VALID; - params.stride_height = 2; - params.stride_width = 2; - - TransposeConv kernel(&output_shape_tensor, &filter_tensor, &input_tensor, &bias_tensor, - &output_tensor, &scratch_tensor, params); - kernel.configure(); - memory_manager->allocate_memory(output_tensor); - memory_manager->allocate_memory(scratch_tensor); - kernel.execute(); - - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape_data)); - EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data)); -} - -TEST(TransposeConvTest, SInt16_CWQ_weights) -{ - std::unique_ptr memory_manager = std::make_unique(); - - const int output_channels = 2; - const Shape input_shape{1, 2, 2, 1}; - const Shape filter_shape{output_channels, 3, 3, 1}; - const Shape bias_shape{output_channels}; - std::vector output_shape_data{1, 5, 5, output_channels}; - - std::vector input_data{1, 2, 3, 4}; - std::vector filter_data{1, 3, 5, 7, 9, 11, 13, 15, 17, 2, 4, 6, 8, 10, 12, 14, 16, 18}; - std::vector bias_data{3, 4}; - - std::vector ref_output_data{ - 4, 6, 6, 8, 10, 14, 9, 12, 13, 16, // - 10, 12, 12, 14, 28, 32, 21, 24, 25, 28, // - 19, 24, 27, 32, 65, 76, 45, 52, 57, 64, // - 24, 28, 30, 34, 64, 72, 39, 44, 47, 52, // - 42, 46, 48, 52, 106, 114, 63, 68, 71, 76, // - }; - - const float input_scale = 0.25; - const float output_scale = 0.5; - const std::vector filter_scales{0.2f, 0.5f}; - std::vector bias_scales{filter_scales[0] * input_scale, filter_scales[1] * input_scale}; - const std::vector zerop(2, 0); - - Tensor input_tensor = - makeInputTensor(input_shape, input_scale, 0, input_data, memory_manager.get()); - Tensor filter_tensor = makeInputTensor(filter_shape, filter_scales, zerop, 0, - filter_data, memory_manager.get()); - Tensor bias_tensor = makeInputTensor(bias_shape, bias_scales, zerop, 0, bias_data, - memory_manager.get()); - Tensor output_shape_tensor = - makeInputTensor({4}, output_shape_data, memory_manager.get()); - Tensor output_tensor = makeOutputTensor(DataType::S16, output_scale, 0); - - DataType scratch_data_type = - input_tensor.element_type() == DataType::S16 ? DataType::S64 : DataType::S32; - Tensor scratch_tensor(scratch_data_type, Shape({}), {}, ""); - - TransposeConvParams params{}; - params.padding = Padding::VALID; - params.stride_height = 2; - params.stride_width = 2; - - TransposeConv kernel(&output_shape_tensor, &filter_tensor, &input_tensor, &bias_tensor, - &output_tensor, &scratch_tensor, params); - kernel.configure(); - memory_manager->allocate_memory(output_tensor); - memory_manager->allocate_memory(scratch_tensor); - kernel.execute(); - - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape_data)); - EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data)); + test_kernel::NegTestDataInvalidInputShapeTransposeConvKernel 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