diff --git a/onert-micro/luci-interpreter/include/luci_interpreter/test_models/quantize/FloatQuantizeKernel.h b/onert-micro/luci-interpreter/include/luci_interpreter/test_models/quantize/FloatQuantizeKernel.h new file mode 100644 index 00000000000..7e5e3cb20d6 --- /dev/null +++ b/onert-micro/luci-interpreter/include/luci_interpreter/test_models/quantize/FloatQuantizeKernel.h @@ -0,0 +1,89 @@ +/* + * 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_QUANTIZE_KERNEL_H +#define LUCI_INTERPRETER_TEST_MODELS_FLOAT_QUANTIZE_KERNEL_H + +#include "TestDataQuantizeBase.h" + +namespace luci_interpreter +{ +namespace test_kernel +{ +namespace quantize_float +{ +/* + * Quantize Kernel: + * + * Input(4) + * | + * Quantize + * | + * Output(4) + */ +const unsigned char test_kernel_model_circle[] = { + 0x18, 0x00, 0x00, 0x00, 0x43, 0x49, 0x52, 0x30, 0x00, 0x00, 0x0e, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x2c, 0x00, 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00, 0x78, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, + 0xfc, 0xff, 0xff, 0xff, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x0c, 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, 0x94, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x13, 0x00, 0x0c, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x54, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x14, 0x00, + 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x3f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x43, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x6f, 0x66, 0x6d, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x69, 0x66, 0x6d, 0x00, 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, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, + 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 = {1.0429811, 8.062888, 10.98376, 3.8719032}; + +const std::vector reference_output_data = {1, 8, 11, 4}; + +} // namespace quantize_float + +class TestDataFloatQuantize : public TestDataQuantizeBase +{ +public: + TestDataFloatQuantize() + { + _input_data = quantize_float::input_data; + _reference_output_data = quantize_float::reference_output_data; + _test_kernel_model_circle = quantize_float::test_kernel_model_circle; + } + + ~TestDataFloatQuantize() override = default; +}; + +} // namespace test_kernel +} // namespace luci_interpreter + +#endif // LUCI_INTERPRETER_TEST_MODELS_FLOAT_QUANTIZE_KERNEL_H diff --git a/onert-micro/luci-interpreter/include/luci_interpreter/test_models/quantize/NegQuantizeKernel.h b/onert-micro/luci-interpreter/include/luci_interpreter/test_models/quantize/NegQuantizeKernel.h new file mode 100644 index 00000000000..d42a00c0e99 --- /dev/null +++ b/onert-micro/luci-interpreter/include/luci_interpreter/test_models/quantize/NegQuantizeKernel.h @@ -0,0 +1,89 @@ +/* + * 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_QUANTIZE_KERNEL_H +#define LUCI_INTERPRETER_TEST_MODELS_NEG_QUANTIZE_KERNEL_H + +#include "TestDataQuantizeBase.h" + +namespace luci_interpreter +{ +namespace test_kernel +{ + +namespace neg_invalid_input_output_shape_mismatch_quantize_kernel +{ +/* + * Quantize Kernel with input-output shape mismatch: + * + * Input(4) = Float32 + * | + * Quantize + * | + * Output(5) = Float32 + */ +const unsigned char test_kernel_model_circle[] = { + 0x18, 0x00, 0x00, 0x00, 0x43, 0x49, 0x52, 0x30, 0x00, 0x00, 0x0e, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x2c, 0x00, 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00, 0x78, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, + 0xfc, 0xff, 0xff, 0xff, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x0c, 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, 0x94, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x13, 0x00, 0x0c, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x54, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x14, 0x00, + 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x3f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x43, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x6f, 0x66, 0x6d, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x05, 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, 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, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, + 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_invalid_input_output_shape_mismatch_quantize_kernel + +class NegTestDataInputOutputShapeMismatchQuantizeKernel : public NegTestDataBase +{ +public: + NegTestDataInputOutputShapeMismatchQuantizeKernel() + { + _test_kernel_model_circle = + neg_invalid_input_output_shape_mismatch_quantize_kernel::test_kernel_model_circle; + } + + ~NegTestDataInputOutputShapeMismatchQuantizeKernel() 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_QUANTIZE_KERNEL_H diff --git a/onert-micro/luci-interpreter/include/luci_interpreter/test_models/quantize/TestDataQuantizeBase.h b/onert-micro/luci-interpreter/include/luci_interpreter/test_models/quantize/TestDataQuantizeBase.h new file mode 100644 index 00000000000..412d01277b9 --- /dev/null +++ b/onert-micro/luci-interpreter/include/luci_interpreter/test_models/quantize/TestDataQuantizeBase.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_QUANTIZE_KERNEL_BASE_H +#define LUCI_INTERPRETER_TEST_MODELS_QUANTIZE_KERNEL_BASE_H + +#include "luci_interpreter/test_models/TestDataBase.h" + +namespace luci_interpreter +{ +namespace test_kernel +{ + +template class TestDataQuantizeBase : public TestDataBase +{ +public: + TestDataQuantizeBase() = 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_QUANTIZE_KERNEL_BASE_H diff --git a/onert-micro/luci-interpreter/pal/cmsisnn/KernelsToBuild.lst b/onert-micro/luci-interpreter/pal/cmsisnn/KernelsToBuild.lst index b7a670b50dd..5e0d6735d62 100644 --- a/onert-micro/luci-interpreter/pal/cmsisnn/KernelsToBuild.lst +++ b/onert-micro/luci-interpreter/pal/cmsisnn/KernelsToBuild.lst @@ -41,6 +41,7 @@ REGISTER_KERNEL(SPLIT, Split) REGISTER_KERNEL(STRIDED_SLICE, StridedSlice) REGISTER_KERNEL(SPLIT_V, SplitV) REGISTER_KERNEL(SQRT, Sqrt) +REGISTER_KERNEL(QUANTIZE, Quantize) REGISTER_KERNEL(TANH, Tanh) REGISTER_KERNEL(TRANSPOSE, Transpose) REGISTER_KERNEL(SOFTMAX, Softmax) diff --git a/onert-micro/luci-interpreter/pal/common/PALQuantize.h b/onert-micro/luci-interpreter/pal/common/PALQuantize.h new file mode 100644 index 00000000000..ad2f6abe8bd --- /dev/null +++ b/onert-micro/luci-interpreter/pal/common/PALQuantize.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2023 Samsung Electronics Co., Ltd. All Rights Reserved + * Copyright 2019 The TensorFlow Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LUCI_INTERPRETER_PAL_QUANTIZE_H +#define LUCI_INTERPRETER_PAL_QUANTIZE_H + +#include "Params.h" +#include + +namespace luci_interpreter_pal +{ +template +inline void Quantize(const QuantizationParams &op_params, const int flat_size, + const InputT *input_data, OutputT *output_data) +{ + const int32_t zero_point = op_params.zero_point; + const double scale = op_params.scale; + static constexpr int32_t min_val = std::numeric_limits::min(); + static constexpr int32_t max_val = std::numeric_limits::max(); + + for (int i = 0; i < flat_size; i++) + { + const InputT val = input_data[i]; + int32_t unclamped = + static_cast(std::round(val / static_cast(scale))) + zero_point; + int32_t clamped = std::min(std::max(unclamped, min_val), max_val); + output_data[i] = clamped; + } +} +} // namespace luci_interpreter_pal + +#endif // LUCI_INTERPRETER_PAL_QUANTIZE_H diff --git a/onert-micro/luci-interpreter/pal/common/Params.h b/onert-micro/luci-interpreter/pal/common/Params.h index a676b1e05a9..d641ab87bc1 100644 --- a/onert-micro/luci-interpreter/pal/common/Params.h +++ b/onert-micro/luci-interpreter/pal/common/Params.h @@ -233,6 +233,12 @@ struct SoftmaxParams int row_size; }; +struct QuantizationParams +{ + float scale; + int zero_point; +}; + } // namespace luci_interpreter_pal #endif // LUCI_INTERPRETER_PAL_PARAMS_H diff --git a/onert-micro/luci-interpreter/pal/mcu/KernelsToBuild.lst b/onert-micro/luci-interpreter/pal/mcu/KernelsToBuild.lst index 9d5617339ac..982b9158d91 100644 --- a/onert-micro/luci-interpreter/pal/mcu/KernelsToBuild.lst +++ b/onert-micro/luci-interpreter/pal/mcu/KernelsToBuild.lst @@ -45,6 +45,7 @@ REGISTER_KERNEL(SPLIT, Split) REGISTER_KERNEL(STRIDED_SLICE, StridedSlice) REGISTER_KERNEL(SPLIT_V, SplitV) REGISTER_KERNEL(SQRT, Sqrt) +REGISTER_KERNEL(QUANTIZE, Quantize) REGISTER_KERNEL(TANH, Tanh) REGISTER_KERNEL(TRANSPOSE, Transpose) REGISTER_KERNEL(TRANSPOSE_CONV, TransposeConv) diff --git a/onert-micro/luci-interpreter/src/kernels/Quantize.cpp b/onert-micro/luci-interpreter/src/kernels/Quantize.cpp index 9f622d0778b..a8c28c67f47 100644 --- a/onert-micro/luci-interpreter/src/kernels/Quantize.cpp +++ b/onert-micro/luci-interpreter/src/kernels/Quantize.cpp @@ -14,147 +14,77 @@ * limitations under the License. */ -#include "kernels/Quantize.h" +#ifndef DIS_QUANT + +#include "Builders.h" #include "kernels/Utils.h" +#include "SISOKernel.h" + #include "PALQuantize.h" namespace luci_interpreter { -namespace kernels -{ -namespace +void configure_kernel_CircleQuantize(const circle::Operator *cur_op, + BaseRuntimeGraph *runtime_graph) { + kernels::SISOKernel kernel(cur_op, runtime_graph); -template void call_requantize(const Tensor *input, Tensor *output) -{ - int32_t multiplier; - int shift; - - const double effective_output_scale = input->scale() / output->scale(); - quantizeMultiplier(effective_output_scale, &multiplier, &shift); - - const auto input_shape = getTensorShape(input); - const auto output_shape = getTensorShape(output); - const auto size = tflite::MatchingFlatSize(input_shape, output_shape); - - const auto input_data = getTensorData(input); - - switch (output->element_type()) - { - case DataType::S8: - luci_interpreter_pal::Requantize(input_data, size, multiplier, shift, input->zero_point(), - output->zero_point(), getTensorData(output)); - break; - case DataType::U8: - luci_interpreter_pal::Requantize(input_data, size, multiplier, shift, input->zero_point(), - output->zero_point(), getTensorData(output)); - break; - case DataType::S16: - luci_interpreter_pal::Requantize(input_data, size, multiplier, shift, input->zero_point(), - output->zero_point(), getTensorData(output)); - break; - default: - assert(false && "Unsupported quantized type, yet!"); - } + 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())); + LUCI_INTERPRETER_CHECK(!Tensor::scales(kernel.output()).empty()); + LUCI_INTERPRETER_CHECK(!Tensor::zero_points(kernel.output()).empty()); } -} // namespace - -Quantize::Quantize(const Tensor *input, Tensor *output) : Kernel({input}, {output}) {} - -void Quantize::configure() +void execute_kernel_CircleQuantize(const circle::Operator *cur_op, BaseRuntimeGraph *runtime_graph) { + kernels::SISOKernel kernel(cur_op, runtime_graph); - if (input()->element_type() == DataType::S16) - LUCI_INTERPRETER_CHECK(input()->zero_point() == 0); + const auto *input_data = runtime_graph->getDataByTensor(kernel.input()); + assert(input_data); - switch (input()->element_type()) - { - case DataType::FLOAT32: - { - LUCI_INTERPRETER_CHECK(output()->element_type() == DataType::U8 || - output()->element_type() == DataType::S8 || - output()->element_type() == DataType::S16); - break; - } - case DataType::S16: - case DataType::S8: - case DataType::U8: - { - LUCI_INTERPRETER_CHECK(output()->element_type() == DataType::S8 || - output()->element_type() == DataType::U8 || - output()->element_type() == DataType::S16); - if (output()->element_type() == DataType::S16) - { - LUCI_INTERPRETER_CHECK(output()->zero_point() == 0); - } - break; - } - default: - assert(false && "Unsupported type"); - } - // TODO: enable it only if kernel with dynamic shapes - output()->resize(input()->shape()); -} + auto *output_data = runtime_graph->getDataByTensor(kernel.output()); + assert(output_data); -void Quantize::execute() const -{ - switch (input()->element_type()) + const int flat_size = kernels::getTensorRuntimeShape(kernel.input(), runtime_graph).flatSize(); + + switch (Tensor::element_type(kernel.input())) { +#ifndef DIS_FLOAT case DataType::FLOAT32: { - tflite::QuantizationParams op_params; - op_params.zero_point = output()->zero_point(); - op_params.scale = output()->scale(); - const auto input_data = getTensorData(input()); - - switch (output()->element_type()) + luci_interpreter_pal::QuantizationParams params{}; + params.zero_point = Tensor::zero_point(kernel.output()); + params.scale = Tensor::scale(kernel.output()); + switch (Tensor::element_type(kernel.output())) { case DataType::S8: - { - luci_interpreter_pal::Quantize(op_params, getTensorShape(input()), input_data, - getTensorShape(output()), getTensorData(output())); + luci_interpreter_pal::Quantize(params, flat_size, + kernels::getTensorData(input_data), + kernels::getTensorData(output_data)); break; - } case DataType::U8: - { - luci_interpreter_pal::Quantize(op_params, getTensorShape(input()), input_data, - getTensorShape(output()), - getTensorData(output())); + luci_interpreter_pal::Quantize(params, flat_size, + kernels::getTensorData(input_data), + kernels::getTensorData(output_data)); break; - } case DataType::S16: - { - luci_interpreter_pal::Quantize(op_params, getTensorShape(input()), input_data, - getTensorShape(output()), - getTensorData(output())); + luci_interpreter_pal::Quantize(params, flat_size, + kernels::getTensorData(input_data), + kernels::getTensorData(output_data)); break; - } default: - assert(false && "Unsupported type."); + assert(false && "Unsupported type"); } break; } - case DataType::S16: - { - call_requantize(input(), output()); - break; - } - case DataType::S8: - { - call_requantize(input(), output()); - break; - } - case DataType::U8: - { - call_requantize(input(), output()); - break; - } +#endif // DIS_FLOAT default: - assert(false && "Unsupported type."); + assert(false && "Unsupported type"); } } -} // namespace kernels } // namespace luci_interpreter + +#endif // DIS_QUANT diff --git a/onert-micro/luci-interpreter/src/kernels/Quantize.h b/onert-micro/luci-interpreter/src/kernels/Quantize.h deleted file mode 100644 index 006c5366fdd..00000000000 --- a/onert-micro/luci-interpreter/src/kernels/Quantize.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2022 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_QUANTIZE_H -#define LUCI_INTERPRETER_KERNELS_QUANTIZE_H - -#include "core/Kernel.h" -#include "core/KernelParams.h" - -namespace luci_interpreter -{ -namespace kernels -{ - -class Quantize : public Kernel -{ -public: - Quantize(const Tensor *input, Tensor *output); - - const Tensor *input() const { return _inputs[0]; } - Tensor *output() const { return _outputs[0]; } - - void configure() override; - void execute() const override; -}; - -} // namespace kernels -} // namespace luci_interpreter - -#endif // LUCI_INTERPRETER_KERNELS_QUANTIZE_H diff --git a/onert-micro/luci-interpreter/src/kernels/Quantize.test.cpp b/onert-micro/luci-interpreter/src/kernels/Quantize.test.cpp index 22e67fe3fd4..8d6f37fe032 100644 --- a/onert-micro/luci-interpreter/src/kernels/Quantize.test.cpp +++ b/onert-micro/luci-interpreter/src/kernels/Quantize.test.cpp @@ -15,14 +15,14 @@ * limitations under the License. */ -#include "kernels/Quantize.h" #include "kernels/TestUtils.h" -#include "luci_interpreter/TestMemoryManager.h" +#include "luci_interpreter/test_models/quantize/FloatQuantizeKernel.h" +#include "luci_interpreter/test_models/quantize/NegQuantizeKernel.h" + +#include "loader/ModuleLoader.h" namespace luci_interpreter { -namespace kernels -{ namespace { @@ -30,225 +30,58 @@ using namespace testing; class QuantizeTest : public ::testing::Test { -protected: - void SetUp() override { _memory_manager = std::make_unique(); } - - std::unique_ptr _memory_manager; + // Do nothing }; -TEST_F(QuantizeTest, FloatUint8) -{ - std::vector input_data{-63.5, -63, -62.5, -62, -61.5, 62, 62.5, 63, 63.5, 64}; - - std::vector ref_output_data{0, 1, 2, 3, 4, 251, 252, 253, 254, 255}; - - Tensor input_tensor = - makeInputTensor({2, 5}, input_data, _memory_manager.get()); - Tensor output_tensor = makeOutputTensor(DataType::U8, /*scale*/ 0.5, /*zero_point*/ 127); - - Quantize kernel(&input_tensor, &output_tensor); - kernel.configure(); - _memory_manager->allocate_memory(output_tensor); - kernel.execute(); - - EXPECT_THAT(extractTensorData(output_tensor), - ::testing::ElementsAreArray(ref_output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({2, 5})); -} - -TEST_F(QuantizeTest, FloatInt8) -{ - std::vector input_data{-63.5, -63, -62.5, -62, -61.5, 62, 62.5, 63, 63.5, 64}; - - std::vector ref_output_data{-128, -127, -126, -125, -124, 123, 124, 125, 126, 127}; - - Tensor input_tensor = - makeInputTensor({2, 5}, input_data, _memory_manager.get()); - Tensor output_tensor = makeOutputTensor(DataType::S8, /*scale*/ 0.5, /*zero_point*/ -1); - - Quantize kernel(&input_tensor, &output_tensor); - kernel.configure(); - _memory_manager->allocate_memory(output_tensor); - kernel.execute(); - - EXPECT_THAT(extractTensorData(output_tensor), - ::testing::ElementsAreArray(ref_output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({2, 5})); -} - -TEST_F(QuantizeTest, FloatInt16) +template +std::vector checkQuantizeKernel(test_kernel::TestDataBase *test_data_base) { - std::vector input_data{-63.5, -63, -3, -2, -1, 1, 2, 3, 63.5, 64}; + MemoryManager memory_manager{}; + RuntimeModule runtime_module{}; + bool dealloc_input = true; - std::vector ref_output_data{-12700, -12600, -600, -400, -200, - 200, 400, 600, 12700, 12800}; + // Load model with single op + auto *model_data_raw = reinterpret_cast(test_data_base->get_model_ptr()); + ModuleLoader::load(&runtime_module, &memory_manager, model_data_raw, dealloc_input); - Tensor input_tensor = - makeInputTensor({2, 5}, input_data, _memory_manager.get()); - Tensor output_tensor = makeOutputTensor(DataType::S16, /*scale*/ 0.005, /*zero_point*/ 0); + auto *main_runtime_graph = runtime_module.getMainGraph(); + assert(main_runtime_graph->getNumOfInputTensors() == 1); - Quantize kernel(&input_tensor, &output_tensor); - kernel.configure(); - _memory_manager->allocate_memory(output_tensor); - kernel.execute(); + // Set input data + { + auto *input_tensor_data = reinterpret_cast(main_runtime_graph->configureGraphInput(0)); + std::copy(test_data_base->get_input_data_by_index(0).begin(), + test_data_base->get_input_data_by_index(0).end(), input_tensor_data); + } - EXPECT_THAT(extractTensorData(output_tensor), - ::testing::ElementsAreArray(ref_output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({2, 5})); -} - -TEST_F(QuantizeTest, Int16Int16) -{ - std::vector input_data{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - - std::vector ref_output_data{2, 4, 6, 8, 10, 12, 14, 16, 18, 20}; - - Tensor input_tensor = makeInputTensor( - {1, 1, 2, 5}, /*scale*/ 1.0, /*zero_point*/ 0, input_data, _memory_manager.get()); - Tensor output_tensor = makeOutputTensor(DataType::S16, /*scale*/ 0.5, /*zero_point*/ 0); + runtime_module.execute(); - Quantize kernel(&input_tensor, &output_tensor); - kernel.configure(); - _memory_manager->allocate_memory(output_tensor); - kernel.execute(); + assert(main_runtime_graph->getNumOfOutputTensors() == 1); - EXPECT_THAT(extractTensorData(output_tensor), - ::testing::ElementsAreArray(ref_output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({1, 1, 2, 5})); + U *output_data = reinterpret_cast(main_runtime_graph->getOutputDataByIndex(0)); + const size_t num_elements = (main_runtime_graph->getOutputDataSizeByIndex(0) / sizeof(U)); + std::vector output_data_vector(output_data, output_data + num_elements); + return output_data_vector; } -TEST_F(QuantizeTest, Int8Int8) +TEST_F(QuantizeTest, Float_P) { - std::vector input_data{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - - std::vector ref_output_data{1, 3, 5, 7, 9, 11, 13, 15, 17, 19}; - - Tensor input_tensor = makeInputTensor( - {1, 1, 2, 5}, /*scale*/ 0.5, /*zero_point*/ -1, input_data, _memory_manager.get()); - Tensor output_tensor = makeOutputTensor(DataType::S8, /*scale*/ 0.5, /*zero_point*/ -1); - - Quantize kernel(&input_tensor, &output_tensor); - kernel.configure(); - _memory_manager->allocate_memory(output_tensor); - kernel.execute(); - - EXPECT_THAT(extractTensorData(output_tensor), - ::testing::ElementsAreArray(ref_output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({1, 1, 2, 5})); + test_kernel::TestDataFloatQuantize test_data_kernel; + std::vector output_data_vector = checkQuantizeKernel(&test_data_kernel); + EXPECT_THAT(output_data_vector, test_data_kernel.get_output_data_by_index(0)); } -TEST_F(QuantizeTest, Uint8Uint8) +TEST_F(QuantizeTest, Input_output_shape_mismatch_NEG) { - std::vector input_data{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - - std::vector ref_output_data{129, 131, 133, 135, 137, 139, 141, 143, 145, 147}; - - Tensor input_tensor = makeInputTensor( - {1, 1, 2, 5}, /*scale*/ 0.5, /*zero_point*/ 127, input_data, _memory_manager.get()); - Tensor output_tensor = makeOutputTensor(DataType::U8, /*scale*/ 0.5, /*zero_point*/ 127); - - Quantize kernel(&input_tensor, &output_tensor); - kernel.configure(); - _memory_manager->allocate_memory(output_tensor); - kernel.execute(); - - EXPECT_THAT(extractTensorData(output_tensor), - ::testing::ElementsAreArray(ref_output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({1, 1, 2, 5})); -} - -TEST_F(QuantizeTest, Int16Int8) -{ - std::vector input_data{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - - std::vector ref_output_data{1, 3, 5, 7, 9, 11, 13, 15, 17, 19}; - - Tensor input_tensor = makeInputTensor( - {1, 1, 2, 5}, /*scale*/ 1.0, /*zero_point*/ 0, input_data, _memory_manager.get()); - Tensor output_tensor = makeOutputTensor(DataType::S8, /*scale*/ 0.5, /*zero_point*/ -1); - - Quantize kernel(&input_tensor, &output_tensor); - kernel.configure(); - _memory_manager->allocate_memory(output_tensor); - kernel.execute(); - - EXPECT_THAT(extractTensorData(output_tensor), - ::testing::ElementsAreArray(ref_output_data)); - EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray({1, 1, 2, 5})); -} - -TEST_F(QuantizeTest, InvalidInputType_NEG) -{ - std::vector input_data{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - - Tensor input_tensor = - makeInputTensor({1, 1, 2, 5}, 0.5, 0, input_data, _memory_manager.get()); - Tensor output_tensor = makeOutputTensor(DataType::S8, /*scale*/ 0.5, /*zero_point*/ -1); - - Quantize kernel(&input_tensor, &output_tensor); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST_F(QuantizeTest, InvalidOutputTypeForFloatInput_NEG) -{ - std::vector input_data{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - - Tensor input_tensor = - makeInputTensor({1, 1, 2, 5}, input_data, _memory_manager.get()); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - Quantize kernel(&input_tensor, &output_tensor); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST_F(QuantizeTest, InvalidOutputTypeForInt16Input_NEG) -{ - std::vector input_data{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - - Tensor input_tensor = - makeInputTensor({1, 1, 2, 5}, 0.5, 0, input_data, _memory_manager.get()); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - Quantize kernel(&input_tensor, &output_tensor); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST_F(QuantizeTest, InvalidOutputTypeForInt8Input_NEG) -{ - std::vector input_data{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - - Tensor input_tensor = - makeInputTensor({1, 1, 2, 5}, 0.5, 0, input_data, _memory_manager.get()); - Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); - - Quantize kernel(&input_tensor, &output_tensor); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST_F(QuantizeTest, InvalidOutputTypeForUint8Input_NEG) -{ - std::vector input_data{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - - Tensor input_tensor = - makeInputTensor({1, 1, 2, 5}, 0.5, 0, input_data, _memory_manager.get()); - Tensor output_tensor = makeOutputTensor(DataType::S32); - - Quantize kernel(&input_tensor, &output_tensor); - EXPECT_ANY_THROW(kernel.configure()); -} - -TEST_F(QuantizeTest, InvalidInputZeroPoint_NEG) -{ - std::vector input_data{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; - - Tensor input_tensor = - makeInputTensor({1, 1, 2, 5}, 0.5, -1, input_data, _memory_manager.get()); - Tensor output_tensor = makeOutputTensor(DataType::S16, 0.5, 0); - - Quantize kernel(&input_tensor, &output_tensor); - EXPECT_ANY_THROW(kernel.configure()); + test_kernel::NegTestDataInputOutputShapeMismatchQuantizeKernel 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