diff --git a/onert-micro/onert-micro/include/OMStatus.h b/onert-micro/onert-micro/include/OMStatus.h index c7d522a812d..9fe91060f8e 100644 --- a/onert-micro/onert-micro/include/OMStatus.h +++ b/onert-micro/onert-micro/include/OMStatus.h @@ -24,6 +24,7 @@ enum OMStatus { Ok, UnsupportedType, + UnsupportedQuantizationType, UnsupportedActivation, UnsupportedOp, UnknownError, diff --git a/onert-micro/onert-micro/include/pal/common/PALFullyConnectedCommon.h b/onert-micro/onert-micro/include/pal/common/PALFullyConnectedCommon.h new file mode 100644 index 00000000000..e0cd74cf8f5 --- /dev/null +++ b/onert-micro/onert-micro/include/pal/common/PALFullyConnectedCommon.h @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2024 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 ONERT_MICRO_EXECUTE_PAL_FULLY_CONNECTED_COMMON_H +#define ONERT_MICRO_EXECUTE_PAL_FULLY_CONNECTED_COMMON_H + +#include "OMStatus.h" +#include "PALUtils.h" + +#include + +namespace onert_micro +{ +namespace execute +{ +namespace pal +{ + +template +OMStatus FullyConnected(const core::FullyConnectedParams ¶ms, const InputType *input_data, + const core::OMRuntimeShape &filter_shape, const WeightType *filter_data, + const BiasType *bias_data, const core::OMRuntimeShape &output_shape, + OutputType *output_data) +{ + const int32_t input_offset = params.input_offset; + const int32_t filter_offset = params.weights_offset; + const int32_t output_offset = params.output_offset; + const int32_t output_multiplier = params.output_multiplier; + const int output_shift = params.output_shift; + const int32_t output_activation_min = params.quantized_activation_min; + const int32_t output_activation_max = params.quantized_activation_max; + + const int filter_dim_count = filter_shape.dimensionsCount(); + const int output_dim_count = output_shape.dimensionsCount(); + const int batches = + flatSizeSkipDim(output_shape.dimsData(), output_dim_count - 1, output_dim_count); + const int output_depth = output_shape.dims(output_dim_count - 1); + + const int accum_depth = filter_shape.dims(filter_dim_count - 1); + for (int b = 0; b < batches; ++b) + { + for (int out_c = 0; out_c < output_depth; ++out_c) + { + BiasType acc = 0; + for (int d = 0; d < accum_depth; ++d) + { + int32_t input_val = input_data[b * accum_depth + d]; + int32_t filter_val = filter_data[out_c * accum_depth + d]; + acc += (filter_val + filter_offset) * (input_val + input_offset); + } + if (bias_data) + { + acc += bias_data[out_c]; + } + int32_t acc_scaled = multiplyByQuantizedMultiplier(acc, output_multiplier, output_shift); + acc_scaled += output_offset; + acc_scaled = std::max(acc_scaled, output_activation_min); + acc_scaled = std::min(acc_scaled, output_activation_max); + output_data[out_c + output_depth * b] = static_cast(acc_scaled); + } + } + return Ok; +} + +template <> +OMStatus inline FullyConnected(const core::FullyConnectedParams ¶ms, + const float *input_data, + const core::OMRuntimeShape &filter_shape, + const float *filter_data, const float *bias_data, + const core::OMRuntimeShape &output_shape, float *output_data) +{ + const float output_activation_min = params.float_activation_min; + const float output_activation_max = params.float_activation_max; + + const int batches = flatSizeSkipDim(output_shape.dimsData(), output_shape.dimensionsCount() - 1, + output_shape.dimensionsCount()); + const int output_depth = output_shape.dims(output_shape.dimensionsCount() - 1); + const int accum_depth = filter_shape.dims(filter_shape.dimensionsCount() - 1); + + for (int b = 0; b < batches; ++b) + { + for (int out_c = 0; out_c < output_depth; ++out_c) + { + float total = 0.f; + for (int d = 0; d < accum_depth; ++d) + { + total += input_data[b * accum_depth + d] * filter_data[out_c * accum_depth + d]; + } + float bias_value = 0.0f; + if (bias_data) + { + bias_value = bias_data[out_c]; + } + output_data[out_c + output_depth * b] = + std::min(std::max(total + bias_value, output_activation_min), output_activation_max); + } + } + return Ok; +} + +} // namespace pal +} // namespace execute +} // namespace onert_micro + +#endif // ONERT_MICRO_EXECUTE_PAL_FULLY_CONNECTED_COMMON_H diff --git a/onert-micro/onert-micro/include/pal/mcu/KernelsToBuild.lst b/onert-micro/onert-micro/include/pal/mcu/KernelsToBuild.lst index 1b565002c68..bf295c98e3f 100644 --- a/onert-micro/onert-micro/include/pal/mcu/KernelsToBuild.lst +++ b/onert-micro/onert-micro/include/pal/mcu/KernelsToBuild.lst @@ -5,3 +5,4 @@ REGISTER_KERNEL(CONCATENATION, Concatenation) REGISTER_KERNEL(MAX_POOL_2D, MaxPool2D) REGISTER_KERNEL(MUL, Mul) REGISTER_KERNEL(SUB, Sub) +REGISTER_KERNEL(FULLY_CONNECTED, FullyConnected) diff --git a/onert-micro/onert-micro/include/pal/mcu/PALFullyConnected.h b/onert-micro/onert-micro/include/pal/mcu/PALFullyConnected.h new file mode 100644 index 00000000000..458a9103f4a --- /dev/null +++ b/onert-micro/onert-micro/include/pal/mcu/PALFullyConnected.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved + * Copyright 2017 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 ONERT_MICRO_EXECUTE_PAL_FULLY_CONNECTED_H +#define ONERT_MICRO_EXECUTE_PAL_FULLY_CONNECTED_H + +#include "PALFullyConnectedCommon.h" + +#endif // ONERT_MICRO_EXECUTE_PAL_FULLY_CONNECTED_H diff --git a/onert-micro/onert-micro/include/test_models/fully_connected/FloatFullyConnectedKernel.h b/onert-micro/onert-micro/include/test_models/fully_connected/FloatFullyConnectedKernel.h new file mode 100644 index 00000000000..00442fa939a --- /dev/null +++ b/onert-micro/onert-micro/include/test_models/fully_connected/FloatFullyConnectedKernel.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2024 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 ONERT_MICRO_TEST_MODELS_FULLY_CONNECTED_KERNEL_FLOAT_H +#define ONERT_MICRO_TEST_MODELS_FULLY_CONNECTED_KERNEL_FLOAT_H + +#include "TestDataFullyConnectedBase.h" + +namespace onert_micro +{ +namespace test_model +{ +namespace fully_connected_float +{ + +/* + * FullyConnected Kernel: + * + * Input(1, 16) Weight(4, 16) Bias(4) + * \ | / + * \ | / + * FullyConnected + * | + * Output(1, 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, + 0x60, 0x01, 0x00, 0x00, 0xa8, 0x02, 0x00, 0x00, 0xc4, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x4c, 0x01, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00, 0x3c, 0x01, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0xe2, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x40, 0xc0, 0x00, 0x00, 0x80, 0x40, + 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0xc0, + 0x00, 0x00, 0x80, 0xc0, 0x00, 0x00, 0xa0, 0xc0, 0x00, 0x00, 0xc0, 0x40, 0x00, 0x00, 0xe0, 0xc0, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x40, 0x40, + 0x00, 0x00, 0x80, 0xbf, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0xc0, 0xc0, 0x00, 0x00, 0xe0, 0x40, + 0x00, 0x00, 0xa0, 0x40, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0xc0, + 0x00, 0x00, 0x80, 0xc0, 0x00, 0x00, 0xa0, 0xc0, 0x00, 0x00, 0xc0, 0x40, 0x00, 0x00, 0xe0, 0xc0, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x40, 0x40, + 0x00, 0x00, 0x80, 0xbf, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0xc0, 0xc0, 0x00, 0x00, 0xe0, 0x40, + 0x00, 0x00, 0xa0, 0x40, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0xc0, + 0x00, 0x00, 0x80, 0xc0, 0x00, 0x00, 0xa0, 0xc0, 0x00, 0x00, 0xc0, 0x40, 0x00, 0x00, 0xe0, 0xc0, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x40, 0x40, + 0x00, 0x00, 0x80, 0xbf, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0xc0, 0xc0, 0x00, 0x00, 0xe0, 0x40, + 0x00, 0x00, 0xa0, 0x40, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0xc0, + 0x00, 0x00, 0x80, 0xc0, 0x00, 0x00, 0xa0, 0xc0, 0x00, 0x00, 0xc0, 0x40, 0x00, 0x00, 0xe0, 0xc0, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x40, 0x40, + 0x00, 0x00, 0x80, 0xbf, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0xc0, 0xc0, 0x00, 0x00, 0xe0, 0x40, + 0x00, 0x00, 0xa0, 0x40, 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, 0x64, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x6c, 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, 0x08, 0x10, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 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, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, + 0x54, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x90, 0xff, 0xff, 0xff, + 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x6f, 0x75, 0x74, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0xb4, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x62, 0x69, 0x61, 0x73, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0xd8, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 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, 0x02, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 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, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 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 = { + 17.491695, 15.660671, 4.7347794, -15.796822, 20.4776, 18.438372, -0.7529831, 10.671711, + 10.699566, 3.1682281, -22.776001, 1.527811, -0.1198349, -5.748741, -5.1772327, 20.06879}; + +const std::vector reference_output_data = {263.84323, 260.84323, 259.84323, 266.84323}; + +} // namespace fully_connected_float + +class TestDataFloatFullyConnected : public TestDataFullyConnectedBase +{ +public: + TestDataFloatFullyConnected() + { + _input_data = fully_connected_float::input_data; + _reference_output_data = fully_connected_float::reference_output_data; + _test_kernel_model_circle = fully_connected_float::test_kernel_model_circle; + } + + ~TestDataFloatFullyConnected() override = default; +}; + +} // namespace test_model +} // namespace onert_micro + +#endif // ONERT_MICRO_TEST_MODELS_FULLY_CONNECTED_KERNEL_FLOAT_H diff --git a/onert-micro/onert-micro/include/test_models/fully_connected/NegFullyConnectedKernel.h b/onert-micro/onert-micro/include/test_models/fully_connected/NegFullyConnectedKernel.h new file mode 100644 index 00000000000..9dcaa5d0edd --- /dev/null +++ b/onert-micro/onert-micro/include/test_models/fully_connected/NegFullyConnectedKernel.h @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2024 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 ONERT_MICRO_TEST_MODELS_NEG_FULLY_CONNECTED_KERNEL_H +#define ONERT_MICRO_TEST_MODELS_NEG_FULLY_CONNECTED_KERNEL_H + +#include "TestDataFullyConnectedBase.h" + +namespace onert_micro +{ +namespace test_model +{ + +namespace neg_fully_connected_wrong_weight_shape +{ +/* + * FullyConnected Kernel with wrong weight shape (rank should be 2): + * + * Input(1, 64) Weight(1, 8, 64) Bias(8) + * \ | / + * \ | / + * FullyConnected + * | + * Output(1, 8) + */ + +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, + 0x38, 0x00, 0x00, 0x00, 0x8c, 0x01, 0x00, 0x00, 0xa8, 0x01, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x84, 0xff, 0xff, 0xff, 0x88, 0xff, 0xff, 0xff, 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, 0x64, 0x00, 0x00, 0x00, + 0x68, 0x00, 0x00, 0x00, 0x74, 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, 0x08, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x04, 0x00, 0x04, 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, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, + 0x54, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x8c, 0xff, 0xff, 0xff, + 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x6f, 0x75, 0x74, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0xb0, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x62, 0x69, 0x61, 0x73, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0xd4, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x40, 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, 0x02, 0x00, 0x00, 0x00, + 0x69, 0x6e, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 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, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, + 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_fully_connected_wrong_weight_shape + +namespace neg_fully_connected_wrong_bias_shape +{ +/* + * FullyConnected Kernel with wrong bias shape should be equal to output.dim(1): + * + * Input(1, 64) Weight(1, 8, 64) Bias(15) + * \ | / + * \ | / + * FullyConnected + * | + * Output(1, 8) + */ +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, + 0x38, 0x00, 0x00, 0x00, 0x88, 0x01, 0x00, 0x00, 0xa4, 0x01, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x84, 0xff, 0xff, 0xff, 0x88, 0xff, 0xff, 0xff, 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, 0x64, 0x00, 0x00, 0x00, + 0x68, 0x00, 0x00, 0x00, 0x74, 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, 0x08, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x04, 0x00, 0x04, 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, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, + 0x54, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x90, 0xff, 0xff, 0xff, + 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x6f, 0x75, 0x74, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0xb4, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x62, 0x69, 0x61, 0x73, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0xd8, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x40, 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, 0x02, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 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, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 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_fully_connected_wrong_bias_shape + +class NegTestDataWrongWeightShapeFullyConnectedKernel : public NegTestDataBase +{ +public: + NegTestDataWrongWeightShapeFullyConnectedKernel() + { + _test_kernel_model_circle = neg_fully_connected_wrong_weight_shape::test_kernel_model_circle; + } + + ~NegTestDataWrongWeightShapeFullyConnectedKernel() override = default; + + const unsigned char *get_model_ptr() override final { return _test_kernel_model_circle; } + +protected: + const unsigned char *_test_kernel_model_circle; +}; + +class NegTestDataWrongBiasShapeFullyConnectedKernel : public NegTestDataBase +{ +public: + NegTestDataWrongBiasShapeFullyConnectedKernel() + { + _test_kernel_model_circle = neg_fully_connected_wrong_bias_shape::test_kernel_model_circle; + } + + ~NegTestDataWrongBiasShapeFullyConnectedKernel() 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_model +} // namespace onert_micro + +#endif // ONERT_MICRO_TEST_MODELS_NEG_FULLY_CONNECTED_KERNEL_H diff --git a/onert-micro/onert-micro/include/test_models/fully_connected/QuantFullyConnectedKernel.h b/onert-micro/onert-micro/include/test_models/fully_connected/QuantFullyConnectedKernel.h new file mode 100644 index 00000000000..c84aed4c6b8 --- /dev/null +++ b/onert-micro/onert-micro/include/test_models/fully_connected/QuantFullyConnectedKernel.h @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2024 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 ONERT_MICRO_TEST_MODELS_QUANT_FULLY_CONNECTED_KERNEL_H +#define ONERT_MICRO_TEST_MODELS_QUANT_FULLY_CONNECTED_KERNEL_H + +#include "TestDataFullyConnectedBase.h" + +namespace onert_micro +{ +namespace test_model +{ +namespace s8_fully_connected +{ + +/* + * S8 FullyConnected Kernel: + * + * Input(1, 64) Weight(8, 64) + * \ | + * \ | + * FullyConnected + * | + * Output(1, 8) + */ + +const unsigned char test_kernel_model_circle[] = { + 0x1c, 0x00, 0x00, 0x00, 0x43, 0x49, 0x52, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x38, 0x04, 0x00, 0x00, 0x54, 0x04, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x2c, 0x02, 0x00, 0x00, 0x24, 0x02, 0x00, 0x00, 0x1c, 0x02, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x14, 0x21, 0x0e, 0x08, 0x13, 0x09, 0x0c, 0x08, + 0x0a, 0x1d, 0x13, 0x1e, 0x00, 0x09, 0x06, 0x0a, 0x20, 0x06, 0x16, 0x07, 0x26, 0xf8, 0x00, 0x15, + 0x18, 0x04, 0x0d, 0xff, 0x11, 0x0d, 0x11, 0x04, 0x16, 0x0d, 0x18, 0xec, 0x13, 0x07, 0x07, 0x0b, + 0xff, 0x10, 0x10, 0x00, 0x06, 0xff, 0x0b, 0x10, 0xfe, 0x06, 0x26, 0x11, 0xfd, 0x03, 0x00, 0x16, + 0x0f, 0x26, 0x14, 0x13, 0x12, 0x09, 0x00, 0x08, 0x0c, 0x10, 0x06, 0xee, 0x12, 0x01, 0x13, 0x08, + 0x0e, 0x1b, 0x0a, 0x02, 0x08, 0x0a, 0xff, 0x00, 0x0a, 0x0f, 0x20, 0x00, 0x08, 0x14, 0x08, 0x08, + 0xff, 0x06, 0x05, 0x04, 0x09, 0x16, 0x1e, 0x1b, 0x10, 0x03, 0x03, 0x19, 0x1c, 0x0f, 0x00, 0x07, + 0x17, 0x0e, 0x16, 0x01, 0x1a, 0x0b, 0xfd, 0x0c, 0x0a, 0x14, 0x0b, 0x13, 0x11, 0x07, 0xfa, 0xf4, + 0xf8, 0x0b, 0x11, 0x06, 0x10, 0x12, 0x11, 0x0d, 0xfa, 0x20, 0xfb, 0xf5, 0x12, 0xf7, 0x0e, 0x12, + 0x0a, 0x15, 0x0e, 0xfd, 0x06, 0x09, 0x18, 0x01, 0x07, 0x0c, 0x04, 0x0a, 0x0e, 0xfc, 0x24, 0xfa, + 0x08, 0x11, 0x02, 0x08, 0x0d, 0x16, 0x00, 0xf4, 0x22, 0x04, 0x09, 0x15, 0xfa, 0x00, 0xfe, 0x0f, + 0xfa, 0xfa, 0xf8, 0x06, 0x00, 0x0c, 0x15, 0x19, 0x0b, 0x0a, 0x04, 0x0d, 0x0e, 0x12, 0x07, 0x0f, + 0x08, 0x04, 0x08, 0x00, 0x0b, 0x02, 0x12, 0x17, 0xfa, 0x06, 0x0d, 0x0a, 0x0f, 0x10, 0x0d, 0x05, + 0x0d, 0x06, 0xf8, 0x11, 0x0a, 0x09, 0x0a, 0x0a, 0x04, 0x10, 0x11, 0x16, 0x17, 0x02, 0x03, 0x0d, + 0x0b, 0x1a, 0x06, 0x0e, 0x1c, 0x05, 0x07, 0x1e, 0x0e, 0xf3, 0x0c, 0x1a, 0x20, 0x00, 0x14, 0x01, + 0x11, 0x04, 0x02, 0x08, 0x0c, 0x09, 0x10, 0x12, 0x18, 0x0d, 0x04, 0x15, 0x0c, 0x0d, 0xfe, 0x16, + 0x0a, 0x0e, 0x0c, 0xff, 0xf9, 0x15, 0x07, 0x02, 0x11, 0x0d, 0x1b, 0x02, 0x0c, 0x0e, 0x1a, 0x01, + 0x11, 0x05, 0x0b, 0x02, 0x0a, 0x1f, 0x06, 0x07, 0x02, 0x09, 0x0e, 0xfe, 0x05, 0x06, 0x11, 0x14, + 0x0e, 0x11, 0x02, 0x06, 0x0c, 0x19, 0x15, 0x0e, 0x09, 0x13, 0x01, 0x0b, 0xfc, 0xfb, 0x0f, 0x13, + 0xff, 0x03, 0x04, 0x0d, 0xfe, 0x0a, 0x09, 0x15, 0x07, 0x0c, 0xf9, 0x0f, 0x02, 0xfd, 0x10, 0x12, + 0x09, 0x00, 0x0a, 0x0f, 0x0f, 0x02, 0x04, 0x0f, 0x00, 0x18, 0x00, 0x11, 0x02, 0xfe, 0x13, 0x0a, + 0x0f, 0x02, 0x14, 0x11, 0x0b, 0x16, 0x07, 0x14, 0x22, 0x1d, 0x0f, 0x18, 0x05, 0x08, 0x04, 0x02, + 0x0e, 0x07, 0x03, 0x00, 0x00, 0x03, 0x07, 0x18, 0x10, 0x0b, 0x1b, 0x10, 0x07, 0x02, 0x0e, 0x07, + 0x0d, 0x09, 0x15, 0x1f, 0xf9, 0xfe, 0xfb, 0x15, 0x14, 0x12, 0x17, 0x03, 0x05, 0x04, 0xfe, 0x0b, + 0x01, 0x00, 0x16, 0x0f, 0x0b, 0x00, 0x0b, 0x26, 0x03, 0x1f, 0xfe, 0x0c, 0xff, 0x1f, 0x15, 0xfd, + 0x02, 0xff, 0x08, 0xfc, 0x03, 0x00, 0x0f, 0x06, 0x01, 0x01, 0x12, 0x0d, 0x12, 0x0a, 0xfd, 0x03, + 0xfd, 0x0b, 0x06, 0x1d, 0x14, 0x02, 0x04, 0x10, 0x0f, 0x00, 0x04, 0x04, 0x17, 0x15, 0x1c, 0x0a, + 0x0e, 0x12, 0x12, 0x04, 0x01, 0x02, 0x0f, 0x11, 0xf8, 0xfa, 0x05, 0x07, 0x12, 0x06, 0xfc, 0x0a, + 0x1a, 0x14, 0x06, 0x13, 0x0e, 0x18, 0x03, 0x0c, 0xfd, 0x1c, 0x09, 0x12, 0x04, 0xfe, 0x0d, 0xfb, + 0x05, 0x02, 0x1b, 0x02, 0x06, 0x0e, 0x10, 0x10, 0x0a, 0x00, 0x00, 0x11, 0x0e, 0x16, 0x0c, 0x0c, + 0x02, 0x01, 0x05, 0x05, 0x0b, 0xf3, 0x14, 0x0f, 0x0f, 0x0e, 0x14, 0x08, 0x01, 0xef, 0x11, 0x13, + 0xff, 0x02, 0x01, 0x07, 0x0b, 0x19, 0x12, 0x04, 0xf5, 0x10, 0x18, 0xff, 0x08, 0x03, 0x03, 0x14, + 0x01, 0x0a, 0xfb, 0x0d, 0x0e, 0x03, 0x10, 0x06, 0x8c, 0xff, 0xff, 0xff, 0x90, 0xff, 0xff, 0xff, + 0x94, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, + 0x18, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, + 0x68, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x08, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, + 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x2a, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x48, 0x00, 0x00, 0x00, + 0x1c, 0xff, 0xff, 0xff, 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, 0xc0, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x03, 0x00, 0x00, 0x00, + 0x6f, 0x75, 0x74, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x92, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x09, 0x4c, 0x00, 0x00, 0x00, 0x84, 0xff, 0xff, 0xff, 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, + 0xd4, 0x59, 0x81, 0x3f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xc1, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x41, 0x06, 0x00, 0x00, 0x00, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x40, 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, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, + 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, 0x20, 0x41, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xc1, 0x02, 0x00, 0x00, 0x00, + 0x69, 0x6e, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 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, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, + 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 = {-5, 0, -5, 4, -3, 4, 5, 2, -3, -1, 5, 0, -4, -1, 2, 5, + 0, 0, -5, 0, -4, 2, 2, -2, -1, 5, -2, 3, 4, 4, -1, 3, + 0, 5, -2, 3, -3, -5, 1, 3, 2, 5, -5, 0, -3, 3, -3, 0, + -3, 2, 0, 4, -1, -3, 1, 5, -5, 2, -5, 2, -5, -2, -4, 5}; + +const std::vector reference_output_data = {-128, -128, 127, 96, 127, 127, 127, 127}; + +} // namespace s8_fully_connected + +class TestDataS8FullyConnected : public TestDataFullyConnectedBase +{ +public: + TestDataS8FullyConnected() + { + _input_data = s8_fully_connected::input_data; + _reference_output_data = s8_fully_connected::reference_output_data; + _test_kernel_model_circle = s8_fully_connected::test_kernel_model_circle; + } + + ~TestDataS8FullyConnected() override = default; +}; + +} // namespace test_model +} // namespace onert_micro + +#endif // ONERT_MICRO_TEST_MODELS_QUANT_FULLY_CONNECTED_KERNEL_H diff --git a/onert-micro/onert-micro/include/test_models/fully_connected/TestDataFullyConnectedBase.h b/onert-micro/onert-micro/include/test_models/fully_connected/TestDataFullyConnectedBase.h new file mode 100644 index 00000000000..86ae1e5eba8 --- /dev/null +++ b/onert-micro/onert-micro/include/test_models/fully_connected/TestDataFullyConnectedBase.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2024 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 ONERT_MICRO_TEST_MODELS_FULLY_CONNECTED_KERNEL_BASE_H +#define ONERT_MICRO_TEST_MODELS_FULLY_CONNECTED_KERNEL_BASE_H + +#include "test_models/TestDataBase.h" + +namespace onert_micro +{ +namespace test_model +{ + +template class TestDataFullyConnectedBase : public TestDataBase +{ +public: + 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_model +} // namespace onert_micro + +#endif // ONERT_MICRO_TEST_MODELS_FULLY_CONNECTED_KERNEL_BASE_H diff --git a/onert-micro/onert-micro/src/execute/kernels/FullyConnected.cpp b/onert-micro/onert-micro/src/execute/kernels/FullyConnected.cpp new file mode 100644 index 00000000000..c86e7146be7 --- /dev/null +++ b/onert-micro/onert-micro/src/execute/kernels/FullyConnected.cpp @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2024 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. + */ + +#include "OMStatus.h" + +#include "core/OMUtils.h" +#include "core/OMKernelData.h" + +#include "execute/OMKernelExecutionBuilder.h" +#include "execute/OMUtils.h" +#include "execute/OMRuntimeKernel.h" + +#include "PALFullyConnected.h" + +using namespace onert_micro; +using namespace onert_micro::core; +using namespace onert_micro::execute; + +namespace +{ + +constexpr uint32_t numInput = 3; +constexpr uint32_t numOutput = 1; + +constexpr uint32_t inputTensorIdx = 0; +constexpr uint32_t weightTensorIdx = 1; +constexpr uint32_t biasTensorIdx = 2; + +constexpr uint32_t outputTensorIdx = 0; + +#ifndef DIS_QUANT +void calculateOpDataFullyConnected(const circle::Tensor *input, const circle::Tensor *weights, + const circle::Tensor *output, + circle::ActivationFunctionType activation, + FullyConnectedParams ¶ms) +{ + double real_multiplier = 0.0; + int output_shift; + int32_t output_activation_min; + int32_t output_activation_max; + int32_t output_multiplier; + + assert(input->quantization() != nullptr); // Fix caller + assert(input->quantization()->scale()->size() == 1); // Fix caller + assert(input->quantization()->zero_point()->size() == 1); // Fix caller + + assert(weights->quantization() != nullptr); // Fix caller + assert(weights->quantization()->scale()->size() == 1); // Fix caller + assert(weights->quantization()->zero_point()->size() == 1); // Fix caller + + assert(output->quantization() != nullptr); // Fix caller + assert(output->quantization()->scale()->size() == 1); // Fix caller + assert(output->quantization()->zero_point()->size() == 1); // Fix caller + + const float input_scale = *input->quantization()->scale()->begin(); + const float weight_scale = *weights->quantization()->scale()->begin(); + const float output_scale = *output->quantization()->scale()->begin(); + + const float input_zero_point = *input->quantization()->zero_point()->begin(); + const float weights_zero_point = *weights->quantization()->zero_point()->begin(); + const float output_zero_point = *output->quantization()->zero_point()->begin(); + + real_multiplier = + execute::getQuantizedConvolutionMultipler(input_scale, weight_scale, output_scale); + execute::quantizeMultiplier(real_multiplier, &output_multiplier, &output_shift); + execute::calculateActivationRangeQuantized(activation, output_zero_point, output_scale, + output->type(), &output_activation_min, + &output_activation_max); + + params.output_shift = output_shift; + params.output_multiplier = output_multiplier; + params.input_offset = -input_zero_point; + params.weights_offset = -weights_zero_point; + params.output_offset = output_zero_point; + params.quantized_activation_max = output_activation_max; + params.quantized_activation_min = output_activation_min; +} +#endif + +} // namespace + +// NOTE: doesnt currently support dynamic shapes +OMStatus +onert_micro::execute::execute_kernel_CircleFullyConnected(const OMExecuteArgs &execute_args) +{ + core::OMRuntimeContext &runtime_context = execute_args.runtime_context; + core::OMRuntimeStorage &runtime_storage = execute_args.runtime_storage; + uint16_t op_index = execute_args.kernel_index; + + const circle::Tensor *input; + const circle::Tensor *weight; + const circle::Tensor *output; + + uint8_t *input_data; + uint8_t *weight_data; + uint8_t *bias_data; + uint8_t *output_data; + + const circle::FullyConnectedOptions *options; + // Read kernel + { + execute::OMRuntimeKernel runtime_kernel; + runtime_kernel.readKernel(op_index, runtime_context); + + input = runtime_kernel.inputs[inputTensorIdx]; + weight = runtime_kernel.inputs[weightTensorIdx]; + output = runtime_kernel.outputs[outputTensorIdx]; + assert(input != nullptr); + assert(weight != nullptr); + // Bias can be nullptr + assert(output != nullptr); + + runtime_kernel.getDataFromStorage(op_index, runtime_storage, runtime_context); + + input_data = runtime_kernel.inputs_data[inputTensorIdx]; + weight_data = runtime_kernel.inputs_data[weightTensorIdx]; + bias_data = runtime_kernel.inputs_data[biasTensorIdx]; + output_data = runtime_kernel.outputs_data[outputTensorIdx]; + assert(input_data != nullptr); + assert(weight_data != nullptr); + // Bias can be nullptr + assert(output_data != nullptr); + + options = runtime_kernel.first_operator->builtin_options_as_FullyConnectedOptions(); + } + + OMStatus status; + + switch (input->type()) + { +#ifndef DIS_FLOAT + case circle::TensorType_FLOAT32: + { + FullyConnectedParams params; + status = calculateActivationRange(options->fused_activation_function(), + ¶ms.float_activation_min, ¶ms.float_activation_max); + if (status != Ok) + return status; + + status = + pal::FullyConnected(params, core::utils::castInputData(input_data), + OMRuntimeShape(weight), core::utils::castInputData(weight_data), + core::utils::castInputData(bias_data), OMRuntimeShape(output), + core::utils::castOutputData(output_data)); + } + break; +#endif // DIS_FLOAT +#ifndef DIS_QUANT + case circle::TensorType_INT8: + { + FullyConnectedParams op_params; + + calculateOpDataFullyConnected(input, weight, output, options->fused_activation_function(), + op_params); + + status = + pal::FullyConnected(op_params, core::utils::castInputData(input_data), + OMRuntimeShape(weight), core::utils::castInputData(weight_data), + core::utils::castInputData(bias_data), OMRuntimeShape(output), + core::utils::castOutputData(output_data)); + } + break; + case circle::TensorType_INT16: + { + FullyConnectedParams op_params; + + calculateOpDataFullyConnected(input, weight, output, options->fused_activation_function(), + op_params); + + status = + pal::FullyConnected(op_params, core::utils::castInputData(input_data), + OMRuntimeShape(weight), core::utils::castInputData(weight_data), + core::utils::castInputData(bias_data), OMRuntimeShape(output), + core::utils::castOutputData(output_data)); + } + break; +#endif // DIS_QUANT + default: + { + status = UnsupportedType; + assert(false && "Unsupported type."); + } + } + + return status; +} diff --git a/onert-micro/onert-micro/src/execute/kernels/tests/FullyConnected.test.cpp b/onert-micro/onert-micro/src/execute/kernels/tests/FullyConnected.test.cpp new file mode 100644 index 00000000000..dd1ab900ab2 --- /dev/null +++ b/onert-micro/onert-micro/src/execute/kernels/tests/FullyConnected.test.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2024 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. + */ + +#include "execute/OMTestUtils.h" +#include "test_models/fully_connected/FloatFullyConnectedKernel.h" +#include "test_models/fully_connected/NegFullyConnectedKernel.h" +#include "test_models/fully_connected/QuantFullyConnectedKernel.h" + +namespace onert_micro +{ +namespace execute +{ +namespace testing +{ + +using namespace testing; + +class FullyConnectedTest : public ::testing::Test +{ + // Do nothing +}; + +TEST_F(FullyConnectedTest, Float_P) +{ + onert_micro::test_model::TestDataFloatFullyConnected test_data_kernel; + std::vector output_data_vector = + onert_micro::execute::testing::checkKernel(1, &test_data_kernel); + EXPECT_THAT(output_data_vector, test_data_kernel.get_output_data_by_index(0)); +} + +TEST_F(FullyConnectedTest, Float_S8) +{ + onert_micro::test_model::TestDataS8FullyConnected test_data_kernel; + std::vector output_data_vector = + onert_micro::execute::testing::checkKernel(1, &test_data_kernel); + EXPECT_THAT(output_data_vector, test_data_kernel.get_output_data_by_index(0)); +} + +TEST_F(FullyConnectedTest, Wrong_weight_shape_NEG) +{ + onert_micro::test_model::NegTestDataWrongWeightShapeFullyConnectedKernel test_data_kernel; + + EXPECT_DEATH(checkNEGSISOKernel(&test_data_kernel), ""); +} + +TEST_F(FullyConnectedTest, Wrong_bias_shape_NEG) +{ + onert_micro::test_model::NegTestDataWrongBiasShapeFullyConnectedKernel test_data_kernel; + + EXPECT_DEATH(checkNEGSISOKernel(&test_data_kernel), ""); +} + +// TODO: add S16 test and more NEG tests + +} // namespace testing +} // namespace execute +} // namespace onert_micro diff --git a/onert-micro/onert-micro/src/import/kernels/FullyConnected.cpp b/onert-micro/onert-micro/src/import/kernels/FullyConnected.cpp new file mode 100644 index 00000000000..fa668b7517e --- /dev/null +++ b/onert-micro/onert-micro/src/import/kernels/FullyConnected.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2024 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. + */ + +#include "OMStatus.h" + +#include "import/OMKernelConfigureBuilder.h" + +#include "core/OMUtils.h" +#include "core/OMKernelData.h" + +#include "execute/OMRuntimeKernel.h" + +using namespace onert_micro; +using namespace onert_micro::core; + +namespace +{ + +constexpr uint32_t inputTensorIdx = 0; +constexpr uint32_t weightTensorIdx = 1; +constexpr uint32_t biasTensorIdx = 2; + +constexpr uint32_t outputTensorIdx = 0; + +} // namespace + +OMStatus +onert_micro::import::configure_kernel_CircleFullyConnected(const OMConfigureArgs &config_args) +{ + OMRuntimeContext &runtime_context = config_args.runtime_context; + uint16_t op_index = config_args.kernel_index; + OMRuntimeStorage &runtime_storage = config_args.runtime_storage; + + execute::OMRuntimeKernel runtime_kernel; + runtime_kernel.readKernel(op_index, runtime_context); + + const circle::Tensor *input = runtime_kernel.inputs[inputTensorIdx]; + const circle::Tensor *weight = runtime_kernel.inputs[weightTensorIdx]; + const circle::Tensor *bias = runtime_kernel.inputs[biasTensorIdx]; + + const circle::Tensor *output = runtime_kernel.outputs[outputTensorIdx]; + + assert(input != nullptr); + assert(weight != nullptr); + // Bias can be nullptr + assert(output != nullptr); + + OMStatus status = Ok; + + if ((input->type() == circle::TensorType_FLOAT32 && + weight->type() != circle::TensorType_FLOAT32) or + (input->type() == circle::TensorType_INT8 && weight->type() != circle::TensorType_INT8) or + (input->type() == circle::TensorType_INT16 && weight->type() != circle::TensorType_INT16)) + { + return UnsupportedType; + } + + core::OMRuntimeShape weight_shape(weight); + core::OMRuntimeShape bias_shape(bias); + core::OMRuntimeShape input_shape(input); + core::OMRuntimeShape output_shape(output); + + status = utils::checkCondition(weight_shape.dimensionsCount() == 2); + if (status != Ok) + return status; + + if (input_shape.flatSize() == 1 and output_shape.flatSize() != 1) + { +#ifndef DIS_DYN_SHAPES + int32_t dynamic_tensor_size = + runtime_storage.getDynamicTensorSize(runtime_kernel.inputs_index[inputTensorIdx]); + if (dynamic_tensor_size == -1) + return UnsupportedDynamicShapeCase; +#else + return UnsupportedDynamicShapeCase; +#endif // DIS_DYN_SHAPES + } + + status = utils::checkCondition(bias == nullptr or weight_shape.dims(0) == bias_shape.flatSize()); + + if (input->type() == circle::TensorType_FLOAT32) + return status; + +#ifndef DIS_QUANT + + // Check quantized version + if (input->quantization() == nullptr or output->quantization() == nullptr or + weight->quantization() == nullptr) + return NoQuantization; + + if (output->quantization()->scale() == nullptr or output->quantization()->scale()->size() != 1) + return UnsupportedQuantizationType; + + if (weight->quantization()->scale() == nullptr or weight->quantization()->scale()->size() != 1) + return UnsupportedQuantizationType; + +#endif // DIS_QUANT + + return status; +}