diff --git a/onert-micro/luci-interpreter/include/luci_interpreter/test_models/l2_normalization/FloatL2NormalizeKernel.h b/onert-micro/luci-interpreter/include/luci_interpreter/test_models/l2_normalization/FloatL2NormalizeKernel.h new file mode 100644 index 00000000000..9d665618c0f --- /dev/null +++ b/onert-micro/luci-interpreter/include/luci_interpreter/test_models/l2_normalization/FloatL2NormalizeKernel.h @@ -0,0 +1,98 @@ +/* + * 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_L2_NORMALIZATION_KERNEL_H +#define LUCI_INTERPRETER_TEST_MODELS_FLOAT_L2_NORMALIZATION_KERNEL_H + +#include "TestDataL2NormalizeBase.h" + +namespace luci_interpreter +{ +namespace test_kernel +{ +namespace l2_normalization_float +{ +/* + * L2Normalization Kernel: + * + * Input(1, 4, 4, 3) + * | + * L2Normalization + * | + * Output(1, 4, 4, 3) + */ +const unsigned char test_kernel_model_circle[] = { + 0x18, 0x00, 0x00, 0x00, 0x43, 0x49, 0x52, 0x30, 0x00, 0x00, 0x0e, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x28, 0x00, 0x00, 0x00, 0x28, 0x01, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x8c, 0xff, 0xff, 0xff, + 0x90, 0xff, 0xff, 0xff, 0x94, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, + 0x60, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x08, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0c, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0xd4, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x6f, 0x66, 0x6d, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 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, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x69, 0x66, 0x6d, 0x31, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 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, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 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.992603, 8.346985, 22.960445, 45.584763, 26.916512, 33.256886, 12.787039, 40.30215, + 32.26641, 13.645262, 36.445396, 33.06842, 37.449368, 14.05669, 17.87454, 7.8050013, + 5.6068754, 17.868938, 40.134842, 24.222584, 42.0985, 26.406887, 11.48271, 33.00633, + 39.676426, 46.740967, 38.20928, 45.924362, 39.70501, 32.05231, 41.742085, 29.257357, + 42.27183, 35.843292, 28.056007, 31.480331, 34.84266, 34.666496, 26.273453, 33.72813, + 23.426928, 14.348057, 52.57121, 17.464836, 33.1741, 29.476301, 22.09747, 32.685722}; + +const std::vector reference_output_data = { + 0.3785766, 0.31623122, 0.86987215, 0.72914726, 0.4305408, 0.53195775, 0.24041508, 0.75773954, + 0.60665584, 0.26719585, 0.71365863, 0.64753205, 0.8547623, 0.32083663, 0.40797707, 0.38468635, + 0.27634698, 0.8807093, 0.63699496, 0.3844456, 0.66816086, 0.6028728, 0.2621518, 0.7535389, + 0.54921657, 0.6470067, 0.5289077, 0.66895926, 0.5783648, 0.46689144, 0.6303393, 0.4418098, + 0.6383389, 0.6476525, 0.506944, 0.56881815, 0.6251807, 0.6220198, 0.47142372, 0.77535427, + 0.53854656, 0.32983825, 0.81417507, 0.2704795, 0.5137703, 0.59851044, 0.44868472, 0.6636771}; + +} // namespace l2_normalization_float + +class TestDataFloatL2Normalization : public TestDataL2NormalizationBase +{ +public: + TestDataFloatL2Normalization() + { + _input_data = l2_normalization_float::input_data; + _reference_output_data = l2_normalization_float::reference_output_data; + _test_kernel_model_circle = l2_normalization_float::test_kernel_model_circle; + } + + ~TestDataFloatL2Normalization() override = default; +}; + +} // namespace test_kernel +} // namespace luci_interpreter + +#endif // LUCI_INTERPRETER_TEST_MODELS_FLOAT_L2_NORMALIZATION_KERNEL_H diff --git a/onert-micro/luci-interpreter/include/luci_interpreter/test_models/l2_normalization/NegL2NormalizeKernel.h b/onert-micro/luci-interpreter/include/luci_interpreter/test_models/l2_normalization/NegL2NormalizeKernel.h new file mode 100644 index 00000000000..e660668080f --- /dev/null +++ b/onert-micro/luci-interpreter/include/luci_interpreter/test_models/l2_normalization/NegL2NormalizeKernel.h @@ -0,0 +1,87 @@ +/* + * 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_L2_NORMALIZE_KERNEL_H +#define LUCI_INTERPRETER_TEST_MODELS_NEG_L2_NORMALIZE_KERNEL_H + +#include "TestDataL2NormalizeBase.h" + +namespace luci_interpreter +{ +namespace test_kernel +{ +namespace neg_input_output_type_mismatch_l2_normalization_kernel +{ +/* + * L2Normalization Kernel with input output type mismatch (should be equal): + * + * Input(1, 4, 4, 3) - Float + * | + * L2Normalization + * | + * Output(1, 4, 4, 3) - Int + */ +const unsigned char test_kernel_model_circle[] = { + 0x18, 0x00, 0x00, 0x00, 0x43, 0x49, 0x52, 0x30, 0x00, 0x00, 0x0e, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x28, 0x00, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0x54, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x8c, 0xff, 0xff, 0xff, + 0x90, 0xff, 0xff, 0xff, 0x94, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, + 0x60, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x08, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0c, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x6f, 0x66, 0x6d, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 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, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x69, 0x66, 0x6d, 0x31, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 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, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x11, 0x00, 0x00, 0x00, + 0x4f, 0x4e, 0x45, 0x2d, 0x74, 0x66, 0x6c, 0x69, 0x74, 0x65, 0x32, 0x63, 0x69, 0x72, 0x63, 0x6c, + 0x65, 0x00, 0x00, 0x00}; + +} // namespace neg_input_output_type_mismatch_l2_normalization_kernel + +class NegTestDataInputOutputTypeMismatchNegKernel : public NegTestDataBase +{ +public: + NegTestDataInputOutputTypeMismatchNegKernel() + { + _test_kernel_model_circle = + neg_input_output_type_mismatch_l2_normalization_kernel::test_kernel_model_circle; + } + + ~NegTestDataInputOutputTypeMismatchNegKernel() 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_L2_NORMALIZE_KERNEL_H diff --git a/onert-micro/luci-interpreter/include/luci_interpreter/test_models/l2_normalization/TestDataL2NormalizeBase.h b/onert-micro/luci-interpreter/include/luci_interpreter/test_models/l2_normalization/TestDataL2NormalizeBase.h new file mode 100644 index 00000000000..3f8ad812ec2 --- /dev/null +++ b/onert-micro/luci-interpreter/include/luci_interpreter/test_models/l2_normalization/TestDataL2NormalizeBase.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_L2_NORMALIZATION_KERNEL_BASE_H +#define LUCI_INTERPRETER_TEST_MODELS_L2_NORMALIZATION_KERNEL_BASE_H + +#include "luci_interpreter/test_models/TestDataBase.h" + +namespace luci_interpreter +{ +namespace test_kernel +{ + +template class TestDataL2NormalizationBase : public TestDataBase +{ +public: + TestDataL2NormalizationBase() = 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_L2_NORMALIZATION_KERNEL_BASE_H diff --git a/onert-micro/luci-interpreter/pal/cmsisnn/KernelsToBuild.lst b/onert-micro/luci-interpreter/pal/cmsisnn/KernelsToBuild.lst index 930fa0d5c72..68dac6a16c5 100644 --- a/onert-micro/luci-interpreter/pal/cmsisnn/KernelsToBuild.lst +++ b/onert-micro/luci-interpreter/pal/cmsisnn/KernelsToBuild.lst @@ -23,6 +23,7 @@ REGISTER_KERNEL(RELU, Relu) REGISTER_KERNEL(RELU6, Relu6) REGISTER_KERNEL(REDUCE_PROD, ReduceCommon) REGISTER_KERNEL(LESS, Less) +REGISTER_KERNEL(L2_NORMALIZATION, L2Normalize) REGISTER_KERNEL(LESS_EQUAL, LessEqual) REGISTER_KERNEL(LOGICAL_AND, LogicalAnd) REGISTER_KERNEL(LOGICAL_OR, LogicalOr) diff --git a/onert-micro/luci-interpreter/pal/cmsisnn/PALL2Pool2D.h b/onert-micro/luci-interpreter/pal/cmsisnn/PALL2Pool2D.h deleted file mode 100644 index 38a302fc68f..00000000000 --- a/onert-micro/luci-interpreter/pal/cmsisnn/PALL2Pool2D.h +++ /dev/null @@ -1,33 +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_L2POOL2D_H -#define LUCI_INTERPRETER_PAL_L2POOL2D_H - -#include - -namespace luci_interpreter_pal -{ -template -static inline void L2Pool(const tflite::PoolParams ¶ms, const tflite::RuntimeShape &input_shape, - const T *input_data, const tflite::RuntimeShape &output_shape, - T *output_data) -{ - tflite::reference_ops::L2Pool(params, input_shape, input_data, output_shape, output_data); -} -} // namespace luci_interpreter_pal - -#endif // LUCI_INTERPRETER_PAL_L2POOL2D_H diff --git a/onert-micro/luci-interpreter/pal/common/PALL2Normalize.h b/onert-micro/luci-interpreter/pal/common/PALL2Normalize.h new file mode 100644 index 00000000000..f890bf020df --- /dev/null +++ b/onert-micro/luci-interpreter/pal/common/PALL2Normalize.h @@ -0,0 +1,55 @@ +/* + * 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_L2_NORMALIZE_COMMON_H +#define LUCI_INTERPRETER_PAL_L2_NORMALIZE_COMMON_H + +#include "PALUtils.h" +#include + +namespace luci_interpreter_pal +{ + +inline void L2Normalization(const luci_interpreter::RuntimeShape &input_shape, + const float *input_data, + const luci_interpreter::RuntimeShape &output_shape, float *output_data, + float epsilon = 1e-6) +{ + const int trailing_dim = input_shape.dimensionsCount() - 1; + const int outer_size = + flatSizeSkipDim(input_shape.dimsData(), trailing_dim, input_shape.dimensionsCount()); + const int depth = MatchingDim(input_shape, trailing_dim, output_shape, trailing_dim); + for (int i = 0; i < outer_size; ++i) + { + float squared_l2_norm = 0; + for (int c = 0; c < depth; ++c) + { + const float val = input_data[depth * i + c]; + squared_l2_norm += val * val; + } + float l2_norm = std::sqrt(squared_l2_norm); + l2_norm = std::fmax(l2_norm, epsilon); + for (int c = 0; c < depth; ++c) + { + output_data[depth * i + c] = input_data[depth * i + c] / l2_norm; + } + } +} + +} // namespace luci_interpreter_pal + +#endif // LUCI_INTERPRETER_PAL_L2_NORMALIZE_COMMON_H diff --git a/onert-micro/luci-interpreter/pal/common/PALUtils.h b/onert-micro/luci-interpreter/pal/common/PALUtils.h index 7205bc2c6b7..1b3796eff55 100644 --- a/onert-micro/luci-interpreter/pal/common/PALUtils.h +++ b/onert-micro/luci-interpreter/pal/common/PALUtils.h @@ -177,6 +177,19 @@ inline int MatchingDim(const luci_interpreter::RuntimeShape &shape1, int index1, return shape1.dims(index1); } +// Data is required to be contiguous, and so many operators can use either the +// full array flat size or the flat size with one dimension skipped (commonly +// the depth). +inline int flatSizeSkipDim(const int32_t *dims_data, int skip_dim, int num_dims) +{ + int flat_size = 1; + for (int i = 0; i < num_dims; ++i) + { + flat_size *= (i == skip_dim) ? 1 : dims_data[i]; + } + return flat_size; +} + 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; diff --git a/onert-micro/luci-interpreter/pal/mcu/KernelsToBuild.lst b/onert-micro/luci-interpreter/pal/mcu/KernelsToBuild.lst index d06543c6988..076c6795751 100644 --- a/onert-micro/luci-interpreter/pal/mcu/KernelsToBuild.lst +++ b/onert-micro/luci-interpreter/pal/mcu/KernelsToBuild.lst @@ -27,6 +27,7 @@ REGISTER_KERNEL(RELU, Relu) REGISTER_KERNEL(RELU6, Relu6) REGISTER_KERNEL(REDUCE_PROD, ReduceCommon) REGISTER_KERNEL(LESS, Less) +REGISTER_KERNEL(L2_NORMALIZATION, L2Normalize) REGISTER_KERNEL(LESS_EQUAL, LessEqual) REGISTER_KERNEL(LOGICAL_AND, LogicalAnd) REGISTER_KERNEL(LOGICAL_OR, LogicalOr) diff --git a/onert-micro/luci-interpreter/pal/mcu/PALL2Pool2D.h b/onert-micro/luci-interpreter/pal/mcu/PALL2Pool2D.h deleted file mode 100644 index 38a302fc68f..00000000000 --- a/onert-micro/luci-interpreter/pal/mcu/PALL2Pool2D.h +++ /dev/null @@ -1,33 +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_L2POOL2D_H -#define LUCI_INTERPRETER_PAL_L2POOL2D_H - -#include - -namespace luci_interpreter_pal -{ -template -static inline void L2Pool(const tflite::PoolParams ¶ms, const tflite::RuntimeShape &input_shape, - const T *input_data, const tflite::RuntimeShape &output_shape, - T *output_data) -{ - tflite::reference_ops::L2Pool(params, input_shape, input_data, output_shape, output_data); -} -} // namespace luci_interpreter_pal - -#endif // LUCI_INTERPRETER_PAL_L2POOL2D_H diff --git a/onert-micro/luci-interpreter/src/kernels/L2Normalize.cpp b/onert-micro/luci-interpreter/src/kernels/L2Normalize.cpp index 97c9db86b8b..f2178a7e523 100644 --- a/onert-micro/luci-interpreter/src/kernels/L2Normalize.cpp +++ b/onert-micro/luci-interpreter/src/kernels/L2Normalize.cpp @@ -14,61 +14,55 @@ * limitations under the License. */ -#include "kernels/L2Normalize.h" +#include "Builders.h" #include "kernels/Utils.h" +#include "SISOKernel.h" #include "PALL2Normalize.h" namespace luci_interpreter { -namespace kernels +void configure_kernel_CircleL2Normalize(const circle::Operator *cur_op, + BaseRuntimeGraph *runtime_graph) { + kernels::SISOKernel kernel(cur_op, runtime_graph); -L2Normalize::L2Normalize(const Tensor *input, Tensor *output, const L2NormParams ¶ms) - : KernelWithParams({input}, {output}, params) -{ + LUCI_INTERPRETER_CHECK(Tensor::element_type(kernel.input()) == + Tensor::element_type(kernel.output())); + LUCI_INTERPRETER_CHECK(Tensor::num_elements(kernel.input()) == + Tensor::num_elements(kernel.output())); + LUCI_INTERPRETER_CHECK(Tensor::num_dims(kernel.input()) == Tensor::num_dims(kernel.output())); } -void L2Normalize::configure() +void execute_kernel_CircleL2Normalize(const circle::Operator *cur_op, + BaseRuntimeGraph *runtime_graph) { - LUCI_INTERPRETER_CHECK(input()->shape().num_dims() <= 4); - LUCI_INTERPRETER_CHECK(output()->element_type() == DataType::FLOAT32 || - output()->element_type() == DataType::U8); - LUCI_INTERPRETER_CHECK(input()->element_type() == output()->element_type()); - if (output()->element_type() == DataType::U8) - { - LUCI_INTERPRETER_CHECK(output()->scale() == (1. / 128.)); - LUCI_INTERPRETER_CHECK(output()->zero_point() == 128); - } - LUCI_INTERPRETER_CHECK(params().activation == Activation::NONE); - // TODO: enable it only if kernel with dynamic shapes - output()->resize(input()->shape()); -} + kernels::SISOKernel kernel(cur_op, runtime_graph); -void L2Normalize::execute() const -{ - switch (output()->element_type()) + const auto *input_data = runtime_graph->getDataByTensor(kernel.input()); + assert(input_data); + + auto *output_data = runtime_graph->getDataByTensor(kernel.output()); + + switch (Tensor::element_type(kernel.input())) { +#ifndef DIS_FLOAT case DataType::FLOAT32: - eval(0); - break; - case DataType::U8: - eval(input()->zero_point()); + { + const auto *input_data_float = kernels::getTensorData(input_data); + auto *output_data_float = kernels::getTensorData(output_data); + + assert(output_data_float); + + luci_interpreter_pal::L2Normalization( + kernels::getTensorRuntimeShape(kernel.input(), runtime_graph), input_data_float, + kernels::getTensorRuntimeShape(kernel.output(), runtime_graph), output_data_float); break; + } +#endif // DIS_FLOAT default: - assert(false && "Unsupported type."); + assert(false && "Unsupported type"); } } - -template void L2Normalize::eval(int32_t zero_point) const -{ - tflite::L2NormalizationParams op_params{}; - op_params.input_zero_point = zero_point; - luci_interpreter_pal::L2Normalization(op_params, getTensorShape(input()), - getTensorData(input()), getTensorShape(output()), - getTensorData(output())); -} - -} // namespace kernels } // namespace luci_interpreter diff --git a/onert-micro/luci-interpreter/src/kernels/L2Normalize.h b/onert-micro/luci-interpreter/src/kernels/L2Normalize.h deleted file mode 100644 index 6c7dac69893..00000000000 --- a/onert-micro/luci-interpreter/src/kernels/L2Normalize.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LUCI_INTERPRETER_KERNELS_L2NORMALIZE_H -#define LUCI_INTERPRETER_KERNELS_L2NORMALIZE_H - -#include "core/Kernel.h" -#include "core/KernelParams.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class L2Normalize : public KernelWithParams -{ -public: - L2Normalize(const Tensor *input, Tensor *output, const L2NormParams ¶ms); - - const Tensor *input() const { return _inputs[0]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; - -private: - template void eval(int32_t zero_point) const; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_L2NORMALIZE_H diff --git a/onert-micro/luci-interpreter/src/kernels/L2Normalize.test.cpp b/onert-micro/luci-interpreter/src/kernels/L2Normalize.test.cpp index 6f960e8b45d..67da4bdcb7d 100644 --- a/onert-micro/luci-interpreter/src/kernels/L2Normalize.test.cpp +++ b/onert-micro/luci-interpreter/src/kernels/L2Normalize.test.cpp @@ -14,113 +14,75 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "kernels/L2Normalize.h" + #include "kernels/TestUtils.h" -#include "luci_interpreter/TestMemoryManager.h" +#include "luci_interpreter/test_models/l2_normalization/FloatL2NormalizeKernel.h" +#include "luci_interpreter/test_models/l2_normalization/NegL2NormalizeKernel.h" + +#include "loader/ModuleLoader.h" namespace luci_interpreter { -namespace kernels -{ namespace { using namespace testing; +class L2NormalizeTest : public ::testing::Test +{ + // Do nothing +}; + template -void Check(std::initializer_list input_shape, std::initializer_list output_shape, - std::initializer_list input_data, std::initializer_list output_data) +std::vector checkL2NormalizeKernel(test_kernel::TestDataBase *test_data_base) { - std::unique_ptr memory_manager = std::make_unique(); - Tensor input_tensor = - makeInputTensor(input_shape, input_data, memory_manager.get()); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); + MemoryManager memory_manager{}; + RuntimeModule runtime_module{}; + bool dealloc_input = true; - L2NormParams params{}; - params.activation = Activation::NONE; + // 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); - L2Normalize kernel(&input_tensor, &output_tensor, params); - kernel.configure(); - memory_manager->allocate_memory(output_tensor); - kernel.execute(); + auto *main_runtime_graph = runtime_module.getMainGraph(); + assert(main_runtime_graph->getNumOfInputTensors() == 1); - EXPECT_THAT(extractTensorData(output_tensor), FloatArrayNear(output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape)); -} + // 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); + } -template <> -void Check(std::initializer_list input_shape, - std::initializer_list output_shape, - std::initializer_list input_data, - std::initializer_list output_data) -{ - std::unique_ptr memory_manager = std::make_unique(); - std::pair quant_param = - quantizationParams(std::min(input_data) < 0 ? std::min(input_data) : 0.f, - std::max(input_data) > 0 ? std::max(input_data) : 0.f); - - Tensor input_tensor = makeInputTensor( - input_shape, quant_param.first, quant_param.second, input_data, memory_manager.get()); - Tensor output_tensor = makeOutputTensor(DataType::U8, 1. / 128., 128); - - L2NormParams params{}; - params.activation = Activation::NONE; - - L2Normalize kernel(&input_tensor, &output_tensor, params); - kernel.configure(); - memory_manager->allocate_memory(output_tensor); - kernel.execute(); - - EXPECT_THAT(dequantizeTensorData(output_tensor), - FloatArrayNear(output_data, output_tensor.scale())); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(output_shape)); -} + runtime_module.execute(); -template class L2NormalizeTest : public ::testing::Test -{ -}; - -using DataTypes = ::testing::Types; -TYPED_TEST_SUITE(L2NormalizeTest, DataTypes); + assert(main_runtime_graph->getNumOfOutputTensors() == 1); -TYPED_TEST(L2NormalizeTest, Simple) -{ - Check({1, 1, 1, 6}, {1, 1, 1, 6}, {-1.1, 0.6, 0.7, 1.2, -0.7, 0.1}, - {-0.55, 0.3, 0.35, 0.6, -0.35, 0.05}); + 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(L2NormalizeTest, ActivationType_NEG) +TEST_F(L2NormalizeTest, Float_P) { - std::unique_ptr memory_manager = std::make_unique(); - std::vector input_data = {-1.1, 0.6, 0.7, 1.2, -0.7, 0.1}; - - Tensor input_tensor = - makeInputTensor({1, 1, 1, 6}, input_data, memory_manager.get()); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - L2NormParams params{}; - params.activation = Activation::RELU6; - - L2Normalize kernel(&input_tensor, &output_tensor, params); - EXPECT_ANY_THROW(kernel.configure()); + test_kernel::TestDataFloatL2Normalization test_data_kernel; + std::vector output_data_vector = checkL2NormalizeKernel(&test_data_kernel); + EXPECT_THAT(output_data_vector, test_data_kernel.get_output_data_by_index(0)); } -TEST(L2NormalizeTest, InvalidOutputQuantParam_NEG) +TEST_F(L2NormalizeTest, Input_output_type_mismatch_NEG) { - std::unique_ptr memory_manager = std::make_unique(); - std::vector input_data = {-1.1, 0.6, 0.7, 1.2, -0.7, 0.1}; - - Tensor input_tensor = - makeInputTensor({1, 1, 1, 6}, 1. / 64., 127, input_data, memory_manager.get()); - Tensor output_tensor = makeOutputTensor(DataType::U8, 1. / 64., 127); - - L2NormParams params{}; - params.activation = Activation::NONE; - - L2Normalize kernel(&input_tensor, &output_tensor, params); - EXPECT_ANY_THROW(kernel.configure()); + test_kernel::NegTestDataInputOutputTypeMismatchNegKernel 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