From 08cfdf512d87904e791e31d751b5fb9354083cd2 Mon Sep 17 00:00:00 2001 From: Jang Jiseob Date: Wed, 7 Aug 2024 09:46:43 +0900 Subject: [PATCH 01/78] [onert] Use default cpu planner for training (#13600) This commit make train backend use default cpu planner to be configured by user. ONE-DCO-1.0-Signed-off-by: ragmani --- runtime/onert/backend/train/Backend.h | 2 +- runtime/onert/backend/train/MemoryManager.cc | 11 ++--------- runtime/onert/backend/train/MemoryManager.h | 3 +-- runtime/onert/backend/train/TensorBuilder.cc | 6 ++---- runtime/onert/backend/train/TensorBuilder.h | 2 +- runtime/onert/backend/train/TensorManager.cc | 10 ++++------ runtime/onert/backend/train/TensorManager.h | 3 +-- 7 files changed, 12 insertions(+), 25 deletions(-) diff --git a/runtime/onert/backend/train/Backend.h b/runtime/onert/backend/train/Backend.h index 9ba689d0343..debde889329 100644 --- a/runtime/onert/backend/train/Backend.h +++ b/runtime/onert/backend/train/Backend.h @@ -54,7 +54,7 @@ class Backend : public ::onert::backend::Backend, public backend::train::ITraina const auto &tgraph = *tdata.tgraph; auto optimizer = createOptimizer(tdata.optim_info); auto tr = std::make_shared(); - auto tb = std::make_shared(tr, optimizer.get(), "Bump"); + auto tb = std::make_shared(tr, optimizer.get()); auto tdata_ptr = std::make_unique(std::move(tdata)); auto context = std::make_unique(this, std::move(tdata_ptr), tr, tb, std::move(optimizer)); diff --git a/runtime/onert/backend/train/MemoryManager.cc b/runtime/onert/backend/train/MemoryManager.cc index 87cd15d55a8..a70d4fa5a4b 100644 --- a/runtime/onert/backend/train/MemoryManager.cc +++ b/runtime/onert/backend/train/MemoryManager.cc @@ -29,9 +29,8 @@ namespace backend namespace train { -GradientMemoryManager::GradientMemoryManager(const std::string planner_id, - uint32_t optim_vars_count) - : MemoryManager{planner_id}, _optim_vars_count{optim_vars_count} +GradientMemoryManager::GradientMemoryManager(uint32_t optim_vars_count) + : _optim_vars_count{optim_vars_count} { // DO NOTHING } @@ -58,12 +57,6 @@ DisposableMemoryManager::DisposableMemoryManager() : _mem_planner{createMemoryPl // DO NOTHING } -DisposableMemoryManager::DisposableMemoryManager(const std::string planner_id) - : _mem_planner{createMemoryPlanner(planner_id)} -{ - // DO NOTHING -} - basic::IMemoryPlanner *DisposableMemoryManager::createMemoryPlanner() { auto planner_id = util::getConfigString(util::config::CPU_MEMORY_PLANNER); diff --git a/runtime/onert/backend/train/MemoryManager.h b/runtime/onert/backend/train/MemoryManager.h index 987cf905100..76520020fb6 100644 --- a/runtime/onert/backend/train/MemoryManager.h +++ b/runtime/onert/backend/train/MemoryManager.h @@ -33,7 +33,7 @@ using MemoryManager = backend::basic::MemoryManager; class GradientMemoryManager : public MemoryManager { public: - GradientMemoryManager(const std::string planner_id, uint32_t optimizer_vars_count); + GradientMemoryManager(uint32_t optimizer_vars_count); virtual ~GradientMemoryManager() = default; void allocate(void); @@ -48,7 +48,6 @@ class DisposableMemoryManager { public: DisposableMemoryManager(); - DisposableMemoryManager(const std::string planner_id); void allocate(void); uint8_t *getBuffer(const DisposableTensorIndex &ind) const; diff --git a/runtime/onert/backend/train/TensorBuilder.cc b/runtime/onert/backend/train/TensorBuilder.cc index 80452858057..ee737222be2 100644 --- a/runtime/onert/backend/train/TensorBuilder.cc +++ b/runtime/onert/backend/train/TensorBuilder.cc @@ -26,10 +26,8 @@ namespace train { TensorBuilder::TensorBuilder(const std::shared_ptr &tensor_reg, - const exec::train::optimizer::Optimizer *optimizer, - const std::string planner_id) - : _tensor_reg{tensor_reg}, - _tensor_mgr{new TensorManager(tensor_reg, planner_id, optimizer->getVarCount())}, + const exec::train::optimizer::Optimizer *optimizer) + : _tensor_reg{tensor_reg}, _tensor_mgr{new TensorManager(tensor_reg, optimizer->getVarCount())}, _optimizer{optimizer} { /* empty */ diff --git a/runtime/onert/backend/train/TensorBuilder.h b/runtime/onert/backend/train/TensorBuilder.h index f6ffbbb0e20..1fa46855142 100644 --- a/runtime/onert/backend/train/TensorBuilder.h +++ b/runtime/onert/backend/train/TensorBuilder.h @@ -36,7 +36,7 @@ class TensorBuilder { public: TensorBuilder(const std::shared_ptr &tensor_reg, - const exec::train::optimizer::Optimizer *optimizer, const std::string planner_id); + const exec::train::optimizer::Optimizer *optimizer); /** * @brief Register tensor information to allocate on train backend diff --git a/runtime/onert/backend/train/TensorManager.cc b/runtime/onert/backend/train/TensorManager.cc index cf5373fae74..b8d9f1b4afd 100644 --- a/runtime/onert/backend/train/TensorManager.cc +++ b/runtime/onert/backend/train/TensorManager.cc @@ -53,13 +53,11 @@ namespace backend namespace train { -TensorManager::TensorManager(const std::shared_ptr ®, - const std::string planner_id, uint32_t optim_vars_count) - : _nonconst_mgr{new MemoryManager(planner_id)}, _trainable_mgr{new MemoryManager(planner_id)}, - _back_prop_mgr{new MemoryManager(planner_id)}, - _gradient_mgr{new GradientMemoryManager(planner_id, optim_vars_count)}, +TensorManager::TensorManager(const std::shared_ptr ®, uint32_t optim_vars_count) + : _nonconst_mgr{new MemoryManager()}, _trainable_mgr{new MemoryManager()}, + _back_prop_mgr{new MemoryManager()}, _gradient_mgr{new GradientMemoryManager(optim_vars_count)}, // TODO Find a suitable planner of disposable tensors to reduce peak memory usage - _disposable_back_prop_mgr{new DisposableMemoryManager(std::string("WIC"))}, _tensors{reg} + _disposable_back_prop_mgr{new DisposableMemoryManager()}, _tensors{reg} { // DO NOTHING } diff --git a/runtime/onert/backend/train/TensorManager.h b/runtime/onert/backend/train/TensorManager.h index f8d29b16e1d..9dc4c3b10c0 100644 --- a/runtime/onert/backend/train/TensorManager.h +++ b/runtime/onert/backend/train/TensorManager.h @@ -41,8 +41,7 @@ class TensorManager static constexpr uint64_t _align = 16; public: - TensorManager(const std::shared_ptr ®, const std::string planner_id, - uint32_t optim_vars_count); + TensorManager(const std::shared_ptr ®, uint32_t optim_vars_count); virtual ~TensorManager() = default; void allocateNonConstTensors(); From cab952055d1199751d5ebf470468629e64f0916a Mon Sep 17 00:00:00 2001 From: Jang Jiseob Date: Wed, 7 Aug 2024 15:31:41 +0900 Subject: [PATCH 02/78] [onert] Fix wrong allocation of optimizer variables (#13601) This commit moves the memory management of optimizer variables into TrainableMemoryManager. Optimizer variables have the same characteristic as TrainableTensor in that memory must not be released during training. The such fact makes it easier for TrainableMemoryManager, rather than GradientMemoryManager, to manage optimizer variables. ONE-DCO-1.0-Signed-off-by: ragmani --- runtime/onert/backend/train/MemoryManager.cc | 7 +++-- runtime/onert/backend/train/MemoryManager.h | 6 ++-- runtime/onert/backend/train/TensorManager.cc | 33 ++++++++++---------- runtime/onert/backend/train/TensorManager.h | 4 +-- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/runtime/onert/backend/train/MemoryManager.cc b/runtime/onert/backend/train/MemoryManager.cc index a70d4fa5a4b..4902e2a7eaa 100644 --- a/runtime/onert/backend/train/MemoryManager.cc +++ b/runtime/onert/backend/train/MemoryManager.cc @@ -29,13 +29,13 @@ namespace backend namespace train { -GradientMemoryManager::GradientMemoryManager(uint32_t optim_vars_count) +TrainableMemoryManager::TrainableMemoryManager(uint32_t optim_vars_count) : _optim_vars_count{optim_vars_count} { // DO NOTHING } -void GradientMemoryManager::allocate(void) +void TrainableMemoryManager::allocate(void) { _mem_alloc = std::make_shared(_mem_planner->capacity()); assert(_mem_alloc->base()); @@ -44,7 +44,8 @@ void GradientMemoryManager::allocate(void) _var_mem_alloc = std::make_shared(vars_capacity); } -uint8_t *GradientMemoryManager::getOptVarBuffer(const ir::OperandIndex &ind, uint32_t pos_var) const +uint8_t *TrainableMemoryManager::getOptVarBuffer(const ir::OperandIndex &ind, + uint32_t pos_var) const { assert(_mem_planner->memory_plans().find(ind) != _mem_planner->memory_plans().end()); const auto var_offset = pos_var * _mem_planner->capacity(); diff --git a/runtime/onert/backend/train/MemoryManager.h b/runtime/onert/backend/train/MemoryManager.h index 76520020fb6..19a60e32deb 100644 --- a/runtime/onert/backend/train/MemoryManager.h +++ b/runtime/onert/backend/train/MemoryManager.h @@ -30,11 +30,11 @@ namespace train using MemoryManager = backend::basic::MemoryManager; -class GradientMemoryManager : public MemoryManager +class TrainableMemoryManager : public MemoryManager { public: - GradientMemoryManager(uint32_t optimizer_vars_count); - virtual ~GradientMemoryManager() = default; + TrainableMemoryManager(uint32_t optimizer_vars_count); + virtual ~TrainableMemoryManager() = default; void allocate(void); uint8_t *getOptVarBuffer(const ir::OperandIndex &ind, uint32_t pos_var) const; diff --git a/runtime/onert/backend/train/TensorManager.cc b/runtime/onert/backend/train/TensorManager.cc index b8d9f1b4afd..d8404fcc9ed 100644 --- a/runtime/onert/backend/train/TensorManager.cc +++ b/runtime/onert/backend/train/TensorManager.cc @@ -54,8 +54,9 @@ namespace train { TensorManager::TensorManager(const std::shared_ptr ®, uint32_t optim_vars_count) - : _nonconst_mgr{new MemoryManager()}, _trainable_mgr{new MemoryManager()}, - _back_prop_mgr{new MemoryManager()}, _gradient_mgr{new GradientMemoryManager(optim_vars_count)}, + : _nonconst_mgr{new MemoryManager()}, + _trainable_mgr{new TrainableMemoryManager(optim_vars_count)}, + _back_prop_mgr{new MemoryManager()}, _gradient_mgr{new MemoryManager()}, // TODO Find a suitable planner of disposable tensors to reduce peak memory usage _disposable_back_prop_mgr{new DisposableMemoryManager()}, _tensors{reg} { @@ -72,6 +73,19 @@ void TensorManager::allocateTrainableTensors() { allocateMemory(_trainable_mgr.get(), _tensors->trainable_tensors(), std::string{" TRAINABLE TENSOR "}); + + // Set buffers of optimizer variables + // Allocating optimizer variables has been done when calling allocate() of TrainableMemoryManager + for (const auto &[index, trainable_tensor] : _tensors->trainable_tensors()) + { + for (uint32_t var_pos = 0; var_pos < trainable_tensor->optVars().size(); ++var_pos) + { + auto *buffer = _trainable_mgr.get()->getOptVarBuffer(index, var_pos); + trainable_tensor->setOptVarBuffer(buffer, var_pos); + VERBOSE(TensorManager) << std::string{" OPTIM_VAR TENSOR "} << index << " : " + << static_cast(buffer) << std::endl; + } + } } void TensorManager::allocateBackPropTensors() @@ -84,21 +98,6 @@ void TensorManager::allocateGradientTensors() { allocateMemory(_gradient_mgr.get(), _tensors->gradient_tensors(), std::string{" GRADIENT TENSOR "}); - - // Set buffers of optimizer variables - // Allocating optimizer variables has been done when calling allocate() of GradientMemoryManager - for (const auto &pair : _tensors->gradient_tensors()) - { - const auto &index = pair.first; - const auto trainable_tensor = _tensors->trainable_tensors().at(index).get(); - for (uint32_t var_pos = 0; var_pos < trainable_tensor->optVars().size(); ++var_pos) - { - auto *buffer = _gradient_mgr.get()->getOptVarBuffer(index, var_pos); - trainable_tensor->setOptVarBuffer(buffer, var_pos); - VERBOSE(TensorManager) << std::string{" OPTIM_VAR TENSOR "} << index << " : " - << static_cast(buffer) << std::endl; - } - } } void TensorManager::allocateDisposableBackPropTensors() diff --git a/runtime/onert/backend/train/TensorManager.h b/runtime/onert/backend/train/TensorManager.h index 9dc4c3b10c0..6e0910e182d 100644 --- a/runtime/onert/backend/train/TensorManager.h +++ b/runtime/onert/backend/train/TensorManager.h @@ -64,9 +64,9 @@ class TensorManager private: std::unique_ptr _nonconst_mgr; - std::unique_ptr _trainable_mgr; + std::unique_ptr _trainable_mgr; std::unique_ptr _back_prop_mgr; - std::unique_ptr _gradient_mgr; + std::unique_ptr _gradient_mgr; std::unique_ptr _disposable_back_prop_mgr; const std::shared_ptr _tensors; }; From 940bd64909c7c8f91b3a7f450cab22694a6bd054 Mon Sep 17 00:00:00 2001 From: NerdyLee <48589307+ljwoo94@users.noreply.github.com> Date: Wed, 7 Aug 2024 17:14:02 +0900 Subject: [PATCH 03/78] [onert-micro] Bring up SparseCrossEntropyAccuracy Metric (#13527) This commit adds SparseCrossEntropyAccuracy metric that can test accuracy of SparseCrossEntropy loss function. ONE-DCO-1.0-Signed-off-by: Jungwoo Lee Co-authored-by: Jungwoo Lee --- onert-micro/onert-micro/include/OMConfig.h | 1 + .../metrics/SparseCrossEntropyAccuracy.h | 43 +++++++++++++++++ .../src/core/train/OMTrainingHandler.cpp | 15 ++++++ .../onert-micro/src/train/CMakeLists.txt | 1 + .../metrics/SparseCrossEntropyAccuracy.cpp | 47 +++++++++++++++++++ 5 files changed, 107 insertions(+) create mode 100644 onert-micro/onert-micro/include/train/metrics/SparseCrossEntropyAccuracy.h create mode 100644 onert-micro/onert-micro/src/train/metrics/SparseCrossEntropyAccuracy.cpp diff --git a/onert-micro/onert-micro/include/OMConfig.h b/onert-micro/onert-micro/include/OMConfig.h index 0ffbf024b1f..2038b57a1e7 100644 --- a/onert-micro/onert-micro/include/OMConfig.h +++ b/onert-micro/onert-micro/include/OMConfig.h @@ -41,6 +41,7 @@ enum OMMetrics MAE_METRICS, CROSS_ENTROPY_METRICS, ACCURACY, + SPARSE_CROSS_ENTROPY_ACCURACY, }; /* diff --git a/onert-micro/onert-micro/include/train/metrics/SparseCrossEntropyAccuracy.h b/onert-micro/onert-micro/include/train/metrics/SparseCrossEntropyAccuracy.h new file mode 100644 index 00000000000..64c73ae20ea --- /dev/null +++ b/onert-micro/onert-micro/include/train/metrics/SparseCrossEntropyAccuracy.h @@ -0,0 +1,43 @@ +/* + * 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_TRAIN_METRICS_SPARSE_CROSS_ENTROPY_ACCURACY_H +#define ONERT_MICRO_TRAIN_METRICS_SPARSE_CROSS_ENTROPY_ACCURACY_H + +#include "OMStatus.h" + +#include + +namespace onert_micro +{ +namespace train +{ +namespace metrics +{ + +// Accuracy metric +struct SparseCrossEntropyAccuracy +{ + // Calculate accuracy metric between calculated and target data + static float calculateValue(const uint32_t flat_size, const float *calculated_data, + const float *target_data); +}; + +} // namespace metrics +} // namespace train +} // namespace onert_micro + +#endif // ONERT_MICRO_TRAIN_METRICS_SPARSE_CROSS_ENTROPY_ACCURACY_H diff --git a/onert-micro/onert-micro/src/core/train/OMTrainingHandler.cpp b/onert-micro/onert-micro/src/core/train/OMTrainingHandler.cpp index 24535625a02..8ab4a9eb60b 100644 --- a/onert-micro/onert-micro/src/core/train/OMTrainingHandler.cpp +++ b/onert-micro/onert-micro/src/core/train/OMTrainingHandler.cpp @@ -23,6 +23,7 @@ #include "train/metrics/CrossEntropy.h" #include "train/metrics/Accuracy.h" #include "train/metrics/MAE.h" +#include "train/metrics/SparseCrossEntropyAccuracy.h" using namespace onert_micro::core::train; using namespace onert_micro::core; @@ -222,6 +223,12 @@ OMStatus OMTrainingHandler::evaluateMetric(OMMetrics metric, void *metric_val, assert(calculated_data != nullptr); // Get target data + /** NOTE: + * This offset will always return 0 if the MODEL OUTPUT is returning 1 value of prediction. + * (forward_output->size() == length of output vector.) + * one-hot: size == target_numbers + * Sparse cross : size == 1 + */ size_t offset = batch_num * sizeof(core::OMDataType(forward_output_tensor->type())) * flat_size; uint8_t *target_data = _training_storage.getTargetData(i) + offset; @@ -261,6 +268,14 @@ OMStatus OMTrainingHandler::evaluateMetric(OMMetrics metric, void *metric_val, reinterpret_cast(target_data)); break; } + case SPARSE_CROSS_ENTROPY_ACCURACY: + { + // Note: sum up new calculated value for current sample + *f_metric_val += metrics::SparseCrossEntropyAccuracy::calculateValue( + flat_size, reinterpret_cast(calculated_data), + reinterpret_cast(target_data)); + break; + } default: { assert(false && "Unsupported loss type"); diff --git a/onert-micro/onert-micro/src/train/CMakeLists.txt b/onert-micro/onert-micro/src/train/CMakeLists.txt index 6374a9dfc9e..1df3a864ef3 100644 --- a/onert-micro/onert-micro/src/train/CMakeLists.txt +++ b/onert-micro/onert-micro/src/train/CMakeLists.txt @@ -18,6 +18,7 @@ set(SOURCES metrics/MAE.cpp metrics/MSE.cpp metrics/Accuracy.cpp + metrics/SparseCrossEntropyAccuracy.cpp train_optimizers/SGD.cpp train_optimizers/Adam.cpp ) diff --git a/onert-micro/onert-micro/src/train/metrics/SparseCrossEntropyAccuracy.cpp b/onert-micro/onert-micro/src/train/metrics/SparseCrossEntropyAccuracy.cpp new file mode 100644 index 00000000000..260e66ba2fe --- /dev/null +++ b/onert-micro/onert-micro/src/train/metrics/SparseCrossEntropyAccuracy.cpp @@ -0,0 +1,47 @@ +/* + * 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 "train/metrics/SparseCrossEntropyAccuracy.h" + +using namespace onert_micro; +using namespace onert_micro::train; +using namespace onert_micro::train::metrics; + +/* + * return 1.0 if predicted class equals to target + * return 0.0 otherwise + */ +float SparseCrossEntropyAccuracy::calculateValue(const uint32_t flat_size, + const float *calculated_data, + const float *target_data) +{ + // Find target class + uint32_t target_class = static_cast(target_data[0]); + + // Find predicted class + float pred_class = 0.f; + float pred_max_val = calculated_data[0]; + for (uint32_t i = 0; i < flat_size; ++i) + { + if (pred_max_val < calculated_data[i]) + { + pred_max_val = calculated_data[i]; + pred_class = static_cast(i); + } + } + + return pred_class == target_class ? 1.0f : 0.0f; +} From 2d56bf0b715772b8cba6ed1e3642d215fd6c3766 Mon Sep 17 00:00:00 2001 From: NerdyLee <48589307+ljwoo94@users.noreply.github.com> Date: Wed, 7 Aug 2024 17:14:18 +0900 Subject: [PATCH 04/78] [onert-micro] Bring up SparseCrossEntropy Loss Function (#13529) This commit adds new loss function "SparseCrossEntropy" Since this function has different number compare to one-hot-encoded target, offset change condition was added. ONE-DCO-1.0-Signed-off-by: Jungwoo Lee --- onert-micro/onert-micro/include/OMConfig.h | 1 + .../losses_functions/SparseCrossEntropy.h | 43 +++++++++++++++++++ .../src/core/train/OMTrainingHandler.cpp | 17 +++++++- .../onert-micro/src/train/CMakeLists.txt | 1 + .../losses_functions/SparseCrossEntropy.cpp | 43 +++++++++++++++++++ 5 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 onert-micro/onert-micro/include/train/losses_functions/SparseCrossEntropy.h create mode 100644 onert-micro/onert-micro/src/train/losses_functions/SparseCrossEntropy.cpp diff --git a/onert-micro/onert-micro/include/OMConfig.h b/onert-micro/onert-micro/include/OMConfig.h index 2038b57a1e7..c9ded00f3a5 100644 --- a/onert-micro/onert-micro/include/OMConfig.h +++ b/onert-micro/onert-micro/include/OMConfig.h @@ -53,6 +53,7 @@ enum OMLoss CROSS_ENTROPY, MSE, MAE, + SPARSE_CROSS_ENTROPY, }; /* diff --git a/onert-micro/onert-micro/include/train/losses_functions/SparseCrossEntropy.h b/onert-micro/onert-micro/include/train/losses_functions/SparseCrossEntropy.h new file mode 100644 index 00000000000..3b30b980b3f --- /dev/null +++ b/onert-micro/onert-micro/include/train/losses_functions/SparseCrossEntropy.h @@ -0,0 +1,43 @@ +/* + * 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_TRAIN_LOSSES_FUNCTIONS_SPARSE_CROSS_ENTROPY_H +#define ONERT_MICRO_TRAIN_LOSSES_FUNCTIONS_SPARSE_CROSS_ENTROPY_H + +#include "OMStatus.h" + +#include + +namespace onert_micro +{ +namespace train +{ +namespace losses_functions +{ + +// Cross Entropy +struct SparseCrossEntropy +{ + // Calculate sparse cross entropy error backpropagation between calculated and target data + static void calculateErrorBackpropagation(const uint32_t flat_size, const float *calculated_data, + const float *target_data, float *output_grad); +}; + +} // namespace losses_functions +} // namespace train +} // namespace onert_micro + +#endif // ONERT_MICRO_TRAIN_LOSSES_FUNCTIONS_SPARSE_CROSS_ENTROPY_H diff --git a/onert-micro/onert-micro/src/core/train/OMTrainingHandler.cpp b/onert-micro/onert-micro/src/core/train/OMTrainingHandler.cpp index 8ab4a9eb60b..e13fd110b58 100644 --- a/onert-micro/onert-micro/src/core/train/OMTrainingHandler.cpp +++ b/onert-micro/onert-micro/src/core/train/OMTrainingHandler.cpp @@ -19,6 +19,7 @@ #include "core/train/OMTrainingHandler.h" #include "train/losses_functions/MSE.h" #include "train/losses_functions/CrossEntropy.h" +#include "train/losses_functions/SparseCrossEntropy.h" #include "train/metrics/MSE.h" #include "train/metrics/CrossEntropy.h" #include "train/metrics/Accuracy.h" @@ -57,11 +58,18 @@ OMStatus OMTrainingHandler::handleError(const OMConfig &config, OMRuntimeStorage OMStatus status = forward_storage.getDataByTensorIndex(&calculated_data, forward_output_index); assert(calculated_data != nullptr); + OMLoss loss_type = config.training_context.loss; + // Get target data auto data_type_size = sizeof(core::OMDataType(forward_output_tensor->type())); size_t offset = batch_num * data_type_size * flat_size; + + // Need to check loss type to control proper offset. + if (loss_type == SPARSE_CROSS_ENTROPY) + { + offset = batch_num * data_type_size; + } uint8_t *target_data = _training_storage.getTargetData(i) + offset; - OMLoss loss_type = config.training_context.loss; // Allocate data for error gradient for current calculated data and target data uint8_t *output_grad_data; @@ -86,6 +94,13 @@ OMStatus OMTrainingHandler::handleError(const OMConfig &config, OMRuntimeStorage reinterpret_cast(target_data), reinterpret_cast(output_grad_data)); break; } + case SPARSE_CROSS_ENTROPY: + { + losses_functions::SparseCrossEntropy::calculateErrorBackpropagation( + flat_size, reinterpret_cast(calculated_data), + reinterpret_cast(target_data), reinterpret_cast(output_grad_data)); + break; + } default: { assert(false && "Unsupported loss type"); diff --git a/onert-micro/onert-micro/src/train/CMakeLists.txt b/onert-micro/onert-micro/src/train/CMakeLists.txt index 1df3a864ef3..f6c97b36887 100644 --- a/onert-micro/onert-micro/src/train/CMakeLists.txt +++ b/onert-micro/onert-micro/src/train/CMakeLists.txt @@ -14,6 +14,7 @@ set(SOURCES OMBackpropExecutionBuilder.cpp losses_functions/MSE.cpp losses_functions/CrossEntropy.cpp + losses_functions/SparseCrossEntropy.cpp metrics/CrossEntropy.cpp metrics/MAE.cpp metrics/MSE.cpp diff --git a/onert-micro/onert-micro/src/train/losses_functions/SparseCrossEntropy.cpp b/onert-micro/onert-micro/src/train/losses_functions/SparseCrossEntropy.cpp new file mode 100644 index 00000000000..4a194c5edbd --- /dev/null +++ b/onert-micro/onert-micro/src/train/losses_functions/SparseCrossEntropy.cpp @@ -0,0 +1,43 @@ +/* + * 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 "train/losses_functions/SparseCrossEntropy.h" +#include + +using namespace onert_micro; +using namespace onert_micro::train; +using namespace onert_micro::train::losses_functions; + +/* + * dE/dZi = (dE/dy) * (dy / dZi) + * where Z - vector of logits, + * y - probaility of target. + * + * Since dE/dy = -(1/y), + * (true label) if i == y : dE/dZi = py - 1 = y - 1 + * (wrong label) else : dE/dZi = pj + */ +void SparseCrossEntropy::calculateErrorBackpropagation(const uint32_t flat_size, + const float *calculated_data, + const float *target_data, float *output_grad) +{ + uint32_t label = static_cast(target_data[0]); + + for (uint32_t i = 0; i < flat_size; ++i) + { + output_grad[i] = (calculated_data[i] + float(10.0e-32)) - (i == label); + } +} From 5df983196ba104ccc8528330c7d3a9e1b5f8c430 Mon Sep 17 00:00:00 2001 From: Balyshev Artem <43214667+BalyshevArtem@users.noreply.github.com> Date: Wed, 7 Aug 2024 12:16:02 +0300 Subject: [PATCH 05/78] [onert-micro] Add Quantize kernel (#13331) This pr adds Quantize kernel. ONE-DCO-1.0-Signed-off-by: Artem Balyshev --- .../include/pal/common/PALQuantize.h | 58 ++++++++++ .../include/pal/mcu/KernelsToBuild.lst | 2 +- .../quantize/FloatQuantizeKernel.h | 88 +++++++++++++++ .../test_models/quantize/NegQuantizeKernel.h | 87 +++++++++++++++ .../quantize/TestDataQuantizeBase.h | 61 +++++++++++ .../src/execute/kernels/Quantize.cpp | 102 ++++++++++++++++++ .../execute/kernels/tests/Quantize.test.cpp | 52 +++++++++ .../src/import/kernels/Quantize.cpp | 73 +++++++++++++ 8 files changed, 522 insertions(+), 1 deletion(-) create mode 100644 onert-micro/onert-micro/include/pal/common/PALQuantize.h create mode 100644 onert-micro/onert-micro/include/test_models/quantize/FloatQuantizeKernel.h create mode 100644 onert-micro/onert-micro/include/test_models/quantize/NegQuantizeKernel.h create mode 100644 onert-micro/onert-micro/include/test_models/quantize/TestDataQuantizeBase.h create mode 100644 onert-micro/onert-micro/src/execute/kernels/Quantize.cpp create mode 100644 onert-micro/onert-micro/src/execute/kernels/tests/Quantize.test.cpp create mode 100644 onert-micro/onert-micro/src/import/kernels/Quantize.cpp diff --git a/onert-micro/onert-micro/include/pal/common/PALQuantize.h b/onert-micro/onert-micro/include/pal/common/PALQuantize.h new file mode 100644 index 00000000000..8f6c9e54966 --- /dev/null +++ b/onert-micro/onert-micro/include/pal/common/PALQuantize.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_EXECUTE_PAL_QUANTIZE_COMMON_H +#define ONERT_MICRO_EXECUTE_PAL_QUANTIZE_COMMON_H + +#include "core/OMRuntimeShape.h" +#include "OMStatus.h" +#include "core/OMKernelData.h" +#include "PALUtils.h" + +#include + +namespace onert_micro +{ +namespace execute +{ +namespace pal +{ + +template +OMStatus Quantize(const core::QuantizationParams op_params, const uint32_t 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; + } + + return Ok; +} +} // namespace pal +} // namespace execute +} // namespace onert_micro + +#endif // ONERT_MICRO_EXECUTE_PAL_DEQUANTIZE_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 b06563c1151..6b472d9f523 100644 --- a/onert-micro/onert-micro/include/pal/mcu/KernelsToBuild.lst +++ b/onert-micro/onert-micro/include/pal/mcu/KernelsToBuild.lst @@ -68,7 +68,7 @@ REGISTER_KERNEL(STRIDED_SLICE, StridedSlice) REGISTER_KERNEL(SQUARE, Square) REGISTER_KERNEL(SQRT, Sqrt) REGISTER_KERNEL(SPACE_TO_DEPTH, SpaceToDepth) -#/*REGISTER_KERNEL(QUANTIZE, Quantize)*/ +REGISTER_KERNEL(QUANTIZE, Quantize) REGISTER_KERNEL(TANH, Tanh) REGISTER_KERNEL(TRANSPOSE, Transpose) REGISTER_KERNEL(TRANSPOSE_CONV, TransposeConv) diff --git a/onert-micro/onert-micro/include/test_models/quantize/FloatQuantizeKernel.h b/onert-micro/onert-micro/include/test_models/quantize/FloatQuantizeKernel.h new file mode 100644 index 00000000000..b3e0068544d --- /dev/null +++ b/onert-micro/onert-micro/include/test_models/quantize/FloatQuantizeKernel.h @@ -0,0 +1,88 @@ +/* + * 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_FLOAT_QUANTIZE_KERNEL_H +#define ONERT_MICRO_TEST_MODELS_FLOAT_QUANTIZE_KERNEL_H + +#include "TestDataQuantizeBase.h" + +namespace onert_micro +{ +namespace test_model +{ +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, 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, + 0x9c, 0xc4, 0x20, 0x40, 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 = {-16.784391, -1.0657115, -2.8470368, 15.907914}; + +const std::vector reference_output_data = {-7, 0, -1, 6}; +} // 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_model +} // namespace onert_micro + +#endif // ONERT_MICRO_TEST_MODELS_FLOAT_DEQUANTIZE_KERNEL_H diff --git a/onert-micro/onert-micro/include/test_models/quantize/NegQuantizeKernel.h b/onert-micro/onert-micro/include/test_models/quantize/NegQuantizeKernel.h new file mode 100644 index 00000000000..06a3a4b895c --- /dev/null +++ b/onert-micro/onert-micro/include/test_models/quantize/NegQuantizeKernel.h @@ -0,0 +1,87 @@ +/* + * 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_QUANTIZE_KERNEL_H +#define ONERT_MICRO_TEST_MODELS_NEG_QUANTIZE_KERNEL_H + +#include "TestDataQuantizeBase.h" + +namespace onert_micro +{ +namespace test_model +{ +namespace neg_invalid_output_shape_quantize_kernel +{ +/* + * Quantize Kernel with invalid input shape - should be the same: + * + * Input(4) + * | + * Dequantize + * | + * Output(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, + 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, 0x54, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x50, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x14, 0x00, + 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x9c, 0xc4, 0x20, 0x40, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x43, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x6f, 0x66, 0x6d, 0x00, 0x02, 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, 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_output_shape_quantize_kernel + +class NegTestDataWithInvalidOutputShapeQuantizeKernel : public NegTestDataBase +{ +public: + NegTestDataWithInvalidOutputShapeQuantizeKernel() + { + _test_kernel_model_circle = neg_invalid_output_shape_quantize_kernel::test_kernel_model_circle; + } + + ~NegTestDataWithInvalidOutputShapeQuantizeKernel() 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_QUANTIZE_KERNEL_H diff --git a/onert-micro/onert-micro/include/test_models/quantize/TestDataQuantizeBase.h b/onert-micro/onert-micro/include/test_models/quantize/TestDataQuantizeBase.h new file mode 100644 index 00000000000..ed8a981956f --- /dev/null +++ b/onert-micro/onert-micro/include/test_models/quantize/TestDataQuantizeBase.h @@ -0,0 +1,61 @@ +/* + * 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_QUANTIZE_KERNEL_BASE_H +#define ONERT_MICRO_TEST_MODELS_QUANTIZE_KERNEL_BASE_H + +#include "test_models/TestDataBase.h" +#include + +namespace onert_micro +{ +namespace test_model +{ + +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_model +} // namespace onert_micro + +#endif // ONERT_MICRO_TEST_MODELS_QUANTIZE_KERNEL_BASE_H diff --git a/onert-micro/onert-micro/src/execute/kernels/Quantize.cpp b/onert-micro/onert-micro/src/execute/kernels/Quantize.cpp new file mode 100644 index 00000000000..3e6301e7628 --- /dev/null +++ b/onert-micro/onert-micro/src/execute/kernels/Quantize.cpp @@ -0,0 +1,102 @@ +/* + * 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/OMKernelExecutionBuilder.h" +#include "OMStatus.h" +#include "execute/OMRuntimeKernel.h" +#include "core/OMUtils.h" +#include "core/OMRuntimeShape.h" + +#include "PALQuantize.h" + +using namespace onert_micro; +using namespace onert_micro::execute; + +namespace +{ + +constexpr uint32_t inputTensorIdx = 0; +constexpr uint32_t outputTensorIdx = 0; + +} // namespace + +// NOTE: doesnt currently support dynamic shapes +OMStatus onert_micro::execute::execute_kernel_CircleQuantize(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 = nullptr; + const circle::Tensor *output = nullptr; + + uint8_t *input_data = nullptr; + uint8_t *output_data = nullptr; + + OMStatus status = Ok; + + { + OMRuntimeKernel runtime_kernel; + runtime_kernel.readKernel(op_index, runtime_context); + + input = runtime_kernel.inputs[inputTensorIdx]; + output = runtime_kernel.outputs[outputTensorIdx]; + + assert(input != nullptr); + assert(output != nullptr); + + status = runtime_kernel.getDataFromStorage(op_index, runtime_storage, runtime_context); + if (status != Ok) + return status; + + input_data = runtime_kernel.inputs_data[inputTensorIdx]; + output_data = runtime_kernel.outputs_data[outputTensorIdx]; + } + + assert(input_data != nullptr); + assert(output_data != nullptr); + + assert(input->type() == circle::TensorType_FLOAT32); + + switch (output->type()) + { +#ifndef DIS_FLOAT + case circle::TensorType_INT8: + { + assert(output->quantization() != nullptr); + assert(output->quantization()->scale() != nullptr and + output->quantization()->scale()->size() == 1); + assert(output->quantization()->zero_point() != nullptr and + output->quantization()->zero_point()->size() == 1); + core::QuantizationParams params{}; + params.zero_point = output->quantization()->zero_point()->operator[](0); + params.scale = output->quantization()->scale()->operator[](0); + + status = pal::Quantize(params, core::OMRuntimeShape(input).flatSize(), + core::utils::castInputData(input_data), + core::utils::castOutputData(output_data)); + } + break; +#endif // DIS_FLOAT + default: + { + status = UnsupportedType; + assert(false && "Unsupported type."); + } + } + + return status; +} diff --git a/onert-micro/onert-micro/src/execute/kernels/tests/Quantize.test.cpp b/onert-micro/onert-micro/src/execute/kernels/tests/Quantize.test.cpp new file mode 100644 index 00000000000..b991d3e6cc8 --- /dev/null +++ b/onert-micro/onert-micro/src/execute/kernels/tests/Quantize.test.cpp @@ -0,0 +1,52 @@ +/* + * 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/quantize/FloatQuantizeKernel.h" +#include "test_models/quantize/NegQuantizeKernel.h" + +namespace onert_micro +{ +namespace execute +{ +namespace testing +{ + +using namespace testing; + +class QuantizeTest : public ::testing::Test +{ + // Do nothing +}; + +TEST_F(QuantizeTest, Float_P) +{ + onert_micro::test_model::TestDataFloatQuantize 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(QuantizeTest, Invalid_output_shape_NEG) +{ + onert_micro::test_model::NegTestDataWithInvalidOutputShapeQuantizeKernel test_data_kernel; + + EXPECT_DEATH(checkNEGSISOKernel(&test_data_kernel), ""); +} + +} // namespace testing +} // namespace execute +} // namespace onert_micro diff --git a/onert-micro/onert-micro/src/import/kernels/Quantize.cpp b/onert-micro/onert-micro/src/import/kernels/Quantize.cpp new file mode 100644 index 00000000000..bf2750c75c6 --- /dev/null +++ b/onert-micro/onert-micro/src/import/kernels/Quantize.cpp @@ -0,0 +1,73 @@ +/* + * 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 "import/OMKernelConfigureBuilder.h" +#include "core/OMUtils.h" +#include "OMStatus.h" +#include "execute/OMRuntimeKernel.h" + +using namespace onert_micro; +using namespace onert_micro::core; + +namespace +{ + +constexpr uint32_t inputTensorIdx = 0; +constexpr uint32_t outputTensorIdx = 0; + +} // namespace + +OMStatus onert_micro::import::configure_kernel_CircleQuantize(const OMConfigureArgs &config_args) +{ + OMRuntimeContext &runtime_context = config_args.runtime_context; + uint16_t op_index = config_args.kernel_index; + + onert_micro::execute::OMRuntimeKernel runtime_kernel; + + OMStatus status = runtime_kernel.readKernel(op_index, runtime_context); + if (status != Ok) + return status; + + const circle::Tensor *input = runtime_kernel.inputs[inputTensorIdx]; + const circle::Tensor *output = runtime_kernel.outputs[outputTensorIdx]; + + assert(input != nullptr); + assert(output != nullptr); + + OMRuntimeShape input_shape(input); + OMRuntimeShape output_shape(output); + + // Check shapes + status = utils::checkCondition(input_shape == output_shape); + if (status != Ok) + return status; + + // Check input type is float + status = utils::checkCondition(input->type() == circle::TensorType_FLOAT32); + if (status != Ok) + return status; + + // Check output quantization params + const auto *output_quantization = output->quantization(); + status = utils::checkCondition(output->type() != circle::TensorType_FLOAT32 or + output_quantization != nullptr and + output_quantization->scale() != nullptr and + output_quantization->scale()->size() == 1); + if (status != Ok) + return status; + + return status; +} From 127456a29598d055971c3b9cc23b50b879821c38 Mon Sep 17 00:00:00 2001 From: Balyshev Artem <43214667+BalyshevArtem@users.noreply.github.com> Date: Wed, 7 Aug 2024 12:16:24 +0300 Subject: [PATCH 06/78] [onert-micro] Add SplitV kernel (#13335) This pr adds SplitV kernel. ONE-DCO-1.0-Signed-off-by: Artem Balyshev --- .../include/pal/mcu/KernelsToBuild.lst | 2 +- .../test_models/split/FloatSplitKernel.h | 6 +- .../test_models/split_v/FloatSplitVKernel.h | 110 +++++++++++++++++ .../test_models/split_v/NegSplitVKernel.h | 104 ++++++++++++++++ .../test_models/split_v/TestDataSplitVBase.h | 69 +++++++++++ .../src/execute/kernels/SplitV.cpp | 112 ++++++++++++++++++ .../src/execute/kernels/tests/SplitV.test.cpp | 52 ++++++++ .../onert-micro/src/import/kernels/SplitV.cpp | 106 +++++++++++++++++ 8 files changed, 557 insertions(+), 4 deletions(-) create mode 100644 onert-micro/onert-micro/include/test_models/split_v/FloatSplitVKernel.h create mode 100644 onert-micro/onert-micro/include/test_models/split_v/NegSplitVKernel.h create mode 100644 onert-micro/onert-micro/include/test_models/split_v/TestDataSplitVBase.h create mode 100644 onert-micro/onert-micro/src/execute/kernels/SplitV.cpp create mode 100644 onert-micro/onert-micro/src/execute/kernels/tests/SplitV.test.cpp create mode 100644 onert-micro/onert-micro/src/import/kernels/SplitV.cpp diff --git a/onert-micro/onert-micro/include/pal/mcu/KernelsToBuild.lst b/onert-micro/onert-micro/include/pal/mcu/KernelsToBuild.lst index 6b472d9f523..433739de6a0 100644 --- a/onert-micro/onert-micro/include/pal/mcu/KernelsToBuild.lst +++ b/onert-micro/onert-micro/include/pal/mcu/KernelsToBuild.lst @@ -64,7 +64,7 @@ REGISTER_KERNEL(SUB, Sub) REGISTER_KERNEL(SPLIT, Split) REGISTER_KERNEL(SPACE_TO_BATCH_ND, SpaceToBatchND) REGISTER_KERNEL(STRIDED_SLICE, StridedSlice) -#/*REGISTER_KERNEL(SPLIT_V, SplitV)*/ +REGISTER_KERNEL(SPLIT_V, SplitV) REGISTER_KERNEL(SQUARE, Square) REGISTER_KERNEL(SQRT, Sqrt) REGISTER_KERNEL(SPACE_TO_DEPTH, SpaceToDepth) diff --git a/onert-micro/onert-micro/include/test_models/split/FloatSplitKernel.h b/onert-micro/onert-micro/include/test_models/split/FloatSplitKernel.h index 29a0bc1781f..0da703d1ea7 100644 --- a/onert-micro/onert-micro/include/test_models/split/FloatSplitKernel.h +++ b/onert-micro/onert-micro/include/test_models/split/FloatSplitKernel.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ONERT_MICRO_TEST_MODELS_FLOAT_SQRT_KERNEL_H -#define ONERT_MICRO_TEST_MODELS_FLOAT_SQRT_KERNEL_H +#ifndef ONERT_MICRO_TEST_MODELS_FLOAT_SPLIT_KERNEL_H +#define ONERT_MICRO_TEST_MODELS_FLOAT_SPLIT_KERNEL_H #include "TestDataSplitBase.h" @@ -100,4 +100,4 @@ class TestDataFloatSplit : public TestDataSplitBase } // namespace test_model } // namespace onert_micro -#endif // ONERT_MICRO_TEST_MODELS_FLOAT_SQRT_KERNEL_H +#endif // ONERT_MICRO_TEST_MODELS_FLOAT_SPLIT_KERNEL_H diff --git a/onert-micro/onert-micro/include/test_models/split_v/FloatSplitVKernel.h b/onert-micro/onert-micro/include/test_models/split_v/FloatSplitVKernel.h new file mode 100644 index 00000000000..8ebf00861e4 --- /dev/null +++ b/onert-micro/onert-micro/include/test_models/split_v/FloatSplitVKernel.h @@ -0,0 +1,110 @@ +/* + * 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_FLOAT_SPLIT_V_KERNEL_H +#define ONERT_MICRO_TEST_MODELS_FLOAT_SPLIT_V_KERNEL_H + +#include "TestDataSplitVBase.h" + +namespace onert_micro +{ +namespace test_model +{ +namespace split_v_kernel +{ +/* + * SplitV Kernel: + * + * Input(6, 1, 2) Size_splits([1, 2, 3]) Split_dim(scalar=0) + * \ | / + * SplitV + * / | \ + * Output(1, 1, 2) Output(2, 1, 2) Output(3, 1, 2) + */ +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, + 0x6c, 0x00, 0x00, 0x00, 0x4c, 0x02, 0x00, 0x00, 0x68, 0x02, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x58, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, + 0x34, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x56, 0xff, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0xff, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xf4, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, + 0xfc, 0xff, 0xff, 0xff, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x74, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x00, 0x16, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x08, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x14, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x08, 0x01, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, + 0x34, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1c, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6f, 0x66, 0x6d, 0x33, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x48, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6f, 0x66, 0x6d, 0x32, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x74, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x6f, 0x66, 0x6d, 0x31, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xd8, 0xff, 0xff, 0xff, + 0x10, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x5f, 0x64, 0x69, 0x6d, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x14, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x73, 0x69, 0x7a, 0x65, 0x5f, 0x73, 0x70, 0x6c, + 0x69, 0x74, 0x73, 0x00, 0x01, 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, 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x69, 0x66, 0x6d, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 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, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, + 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 = {-3.9030151, -4.558613, -12.806297, -2.64188, + 17.035677, 26.150639, -12.618465, 0.8286438, + -4.850197, -0.20810127, 3.8918018, 4.1862106}; + +const std::vector reference_output_data_1 = {-3.9030151, -4.558613}; +const std::vector reference_output_data_2 = {-12.806297, -2.64188, 17.035677, 26.150639}; +const std::vector reference_output_data_3 = {-12.618465, 0.8286438, -4.850197, + -0.20810127, 3.8918018, 4.1862106}; + +} // namespace split_v_kernel + +class TestDataFloatSplitV : public TestDataSplitVBase +{ +public: + TestDataFloatSplitV() + { + _input_data = split_v_kernel::input_data; + _reference_output_data_1 = split_v_kernel::reference_output_data_1; + _reference_output_data_2 = split_v_kernel::reference_output_data_2; + _test_kernel_model_circle = split_v_kernel::test_kernel_model_circle; + } + + ~TestDataFloatSplitV() override = default; +}; + +} // namespace test_model +} // namespace onert_micro + +#endif // ONERT_MICRO_TEST_MODELS_FLOAT_SPLIT_V_KERNEL_H diff --git a/onert-micro/onert-micro/include/test_models/split_v/NegSplitVKernel.h b/onert-micro/onert-micro/include/test_models/split_v/NegSplitVKernel.h new file mode 100644 index 00000000000..10b7f052336 --- /dev/null +++ b/onert-micro/onert-micro/include/test_models/split_v/NegSplitVKernel.h @@ -0,0 +1,104 @@ +/* + * 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_SPLITV_KERNEL_H +#define ONERT_MICRO_TEST_MODELS_NEG_SPLITV_KERNEL_H + +#include "TestDataSplitVBase.h" + +namespace onert_micro +{ +namespace test_model +{ +namespace neg_input_output_type_mismatch_splitv_kernel +{ +/* + * SplitV Kernel input output type mismatch: should be the sa,e: + * + * Input(6, 1, 2) Size_splits([1, 2, 3]) Split_dim(scalar=0) + * \ | / + * SplitV + * / | \ + * Output(1, 1, 2)-INT32 Output(2, 1, 2) Output(3, 1, 2) + */ +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, + 0x6c, 0x00, 0x00, 0x00, 0x50, 0x02, 0x00, 0x00, 0x6c, 0x02, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x58, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, + 0x34, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x56, 0xff, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0xff, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xf4, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, + 0xfc, 0xff, 0xff, 0xff, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x74, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x00, 0x16, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x08, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x14, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x0c, 0x01, 0x00, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, + 0x34, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x18, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6f, 0x66, 0x6d, 0x33, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x44, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6f, 0x66, 0x6d, 0x32, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0xa8, 0xff, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6f, 0x66, 0x6d, 0x31, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0xd8, 0xff, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x14, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x5f, 0x64, 0x69, + 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0f, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x73, 0x69, 0x7a, 0x65, + 0x5f, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x73, 0x00, 0x01, 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, 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x69, 0x66, 0x6d, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 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, 0x66, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x66, 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_splitv_kernel + +class NegTestDataInputOutputTypeMismatchSplitVKernel : public NegTestDataBase +{ +public: + NegTestDataInputOutputTypeMismatchSplitVKernel() + { + _test_kernel_model_circle = + neg_input_output_type_mismatch_splitv_kernel::test_kernel_model_circle; + } + + ~NegTestDataInputOutputTypeMismatchSplitVKernel() 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_SPLIT_KERNEL_H diff --git a/onert-micro/onert-micro/include/test_models/split_v/TestDataSplitVBase.h b/onert-micro/onert-micro/include/test_models/split_v/TestDataSplitVBase.h new file mode 100644 index 00000000000..674a68a3ef6 --- /dev/null +++ b/onert-micro/onert-micro/include/test_models/split_v/TestDataSplitVBase.h @@ -0,0 +1,69 @@ +/* + * 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_SPLITV_KERNEL_BASE_H +#define ONERT_MICRO_TEST_MODELS_SPLITV_KERNEL_BASE_H + +#include "test_models/TestDataBase.h" +#include + +namespace onert_micro +{ +namespace test_model +{ + +template class TestDataSplitVBase : public TestDataBase +{ +public: + TestDataSplitVBase() = 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 + { + switch (i) + { + case 0: + return _reference_output_data_1; + case 1: + return _reference_output_data_2; + default: + assert(false && "Wrong input index"); + } + } + +protected: + std::vector _input_data; + std::vector _reference_output_data_1; + std::vector _reference_output_data_2; + const unsigned char *_test_kernel_model_circle; +}; + +} // namespace test_model +} // namespace onert_micro + +#endif // ONERT_MICRO_TEST_MODELS_SPLITV_KERNEL_BASE_H diff --git a/onert-micro/onert-micro/src/execute/kernels/SplitV.cpp b/onert-micro/onert-micro/src/execute/kernels/SplitV.cpp new file mode 100644 index 00000000000..c3da0afeb35 --- /dev/null +++ b/onert-micro/onert-micro/src/execute/kernels/SplitV.cpp @@ -0,0 +1,112 @@ +/* + * 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 "PALSplit.h" + +using namespace onert_micro; +using namespace onert_micro::core; +using namespace onert_micro::execute; + +namespace +{ + +constexpr uint32_t inputTensorIdx = 0; +constexpr uint32_t axisTensorIdx = 2; +constexpr uint32_t outputTensorIdx = 0; + +} // namespace + +OMStatus onert_micro::execute::execute_kernel_CircleSplitV(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 *axis; + const circle::Tensor *output; + + uint8_t *input_data; + uint8_t *axis_data; + + // Read kernel + core::SplitParams params{}; + { + execute::OMRuntimeKernel runtime_kernel; + OMStatus status = runtime_kernel.readKernel(op_index, runtime_context); + if (status != Ok) + return status; + + input = runtime_kernel.inputs[inputTensorIdx]; + axis = runtime_kernel.inputs[axisTensorIdx]; + output = runtime_kernel.outputs[outputTensorIdx]; + assert(input != nullptr); + assert(axis != nullptr); + assert(output != nullptr); + + status = runtime_kernel.getDataFromStorage(op_index, runtime_storage, runtime_context); + if (status != Ok) + return status; + + input_data = runtime_kernel.inputs_data[inputTensorIdx]; + axis_data = runtime_kernel.inputs_data[axisTensorIdx]; + assert(input_data != nullptr); + assert(axis_data != nullptr); + + params.num_outputs = runtime_kernel.outputs_num; + + for (uint32_t i = 0; i < params.num_outputs; ++i) + { + params.output_data[i] = runtime_kernel.outputs_data[i]; + } + } + OMStatus status; + OMRuntimeShape axis_shape(axis); + OMRuntimeShape input_shape(input); + OMRuntimeShape output_shape(output); + + int32_t axis_value = axis_data[0]; + if (axis_value < 0) + { + axis_value += input_shape.dimensionsCount() + 1; + } + + switch (input->type()) + { +#ifndef DIS_FLOAT + case circle::TensorType_FLOAT32: + status = pal::Split(params, input_shape, core::utils::castInputData(input_data), + output_shape, axis_value); + break; +#endif // DIS_FLOAT + default: + { + status = UnsupportedActivation; + assert(false && "Unsupported type."); + } + } + + return status; +} diff --git a/onert-micro/onert-micro/src/execute/kernels/tests/SplitV.test.cpp b/onert-micro/onert-micro/src/execute/kernels/tests/SplitV.test.cpp new file mode 100644 index 00000000000..153d1371717 --- /dev/null +++ b/onert-micro/onert-micro/src/execute/kernels/tests/SplitV.test.cpp @@ -0,0 +1,52 @@ +/* + * 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/split_v/FloatSplitVKernel.h" +#include "test_models/split_v/NegSplitVKernel.h" + +namespace onert_micro +{ +namespace execute +{ +namespace testing +{ + +using namespace testing; + +class SplitVTest : public ::testing::Test +{ + // Do nothing +}; + +TEST_F(SplitVTest, Float_P) +{ + onert_micro::test_model::TestDataFloatSplitV 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(SplitVTest, Input_output_type_mismatch_NEG) +{ + onert_micro::test_model::NegTestDataInputOutputTypeMismatchSplitVKernel test_data_kernel; + + EXPECT_DEATH(checkNEGSISOKernel(&test_data_kernel), ""); +} + +} // namespace testing +} // namespace execute +} // namespace onert_micro diff --git a/onert-micro/onert-micro/src/import/kernels/SplitV.cpp b/onert-micro/onert-micro/src/import/kernels/SplitV.cpp new file mode 100644 index 00000000000..44854b8c2e8 --- /dev/null +++ b/onert-micro/onert-micro/src/import/kernels/SplitV.cpp @@ -0,0 +1,106 @@ +/* + * 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 "import/OMKernelConfigureBuilder.h" +#include "execute/OMRuntimeKernel.h" + +using namespace onert_micro; +using namespace onert_micro::core; + +namespace +{ + +constexpr uint32_t inputTensorIdx = 0; +constexpr uint32_t sizeTensorIdx = 1; +constexpr uint32_t axisTensorIdx = 2; +constexpr uint32_t outputTensorIdx = 0; + +} // namespace + +OMStatus onert_micro::import::configure_kernel_CircleSplitV(const OMConfigureArgs &config_args) +{ + OMRuntimeContext &runtime_context = config_args.runtime_context; + OMRuntimeStorage &runtime_storage = config_args.runtime_storage; + uint16_t op_index = config_args.kernel_index; + + onert_micro::execute::OMRuntimeKernel runtime_kernel; + + OMStatus status = runtime_kernel.readKernel(op_index, runtime_context); + if (status != Ok) + return status; + + const circle::Tensor *input = runtime_kernel.inputs[inputTensorIdx]; + const circle::Tensor *size = runtime_kernel.inputs[sizeTensorIdx]; + const circle::Tensor *axis = runtime_kernel.inputs[axisTensorIdx]; + const circle::Tensor *output = runtime_kernel.outputs[outputTensorIdx]; + + assert(input != nullptr); + assert(axis != nullptr); + assert(size != nullptr); + assert(output != nullptr); + + status = utils::checkCondition(output->type() == input->type()); + if (status != Ok) + return status; + + // Check all outputs have the same type + for (uint32_t i = 1; i < runtime_kernel.outputs_num; ++i) + { + status = utils::checkCondition(output->type() == runtime_kernel.outputs[i]->type()); + if (status != Ok) + return status; + } + + status = utils::checkCondition(axis->type() == circle::TensorType_INT32); + if (status != Ok) + return status; + + status = utils::checkCondition(size->type() == circle::TensorType_INT32); + if (status != Ok) + return status; + + // Check size tensor contains exactly output_nums_tensors values + status = utils::checkCondition(OMRuntimeShape(size).flatSize() == runtime_kernel.outputs_num); + + // Check it is scalar + status = utils::checkCondition(OMRuntimeShape(axis).flatSize() == 1); + if (status != Ok) + return status; + + // Check axis value + runtime_kernel.getDataFromStorage(op_index, runtime_storage, runtime_context); + auto *axis_data = reinterpret_cast(runtime_kernel.inputs_data[axisTensorIdx]); + status = utils::checkCondition(axis_data != nullptr); + if (status != Ok) + return status; + + int32_t axis_value = axis_data[0]; + + OMRuntimeShape input_shape(input); + if (axis_value < 0) + { + axis_value += input_shape.dimensionsCount() + 1; + } + + status = utils::checkCondition(axis_value <= input_shape.dimensionsCount() and axis_value >= 0); + if (status != Ok) + return status; + + return status; +} From 5a6bc24481dd0775867fe418872f988812e4e3f3 Mon Sep 17 00:00:00 2001 From: Balyshev Artem <43214667+BalyshevArtem@users.noreply.github.com> Date: Wed, 7 Aug 2024 12:16:52 +0300 Subject: [PATCH 07/78] [onert-micro] Add SVDF kernel (#13337) This pr adds SVDF kernel. ONE-DCO-1.0-Signed-off-by: Artem Balyshev --- .../include/pal/common/PALSVDFCommon.h | 195 +++++++ .../include/pal/mcu/KernelsToBuild.lst | 2 +- .../onert-micro/include/pal/mcu/PALSVDF.h | 23 + .../test_models/svdf/FloatSVDFKernel.h | 514 ++++++++++++++++++ .../include/test_models/svdf/NegSVDFKernel.h | 505 +++++++++++++++++ .../test_models/svdf/TestDataSVDFBase.h | 61 +++ .../onert-micro/src/execute/kernels/SVDF.cpp | 169 ++++++ .../src/execute/kernels/tests/SVDF.test.cpp | 53 ++ .../onert-micro/src/import/kernels/SVDF.cpp | 157 ++++++ 9 files changed, 1678 insertions(+), 1 deletion(-) create mode 100644 onert-micro/onert-micro/include/pal/common/PALSVDFCommon.h create mode 100644 onert-micro/onert-micro/include/pal/mcu/PALSVDF.h create mode 100644 onert-micro/onert-micro/include/test_models/svdf/FloatSVDFKernel.h create mode 100644 onert-micro/onert-micro/include/test_models/svdf/NegSVDFKernel.h create mode 100644 onert-micro/onert-micro/include/test_models/svdf/TestDataSVDFBase.h create mode 100644 onert-micro/onert-micro/src/execute/kernels/SVDF.cpp create mode 100644 onert-micro/onert-micro/src/execute/kernels/tests/SVDF.test.cpp create mode 100644 onert-micro/onert-micro/src/import/kernels/SVDF.cpp diff --git a/onert-micro/onert-micro/include/pal/common/PALSVDFCommon.h b/onert-micro/onert-micro/include/pal/common/PALSVDFCommon.h new file mode 100644 index 00000000000..673d389299f --- /dev/null +++ b/onert-micro/onert-micro/include/pal/common/PALSVDFCommon.h @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2024 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 ONERT_MICRO_EXECUTE_PAL_SVDF_COMMON_H +#define ONERT_MICRO_EXECUTE_PAL_SVDF_COMMON_H + +#include "PALUtils.h" + +#include "core/OMKernelData.h" + +#include + +namespace onert_micro +{ +namespace execute +{ +namespace pal +{ + +namespace +{ +// Returns the floating point value for a fused activation: +inline float activationValFloat(const circle::ActivationFunctionType act, float a) +{ + switch (act) + { + case circle::ActivationFunctionType_NONE: + return a; + case circle::ActivationFunctionType_RELU: + return std::max(0.0f, a); + case circle::ActivationFunctionType_RELU_N1_TO_1: + return std::max(-1.0f, std::min(a, 1.0f)); + case circle::ActivationFunctionType_RELU6: + return std::max(0.0f, std::min(a, 6.0f)); + case circle::ActivationFunctionType_TANH: + return std::tanh(a); + case circle::ActivationFunctionType_SIGN_BIT: + return std::signbit(a); + default: + assert(false && "Not supported"); + } + return 0.0f; // To indicate an unsupported activation (i.e. when a new fused + // activation is added to the enum and not handled here). +} + +static inline void +applyTimeWeightsBiasAndActivation(int batch_size, int memory_size, int num_filters, int num_units, + int rank, const float *const weights_time_ptr, + const float *const bias_ptr, + circle::ActivationFunctionType activation, float *const state_ptr, + float *const scratch_ptr, float *const output_ptr) +{ + // Compute matmul(activation_state, weights_time). + for (int b = 0; b < batch_size; ++b) + { + // Perform batched vector dot product: + float *scratch_ptr_batch = scratch_ptr + b * num_filters; + const float *vector1_ptr = weights_time_ptr; + const float *vector2_ptr = state_ptr + b * memory_size * num_filters; + for (int i = 0; i < num_filters; ++i) + { + *scratch_ptr_batch = 0.f; + for (int j = 0; j < memory_size; ++j) + { + *scratch_ptr_batch += *vector1_ptr++ * *vector2_ptr++; + } + scratch_ptr_batch++; + } + } + + // Initialize output with bias if provided. + if (bias_ptr) + { + // VectorBatchVectorAssign + for (int i = 0; i < batch_size; ++i) + { + float *output_data = output_ptr + i * num_units; + const float *bias_data = bias_ptr; + for (int j = 0; j < num_units; ++j) + { + *output_data++ = *bias_data++; + } + } + } + else + { + float *output_data = output_ptr; + for (int i = 0; i < batch_size * num_units; ++i) + { + *output_data++ = 0.0f; + } + } + + // Reduction sum. + for (int b = 0; b < batch_size; ++b) + { + float *output_ptr_batch = output_ptr + b * num_units; + float *scratch_ptr_batch = scratch_ptr + b * num_filters; + + // Reduction sum vector + for (int i = 0; i < num_units; ++i) + { + for (int j = 0; j < rank; j++) + { + output_ptr_batch[i] += *scratch_ptr_batch++; + } + } + } + + // Apply activation. + for (int b = 0; b < batch_size; ++b) + { + float *output_ptr_batch = output_ptr + b * num_units; + for (int i = 0; i < num_units; ++i) + { + *output_ptr_batch = activationValFloat(activation, *output_ptr_batch); + ++output_ptr_batch; + } + } +} + +} // namespace + +OMStatus SVDF(const float *input_data, const float *weights_feature_data, + const float *weights_time_data, const float *bias_data, float *state_data, + float *scratch_data, float *output_data, const int rank, const int input_size, + const int batch_size, const int num_filters, const int num_units, + const int memory_size, const circle::ActivationFunctionType activation) +{ + // Left shift the activation_state. + { + float *new_state_start = state_data; + const float *old_state_start = state_data + 1; + const float *old_state_end = state_data + batch_size * num_filters * memory_size; + while (old_state_start != old_state_end) + { + *new_state_start++ = *old_state_start++; + } + } + + // Note: no need to clear the latest activation, matmul is not accumulative. + + // Compute conv1d(inputs, weights_feature). + // The activation_state's rightmost column is used to save current cycle + // activation. This is achieved by starting at state_ptr[memory_size - 1] and + // having the stride equal to memory_size. + + // Perform batched matrix vector multiply operation: + { + const float *matrix = weights_feature_data; + const float *vector = input_data; + float *result = &state_data[memory_size - 1]; + float *result_in_batch = result; + for (int i = 0; i < batch_size; ++i) + { + const float *matrix_ptr = matrix; + for (int j = 0; j < num_filters; ++j) + { + float dot_prod = 0.0f; + const float *vector_in_batch = vector + i * input_size; + for (int k = 0; k < input_size; ++k) + { + dot_prod += *matrix_ptr++ * *vector_in_batch++; + } + *result_in_batch = dot_prod; + result_in_batch += memory_size; + } + } + } + + applyTimeWeightsBiasAndActivation(batch_size, memory_size, num_filters, num_units, rank, + weights_time_data, bias_data, activation, state_data, + scratch_data, output_data); + return Ok; +} + +} // namespace pal +} // namespace execute +} // namespace onert_micro + +#endif // ONERT_MICRO_EXECUTE_PAL_SVDF_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 433739de6a0..83208f90cc3 100644 --- a/onert-micro/onert-micro/include/pal/mcu/KernelsToBuild.lst +++ b/onert-micro/onert-micro/include/pal/mcu/KernelsToBuild.lst @@ -75,7 +75,7 @@ REGISTER_KERNEL(TRANSPOSE_CONV, TransposeConv) REGISTER_KERNEL(SOFTMAX, Softmax) #/*REGISTER_KERNEL(SUM, Sum)*/ #/*REGISTER_KERNEL(SELECT_V2, SelectV2)*/ -#/*REGISTER_KERNEL(SVDF, SVDF)*/ +REGISTER_KERNEL(SVDF, SVDF) REGISTER_KERNEL(WHILE, While) #/*REGISTER_KERNEL(UNIDIRECTIONAL_SEQUENCE_LSTM, UnidirectionalSequenceLSTM)*/ #/*REGISTER_KERNEL(RESIZE_BILINEAR, ResizeBilinear)*/ diff --git a/onert-micro/onert-micro/include/pal/mcu/PALSVDF.h b/onert-micro/onert-micro/include/pal/mcu/PALSVDF.h new file mode 100644 index 00000000000..e1c707607c4 --- /dev/null +++ b/onert-micro/onert-micro/include/pal/mcu/PALSVDF.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2024 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 ONERT_MICRO_EXECUTE_PAL_SVDF_H +#define ONERT_MICRO_EXECUTE_PAL_SVDF_H + +#include "PALSVDFCommon.h" + +#endif // ONERT_MICRO_EXECUTE_PAL_SVDF_H diff --git a/onert-micro/onert-micro/include/test_models/svdf/FloatSVDFKernel.h b/onert-micro/onert-micro/include/test_models/svdf/FloatSVDFKernel.h new file mode 100644 index 00000000000..0a445597b66 --- /dev/null +++ b/onert-micro/onert-micro/include/test_models/svdf/FloatSVDFKernel.h @@ -0,0 +1,514 @@ +/* + * 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 ONERT_MICRO_TEST_MODELS_FLOAT_SVDF_KERNEL_H +#define ONERT_MICRO_TEST_MODELS_FLOAT_SVDF_KERNEL_H + +#include "TestDataSVDFBase.h" + +namespace onert_micro +{ +namespace test_model +{ +namespace svdf_float +{ +/* + * SVDF Kernel: + * + * Input(1, 16) + * | + * SVDF + * | + * Output(1, 64) + */ +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, + 0x6c, 0x19, 0x00, 0x00, 0x50, 0x1b, 0x00, 0x00, 0x6c, 0x1b, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x58, 0x19, 0x00, 0x00, 0x4c, 0x19, 0x00, 0x00, 0x44, 0x19, 0x00, 0x00, 0x34, 0x09, 0x00, 0x00, + 0x1c, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xc8, 0xe6, 0xff, 0xff, + 0xe6, 0xf6, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x35, 0x99, 0x20, 0x3f, + 0xda, 0x4f, 0xd8, 0xbd, 0x67, 0xa6, 0x33, 0x3f, 0xbb, 0x81, 0x2a, 0x3f, 0x6d, 0x7d, 0x87, 0x3f, + 0x2d, 0xbd, 0x64, 0x3e, 0xa6, 0x1f, 0x50, 0x3f, 0x98, 0x2e, 0x03, 0xc0, 0xa4, 0x8d, 0xe5, 0x3f, + 0xe6, 0x11, 0xbc, 0x3f, 0x17, 0xc3, 0x70, 0xbf, 0x54, 0xca, 0x3d, 0x3f, 0x14, 0xdc, 0x1e, 0xbf, + 0xe1, 0x81, 0x90, 0xbe, 0x8b, 0xa6, 0xf8, 0x3f, 0x5f, 0xbe, 0x79, 0x3e, 0x88, 0x81, 0xb2, 0xbf, + 0xf8, 0x40, 0x70, 0x3f, 0x7e, 0xc0, 0x0d, 0x40, 0x13, 0x79, 0x08, 0x3f, 0x16, 0xbf, 0xf4, 0x3e, + 0xfb, 0xd9, 0xa3, 0x3f, 0xd4, 0x08, 0x86, 0x3f, 0x14, 0xd3, 0xb8, 0x3e, 0xe5, 0x82, 0x36, 0x3f, + 0xb6, 0xd8, 0xdf, 0xbf, 0xfa, 0x99, 0x00, 0x3e, 0xcc, 0xb9, 0x42, 0x3f, 0x3e, 0x3a, 0x29, 0xbf, + 0x1c, 0x2a, 0xa4, 0xbe, 0x4d, 0x34, 0x4c, 0x3f, 0x2f, 0x5b, 0x0f, 0x3f, 0xe9, 0x7c, 0x1e, 0xbf, + 0x6d, 0x5a, 0x8f, 0x3f, 0x42, 0x07, 0xa8, 0x3f, 0x37, 0x59, 0x26, 0x3f, 0x4b, 0xf0, 0xe2, 0xbf, + 0x9b, 0x10, 0xaa, 0x3c, 0xd1, 0x74, 0x0b, 0xbf, 0xed, 0xfd, 0xe1, 0x3d, 0xd8, 0x76, 0x97, 0x3f, + 0x8e, 0x81, 0xd3, 0x3e, 0xc7, 0x97, 0x2e, 0x3f, 0x61, 0xf6, 0x0b, 0x3e, 0xd6, 0xff, 0x90, 0xbf, + 0x1f, 0xe6, 0x83, 0xbe, 0x8c, 0x42, 0x54, 0x3f, 0x3c, 0x95, 0x24, 0x3f, 0xd2, 0x7f, 0x94, 0xbf, + 0x2a, 0x18, 0xa5, 0xbf, 0xdc, 0x72, 0xa7, 0xbf, 0x2d, 0x54, 0x84, 0xbf, 0x88, 0xc1, 0xf7, 0xbe, + 0x7b, 0xe8, 0x99, 0xbe, 0x09, 0x21, 0xd2, 0x3f, 0x47, 0xa1, 0x92, 0xbf, 0x13, 0xa3, 0x52, 0x3f, + 0x5b, 0x23, 0x3f, 0x3f, 0xb2, 0xf2, 0xdd, 0xbf, 0x0c, 0xd7, 0x07, 0xbf, 0x68, 0xc5, 0x32, 0xbf, + 0x94, 0xbf, 0x30, 0x3e, 0x90, 0x1e, 0x55, 0x3f, 0x96, 0x51, 0x28, 0xbf, 0xf2, 0xf7, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x0c, 0x6e, 0x8f, 0x3c, 0x43, 0x1d, 0xc2, 0x3e, + 0x4a, 0xec, 0xc2, 0x3f, 0xce, 0x89, 0x27, 0x3e, 0xd9, 0xe0, 0x2c, 0xbf, 0xe4, 0x54, 0x22, 0xbf, + 0xae, 0x26, 0xb4, 0xbe, 0x81, 0xf4, 0x49, 0x3e, 0x87, 0x1c, 0xf6, 0xbe, 0xd9, 0x78, 0x1b, 0xbf, + 0x2b, 0xa6, 0xd3, 0x3f, 0x25, 0x20, 0x3e, 0x3f, 0xd6, 0x2c, 0xa7, 0x3f, 0x62, 0xed, 0x0c, 0x3f, + 0x20, 0x6e, 0xc6, 0x3e, 0x87, 0x31, 0x10, 0xc0, 0xf1, 0x84, 0x50, 0xbf, 0x22, 0xf6, 0x03, 0xbf, + 0xff, 0x80, 0xf1, 0xbf, 0x65, 0xfc, 0x82, 0xbf, 0x37, 0x0b, 0x01, 0xc0, 0x90, 0x38, 0x98, 0x3f, + 0x03, 0x5a, 0xa9, 0xbf, 0x0b, 0x95, 0x9d, 0x3e, 0x5c, 0xb7, 0x70, 0x3f, 0x9d, 0xff, 0x65, 0x3f, + 0x99, 0x25, 0xa6, 0x3e, 0xbd, 0x5c, 0x84, 0x3e, 0xa9, 0xb4, 0x50, 0xbf, 0xae, 0x70, 0x4e, 0x3f, + 0x60, 0x8c, 0x83, 0x3f, 0xd0, 0xc5, 0xc6, 0x3f, 0x7b, 0x70, 0xd0, 0x3d, 0xa9, 0xc1, 0x76, 0xbf, + 0x39, 0x37, 0xb2, 0xbe, 0xea, 0x40, 0xbd, 0xbd, 0x31, 0x2b, 0x86, 0x3f, 0xb6, 0x28, 0xc5, 0xbf, + 0x92, 0x9a, 0x8e, 0x3e, 0x86, 0x10, 0x1c, 0x3e, 0xd8, 0x24, 0x9e, 0xbf, 0xac, 0x22, 0xa1, 0x3d, + 0x78, 0xee, 0xed, 0xbf, 0x68, 0xce, 0x1d, 0x40, 0xf6, 0x1b, 0xdf, 0x3e, 0x97, 0x10, 0x44, 0x3e, + 0x52, 0xde, 0x19, 0x3f, 0x1c, 0xbd, 0xfd, 0xbf, 0xa1, 0x64, 0x4c, 0x3f, 0x1b, 0xaa, 0x00, 0xbf, + 0x36, 0xa7, 0x11, 0xbe, 0x6e, 0xdf, 0x9b, 0xbf, 0x3d, 0xc8, 0x11, 0x40, 0xda, 0x8f, 0xc9, 0x3f, + 0x36, 0x26, 0x99, 0xbf, 0x54, 0x0f, 0x7a, 0x3f, 0x3e, 0x41, 0x64, 0x3d, 0xc5, 0xd4, 0x54, 0xc0, + 0xb2, 0x18, 0xa6, 0x3e, 0xd3, 0xed, 0x3c, 0xbe, 0xea, 0x0c, 0x7f, 0xbf, 0xf6, 0xd5, 0xd7, 0xbe, + 0xf8, 0x29, 0x65, 0xbd, 0x79, 0x6e, 0x6a, 0xbf, 0x78, 0x61, 0xde, 0x3f, 0x18, 0xef, 0x7d, 0xbf, + 0xde, 0x29, 0x42, 0x3f, 0x21, 0xfc, 0x0c, 0xbf, 0x90, 0x77, 0x82, 0x3f, 0x85, 0x5e, 0x14, 0xc0, + 0xfd, 0x7d, 0xf2, 0x3e, 0x3f, 0x7a, 0xc9, 0xbf, 0x70, 0x99, 0x5b, 0x3f, 0x63, 0xe9, 0x1c, 0x3e, + 0x29, 0x07, 0x95, 0xbe, 0xa9, 0x3e, 0x0e, 0x3f, 0x2f, 0x57, 0x67, 0x3e, 0x18, 0xe0, 0xb4, 0xbe, + 0xcb, 0x10, 0xe4, 0x3e, 0xc5, 0xd6, 0xa2, 0xbd, 0x7f, 0x1a, 0x59, 0x3e, 0xf3, 0x3b, 0x62, 0x3f, + 0xad, 0x5f, 0x18, 0x3f, 0x87, 0x9a, 0x52, 0x3e, 0x6c, 0x91, 0xc2, 0xbf, 0x32, 0xcc, 0xb9, 0xbf, + 0x17, 0x14, 0xc2, 0x3f, 0xed, 0xbb, 0x73, 0x3f, 0xe2, 0xba, 0x10, 0xbf, 0x62, 0x23, 0xc3, 0xbf, + 0x05, 0x41, 0xed, 0xbe, 0xc9, 0x13, 0xca, 0xbe, 0xa1, 0x7f, 0x8d, 0xbe, 0x1b, 0x08, 0x09, 0x3f, + 0xfe, 0xc7, 0x39, 0x3f, 0x41, 0x06, 0x0f, 0xc0, 0xdd, 0x06, 0xdb, 0x3f, 0x96, 0x5f, 0x07, 0x3e, + 0x37, 0x22, 0x66, 0xbf, 0x59, 0xf4, 0xfd, 0xbf, 0x00, 0x6f, 0x68, 0xbd, 0x2e, 0x62, 0x0f, 0xc0, + 0xf3, 0xb0, 0xc5, 0xbf, 0xb8, 0xaa, 0x62, 0xbf, 0x9b, 0x00, 0x4f, 0x3f, 0xec, 0xbd, 0xfe, 0x3e, + 0x4e, 0x7e, 0xc4, 0xbc, 0x8e, 0x8d, 0xa7, 0x3f, 0xef, 0xa5, 0xfb, 0xbf, 0xaf, 0x17, 0x92, 0xbf, + 0xe5, 0x98, 0xc5, 0xbf, 0x6d, 0x3a, 0x19, 0x3f, 0x25, 0x29, 0x57, 0xbf, 0x80, 0x58, 0x00, 0x3f, + 0x10, 0x21, 0x80, 0xbe, 0x19, 0x5c, 0x50, 0xbe, 0x4f, 0xb2, 0x71, 0x3f, 0x4b, 0xa0, 0x2f, 0x3f, + 0x0f, 0xcf, 0x82, 0xbd, 0x51, 0x86, 0x8b, 0x3f, 0x33, 0xa9, 0x83, 0xbf, 0xa4, 0x21, 0x53, 0x3e, + 0xae, 0x6a, 0x08, 0x3c, 0x23, 0xf4, 0xb6, 0x3f, 0xb2, 0x5b, 0xcc, 0x3e, 0xf3, 0xd1, 0x5c, 0x3f, + 0xea, 0x1c, 0xeb, 0x3e, 0xe9, 0x4e, 0x03, 0xbf, 0x30, 0x56, 0xe6, 0xbe, 0x17, 0xf5, 0xc4, 0xbd, + 0x94, 0x41, 0xcf, 0x3f, 0x0c, 0xb2, 0xec, 0x3f, 0xcb, 0xc5, 0x99, 0xbe, 0x05, 0x18, 0xa6, 0x3f, + 0x1d, 0x06, 0x1a, 0xbf, 0xbe, 0x1d, 0x0a, 0x40, 0xad, 0x0e, 0xb4, 0x3f, 0x51, 0xd6, 0x25, 0xbf, + 0x61, 0x87, 0xa7, 0xbf, 0x13, 0x07, 0x7a, 0x3e, 0xc6, 0x13, 0xe0, 0xbe, 0x1f, 0xfe, 0x42, 0xbf, + 0x26, 0x9c, 0x96, 0xbe, 0x15, 0x1f, 0xdf, 0x3e, 0x80, 0x11, 0x06, 0xbd, 0xf5, 0x7f, 0x03, 0x3d, + 0x9c, 0x46, 0x5f, 0xbe, 0xe9, 0x86, 0x2b, 0x3f, 0x3e, 0x82, 0x02, 0xc0, 0x70, 0xa4, 0xd9, 0x3f, + 0x05, 0xcf, 0xf8, 0xbe, 0xb3, 0x0a, 0x9d, 0xbf, 0x20, 0xfc, 0x87, 0xbf, 0xec, 0xe9, 0x1a, 0x3f, + 0x37, 0x5f, 0x4f, 0xbe, 0xc6, 0x3d, 0x0f, 0xbf, 0x9d, 0x72, 0xa4, 0xbf, 0x87, 0x45, 0x87, 0xbd, + 0xb8, 0xc2, 0x60, 0xbe, 0x65, 0x2e, 0xe0, 0x3f, 0x69, 0xaa, 0xbc, 0x3e, 0xb5, 0xc4, 0x2c, 0xbf, + 0x62, 0x2d, 0x4c, 0x3e, 0x5d, 0x10, 0x09, 0xbe, 0x75, 0xe9, 0x0e, 0xbf, 0x88, 0x3a, 0x46, 0x3e, + 0xd1, 0x5b, 0x86, 0x3f, 0x10, 0x73, 0x36, 0xbf, 0x8c, 0x9d, 0xfb, 0x3e, 0xd6, 0x35, 0xac, 0x3f, + 0x3b, 0x14, 0xe1, 0xbe, 0xab, 0xe9, 0xc0, 0x3f, 0x1c, 0x97, 0xe9, 0x3d, 0xdf, 0x26, 0xac, 0x3e, + 0x67, 0x88, 0x59, 0xbf, 0x4e, 0xf7, 0xb8, 0xbf, 0x52, 0x85, 0x46, 0x3f, 0xa7, 0x8b, 0x0c, 0x3f, + 0x2a, 0x14, 0x48, 0xbe, 0x13, 0x62, 0xe6, 0xbf, 0x5d, 0x88, 0x18, 0x3f, 0xea, 0x9c, 0x17, 0x40, + 0x20, 0x77, 0xb0, 0xbf, 0x71, 0xb1, 0x56, 0x3f, 0x4e, 0x88, 0xcc, 0xbf, 0x2f, 0x42, 0x00, 0x40, + 0x2d, 0x52, 0x4a, 0xbf, 0x08, 0x8d, 0xff, 0x3f, 0x6e, 0x6f, 0x05, 0x3f, 0xcc, 0x05, 0x5e, 0x3f, + 0xe0, 0x25, 0x24, 0x3f, 0xd0, 0xaf, 0x15, 0x40, 0xb7, 0x6a, 0xba, 0xbe, 0x51, 0xeb, 0x83, 0xbe, + 0x0b, 0x12, 0x58, 0x3e, 0x4e, 0x78, 0xe3, 0x3f, 0xcb, 0x34, 0xa1, 0x3f, 0xb6, 0xb4, 0x85, 0xbf, + 0x27, 0xf2, 0xf7, 0x3d, 0xee, 0x30, 0x27, 0xbf, 0x5f, 0xd1, 0x53, 0xbf, 0xf0, 0x42, 0x0c, 0xbf, + 0xa0, 0x57, 0xad, 0xbf, 0x47, 0x27, 0xcb, 0x3f, 0xfb, 0x02, 0xb5, 0x3e, 0x06, 0xb4, 0xfa, 0xbf, + 0xab, 0x85, 0x0c, 0x3f, 0x41, 0x8f, 0xb6, 0xbf, 0x01, 0xca, 0x1b, 0x3f, 0xd3, 0xf1, 0x48, 0x40, + 0x40, 0x4c, 0x01, 0x40, 0x60, 0xb3, 0x2c, 0x3f, 0x48, 0x48, 0xce, 0x3b, 0x6e, 0x7d, 0x50, 0x3e, + 0xe9, 0xbf, 0x6e, 0xbf, 0x5e, 0x24, 0x13, 0x3f, 0x65, 0x3a, 0x80, 0xbf, 0x07, 0x43, 0x86, 0x3e, + 0x66, 0x9d, 0x76, 0xbf, 0x46, 0xb3, 0x42, 0xbf, 0x3a, 0x69, 0xc9, 0xbf, 0xb8, 0x61, 0x6f, 0x3f, + 0xc8, 0xbd, 0xd4, 0x3f, 0x74, 0x73, 0x98, 0x3f, 0x92, 0x49, 0x05, 0xc0, 0xbe, 0x9d, 0xb5, 0x3e, + 0x9d, 0x72, 0x58, 0x3f, 0x12, 0x29, 0x78, 0x3d, 0x74, 0x96, 0xf1, 0xbe, 0x02, 0xab, 0x02, 0xbf, + 0xca, 0xf9, 0x18, 0xbe, 0xb0, 0x33, 0x6b, 0xbf, 0xd7, 0x1e, 0x89, 0xbf, 0xb0, 0xc5, 0x26, 0xbf, + 0x99, 0xcf, 0xd0, 0x3e, 0xb1, 0xae, 0x68, 0xbf, 0xb7, 0xc3, 0xd0, 0xbe, 0x1a, 0x33, 0x37, 0xbf, + 0x4d, 0xf8, 0x95, 0xbf, 0xb4, 0x3e, 0x8e, 0xbf, 0x25, 0x81, 0x6f, 0x3f, 0x78, 0x33, 0xd2, 0xbf, + 0x16, 0x3b, 0xf2, 0x3d, 0x8f, 0x27, 0x53, 0x3f, 0x08, 0x75, 0x27, 0x40, 0x2f, 0x89, 0xd1, 0xbe, + 0xd8, 0x59, 0xb8, 0x3e, 0x41, 0x36, 0x1a, 0xbf, 0xa5, 0x92, 0x01, 0x3e, 0x90, 0xef, 0xb9, 0x3f, + 0xcf, 0x82, 0x8d, 0xbf, 0x04, 0x60, 0x54, 0xbe, 0x93, 0xc2, 0xf1, 0x3f, 0xbb, 0x09, 0x36, 0xbf, + 0xf8, 0x6b, 0x59, 0x3f, 0x01, 0xa7, 0x8f, 0x3f, 0xd3, 0x11, 0x33, 0xbf, 0xed, 0x9d, 0xc7, 0x3f, + 0x55, 0x60, 0x1d, 0x3e, 0x46, 0xff, 0x08, 0xbf, 0xcf, 0xc5, 0xd3, 0xbf, 0x4c, 0xa6, 0x35, 0xbf, + 0x86, 0x41, 0x49, 0xbf, 0x56, 0xef, 0xb1, 0xbf, 0x2c, 0x62, 0x54, 0xbf, 0xe7, 0x81, 0x7a, 0x3f, + 0x38, 0x4b, 0x80, 0x3f, 0xd5, 0x37, 0xf3, 0xbf, 0x0c, 0x67, 0xa7, 0x3f, 0xb7, 0xbf, 0x32, 0x3e, + 0xa1, 0x05, 0x36, 0xbf, 0x0c, 0x7b, 0x95, 0x3f, 0x8d, 0xd0, 0x86, 0xbf, 0x3b, 0x74, 0xe9, 0xbe, + 0x02, 0x76, 0xb1, 0xbe, 0x6b, 0xbe, 0xb3, 0xbf, 0x12, 0xda, 0x8f, 0xbf, 0xc3, 0x7d, 0x2c, 0xbf, + 0x0a, 0x9a, 0x14, 0x3f, 0xf3, 0xbb, 0x77, 0x3f, 0x5d, 0x8f, 0x87, 0xbf, 0x2c, 0x03, 0xdc, 0x3f, + 0xc0, 0xb0, 0xd0, 0x3f, 0x7f, 0xde, 0x47, 0x3f, 0x02, 0xc0, 0x98, 0xbf, 0xec, 0x93, 0x08, 0xc0, + 0x8e, 0x78, 0x9f, 0x3f, 0x27, 0xc5, 0x85, 0x3f, 0xa1, 0x13, 0x40, 0x3f, 0x77, 0xec, 0xc5, 0xbf, + 0x88, 0x7a, 0x6d, 0xbe, 0x96, 0xa1, 0xa9, 0xbf, 0x0e, 0x67, 0xb9, 0x3f, 0xa0, 0x0e, 0xa9, 0xbf, + 0x61, 0xce, 0x4c, 0x3f, 0xcb, 0xd4, 0x73, 0xbf, 0xf6, 0x2d, 0xb6, 0x3e, 0xa0, 0xd3, 0xb4, 0xbf, + 0x42, 0x20, 0x21, 0xbf, 0xf3, 0xf2, 0x00, 0xbf, 0xe3, 0x01, 0x92, 0x3f, 0x19, 0x4f, 0x3f, 0xbf, + 0xb4, 0x47, 0x28, 0xbf, 0x22, 0xa3, 0x94, 0x3f, 0x90, 0x21, 0x9a, 0xbf, 0x35, 0xdd, 0x62, 0xbf, + 0x50, 0x78, 0x8b, 0xbe, 0x9e, 0xac, 0x7d, 0x3f, 0xb3, 0x12, 0xaf, 0x3f, 0x5b, 0x3e, 0xbb, 0x3d, + 0x85, 0xcf, 0x87, 0xbf, 0x51, 0xa3, 0xb5, 0x3f, 0x91, 0x6f, 0xbd, 0xbf, 0xb6, 0x66, 0x3a, 0xbf, + 0x0c, 0x74, 0xc1, 0x3f, 0xa6, 0x79, 0x0b, 0x3f, 0x77, 0x2f, 0x51, 0x3f, 0x3d, 0x3c, 0x51, 0xbf, + 0x3e, 0x83, 0x64, 0xbf, 0xab, 0x82, 0xd7, 0xbe, 0x2c, 0xdf, 0x9f, 0xbe, 0x73, 0x76, 0x1f, 0xbf, + 0x53, 0xfd, 0xf0, 0xbd, 0xec, 0xb5, 0x8a, 0xbf, 0x4b, 0xc8, 0x6e, 0xbf, 0xc6, 0xd2, 0xc4, 0x3e, + 0x27, 0xc9, 0x77, 0x3d, 0xce, 0x0e, 0x5a, 0x3e, 0x7d, 0xbe, 0x22, 0x3f, 0x5b, 0xc8, 0x9a, 0x3e, + 0xe4, 0x5f, 0x9b, 0x3f, 0x18, 0x35, 0x41, 0xbf, 0x5d, 0x5c, 0xd5, 0x3e, 0x46, 0x06, 0x43, 0xbe, + 0xb9, 0x0b, 0x80, 0x3f, 0x70, 0x5a, 0x47, 0x3f, 0xb6, 0x48, 0xa8, 0x3e, 0x5c, 0x5e, 0x24, 0xbf, + 0x8d, 0x46, 0x6c, 0xbe, 0x53, 0x39, 0xf7, 0xbe, 0xac, 0xae, 0x8a, 0xbe, 0x56, 0x69, 0xe2, 0xbf, + 0x1e, 0xb3, 0x85, 0x3f, 0x5a, 0x79, 0x75, 0xbf, 0x9e, 0x78, 0x16, 0x3f, 0xbf, 0xf0, 0x50, 0xbf, + 0x64, 0x26, 0x1e, 0xbd, 0xd4, 0x6a, 0x97, 0xbe, 0xf5, 0x47, 0xab, 0xbf, 0xca, 0x3a, 0x85, 0x3f, + 0x25, 0xbf, 0x58, 0xbf, 0x3c, 0x13, 0xf2, 0x3c, 0x0b, 0x0c, 0xa9, 0xbf, 0xea, 0xf8, 0xf8, 0x3f, + 0x8a, 0x5a, 0xe4, 0x3e, 0xa2, 0x6e, 0x44, 0xbf, 0x37, 0x66, 0x88, 0xbf, 0xa5, 0x52, 0xb2, 0xbf, + 0xef, 0x3f, 0xd5, 0xbf, 0x0b, 0x74, 0x31, 0xbe, 0x74, 0x86, 0x5b, 0xbf, 0x6f, 0x58, 0x5d, 0xbf, + 0x94, 0x04, 0xdc, 0x3f, 0xc4, 0x9e, 0x55, 0x3e, 0x3b, 0x18, 0x07, 0xbf, 0x8d, 0x07, 0x7a, 0x3f, + 0xb9, 0x29, 0x15, 0xc0, 0xc7, 0xa1, 0xd1, 0x3e, 0x3c, 0x44, 0x98, 0xbd, 0x60, 0xce, 0x09, 0xbf, + 0xf7, 0x72, 0x85, 0xbe, 0x38, 0x6e, 0x05, 0xc0, 0x98, 0xee, 0xc2, 0xbf, 0x45, 0x73, 0xaa, 0xbd, + 0x3c, 0xef, 0xc9, 0xbf, 0x13, 0x64, 0xb4, 0x3f, 0x26, 0x6b, 0x38, 0x3f, 0x52, 0x90, 0xca, 0xbf, + 0x9c, 0x66, 0xd1, 0x3f, 0x77, 0x8d, 0x2d, 0xbf, 0x84, 0xe2, 0x91, 0xbe, 0x9b, 0x02, 0x19, 0x3f, + 0x27, 0x9c, 0x82, 0xbf, 0x38, 0xb1, 0x77, 0x3f, 0x75, 0xbd, 0x5f, 0x3f, 0x30, 0xa6, 0x0c, 0xbd, + 0xc8, 0xc5, 0xa9, 0x3e, 0xba, 0x84, 0x40, 0xbe, 0xb6, 0x11, 0xd8, 0xbd, 0xdd, 0x1c, 0x27, 0xbf, + 0x63, 0x10, 0x0c, 0x40, 0xbc, 0xfc, 0x24, 0xbf, 0x70, 0xc8, 0x82, 0xbf, 0x5b, 0x57, 0x51, 0x3e, + 0x35, 0xb6, 0x86, 0x3f, 0xa2, 0x44, 0x0e, 0x40, 0xbf, 0x7e, 0x8c, 0x3e, 0x4c, 0x6b, 0x96, 0x3f, + 0xc0, 0x85, 0xcb, 0x3e, 0x64, 0x83, 0x86, 0xbf, 0xe3, 0x41, 0xed, 0x3e, 0x5f, 0x77, 0x27, 0xbd, + 0x9e, 0x94, 0xd2, 0x3f, 0xe0, 0x62, 0xa2, 0xbe, 0x78, 0xe5, 0xb5, 0xbe, 0xba, 0xfc, 0xed, 0xbe, + 0xfe, 0xd0, 0xe6, 0xbf, 0x33, 0xd5, 0xbd, 0xbe, 0xed, 0x7e, 0x7a, 0xbf, 0x75, 0x0e, 0xe6, 0x3e, + 0xf6, 0x05, 0x0d, 0x3f, 0x40, 0x53, 0x6c, 0x3e, 0xbe, 0xf3, 0x4a, 0xbe, 0x78, 0x92, 0x02, 0xbf, + 0x1e, 0x9a, 0xb3, 0x3e, 0x2f, 0x32, 0x94, 0xbf, 0x33, 0xb2, 0x46, 0xbf, 0x5b, 0x5f, 0x18, 0x3d, + 0x81, 0xe8, 0xa5, 0x3f, 0xf9, 0xeb, 0xa9, 0xbe, 0x2c, 0x46, 0x76, 0x3f, 0xf4, 0x34, 0x43, 0x3f, + 0xfe, 0x03, 0x75, 0x3f, 0x57, 0x4c, 0x97, 0x3f, 0xdc, 0x54, 0xb1, 0xbe, 0x68, 0x1b, 0xaa, 0x3f, + 0x82, 0xd0, 0xe5, 0x3f, 0x08, 0xa7, 0x1c, 0x3f, 0xbc, 0x1c, 0x5e, 0xbf, 0xba, 0x18, 0x74, 0xbf, + 0x48, 0xed, 0xc0, 0xbf, 0xd9, 0xf8, 0xbe, 0xbe, 0x0b, 0x86, 0x4a, 0xbf, 0x9b, 0x83, 0x51, 0x3c, + 0x0f, 0x9e, 0xba, 0x3e, 0xc9, 0x59, 0xca, 0xbf, 0x6a, 0x26, 0x6c, 0x3f, 0x35, 0xfa, 0x6d, 0x3f, + 0x15, 0xea, 0x3c, 0xbf, 0x26, 0xe8, 0x1b, 0x3e, 0x97, 0xec, 0x1a, 0xbf, 0x5e, 0x58, 0x86, 0x3e, + 0xdc, 0xed, 0x16, 0xbf, 0x6e, 0xc6, 0x1c, 0x3f, 0xee, 0xd4, 0x91, 0x3c, 0x4d, 0x2f, 0x6d, 0x3e, + 0x86, 0x76, 0x33, 0xbf, 0xdd, 0x07, 0xb2, 0x3f, 0x49, 0x01, 0x17, 0x3f, 0x5c, 0xc6, 0xd9, 0xbf, + 0x89, 0xf2, 0x5f, 0xbf, 0xbc, 0xe6, 0xea, 0xbe, 0x19, 0xec, 0x11, 0xbd, 0x50, 0x0b, 0xe5, 0x3d, + 0x73, 0x8b, 0xa5, 0x3e, 0xff, 0x41, 0x34, 0xbf, 0x0d, 0xa5, 0xb2, 0xbf, 0xef, 0x88, 0xdd, 0x3d, + 0x40, 0x66, 0x92, 0xbe, 0x1d, 0x5b, 0x22, 0xbf, 0x9c, 0x7f, 0xfb, 0x3d, 0x59, 0xfb, 0xc8, 0xbd, + 0x34, 0xe3, 0x47, 0x3e, 0x85, 0x8d, 0xf1, 0xbe, 0xb2, 0x56, 0xdf, 0xbe, 0x82, 0x67, 0x08, 0x3f, + 0x69, 0x40, 0xec, 0x3e, 0x48, 0x59, 0xd4, 0x3f, 0xc7, 0xac, 0xf1, 0x3e, 0x01, 0xe6, 0x48, 0xbe, + 0x51, 0xa7, 0x0b, 0xbf, 0xda, 0x0a, 0x54, 0xbf, 0x0a, 0x87, 0x91, 0x3f, 0x00, 0x86, 0x4d, 0xbf, + 0x4e, 0xba, 0xb5, 0x3f, 0xee, 0x28, 0xeb, 0x3f, 0x3d, 0xde, 0xb0, 0xbf, 0xc4, 0x0c, 0x69, 0xbe, + 0xc2, 0x91, 0xf9, 0xbd, 0x37, 0x7c, 0x6a, 0xbf, 0xd9, 0x9b, 0xbc, 0xbc, 0x46, 0x17, 0x09, 0xc0, + 0x5c, 0xa8, 0xd2, 0x3e, 0xb8, 0xfd, 0x3f, 0xbf, 0x25, 0x11, 0x90, 0x3f, 0xdc, 0x01, 0xa5, 0x3e, + 0xae, 0x16, 0x3e, 0xbf, 0xbb, 0xb4, 0x1b, 0x3f, 0x4c, 0x43, 0x5e, 0x3f, 0x96, 0xeb, 0x83, 0xbe, + 0x0b, 0xd6, 0x0f, 0x3f, 0xd9, 0xa2, 0xa8, 0xbc, 0x04, 0x25, 0x9d, 0x3f, 0x35, 0xc1, 0x32, 0xbf, + 0x22, 0x3f, 0x6b, 0xbf, 0x5b, 0x10, 0xff, 0xbd, 0x6c, 0xd2, 0x94, 0xbf, 0x6f, 0x8e, 0x97, 0xbf, + 0x36, 0x88, 0xd8, 0xbf, 0xf6, 0x1d, 0x49, 0xbf, 0xc0, 0x35, 0x50, 0x3f, 0x37, 0x39, 0x72, 0x3f, + 0x92, 0x97, 0x5f, 0x3e, 0xd3, 0xa8, 0x45, 0xbe, 0xef, 0x0a, 0x00, 0x3f, 0xd0, 0x2c, 0x03, 0xc0, + 0x6e, 0x1c, 0x4c, 0xbf, 0xb6, 0xd4, 0x22, 0x3f, 0x54, 0xfe, 0x05, 0x3f, 0xf9, 0x6e, 0x44, 0x3f, + 0xed, 0x1b, 0x27, 0xc0, 0x7b, 0x39, 0x84, 0x3e, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x8c, 0x6e, 0x1a, 0xbe, + 0x55, 0x01, 0xb5, 0x3f, 0xd3, 0x3f, 0x3d, 0xbf, 0x05, 0x55, 0x2e, 0x3f, 0xb9, 0xf7, 0x3f, 0xbf, + 0xcf, 0x42, 0x9e, 0xbf, 0x6b, 0xff, 0x7a, 0xbe, 0x9d, 0x11, 0x7f, 0xbf, 0xe1, 0xe9, 0x32, 0xbf, + 0x91, 0xaa, 0x7b, 0xbf, 0x54, 0xa4, 0xb7, 0x3b, 0x77, 0x80, 0xa9, 0xbd, 0x1d, 0xfc, 0x6d, 0xbf, + 0xf4, 0x7d, 0x86, 0xbf, 0x43, 0x92, 0x49, 0x3e, 0x3d, 0x0d, 0x60, 0x3f, 0x77, 0xbf, 0x08, 0x40, + 0x12, 0x2d, 0x71, 0x3d, 0xf9, 0xca, 0xc6, 0x3f, 0xb8, 0x57, 0x05, 0xc0, 0xec, 0xe0, 0x02, 0x3f, + 0x40, 0x33, 0x25, 0x3f, 0x13, 0x97, 0x67, 0x3e, 0x33, 0x1e, 0x80, 0xbe, 0xb4, 0xe6, 0x15, 0xbf, + 0x62, 0x11, 0x82, 0xbf, 0x34, 0x91, 0x83, 0x3f, 0x8c, 0x38, 0xe8, 0xbd, 0xf5, 0x3e, 0x90, 0xbf, + 0xcf, 0x66, 0x49, 0x3f, 0x8d, 0xa2, 0xc0, 0x3f, 0x76, 0x3a, 0xc7, 0x3e, 0x6e, 0xcf, 0x9f, 0x3f, + 0xf4, 0x0c, 0xc0, 0xbe, 0xbe, 0x83, 0xc5, 0xbf, 0xfd, 0xb3, 0xa8, 0x3e, 0xca, 0x78, 0x83, 0x3f, + 0x95, 0x08, 0x46, 0xbe, 0x97, 0xa6, 0x40, 0x3f, 0xf2, 0x5e, 0xaf, 0xbe, 0x4e, 0x27, 0x0c, 0xc0, + 0xe7, 0xd0, 0x03, 0x3f, 0x5e, 0x09, 0x74, 0xbf, 0x03, 0x93, 0xd2, 0x3e, 0xc0, 0xfa, 0x01, 0x3f, + 0xb7, 0xea, 0xd4, 0xbf, 0xd4, 0xad, 0xcf, 0x3d, 0xdf, 0x2f, 0xff, 0xbf, 0x16, 0xc5, 0x27, 0xbf, + 0xf3, 0x69, 0xff, 0xbe, 0xb0, 0x4b, 0xb9, 0xbf, 0x25, 0xa2, 0x92, 0x3c, 0xb0, 0xf7, 0xf0, 0x3f, + 0x0e, 0x74, 0x95, 0x3f, 0xb0, 0x75, 0x84, 0x3f, 0x88, 0x54, 0x18, 0x3f, 0x29, 0xa2, 0x6c, 0xbd, + 0x0c, 0x49, 0x29, 0xbf, 0xf7, 0x5b, 0xb1, 0x3f, 0x3e, 0x6a, 0x17, 0x3f, 0x2d, 0xe8, 0x0c, 0xbf, + 0x87, 0xc6, 0x48, 0xbf, 0x71, 0x80, 0xc5, 0x3e, 0x51, 0x27, 0x0e, 0x3e, 0x80, 0xb2, 0x1b, 0x40, + 0x19, 0xe3, 0xc8, 0x3e, 0x29, 0x9e, 0xb1, 0xbe, 0xe6, 0x2a, 0x40, 0xbf, 0x2f, 0xc3, 0x1c, 0xc0, + 0xc5, 0x83, 0xbf, 0xbe, 0xfb, 0x70, 0xb4, 0xbf, 0x6a, 0xa7, 0x49, 0xbf, 0x4c, 0x7a, 0x9d, 0xbf, + 0xc9, 0x3c, 0xd0, 0x3e, 0x0b, 0x76, 0xa8, 0xbe, 0x78, 0xe0, 0xd4, 0x3e, 0xa8, 0x00, 0xad, 0xbf, + 0x44, 0xb5, 0x94, 0x3f, 0x36, 0xd5, 0x9c, 0xbd, 0xb6, 0xe7, 0xaf, 0x3e, 0x14, 0xcc, 0x1f, 0xbe, + 0x26, 0x1b, 0xae, 0xbf, 0x63, 0xdf, 0xe3, 0x3d, 0x90, 0xff, 0x27, 0xbe, 0xc5, 0x77, 0x92, 0xbd, + 0x6d, 0x7a, 0x61, 0xbf, 0x55, 0x50, 0x9c, 0x3d, 0x5f, 0x74, 0x4a, 0x3c, 0x1f, 0x2f, 0x80, 0x3d, + 0x92, 0xa6, 0xb4, 0xbf, 0xe4, 0x5f, 0x49, 0xbf, 0x61, 0xfb, 0x3d, 0x3f, 0xf0, 0x12, 0x96, 0x3f, + 0xe6, 0x94, 0xd9, 0xbf, 0xe2, 0x8e, 0xa2, 0x3f, 0x18, 0x65, 0xee, 0x3e, 0x2c, 0x7d, 0x0d, 0xbe, + 0x9d, 0xb3, 0xda, 0x3f, 0x71, 0x09, 0x8f, 0x3e, 0xd0, 0xd0, 0xe0, 0xbf, 0x36, 0x43, 0x3f, 0x3e, + 0x44, 0xc5, 0x0b, 0x3f, 0xe5, 0x1a, 0x19, 0xbf, 0x0a, 0x90, 0x00, 0x3f, 0xe0, 0x15, 0xe2, 0x3e, + 0x5c, 0xf6, 0xd4, 0x3e, 0x2b, 0x27, 0x89, 0x3c, 0xc9, 0x33, 0xf5, 0x3e, 0x7e, 0x7f, 0x2c, 0x3f, + 0xcb, 0xda, 0xdd, 0x3f, 0x61, 0x32, 0xed, 0xbf, 0xde, 0x93, 0xdc, 0xbe, 0xfe, 0x17, 0x0a, 0x3e, + 0xe9, 0xd5, 0x65, 0xbd, 0xf4, 0xd9, 0x94, 0xbf, 0xa5, 0x6b, 0xaa, 0xbd, 0x80, 0xa2, 0x1b, 0x3f, + 0xa6, 0xdb, 0xa3, 0xbf, 0xd9, 0xb7, 0x8d, 0xbf, 0xec, 0xf1, 0x49, 0xbf, 0xef, 0x4f, 0x28, 0xbf, + 0x74, 0x4e, 0x19, 0x3f, 0xed, 0x71, 0xd1, 0xbf, 0x5c, 0x6e, 0xa0, 0xbf, 0xc0, 0x5b, 0xe2, 0xbe, + 0x8f, 0xf2, 0xc9, 0x3e, 0x30, 0x1f, 0x2b, 0xbe, 0x0f, 0x96, 0xfb, 0xbf, 0xa3, 0x49, 0xfb, 0x3f, + 0x23, 0x34, 0x8b, 0x3f, 0xbd, 0x38, 0x77, 0xbe, 0x9f, 0x90, 0x07, 0x3f, 0x9f, 0xdf, 0xab, 0x3e, + 0x91, 0xaa, 0xc2, 0xbf, 0xfb, 0x33, 0x0d, 0xbf, 0x42, 0x52, 0x95, 0xbe, 0xf7, 0x52, 0x51, 0x3f, + 0x83, 0x3e, 0xa3, 0x3e, 0x5c, 0x26, 0xe5, 0x3e, 0x4f, 0x14, 0xc0, 0x3e, 0x88, 0xdf, 0xcf, 0xbf, + 0xc9, 0xdc, 0x5b, 0x3f, 0x1f, 0xa9, 0x53, 0x3f, 0x91, 0x66, 0xa4, 0x3f, 0xab, 0xfe, 0x79, 0x3e, + 0xe3, 0xce, 0x66, 0x3f, 0x6a, 0xa9, 0x0f, 0xc0, 0x32, 0x12, 0x9a, 0x3f, 0x97, 0xee, 0x35, 0x3f, + 0xc8, 0x0b, 0x56, 0x3e, 0x82, 0xd5, 0xa1, 0xbe, 0xc8, 0x5d, 0x5d, 0xbd, 0x06, 0x1f, 0x02, 0x3f, + 0x65, 0x32, 0x33, 0x40, 0xd2, 0xa2, 0x2f, 0xbf, 0xb9, 0xca, 0x92, 0x3d, 0x4b, 0xea, 0xc9, 0x3f, + 0xf7, 0x3e, 0xce, 0x3e, 0xf2, 0x8f, 0x0a, 0xbe, 0x66, 0xcb, 0xe5, 0x3e, 0x7a, 0x98, 0x89, 0x3f, + 0x04, 0x8a, 0xc8, 0xbe, 0xbe, 0x83, 0xbe, 0x3f, 0x13, 0x5f, 0xad, 0x3d, 0x15, 0x6c, 0x43, 0xbe, + 0xab, 0x85, 0xf5, 0xbe, 0xa0, 0x12, 0xf4, 0x3d, 0x58, 0x6d, 0x90, 0x3f, 0x8e, 0x8a, 0x10, 0xc0, + 0x2a, 0x80, 0xad, 0xbf, 0x2e, 0xac, 0x8c, 0xbe, 0xe5, 0xe5, 0x67, 0xbf, 0xe6, 0xd8, 0x0f, 0x3f, + 0x4c, 0x61, 0x8a, 0xbf, 0x12, 0x06, 0x37, 0xbf, 0xf1, 0xcd, 0xdc, 0xbf, 0xa9, 0xd9, 0x00, 0xbe, + 0x33, 0x0b, 0x91, 0x3d, 0x1b, 0xb4, 0x44, 0xbd, 0x82, 0xe3, 0xce, 0x3e, 0x1d, 0x55, 0x73, 0xbf, + 0x47, 0x84, 0xfa, 0x3f, 0x7d, 0x18, 0xa6, 0x3f, 0xf1, 0x23, 0x25, 0xbf, 0xce, 0x0b, 0x25, 0xc0, + 0xaf, 0xce, 0x1d, 0xbc, 0x6c, 0x91, 0xdc, 0xbe, 0x96, 0xd2, 0x82, 0x3b, 0x05, 0x89, 0x6d, 0xbf, + 0x4a, 0x1a, 0x14, 0xbf, 0x36, 0xac, 0x22, 0xc0, 0xd1, 0x78, 0x9d, 0xbe, 0xa8, 0x6c, 0xa2, 0xbc, + 0x39, 0x81, 0x2b, 0x3d, 0x52, 0xe5, 0x5d, 0x3f, 0xfa, 0x88, 0x2b, 0xbf, 0x2a, 0xca, 0x61, 0xbf, + 0x1b, 0x6c, 0xd1, 0x3c, 0xd7, 0x99, 0xc3, 0x3e, 0x7a, 0x8c, 0xc2, 0xbe, 0xc3, 0x4c, 0x31, 0xbf, + 0x6c, 0xbc, 0x2f, 0x3f, 0x5c, 0x15, 0x4a, 0xbf, 0xa0, 0xa1, 0x12, 0x3e, 0x43, 0x5b, 0xf1, 0x3e, + 0xbf, 0xc1, 0x4f, 0x3f, 0xf9, 0xdb, 0x04, 0xbf, 0x2a, 0x9b, 0x39, 0xbf, 0xed, 0x24, 0x68, 0xbf, + 0xd0, 0xe2, 0xe2, 0xbe, 0x7a, 0x5f, 0xb4, 0xbf, 0x1a, 0x83, 0xb9, 0xbf, 0xef, 0x0e, 0x3d, 0x3d, + 0x2c, 0x4d, 0x06, 0x3f, 0x75, 0x03, 0xbd, 0xbe, 0x1c, 0x32, 0x28, 0xbf, 0x99, 0x41, 0x94, 0x3f, + 0x5f, 0x3f, 0x0a, 0x40, 0x64, 0x0c, 0x8d, 0xc0, 0x99, 0xdb, 0x5d, 0x3f, 0x49, 0x3c, 0x53, 0x3d, + 0xb9, 0xb2, 0xbf, 0x3f, 0x64, 0x93, 0x58, 0xbf, 0x9d, 0x08, 0x0a, 0xbf, 0x90, 0xc6, 0x18, 0x3f, + 0xeb, 0xa3, 0x98, 0x3e, 0xe9, 0x92, 0x01, 0xbc, 0x68, 0xef, 0xb6, 0xba, 0x43, 0xed, 0x94, 0x3f, + 0x8b, 0xf6, 0x43, 0x3f, 0x3e, 0x13, 0xa5, 0xbe, 0x70, 0x0d, 0x97, 0x3e, 0x83, 0x81, 0x26, 0xbd, + 0x9b, 0x8f, 0xae, 0x3f, 0x03, 0x14, 0x60, 0xbf, 0x16, 0x9d, 0xac, 0xbf, 0x4f, 0xac, 0xc0, 0x3f, + 0xc6, 0x6d, 0x98, 0xbf, 0xe4, 0xe7, 0x26, 0x3f, 0x2d, 0x12, 0x28, 0xbe, 0x53, 0x28, 0x01, 0xbe, + 0x0e, 0x24, 0xae, 0x3f, 0x7c, 0x6e, 0x96, 0x3f, 0x4e, 0xc1, 0xd3, 0xbf, 0x76, 0xb7, 0xc8, 0xbe, + 0xdb, 0x89, 0x02, 0xbf, 0xe6, 0x79, 0xeb, 0x3e, 0x8d, 0xaa, 0x06, 0xbe, 0x15, 0xd4, 0x14, 0xbf, + 0xb7, 0xee, 0xd7, 0x3e, 0x07, 0x02, 0xd8, 0x3f, 0x59, 0x81, 0x03, 0xc0, 0xeb, 0x2c, 0x09, 0xbf, + 0x56, 0x63, 0xcb, 0xbf, 0x56, 0x93, 0x3b, 0x3e, 0x95, 0x5c, 0xed, 0xbe, 0xea, 0x26, 0x75, 0x3f, + 0xb3, 0xdb, 0x96, 0x3e, 0xb4, 0xa9, 0x20, 0x3e, 0x87, 0x35, 0xd5, 0x3f, 0xa0, 0x3b, 0xdc, 0x3e, + 0x10, 0x74, 0xeb, 0x3f, 0xee, 0xbf, 0xac, 0xbf, 0x0f, 0xb3, 0x1c, 0xbf, 0x6b, 0x1a, 0xb9, 0x3f, + 0xe5, 0xbb, 0x0c, 0x40, 0x3d, 0xea, 0xb9, 0x3f, 0xa3, 0xf5, 0x7f, 0x3f, 0x95, 0x6f, 0xc1, 0x3e, + 0x48, 0xdb, 0xa7, 0xbf, 0x7c, 0x10, 0x74, 0xbe, 0x03, 0xbd, 0x77, 0x3f, 0x44, 0x38, 0x0a, 0xbf, + 0x88, 0x40, 0x08, 0x3f, 0x34, 0xac, 0x2a, 0x3f, 0xe7, 0x71, 0x77, 0x3f, 0xf5, 0xa0, 0x22, 0x3e, + 0x73, 0x3c, 0xe0, 0x3f, 0xfd, 0xb0, 0xaa, 0xbe, 0xb1, 0xb0, 0x1f, 0x3f, 0x35, 0xae, 0xae, 0xbf, + 0x46, 0xdc, 0x03, 0x40, 0xeb, 0x54, 0xcd, 0x3e, 0xc1, 0x3b, 0x21, 0xbe, 0xce, 0x67, 0x43, 0xbe, + 0xc5, 0x2b, 0xb2, 0x3f, 0x46, 0x30, 0x53, 0x3f, 0x76, 0x5a, 0x5a, 0xbf, 0x1b, 0x33, 0xa6, 0x3e, + 0x97, 0x19, 0x0c, 0x3f, 0x4d, 0x67, 0x25, 0xbf, 0xae, 0xa5, 0x6c, 0x3f, 0xb1, 0xfe, 0x17, 0x3d, + 0xfc, 0x32, 0x03, 0xbe, 0xbc, 0x9e, 0xa7, 0xbe, 0x7c, 0x69, 0x98, 0x3f, 0xed, 0x41, 0xdb, 0x3e, + 0x81, 0x72, 0x7c, 0xbe, 0xc2, 0x3d, 0x9a, 0xbf, 0xcc, 0x47, 0x26, 0xc0, 0x53, 0xeb, 0x8b, 0x3e, + 0x04, 0x58, 0x8d, 0x3f, 0x7e, 0x73, 0x1e, 0xbe, 0x54, 0x43, 0xc9, 0xbe, 0x29, 0x4d, 0xe5, 0xbf, + 0x9a, 0x4d, 0x52, 0x3d, 0x25, 0xe5, 0x7c, 0x3e, 0x69, 0x23, 0x55, 0xbf, 0x96, 0xc5, 0xfe, 0x3e, + 0xb6, 0x40, 0x6a, 0x3f, 0x3a, 0x36, 0x62, 0x3f, 0x3e, 0x27, 0x8c, 0x3e, 0x07, 0xd0, 0x36, 0x3f, + 0x4f, 0x34, 0x1c, 0x3f, 0x87, 0x2d, 0x01, 0x3f, 0x98, 0xf4, 0xe1, 0xbe, 0x40, 0x21, 0xae, 0x3f, + 0x5c, 0x6e, 0xa9, 0xbe, 0x88, 0x09, 0x05, 0xbf, 0x8c, 0x9a, 0x1c, 0x3f, 0x4f, 0xba, 0x86, 0xbe, + 0x95, 0x1a, 0xf0, 0xbf, 0x80, 0x85, 0x96, 0xbf, 0xcf, 0xd5, 0x3d, 0x3f, 0x61, 0x23, 0xb8, 0x3e, + 0x0d, 0x12, 0x0b, 0xbf, 0x80, 0x08, 0x83, 0xbf, 0xc8, 0x8a, 0x0e, 0xbe, 0x9e, 0x2c, 0xc8, 0xbe, + 0xf1, 0xce, 0xef, 0xbf, 0x74, 0x62, 0x9f, 0xbe, 0x74, 0x23, 0x80, 0xbe, 0x00, 0xd1, 0x84, 0x3f, + 0x45, 0xff, 0x60, 0x3f, 0x4b, 0x78, 0x17, 0xbf, 0x47, 0xdd, 0xa6, 0xbf, 0xf5, 0xec, 0x17, 0x3f, + 0xf6, 0x66, 0xa5, 0x3f, 0x40, 0x8e, 0x4e, 0xbf, 0xab, 0x71, 0x28, 0x3e, 0x0c, 0xad, 0xb5, 0xbe, + 0xd6, 0x5c, 0x59, 0xbf, 0x71, 0x1c, 0x21, 0x3f, 0x80, 0x7e, 0x0d, 0x40, 0x5e, 0x1d, 0x23, 0x3e, + 0x8f, 0x0d, 0x45, 0xbf, 0x16, 0xb6, 0x3c, 0xc0, 0x74, 0xb7, 0x96, 0xbf, 0xdc, 0xa4, 0xc2, 0xbf, + 0xd2, 0x3e, 0xca, 0xbf, 0xf3, 0x38, 0x0b, 0xbf, 0x00, 0x07, 0x7a, 0x3f, 0x43, 0x9c, 0x2c, 0x3f, + 0x5f, 0xaa, 0xcf, 0xbf, 0x90, 0x8a, 0x45, 0xbf, 0x1d, 0xd2, 0x83, 0xbf, 0x23, 0xf3, 0x30, 0xbd, + 0x33, 0xa1, 0xf3, 0xbf, 0xc8, 0x41, 0x93, 0xbe, 0x3c, 0x1a, 0x65, 0xbe, 0xfd, 0xda, 0xed, 0xbe, + 0x26, 0x3d, 0xd3, 0xbe, 0xcd, 0xb0, 0x0f, 0xc0, 0x74, 0x92, 0x19, 0x3f, 0x00, 0x4d, 0x6f, 0x3f, + 0xa0, 0x47, 0xa9, 0x3e, 0x38, 0x05, 0xdf, 0xbf, 0x41, 0x4e, 0xc3, 0xbe, 0x52, 0xc2, 0x1e, 0xbe, + 0xc9, 0xb3, 0xe6, 0x3e, 0x03, 0xbe, 0x1e, 0x3f, 0x9f, 0xaf, 0x85, 0xbf, 0xbb, 0xbc, 0x9c, 0x3f, + 0xe1, 0xfc, 0x16, 0xbf, 0xea, 0x09, 0x3e, 0xbe, 0xbb, 0xe0, 0x42, 0x40, 0xd2, 0x28, 0xd4, 0x3e, + 0x7b, 0xd1, 0x73, 0xbf, 0xd3, 0x77, 0x98, 0x3f, 0x73, 0x4c, 0x5e, 0xbf, 0x2c, 0x3e, 0x11, 0x3f, + 0x95, 0x64, 0x15, 0xbe, 0x0d, 0x4f, 0x1a, 0x3f, 0x7f, 0x1b, 0xc8, 0x3e, 0x1d, 0x68, 0x35, 0x3f, + 0x99, 0xf7, 0xd6, 0xbe, 0x3d, 0xb9, 0x99, 0x3f, 0x17, 0x50, 0xce, 0x3e, 0x8e, 0x04, 0x8d, 0xbe, + 0x08, 0x0c, 0xf9, 0x3f, 0x6b, 0xb2, 0xd0, 0xbe, 0xc7, 0xcb, 0xba, 0xbe, 0xd0, 0x70, 0x3a, 0x3e, + 0xa9, 0x54, 0xe8, 0x3e, 0xe7, 0x3b, 0xc4, 0xbe, 0x94, 0x5b, 0x5c, 0x3f, 0x57, 0xc4, 0xfc, 0xbd, + 0x38, 0x6f, 0x9b, 0xbd, 0xdb, 0x1d, 0x47, 0x3f, 0x36, 0x78, 0x78, 0x3f, 0x9f, 0x61, 0x52, 0xbf, + 0x67, 0x23, 0x86, 0x3e, 0x74, 0x04, 0xde, 0xbe, 0x19, 0x1b, 0x51, 0xbf, 0x73, 0x5f, 0x05, 0x3e, + 0x06, 0xe6, 0x9c, 0x3e, 0x95, 0xfe, 0x9b, 0x3f, 0x94, 0xce, 0x76, 0xbf, 0xc1, 0xf8, 0x8e, 0x3f, + 0x8c, 0x5b, 0x63, 0x3f, 0x70, 0x00, 0xaa, 0xbf, 0x1a, 0xb8, 0x6c, 0xbf, 0x42, 0x20, 0x91, 0x3d, + 0x97, 0x4b, 0x1a, 0xbf, 0xbc, 0x32, 0xb4, 0x3e, 0x77, 0xf0, 0xc6, 0x3e, 0xeb, 0x56, 0xa2, 0x3f, + 0x0e, 0xb0, 0x25, 0x40, 0x4b, 0xce, 0x40, 0xbf, 0x5b, 0xfd, 0x35, 0xbf, 0x9e, 0x78, 0x7f, 0xbe, + 0xe3, 0x03, 0xac, 0xbf, 0x89, 0xc2, 0x77, 0x3f, 0xd8, 0x2e, 0x63, 0xbf, 0xce, 0x9f, 0x40, 0x3f, + 0xe2, 0x52, 0xce, 0x3e, 0x5c, 0xeb, 0x63, 0x3f, 0x4e, 0xd3, 0x9d, 0x3f, 0x7c, 0xe3, 0x47, 0xbf, + 0xea, 0xca, 0x31, 0xbf, 0xae, 0x7b, 0x0d, 0x3f, 0x04, 0xa0, 0x58, 0x3f, 0x8a, 0xc5, 0x87, 0x3f, + 0x22, 0xfa, 0xa8, 0xbf, 0x5e, 0x7e, 0xbf, 0xbd, 0xdc, 0x05, 0x70, 0x3f, 0x8e, 0x2c, 0xee, 0x3e, + 0xfb, 0x13, 0x14, 0xbf, 0x2e, 0xf2, 0x17, 0x3d, 0x7f, 0x3e, 0xe8, 0x3c, 0x86, 0xfa, 0x35, 0xbf, + 0x21, 0x83, 0x8d, 0x3e, 0x77, 0xab, 0x3b, 0xbf, 0xda, 0x43, 0x00, 0xbf, 0x32, 0xd5, 0x7e, 0xbd, + 0x5a, 0xd6, 0xa1, 0xbf, 0xc3, 0xad, 0xdd, 0xbe, 0x33, 0xa0, 0x20, 0x3f, 0x07, 0x4a, 0x0e, 0x3f, + 0x4c, 0x98, 0x5d, 0x3e, 0x0e, 0xba, 0x86, 0x3f, 0xe4, 0xc3, 0x42, 0xbc, 0x42, 0x8f, 0x04, 0x3f, + 0x49, 0xc0, 0x68, 0xbe, 0xe9, 0x21, 0x18, 0x40, 0xd0, 0x13, 0x85, 0x3e, 0x65, 0xc6, 0x8c, 0xbd, + 0xa4, 0x15, 0xff, 0x3e, 0xf5, 0x61, 0x79, 0xbd, 0x44, 0xbb, 0x3e, 0x3f, 0xc5, 0xdd, 0xa5, 0xbe, + 0xc7, 0x8d, 0xea, 0xbf, 0x31, 0xf2, 0xce, 0x3f, 0x7e, 0xb7, 0x5d, 0x3f, 0xfa, 0x62, 0x8a, 0xbe, + 0x98, 0x4a, 0x82, 0xbe, 0x3a, 0x08, 0x29, 0x40, 0xb1, 0xc8, 0xec, 0x3f, 0x60, 0x74, 0x82, 0x3f, + 0x35, 0x65, 0x1c, 0x3f, 0x9b, 0x63, 0x75, 0x3d, 0xe5, 0x3c, 0x21, 0x3f, 0xf8, 0xac, 0x84, 0x3f, + 0xc5, 0xe6, 0x9d, 0xbf, 0x2a, 0xf6, 0xc5, 0x3e, 0x34, 0x33, 0x6b, 0xbf, 0x66, 0x93, 0x71, 0xbd, + 0x4b, 0xff, 0xbe, 0xbf, 0x8f, 0x72, 0x05, 0xbf, 0x4e, 0xee, 0xc7, 0xbc, 0x20, 0x1a, 0xa1, 0x3e, + 0xec, 0x65, 0x9c, 0xbf, 0x94, 0x44, 0x4a, 0xbe, 0x6f, 0x68, 0x20, 0x3e, 0xd7, 0x49, 0x04, 0x40, + 0x53, 0x37, 0x30, 0xbf, 0x92, 0x86, 0x1c, 0xbe, 0x20, 0x0c, 0xd9, 0x3f, 0xfe, 0xa7, 0x98, 0x3f, + 0x92, 0xa3, 0x72, 0x3f, 0xed, 0x1c, 0xce, 0x3d, 0x41, 0xb5, 0x94, 0xbe, 0xae, 0x1c, 0xa7, 0x3e, + 0x9d, 0xdc, 0x9b, 0xbf, 0xe7, 0x82, 0x23, 0x40, 0xe6, 0x19, 0x28, 0xbf, 0xb9, 0xfb, 0x94, 0xbf, + 0xb1, 0x45, 0xa2, 0xbe, 0x79, 0x6e, 0x9c, 0xbe, 0xc6, 0x56, 0x6d, 0x3f, 0xa4, 0x5a, 0x02, 0x40, + 0x10, 0x10, 0x41, 0xbd, 0xbd, 0x92, 0xbf, 0xbe, 0xa7, 0x20, 0x63, 0x3f, 0x15, 0x39, 0x83, 0xbf, + 0x53, 0x34, 0x2b, 0xbe, 0x96, 0x72, 0xa4, 0x3f, 0x47, 0x91, 0xfe, 0xbf, 0x36, 0xea, 0xcd, 0xbe, + 0x8e, 0x28, 0x91, 0xbe, 0x89, 0x45, 0x9e, 0x3e, 0xa6, 0x56, 0x18, 0x3c, 0x4c, 0x2c, 0x5d, 0x3e, + 0x13, 0xbd, 0x3b, 0xbf, 0x10, 0xcb, 0xcc, 0xbf, 0x33, 0x58, 0x9f, 0xbf, 0x2d, 0x85, 0x29, 0x3f, + 0xfe, 0x70, 0x85, 0xbf, 0x67, 0x91, 0x09, 0x3f, 0xf4, 0xda, 0x28, 0xbe, 0xa3, 0x72, 0x85, 0xbf, + 0x2c, 0x0d, 0xce, 0x3e, 0x49, 0xc4, 0x34, 0xbf, 0xb8, 0x18, 0x80, 0xbe, 0x63, 0x92, 0xc8, 0x3e, + 0x59, 0x84, 0xb9, 0x3f, 0x30, 0xb0, 0x94, 0x3f, 0x5b, 0xaa, 0xf2, 0xbe, 0x00, 0x52, 0x32, 0xbf, + 0x2c, 0x14, 0x8b, 0x3f, 0xf2, 0x65, 0xa4, 0xbf, 0x72, 0x30, 0xec, 0xbd, 0xaf, 0xb0, 0x9d, 0xbe, + 0x9b, 0xdc, 0x93, 0xbf, 0x3b, 0x8c, 0x1d, 0xbe, 0x22, 0x50, 0x39, 0x3e, 0x2c, 0xdf, 0x80, 0xbf, + 0x0a, 0x89, 0x18, 0xbf, 0xe8, 0x84, 0xb1, 0xbf, 0x36, 0x36, 0x7a, 0x3f, 0xe2, 0xdb, 0x28, 0x40, + 0x99, 0x1b, 0x01, 0xc0, 0x23, 0x56, 0x1d, 0xbf, 0x9f, 0xf0, 0x41, 0x3f, 0x50, 0x0c, 0x44, 0x3f, + 0x6a, 0x7b, 0x02, 0xbf, 0xd9, 0xdf, 0xe6, 0x3f, 0xca, 0xac, 0xe9, 0xbe, 0x32, 0x20, 0x19, 0xbf, + 0x74, 0x1a, 0xa5, 0xbf, 0xf8, 0xf1, 0x24, 0x3f, 0xfd, 0x45, 0x00, 0x3f, 0xca, 0x6f, 0x80, 0xbe, + 0x1f, 0x86, 0x5c, 0x3e, 0xc6, 0x34, 0x41, 0x3f, 0xeb, 0x0b, 0xd7, 0xbd, 0x9c, 0x6c, 0x90, 0x3e, + 0x2b, 0x87, 0xcb, 0x3e, 0x7a, 0xbc, 0x57, 0x3f, 0x36, 0x6f, 0x1e, 0xbe, 0x12, 0xbd, 0x6d, 0x3e, + 0x7e, 0x8f, 0xbc, 0x3e, 0x82, 0x91, 0xaf, 0xbe, 0x61, 0x72, 0x3b, 0x3f, 0xfa, 0x54, 0x7d, 0x3f, + 0x5a, 0x38, 0x81, 0x3f, 0x09, 0x04, 0xf7, 0x3e, 0xc1, 0x7b, 0xa0, 0xbf, 0xd1, 0x5c, 0x81, 0x3e, + 0x48, 0x6e, 0x3f, 0x3e, 0x42, 0x28, 0x03, 0x3f, 0x3f, 0x22, 0xc8, 0xbf, 0x11, 0x34, 0xf2, 0xbe, + 0xff, 0xa4, 0x0a, 0xbf, 0x34, 0xe0, 0x1f, 0xbe, 0xcb, 0x44, 0x04, 0x40, 0x07, 0x7b, 0x05, 0x3f, + 0xa1, 0x37, 0x85, 0xbe, 0x72, 0x32, 0x2f, 0x3f, 0xf0, 0x9b, 0x77, 0x3e, 0x09, 0xef, 0xac, 0x3d, + 0x6d, 0xc4, 0x60, 0xbe, 0xc3, 0xa4, 0x63, 0xbf, 0x15, 0xa8, 0x94, 0xbe, 0x12, 0xe4, 0x2a, 0x40, + 0x48, 0xc3, 0x51, 0x3f, 0x5e, 0x42, 0x86, 0x3f, 0x4b, 0x5e, 0x2d, 0x3f, 0x95, 0x04, 0x83, 0xbe, + 0xbe, 0x31, 0x07, 0x40, 0xed, 0xcb, 0xbd, 0xbe, 0x63, 0xa7, 0x36, 0x3e, 0xf9, 0xa5, 0x2b, 0x3f, + 0x12, 0xbd, 0x6d, 0x3f, 0x66, 0xa4, 0xcb, 0x3f, 0x3e, 0xd0, 0xc5, 0x3f, 0x32, 0xeb, 0xdc, 0x3f, + 0x8c, 0x0d, 0x99, 0xbe, 0xd3, 0x07, 0x96, 0x3f, 0x64, 0xc0, 0xee, 0x3f, 0xbe, 0x0b, 0xcb, 0x3f, + 0x64, 0x45, 0xc5, 0x3c, 0xcc, 0x2d, 0x84, 0xbf, 0xa3, 0xcf, 0x34, 0xbf, 0xa3, 0xce, 0x32, 0xbe, + 0xc6, 0x11, 0xa5, 0xbe, 0xf0, 0xb5, 0x42, 0x3f, 0x18, 0xd5, 0xe9, 0x3e, 0x30, 0x23, 0xd4, 0x3e, + 0xe8, 0x81, 0x0b, 0xc0, 0x20, 0x1a, 0x91, 0xbe, 0xcf, 0x6c, 0xbd, 0x3f, 0x33, 0x54, 0xf3, 0x3d, + 0xce, 0xf8, 0xa4, 0x3f, 0xc4, 0x15, 0x9e, 0xbd, 0x10, 0x5a, 0x43, 0x3e, 0x73, 0x5f, 0x5c, 0x3d, + 0x1c, 0xb9, 0x20, 0xbf, 0x00, 0xdb, 0x30, 0x3f, 0xeb, 0x76, 0x13, 0x3d, 0x6e, 0x88, 0x5c, 0xbf, + 0xc9, 0xf0, 0x8b, 0xbd, 0xb0, 0x89, 0xc4, 0x3e, 0x94, 0xcc, 0x55, 0xbe, 0x9c, 0xfb, 0x4c, 0x3f, + 0x9f, 0xb2, 0xf4, 0xbf, 0x98, 0xef, 0xf9, 0x3e, 0x4e, 0x62, 0x28, 0x3f, 0x0d, 0x53, 0x31, 0xbf, + 0x53, 0x48, 0x76, 0xbf, 0x27, 0x4f, 0xce, 0xbd, 0x38, 0x36, 0xac, 0x3f, 0xe0, 0xcf, 0x49, 0x3f, + 0x9c, 0xa2, 0x80, 0xbf, 0x0d, 0x87, 0xf0, 0x3d, 0x98, 0xee, 0xce, 0x3f, 0x74, 0x70, 0x26, 0xbf, + 0x9b, 0x52, 0x84, 0xbf, 0x72, 0x8f, 0xe4, 0xbe, 0x0a, 0x5f, 0x54, 0xbe, 0x20, 0xe8, 0xb4, 0x3f, + 0x5f, 0x57, 0xd2, 0xbf, 0xff, 0xf7, 0x12, 0x3f, 0xd2, 0x28, 0x99, 0xbf, 0xf0, 0x4a, 0x4f, 0x3e, + 0x9d, 0x98, 0xec, 0xbf, 0x98, 0x1d, 0xb4, 0xbf, 0x65, 0xd7, 0x2a, 0x3d, 0x09, 0x9b, 0x93, 0x3f, + 0x36, 0xd8, 0x1b, 0xbf, 0xcb, 0x5a, 0xbe, 0xbe, 0x63, 0x99, 0x3e, 0xbf, 0x59, 0x44, 0xec, 0xbd, + 0xc2, 0x30, 0x1d, 0xbf, 0x83, 0xcf, 0xeb, 0x3e, 0x93, 0x49, 0xe2, 0xbe, 0xbe, 0x26, 0x3a, 0xbf, + 0xc1, 0x9e, 0xf9, 0xbf, 0xbb, 0x1b, 0x58, 0xbf, 0xaa, 0xba, 0x2c, 0xbe, 0x71, 0x66, 0xaf, 0xbf, + 0x5f, 0x4f, 0x52, 0x3e, 0xe2, 0x1f, 0x5c, 0x3f, 0x4c, 0xd4, 0x6a, 0x3e, 0x12, 0xc7, 0xee, 0x3d, + 0x37, 0x50, 0x18, 0x3d, 0xa3, 0x31, 0xd1, 0xbd, 0xd6, 0xda, 0x74, 0xbe, 0x79, 0xbc, 0xa1, 0x3f, + 0x97, 0xbc, 0x0a, 0xbf, 0xc6, 0x5b, 0x41, 0x3f, 0xbb, 0x04, 0xcf, 0xbf, 0xc5, 0x18, 0x43, 0xbf, + 0xfb, 0x76, 0xe5, 0x3f, 0x67, 0x2e, 0x86, 0x3d, 0xc7, 0xec, 0x6d, 0xbf, 0xf1, 0xb7, 0xac, 0x3f, + 0x57, 0x11, 0x3e, 0x3f, 0xdf, 0xa7, 0x7f, 0x3e, 0x77, 0x61, 0x3e, 0xbf, 0x79, 0xec, 0xfe, 0x3f, + 0xf7, 0x27, 0xe7, 0x3e, 0x1a, 0xc5, 0xa5, 0xbe, 0xec, 0xf9, 0xf7, 0x3e, 0x8f, 0x6b, 0xd0, 0xbe, + 0xfe, 0x31, 0xe4, 0xbd, 0x4c, 0x97, 0x85, 0xbe, 0xcf, 0x85, 0x46, 0xbe, 0x2f, 0x0b, 0x99, 0x3f, + 0x66, 0x7b, 0x29, 0xbd, 0xb9, 0xff, 0xff, 0xbe, 0xef, 0x41, 0x25, 0x3f, 0xe5, 0x50, 0xf7, 0x3e, + 0xe0, 0xe9, 0xa2, 0xbe, 0xaa, 0x40, 0x37, 0xbf, 0x85, 0x73, 0xe4, 0x3e, 0x28, 0xdc, 0x9d, 0xbe, + 0x53, 0xec, 0xd4, 0x3e, 0x63, 0xa7, 0x36, 0x3f, 0xcb, 0xe3, 0x09, 0x3f, 0x6a, 0x54, 0xc7, 0xbd, + 0x96, 0x45, 0xf4, 0x3f, 0x02, 0xa9, 0x07, 0xbd, 0x7c, 0x2e, 0x3f, 0xbf, 0x04, 0x19, 0x7c, 0xbf, + 0xf8, 0x36, 0x61, 0x3e, 0x25, 0xef, 0xc3, 0xbf, 0x0e, 0xd7, 0x98, 0x3f, 0x16, 0xae, 0x51, 0x3f, + 0xff, 0xd4, 0xea, 0xbe, 0x02, 0x5d, 0x0c, 0xbf, 0x8d, 0x5e, 0xf8, 0xbe, 0x2d, 0x66, 0xb1, 0xbd, + 0x2e, 0xd4, 0x51, 0x3f, 0xe0, 0x1a, 0x93, 0xbe, 0x95, 0x96, 0xcb, 0x3f, 0x99, 0xa0, 0xab, 0xbf, + 0x87, 0x75, 0x0d, 0x3f, 0x90, 0xf4, 0xbd, 0xbf, 0xd7, 0x1e, 0x26, 0x40, 0x5d, 0xc9, 0x83, 0x3f, + 0x5b, 0x1b, 0x17, 0x3f, 0xd4, 0xe6, 0x07, 0xc0, 0xae, 0x09, 0xcb, 0x3e, 0x83, 0xa9, 0x97, 0x3d, + 0x9d, 0xf4, 0xbf, 0x3f, 0x01, 0xe5, 0xb3, 0x3d, 0xf2, 0x3a, 0x9a, 0x3e, 0x65, 0x1c, 0x0c, 0xbf, + 0xad, 0x91, 0x6a, 0xbe, 0x7a, 0x8b, 0x0f, 0x3f, 0xfe, 0x20, 0x2a, 0x3d, 0xae, 0xbe, 0x09, 0x40, + 0xed, 0xfe, 0xa4, 0x3f, 0xa3, 0xfe, 0x21, 0xbf, 0xba, 0x12, 0x22, 0xbe, 0xc0, 0xf7, 0xcb, 0xbe, + 0xdf, 0x81, 0xa1, 0x3d, 0x2a, 0x80, 0x27, 0x3f, 0xb0, 0xa6, 0x03, 0x3f, 0x9f, 0xb1, 0xe4, 0x3f, + 0x00, 0xee, 0x8a, 0xbe, 0xbc, 0x85, 0x18, 0xbf, 0xf5, 0x8c, 0x65, 0x3e, 0x69, 0xaf, 0xb3, 0xbd, + 0x01, 0xba, 0x20, 0xc0, 0x67, 0x8c, 0x53, 0x3f, 0xc7, 0x91, 0xe9, 0x3e, 0x82, 0x1e, 0x66, 0xbe, + 0xfa, 0xed, 0x1b, 0x3f, 0xde, 0x84, 0x04, 0xbf, 0xce, 0x2b, 0xa8, 0x3f, 0x8f, 0xfd, 0x34, 0xbf, + 0x61, 0x17, 0x53, 0xbe, 0x7f, 0xc1, 0xf1, 0x3e, 0x84, 0x66, 0x63, 0xbd, 0x40, 0xf4, 0x95, 0x3e, + 0x2b, 0x75, 0x2f, 0x3f, 0x7a, 0x89, 0x17, 0xbf, 0x21, 0x51, 0x94, 0xbf, 0xbb, 0x9b, 0xc0, 0x3f, + 0x2d, 0xce, 0xa4, 0x3f, 0x8c, 0x30, 0xdc, 0x3e, 0x92, 0xca, 0x0e, 0x3e, 0x26, 0x66, 0x2a, 0xbf, + 0xb3, 0x26, 0xdc, 0x3d, 0xd0, 0xcd, 0xa2, 0x3f, 0x47, 0x8d, 0x2b, 0xbe, 0xbf, 0xa4, 0x10, 0xbf, + 0x23, 0x07, 0x71, 0x3e, 0xc2, 0xa6, 0xc5, 0xbf, 0x80, 0x4f, 0xb1, 0xbf, 0x74, 0xe1, 0xc5, 0x3e, + 0xae, 0xb7, 0x0b, 0x3f, 0xdf, 0xbd, 0xab, 0x3f, 0x5f, 0xd1, 0x63, 0x3e, 0xa6, 0x82, 0x00, 0x3f, + 0xe4, 0xa4, 0x27, 0xbe, 0xc2, 0x41, 0x01, 0xbf, 0xdb, 0xf7, 0x53, 0x3e, 0x08, 0x77, 0x4f, 0xbe, + 0x7c, 0x5a, 0x57, 0xbf, 0x78, 0x96, 0x02, 0x3d, 0xd8, 0x7f, 0x90, 0xbf, 0x9c, 0xec, 0x29, 0xbd, + 0xb2, 0x61, 0xa7, 0x3f, 0x9c, 0xca, 0xb0, 0x3f, 0x5a, 0x17, 0xc2, 0x3f, 0x4b, 0x84, 0xcd, 0xbe, + 0x61, 0x0e, 0xc7, 0x3e, 0xfe, 0xdc, 0x27, 0xbf, 0x6f, 0xba, 0x80, 0x3e, 0x0b, 0x12, 0xb5, 0xbd, + 0x72, 0xb3, 0xc9, 0x3d, 0xa5, 0xd9, 0x66, 0x3f, 0x03, 0x27, 0x14, 0x3f, 0x1c, 0x5c, 0xac, 0x3e, + 0xf1, 0xaf, 0xa8, 0x3f, 0xf5, 0x8a, 0x5e, 0x3e, 0x21, 0x7a, 0xcb, 0x3e, 0x6a, 0x1b, 0x3a, 0xbf, + 0x61, 0x1a, 0x36, 0x3e, 0x47, 0x18, 0xf4, 0xbe, 0xfb, 0x44, 0xeb, 0x3f, 0xed, 0xec, 0x84, 0xbf, + 0xa9, 0xba, 0x2f, 0xbf, 0x57, 0x9b, 0xd4, 0x3e, 0xb8, 0xed, 0xde, 0x3f, 0xc2, 0x0f, 0x15, 0x3e, + 0xb8, 0x75, 0x43, 0xbf, 0x98, 0x16, 0x0e, 0xbd, 0x92, 0x44, 0x84, 0x3e, 0x6e, 0x4c, 0xe5, 0x3f, + 0x36, 0x90, 0x6f, 0xbd, 0x49, 0x20, 0x0a, 0xbf, 0x56, 0x7d, 0x0a, 0x40, 0x4d, 0xc7, 0xad, 0x3f, + 0x7f, 0x1a, 0x89, 0xbe, 0xc0, 0x51, 0xe7, 0x3f, 0xdf, 0x12, 0x74, 0x3e, 0x33, 0x0e, 0x8d, 0xbf, + 0x3b, 0xf9, 0x50, 0xbf, 0x5a, 0x90, 0x95, 0xbf, 0x8e, 0x4d, 0x14, 0xbf, 0x7b, 0x43, 0x4f, 0xbf, + 0x81, 0xee, 0x56, 0x3f, 0xa8, 0x23, 0x13, 0xbe, 0x40, 0xe0, 0x80, 0x3f, 0x40, 0x42, 0xe2, 0xbf, + 0x58, 0x4f, 0x39, 0x3f, 0xc3, 0x30, 0x46, 0x3e, 0x2d, 0x04, 0xc6, 0xbf, 0xd3, 0x04, 0x0b, 0xbf, + 0x0f, 0xa8, 0xfd, 0x3f, 0x8b, 0xc7, 0xa8, 0x3f, 0xb4, 0x24, 0xe2, 0x3e, 0x51, 0x9e, 0x54, 0xbe, + 0xd1, 0x8d, 0x6e, 0xbe, 0xf8, 0x1b, 0x15, 0x3e, 0xb7, 0xaf, 0x17, 0x3f, 0xf1, 0x2f, 0xda, 0x3f, + 0x92, 0xc8, 0x17, 0x3f, 0xee, 0x0b, 0x6c, 0xbf, 0xd3, 0x35, 0x69, 0xbf, 0x48, 0x69, 0x1e, 0x3f, + 0x2a, 0x98, 0xb1, 0x3e, 0x9e, 0xab, 0x83, 0xbe, 0x47, 0x71, 0x8d, 0xbf, 0x2f, 0x13, 0x59, 0x3f, + 0x31, 0xed, 0xc8, 0x3e, 0x25, 0x9b, 0xc3, 0xbe, 0x82, 0xe8, 0x3c, 0xbf, 0x5e, 0xf0, 0x04, 0x3e, + 0x81, 0x07, 0xaa, 0xbf, 0x23, 0xe6, 0x87, 0xbf, 0x85, 0x1e, 0x92, 0xbe, 0xf1, 0xfb, 0xaf, 0xbd, + 0xb0, 0xb0, 0x2d, 0x3f, 0xc9, 0xd5, 0x25, 0x3f, 0x7b, 0xe9, 0x06, 0x3e, 0xb3, 0xf0, 0xc5, 0xbe, + 0x2a, 0xcf, 0x57, 0x3e, 0xeb, 0x4d, 0x87, 0x3e, 0xaa, 0x3a, 0x89, 0x3f, 0x5f, 0x35, 0xd8, 0x3e, + 0x5a, 0xd9, 0xc6, 0xbe, 0xb7, 0xe4, 0x12, 0xbf, 0x95, 0x20, 0x65, 0x3f, 0x8a, 0x2f, 0xa8, 0xbd, + 0x09, 0x11, 0xc8, 0xbf, 0x93, 0xf5, 0x80, 0x3f, 0x78, 0x3a, 0x1f, 0x3f, 0x3a, 0x9d, 0x0e, 0xbf, + 0x25, 0x38, 0x67, 0x3f, 0x0d, 0xbe, 0x74, 0x3f, 0x84, 0x08, 0x11, 0xbd, 0xae, 0xae, 0xa4, 0xbf, + 0xd6, 0xe0, 0x9b, 0x3f, 0x64, 0x85, 0x26, 0x3f, 0xd0, 0x7b, 0x82, 0x3f, 0xa3, 0xc7, 0x62, 0x3f, + 0x54, 0xdd, 0xf6, 0x3e, 0x9b, 0xe5, 0x6f, 0xbf, 0x35, 0xa9, 0x9d, 0xbf, 0x3e, 0x21, 0xa1, 0xbf, + 0x56, 0x58, 0x8a, 0xbf, 0x52, 0x54, 0x14, 0x3f, 0x36, 0xcb, 0x64, 0xbf, 0x78, 0xac, 0x58, 0x3f, + 0x63, 0x7e, 0x5e, 0x3f, 0x23, 0xc9, 0x91, 0x3f, 0x41, 0x95, 0xb0, 0x3f, 0x99, 0xa2, 0x30, 0x3f, + 0x9d, 0xf4, 0x27, 0xbf, 0x3e, 0xe1, 0xaf, 0x3e, 0x39, 0x54, 0xad, 0xbf, 0xe0, 0x5c, 0xf8, 0xbe, + 0x36, 0x19, 0x8a, 0x3f, 0x0f, 0x5b, 0x68, 0xbe, 0x51, 0xdf, 0x98, 0x3f, 0x1a, 0xf8, 0x06, 0xbf, + 0xf6, 0xc1, 0x16, 0x3f, 0x30, 0x2e, 0x3e, 0xbf, 0x38, 0xe0, 0xaf, 0x3e, 0x0d, 0xf9, 0x61, 0x3f, + 0xdd, 0xbb, 0x68, 0x3e, 0x3e, 0x61, 0xc4, 0x3d, 0x25, 0x7a, 0x15, 0x3e, 0xce, 0xb5, 0x1c, 0x3e, + 0x49, 0x88, 0x09, 0x3f, 0x86, 0x5b, 0xf9, 0x3f, 0xcb, 0xed, 0x96, 0xbd, 0xcb, 0xd9, 0x3f, 0x3f, + 0x84, 0x9f, 0x0f, 0x3f, 0x5d, 0x0a, 0xa1, 0xbd, 0x30, 0xb1, 0xa6, 0xbf, 0xb1, 0x23, 0x20, 0x3e, + 0x4b, 0xbb, 0xcc, 0x3e, 0xdf, 0x65, 0xfa, 0x3f, 0x5a, 0xb8, 0x32, 0xbf, 0x55, 0x4a, 0xc6, 0xbd, + 0x3d, 0x14, 0x7e, 0xbf, 0xc9, 0x6a, 0x41, 0x3e, 0x1a, 0x7b, 0xc8, 0x3e, 0xd4, 0x52, 0x1b, 0x3e, + 0x81, 0xcb, 0x8c, 0xbd, 0xc4, 0xae, 0xba, 0x3f, 0xca, 0xba, 0x95, 0x3f, 0x71, 0xbd, 0x4b, 0xbf, + 0x08, 0x26, 0xe5, 0x3e, 0xed, 0xad, 0x1a, 0xbf, 0xcd, 0x2c, 0x09, 0x3f, 0xfd, 0x48, 0x3e, 0x3f, + 0x14, 0x76, 0x5a, 0x3f, 0x31, 0x8d, 0x7a, 0x3f, 0xae, 0xba, 0x0f, 0x3e, 0x11, 0x27, 0xa4, 0x3f, + 0xd9, 0xae, 0x9b, 0xbe, 0x45, 0x9b, 0xcc, 0x3f, 0x63, 0x00, 0xbd, 0xbf, 0x3f, 0x81, 0x59, 0xbf, + 0x66, 0xcc, 0x1a, 0xbf, 0x25, 0x25, 0xab, 0xbf, 0x6a, 0x64, 0x91, 0x3f, 0xb2, 0xed, 0x92, 0x3f, + 0x7b, 0xf2, 0x30, 0xbd, 0x0f, 0x53, 0x30, 0xbd, 0x1c, 0x73, 0x04, 0xbf, 0x69, 0xae, 0x91, 0x3f, + 0x24, 0x91, 0x2e, 0x3f, 0x2a, 0x51, 0xdd, 0x3f, 0xc8, 0xf0, 0xa1, 0xbf, 0xe6, 0x5e, 0x23, 0xbe, + 0x1f, 0x74, 0x3e, 0xbf, 0x36, 0x5c, 0x66, 0x3f, 0xe9, 0xb1, 0xdf, 0xbe, 0x03, 0x80, 0x90, 0x3f, + 0x62, 0x31, 0x8a, 0xbf, 0x04, 0x89, 0x0b, 0x3f, 0xff, 0xc5, 0x76, 0x3f, 0x6e, 0xf7, 0x96, 0xbf, + 0x6c, 0xda, 0x9b, 0xbe, 0x7b, 0xde, 0x89, 0x3e, 0x74, 0x7d, 0x61, 0xbe, 0x66, 0xf3, 0xe1, 0x3f, + 0xcf, 0xd5, 0x82, 0xbf, 0x6d, 0xa7, 0x9c, 0x3f, 0x6d, 0x3b, 0xf2, 0xbe, 0xc7, 0x15, 0xa8, 0xbf, + 0xa1, 0x9a, 0xa8, 0x3f, 0xb9, 0xa3, 0x1a, 0x3f, 0x6d, 0x80, 0x2e, 0x3f, 0x4b, 0xe3, 0xc0, 0xbe, + 0x14, 0xba, 0x91, 0x3f, 0x88, 0x11, 0xed, 0xbc, 0xb2, 0xe1, 0xc1, 0xbe, 0x40, 0x18, 0x17, 0xbf, + 0x3c, 0x5e, 0xbb, 0x3c, 0x06, 0x97, 0x23, 0x40, 0xe4, 0x06, 0xb9, 0xbf, 0x57, 0xf1, 0x1a, 0xbe, + 0x49, 0x85, 0xa8, 0x3c, 0xd7, 0xfa, 0x62, 0x3d, 0x63, 0x9d, 0x96, 0xbe, 0x64, 0x02, 0x23, 0x3e, + 0x9a, 0x9d, 0x15, 0x3c, 0xeb, 0xbb, 0x6a, 0xbf, 0xfb, 0xd8, 0xa7, 0x3f, 0x2f, 0x3e, 0xc7, 0xbe, + 0xe8, 0x3b, 0xeb, 0xbe, 0x90, 0x12, 0x75, 0x3d, 0xd0, 0x35, 0x94, 0x3d, 0x04, 0x0e, 0x4b, 0xbf, + 0x20, 0xff, 0xc2, 0x3e, 0x98, 0xb2, 0x4a, 0xbf, 0x9f, 0x8d, 0x2b, 0x3f, 0x7c, 0x8e, 0xcb, 0x3e, + 0x9d, 0xbc, 0x80, 0x3e, 0x59, 0xa0, 0x4b, 0x3f, 0x52, 0x95, 0x13, 0xbf, 0xe4, 0x5e, 0x50, 0xbe, + 0x9b, 0x5e, 0xb7, 0x3f, 0x6d, 0xa0, 0xa8, 0x3f, 0x82, 0xc6, 0x1b, 0xbe, 0xbd, 0x47, 0x24, 0x3d, + 0xd6, 0x2d, 0x9a, 0xbf, 0x28, 0xd2, 0x42, 0x3e, 0x3f, 0xf4, 0x86, 0xbf, 0x90, 0xa8, 0x1b, 0x3f, + 0x5b, 0x22, 0x1b, 0xbe, 0x46, 0x77, 0x04, 0x3f, 0x63, 0x8c, 0xba, 0xbe, 0x45, 0x27, 0xc5, 0x3f, + 0xb9, 0x8a, 0xa4, 0xbe, 0xda, 0xd1, 0x8a, 0xbd, 0x09, 0xe6, 0x53, 0xbf, 0xad, 0xad, 0x0b, 0xbf, + 0xc2, 0x14, 0x71, 0x3f, 0x15, 0x78, 0x25, 0x3f, 0x53, 0x26, 0x6a, 0xbf, 0x07, 0x3a, 0xbe, 0x3e, + 0xb9, 0x37, 0x1e, 0xbf, 0x0d, 0x07, 0x80, 0x3f, 0xd9, 0x9f, 0x01, 0x3e, 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, + 0x78, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x80, 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, 0x06, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x07, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, + 0xd4, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x6f, 0x66, 0x6d, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x10, 0x00, 0x14, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x0c, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x62, 0x69, 0x61, 0x73, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0xa4, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x77, 0x65, 0x69, 0x67, + 0x68, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0xd0, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x5f, 0x66, + 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 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, + 0x03, 0x00, 0x00, 0x00, 0x69, 0x66, 0x6d, 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, 0x1b, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1b, 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 = { + -88.04056, 80.27833, 21.511183, 85.93182, 90.22253, -50.795647, 78.00544, -17.377474, + -62.31908, 14.504589, 3.2413504, 32.54737, 25.954002, 9.092799, 70.73234, -45.636135}; + +const std::vector reference_output_data = { + 26.202744, 463.3182, 84.626854, 289.90292, 0.0, 0.0, 0.0, 0.0, + 69.141045, 0.0, 31.10253, 130.52267, 5.652733, 0.0, 72.082275, 0.0, + 0.0, 128.29478, 63.66363, 136.1562, 47.363857, 197.50403, 0.0, 48.581432, + 102.55079, 0.0, 75.65965, 0.0, 0.0, 0.0, 0.0, 338.36807, + 0.0, 211.63658, 39.766064, 0.0, 215.11708, 363.6181, 0.0, 109.92663, + 0.0, 0.0, 0.0, 0.84396774, 0.0, 0.0, 161.46375, 28.506226, + 0.0, 0.0, 0.0, 92.488815, 222.40182, 48.270275, 26.44544, 0.0, + 0.0, 0.0, 51.692745, 0.0, 316.81906, 0.6861581, 0.0, 42.598343}; + +} // namespace svdf_float + +class TestDataFloatSVDF : public TestDataSVDFBase +{ +public: + TestDataFloatSVDF() + { + _input_data = svdf_float::input_data; + _reference_output_data = svdf_float::reference_output_data; + _test_kernel_model_circle = svdf_float::test_kernel_model_circle; + } + + ~TestDataFloatSVDF() override = default; +}; + +} // namespace test_model +} // namespace onert_micro + +#endif // ONERT_MICRO_TEST_MODELS_FLOAT_SVDF_KERNEL_H diff --git a/onert-micro/onert-micro/include/test_models/svdf/NegSVDFKernel.h b/onert-micro/onert-micro/include/test_models/svdf/NegSVDFKernel.h new file mode 100644 index 00000000000..43fff152f21 --- /dev/null +++ b/onert-micro/onert-micro/include/test_models/svdf/NegSVDFKernel.h @@ -0,0 +1,505 @@ +/* + * 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 ONERT_MICRO_TEST_MODELS_NEG_SVDF_KERNEL_H +#define ONERT_MICRO_TEST_MODELS_NEG_SVDF_KERNEL_H + +#include "test_models/TestDataBase.h" + +namespace onert_micro +{ +namespace test_model +{ +namespace neg_input_output_type_mismatch_svdf_kernel +{ +/* + * SVDF Kernel with input output type mismatch: + * + * Input(1, 16) - Float32 + * | + * SVDF + * | + * Output(1, 64) - Int32 + */ +const unsigned char test_kernel_model_circle[] = { + 0x18, 0x00, 0x00, 0x00, 0x43, 0x49, 0x52, 0x30, 0x00, 0x00, 0x0e, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x6c, 0x19, 0x00, 0x00, 0x60, 0x1b, 0x00, 0x00, 0x7c, 0x1b, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x58, 0x19, 0x00, 0x00, 0x4c, 0x19, 0x00, 0x00, 0x44, 0x19, 0x00, 0x00, 0x34, 0x09, 0x00, 0x00, + 0x1c, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xc8, 0xe6, 0xff, 0xff, + 0xe6, 0xf6, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xc3, 0x55, 0x87, 0x3f, + 0xc4, 0xb8, 0xd9, 0xbf, 0x10, 0xa4, 0x80, 0xbe, 0x8e, 0x9f, 0x95, 0x3f, 0xc6, 0xfb, 0x45, 0xbf, + 0x52, 0x7d, 0xd3, 0x3e, 0xe0, 0xc9, 0x02, 0x3f, 0xe9, 0xd1, 0xee, 0x3d, 0xeb, 0x3a, 0xbc, 0xbf, + 0x2b, 0xc6, 0x94, 0x3f, 0x00, 0x04, 0x98, 0xbe, 0x03, 0xb9, 0x23, 0x3f, 0x52, 0x74, 0x80, 0xbf, + 0xcc, 0x61, 0x9d, 0xbf, 0x07, 0x81, 0x32, 0xbf, 0x27, 0x68, 0x0b, 0xbf, 0x0d, 0xef, 0xe7, 0xbe, + 0xbd, 0xda, 0xb1, 0xbf, 0x2e, 0xc0, 0x96, 0x3f, 0x4c, 0x5a, 0x82, 0x3e, 0xdd, 0x0d, 0x31, 0xbf, + 0x9e, 0xaa, 0x09, 0xbf, 0x04, 0xca, 0xc7, 0xbf, 0x75, 0xc6, 0x4b, 0x3e, 0x23, 0x2e, 0x94, 0x3e, + 0x54, 0x1b, 0x85, 0x3f, 0xe2, 0x42, 0xf3, 0xbf, 0x86, 0xe9, 0x10, 0xc0, 0x73, 0xb9, 0x0a, 0x3f, + 0x9a, 0xb2, 0x34, 0x3e, 0xd5, 0x03, 0x80, 0x3e, 0x51, 0x91, 0x2b, 0xbf, 0x5f, 0x5a, 0x37, 0xbf, + 0xed, 0x27, 0xec, 0x3f, 0x1e, 0x65, 0xaa, 0x3e, 0xa7, 0x3f, 0x9c, 0x3e, 0x4a, 0xf7, 0x7e, 0xbf, + 0x24, 0x57, 0xb0, 0xbf, 0xa4, 0x06, 0x61, 0x3f, 0x82, 0x86, 0xce, 0x3e, 0x99, 0x32, 0x9b, 0xbf, + 0xc9, 0xc1, 0xc3, 0x3f, 0x51, 0xed, 0x85, 0x3f, 0x8d, 0x3a, 0x30, 0x3f, 0xd4, 0xe0, 0x2a, 0xc0, + 0xf1, 0x5d, 0x92, 0xbf, 0x09, 0x85, 0x0e, 0xbf, 0x1b, 0x93, 0x0f, 0xbf, 0x80, 0xae, 0x98, 0x3e, + 0x7e, 0x7e, 0x77, 0x3f, 0xfe, 0x4b, 0x26, 0xbe, 0x77, 0x12, 0x1b, 0xbf, 0x81, 0xf5, 0xcc, 0xbe, + 0x55, 0xdd, 0x28, 0x3f, 0xad, 0x11, 0x25, 0xc0, 0xff, 0x87, 0xfd, 0x3f, 0x6f, 0x5a, 0x2e, 0x3f, + 0x59, 0x8f, 0x8e, 0x3f, 0xf0, 0x03, 0xe8, 0x3f, 0xbb, 0x41, 0x0e, 0x3f, 0x62, 0x9d, 0x0d, 0xbf, + 0xaf, 0xcc, 0xec, 0xbc, 0x71, 0x8d, 0x87, 0xbf, 0xbe, 0x72, 0x5a, 0x3f, 0xf2, 0xf7, 0xff, 0xff, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0xd3, 0xc7, 0xee, 0x3e, 0xe8, 0x29, 0x4e, 0x40, + 0xbb, 0xc5, 0x9c, 0xbe, 0xeb, 0x24, 0x9c, 0xbf, 0xf3, 0x50, 0x92, 0xbe, 0x22, 0x9a, 0x70, 0x3f, + 0x60, 0xea, 0xcf, 0x3c, 0x25, 0x80, 0xa0, 0x3f, 0xef, 0xde, 0xb5, 0xbe, 0x04, 0x9e, 0x53, 0xbf, + 0xc4, 0xac, 0xd7, 0x3f, 0xd6, 0xef, 0xba, 0xbf, 0x19, 0x73, 0x13, 0x40, 0xec, 0x4d, 0x81, 0x3f, + 0xe1, 0xd3, 0xf3, 0x3d, 0x46, 0xb7, 0x51, 0x3f, 0x2c, 0xc7, 0x96, 0x3f, 0x6a, 0x42, 0x29, 0xbe, + 0xc7, 0x72, 0x29, 0xbd, 0x88, 0x8c, 0xa3, 0x3f, 0xf9, 0xb8, 0xf0, 0x3f, 0x39, 0xde, 0x5b, 0xbf, + 0xa5, 0x7c, 0xfc, 0x3f, 0xfe, 0xa7, 0x1d, 0xbe, 0x42, 0x6c, 0xb1, 0x3f, 0xa7, 0x06, 0x12, 0xbf, + 0x6a, 0x1d, 0x7f, 0x3f, 0x38, 0xe0, 0x4a, 0xbf, 0xdd, 0x30, 0xc4, 0xbf, 0x8a, 0x51, 0x0d, 0xbe, + 0x67, 0xef, 0x47, 0x3e, 0xad, 0x06, 0x1d, 0xbe, 0x9f, 0x53, 0xe1, 0x3f, 0x85, 0xbe, 0x38, 0xbe, + 0xe2, 0x3b, 0x82, 0xbf, 0xda, 0xce, 0x9c, 0xbf, 0x00, 0xa8, 0x20, 0xbf, 0x45, 0x30, 0x45, 0xc0, + 0x4f, 0x52, 0xe8, 0x3d, 0x08, 0x86, 0xd9, 0x3f, 0x08, 0xb4, 0x61, 0xbe, 0x92, 0x6f, 0x9e, 0x3e, + 0xba, 0xa1, 0x78, 0x3f, 0x2f, 0x86, 0xfa, 0xbe, 0x02, 0xfc, 0x98, 0x3c, 0x5c, 0x64, 0xc8, 0x3f, + 0x98, 0x48, 0x18, 0xc0, 0x53, 0xa8, 0xee, 0xbe, 0xfa, 0xe3, 0x39, 0x3f, 0x28, 0x7e, 0x23, 0xbf, + 0x26, 0xac, 0xb8, 0xbf, 0xc9, 0x35, 0x8b, 0x3f, 0xa3, 0x96, 0xb7, 0x3e, 0x3d, 0x5c, 0x9a, 0x3f, + 0xb4, 0xaa, 0xd5, 0xbf, 0x04, 0xd3, 0x93, 0xbf, 0xd6, 0xf5, 0x80, 0xbe, 0x4b, 0xf1, 0x6a, 0x3f, + 0xbd, 0xae, 0x89, 0xbb, 0x45, 0x8f, 0xaa, 0x3d, 0x52, 0xde, 0x17, 0xc0, 0xa8, 0xfe, 0x82, 0xbf, + 0x60, 0xcd, 0xf8, 0xbe, 0xfa, 0xdc, 0x25, 0x3e, 0x13, 0xd8, 0x7d, 0xbe, 0x2b, 0x7b, 0xac, 0xbf, + 0x71, 0xde, 0x8f, 0xbf, 0x48, 0xf3, 0x18, 0xbf, 0xd0, 0x50, 0x70, 0x3e, 0x12, 0x48, 0xb6, 0xbe, + 0x5e, 0xda, 0x49, 0x3f, 0x28, 0x57, 0xf8, 0x3f, 0x2e, 0x2b, 0xf4, 0x3d, 0x6f, 0xa7, 0xa3, 0x3e, + 0xd3, 0x19, 0xa9, 0xbf, 0xa1, 0x2d, 0xe4, 0xbe, 0x44, 0x66, 0x7b, 0x3e, 0x28, 0x66, 0x02, 0x3e, + 0x0b, 0xae, 0xa1, 0xbf, 0xec, 0xb1, 0x8e, 0x3e, 0x1b, 0xb5, 0x1f, 0xbf, 0xe1, 0x2c, 0xa1, 0xbe, + 0xbb, 0x0f, 0x2e, 0xbf, 0x3b, 0xb1, 0xf5, 0x3d, 0x08, 0x75, 0xeb, 0xbf, 0x3a, 0x2f, 0xa2, 0xbf, + 0x35, 0x46, 0xe6, 0xbf, 0xa6, 0xac, 0xcb, 0xbe, 0xb3, 0xb0, 0x70, 0xbf, 0x0d, 0xd4, 0x89, 0x3e, + 0x13, 0x5b, 0x3b, 0x3d, 0x89, 0x15, 0x21, 0xbf, 0x43, 0xf2, 0x93, 0xbf, 0x36, 0x8f, 0xed, 0x3f, + 0x90, 0x41, 0x17, 0xbf, 0x35, 0x6d, 0xd6, 0x3f, 0xe9, 0xa7, 0x5d, 0x3e, 0xe4, 0xcf, 0xbd, 0x3e, + 0xb7, 0xb1, 0xed, 0xbe, 0x97, 0x8a, 0xbe, 0xbf, 0xd0, 0x5e, 0xb2, 0x3e, 0x08, 0x4f, 0xb0, 0x3f, + 0x08, 0xfe, 0x2f, 0xc0, 0xc8, 0x4f, 0x97, 0x3f, 0x5e, 0x4d, 0xc3, 0x3f, 0x4f, 0x56, 0x6f, 0x3b, + 0x7a, 0xdb, 0x3f, 0x3f, 0x88, 0xb5, 0x80, 0x3e, 0xf4, 0x8b, 0x68, 0x3f, 0x32, 0xd3, 0xb8, 0x3e, + 0x37, 0x92, 0xc9, 0xbf, 0x87, 0x6d, 0x99, 0xbe, 0xd2, 0x96, 0x81, 0xbf, 0x6f, 0x47, 0xab, 0x3f, + 0x20, 0x81, 0x98, 0xbd, 0x55, 0xef, 0xe8, 0xbe, 0xb4, 0x0a, 0x93, 0xbe, 0x05, 0x3a, 0xe5, 0x3d, + 0x99, 0x94, 0x99, 0xbe, 0x1b, 0xaf, 0xe2, 0xbd, 0x9c, 0x30, 0x22, 0xbf, 0x22, 0x7f, 0xc9, 0x3f, + 0x91, 0xbc, 0x10, 0x3f, 0x29, 0xcc, 0xeb, 0x3f, 0xc0, 0x1b, 0xec, 0x3e, 0x5c, 0x5a, 0xae, 0xbf, + 0x0f, 0x5b, 0xf5, 0xbf, 0x61, 0xc9, 0x8b, 0x3f, 0x38, 0xd9, 0x1e, 0x3f, 0xf5, 0x1f, 0x82, 0x3e, + 0x99, 0x04, 0xae, 0x3f, 0x20, 0xd3, 0x00, 0x3f, 0xe7, 0x58, 0xd9, 0x3d, 0xcb, 0x1b, 0x67, 0xbf, + 0xc5, 0x95, 0x8c, 0x3f, 0x64, 0x39, 0x5b, 0x3b, 0x2a, 0x80, 0x20, 0x3f, 0x44, 0x4f, 0x1e, 0xbf, + 0x3f, 0xf4, 0xb7, 0x3e, 0x22, 0x5e, 0x45, 0xbd, 0x87, 0x00, 0x26, 0xbf, 0xa3, 0x7a, 0xc2, 0x3f, + 0xac, 0x45, 0x9b, 0xbf, 0xa4, 0x59, 0x87, 0x3e, 0x0c, 0xc1, 0x19, 0xbf, 0x78, 0x40, 0xc3, 0x3f, + 0x5a, 0x69, 0xef, 0x3f, 0x47, 0x5b, 0x8c, 0xbf, 0x10, 0x73, 0x22, 0x3f, 0xd0, 0xe0, 0x7d, 0xbf, + 0xdd, 0x87, 0xd7, 0x3d, 0x60, 0xd7, 0xd8, 0x3e, 0x2e, 0xbf, 0x47, 0x3f, 0xdb, 0x13, 0xbe, 0xbf, + 0x80, 0x90, 0xc5, 0x3e, 0xe5, 0x46, 0x62, 0x3f, 0x9d, 0x13, 0xb8, 0xbf, 0x2d, 0x31, 0x68, 0xbf, + 0xa1, 0xe4, 0x13, 0xbf, 0x91, 0xba, 0x5b, 0xbd, 0xb6, 0x07, 0xc0, 0xbf, 0x83, 0xde, 0x1f, 0xc0, + 0xb2, 0xee, 0x06, 0xbf, 0x33, 0xbf, 0x3d, 0x3f, 0x10, 0xbb, 0x64, 0x3f, 0x4d, 0x9a, 0xd2, 0xbe, + 0x85, 0xf4, 0xf8, 0xbe, 0xf9, 0x2f, 0x8a, 0xbf, 0x4f, 0xc6, 0x61, 0x3f, 0x3f, 0x19, 0xde, 0xbf, + 0x39, 0xd7, 0x83, 0xbc, 0x8a, 0xe7, 0xa9, 0xbe, 0x8f, 0x41, 0xb8, 0x3e, 0x5a, 0x75, 0xb6, 0xbe, + 0xd1, 0x33, 0x4a, 0xbe, 0xc0, 0xf4, 0x1b, 0xbf, 0xc8, 0xc4, 0xdb, 0xbe, 0xca, 0x58, 0x90, 0x3e, + 0x24, 0x3c, 0xf4, 0xbf, 0x01, 0xe5, 0x77, 0xbf, 0xc4, 0x16, 0x94, 0xbe, 0xee, 0x88, 0x65, 0x3f, + 0x34, 0xe3, 0x87, 0xbf, 0x9d, 0x7d, 0x5d, 0xbf, 0xdc, 0x18, 0x22, 0x3e, 0x39, 0x31, 0x12, 0xc0, + 0x3f, 0x6f, 0xce, 0x3f, 0x5a, 0xa4, 0x90, 0xbf, 0x9e, 0x51, 0xd0, 0xbf, 0x19, 0xb0, 0xdf, 0xbf, + 0xbf, 0x27, 0xb9, 0x3d, 0xdf, 0x28, 0x5d, 0xbf, 0x1f, 0x15, 0x07, 0xbf, 0x98, 0xfb, 0xf6, 0xbf, + 0x17, 0x2b, 0x49, 0x3e, 0x68, 0x8e, 0x0b, 0xc0, 0xbd, 0xab, 0x06, 0xbe, 0x31, 0xb5, 0x95, 0x3f, + 0x31, 0xcd, 0xb5, 0x3f, 0x1a, 0x46, 0x16, 0xbf, 0x95, 0xf0, 0xbc, 0xbe, 0xae, 0xae, 0xb3, 0xbf, + 0xb7, 0x30, 0x1b, 0x3f, 0x37, 0x42, 0xf3, 0x3f, 0x7a, 0x64, 0x01, 0xbf, 0xbc, 0x47, 0x10, 0x3f, + 0xd9, 0x9b, 0xae, 0x3f, 0x18, 0x34, 0x40, 0xbf, 0x23, 0x6f, 0x66, 0x3e, 0x4c, 0x46, 0x68, 0x3e, + 0x71, 0x4d, 0xe5, 0xbf, 0x23, 0x2b, 0xe0, 0xbc, 0x0a, 0x92, 0x27, 0xbe, 0xe6, 0x3c, 0x12, 0x3f, + 0x2b, 0x68, 0xac, 0x3f, 0x60, 0xcd, 0xb8, 0xbf, 0x37, 0x90, 0xbd, 0xbe, 0x77, 0x1a, 0xd4, 0x3f, + 0xd2, 0x67, 0x95, 0x3f, 0xf4, 0xdf, 0xd7, 0x3f, 0x3c, 0x61, 0x70, 0x3e, 0xb7, 0xfc, 0x8e, 0x3f, + 0x70, 0x89, 0x97, 0xbf, 0xc1, 0x97, 0xa3, 0xbe, 0x12, 0x8c, 0x36, 0x3e, 0x64, 0xdf, 0x83, 0xbf, + 0xd2, 0xce, 0xbc, 0x3f, 0x64, 0xbd, 0x2e, 0x3e, 0x39, 0xe6, 0x1c, 0xbf, 0x04, 0xc6, 0x43, 0xbf, + 0x5d, 0x21, 0x8a, 0x3f, 0xd8, 0x09, 0x31, 0x3f, 0x6e, 0xd6, 0xc8, 0x3d, 0x67, 0x5a, 0x22, 0xc0, + 0x72, 0xbd, 0x18, 0xbf, 0xab, 0xb6, 0x3e, 0x3e, 0x62, 0x34, 0x9f, 0xbd, 0xcc, 0x5a, 0x94, 0xbf, + 0xd5, 0x9c, 0x9b, 0xbe, 0xbc, 0x0f, 0x89, 0x3e, 0xa5, 0x30, 0x04, 0xc0, 0xa4, 0x16, 0x75, 0xbf, + 0x37, 0xea, 0x2f, 0x3e, 0xb0, 0xcd, 0xf0, 0x3e, 0x5a, 0x86, 0xe4, 0x3e, 0xe0, 0x31, 0x92, 0xbf, + 0xb5, 0x56, 0xa4, 0xbe, 0xf8, 0xf6, 0xdd, 0x3f, 0x45, 0x27, 0x25, 0xbe, 0xff, 0x8d, 0x2c, 0x3e, + 0x10, 0x84, 0x6b, 0xbf, 0x80, 0xb7, 0x95, 0x3e, 0xdf, 0xe0, 0xe0, 0x3f, 0x5e, 0xfe, 0xc7, 0xbe, + 0xd0, 0xd3, 0x8e, 0xbf, 0xcf, 0x68, 0x8d, 0x3f, 0x23, 0x49, 0x3e, 0xbf, 0x4e, 0x4c, 0x92, 0x3f, + 0x5d, 0xba, 0x8c, 0x3e, 0xf6, 0x8b, 0x4f, 0x3f, 0x0a, 0x1e, 0xf6, 0xbf, 0x28, 0xc7, 0x8d, 0x3f, + 0xcd, 0xf2, 0x12, 0xbf, 0x0b, 0x84, 0xe3, 0x3f, 0xdc, 0x9d, 0xcc, 0x3f, 0xa5, 0x46, 0x4a, 0xbf, + 0x95, 0x2d, 0x77, 0xbe, 0x64, 0x9d, 0x96, 0x3e, 0x96, 0x02, 0x7a, 0xbf, 0x4d, 0x58, 0x41, 0x3f, + 0x74, 0x5b, 0xca, 0xbf, 0x50, 0x70, 0xe1, 0x3e, 0x68, 0xa4, 0xa1, 0x3f, 0xb5, 0x10, 0x05, 0x3f, + 0x99, 0x3e, 0x37, 0x40, 0xec, 0x59, 0xc7, 0x3f, 0x56, 0x68, 0x63, 0xbf, 0x03, 0xfd, 0xd6, 0x3e, + 0x7a, 0x63, 0x84, 0x3f, 0x09, 0x18, 0x99, 0x3f, 0x3c, 0x41, 0xbb, 0x3e, 0x2c, 0x06, 0x8f, 0xbf, + 0xf1, 0x31, 0x96, 0xbe, 0x56, 0x5e, 0xdf, 0x3f, 0xa3, 0x51, 0x94, 0x3f, 0x2b, 0xc4, 0x34, 0x3e, + 0xe4, 0x0b, 0xf2, 0x3e, 0x2b, 0x4f, 0xdc, 0x3e, 0xb7, 0xbb, 0x8d, 0x3e, 0xb8, 0xfe, 0xcf, 0xbe, + 0xa1, 0xe6, 0x28, 0x3f, 0xa0, 0xa6, 0x21, 0x3f, 0xbf, 0xa8, 0xba, 0x3e, 0xe3, 0xb2, 0xb3, 0xbd, + 0x16, 0x8a, 0x09, 0x3f, 0x06, 0x3c, 0xe5, 0xbd, 0xe9, 0xcf, 0x7d, 0x3e, 0xdd, 0x8a, 0x13, 0x3f, + 0xd2, 0xd6, 0x43, 0xbf, 0xd6, 0x99, 0xad, 0xbe, 0xeb, 0xfa, 0x03, 0x40, 0xc0, 0x1e, 0xac, 0xbd, + 0x0c, 0x8a, 0x70, 0xbd, 0x8a, 0x78, 0x1a, 0xbc, 0x90, 0xc5, 0xf1, 0xbe, 0x48, 0xfc, 0xb2, 0xbe, + 0x70, 0x87, 0x50, 0xbf, 0x00, 0x5a, 0x56, 0xbf, 0xce, 0xe9, 0x28, 0x3f, 0xf6, 0x8a, 0x82, 0xbe, + 0xb1, 0x12, 0xf0, 0xbf, 0x9a, 0xbc, 0x1d, 0xbf, 0x31, 0x71, 0xec, 0x3d, 0x14, 0x67, 0x9a, 0xbc, + 0x92, 0xc1, 0x19, 0x3f, 0xcc, 0x6c, 0xe4, 0xbf, 0xde, 0x5a, 0x9f, 0x3f, 0x6d, 0xf3, 0x12, 0x3e, + 0x49, 0x3f, 0xd9, 0xbf, 0x9d, 0xc5, 0x62, 0xbe, 0x2d, 0xcd, 0xe9, 0xbe, 0xfc, 0xda, 0xc2, 0xbf, + 0x0e, 0xa1, 0x4a, 0x3d, 0xa4, 0x58, 0x04, 0x40, 0x71, 0xe1, 0x4c, 0x3f, 0x40, 0xfc, 0xd9, 0x3d, + 0xa3, 0x49, 0x03, 0x3f, 0xbe, 0xaa, 0x5e, 0x3e, 0xde, 0x4e, 0x07, 0x40, 0xe2, 0x20, 0x17, 0x3f, + 0xe0, 0x35, 0xe2, 0x3f, 0xad, 0x18, 0x1d, 0xbd, 0x67, 0xbb, 0x13, 0xbf, 0x9d, 0x36, 0xb6, 0x3e, + 0x09, 0x38, 0x38, 0xbf, 0x6d, 0x88, 0x01, 0x3e, 0x3c, 0x4e, 0x84, 0x3f, 0x71, 0xc2, 0x0a, 0xbf, + 0x2b, 0x80, 0x91, 0xbe, 0x99, 0x77, 0x7f, 0xbf, 0x07, 0xa4, 0x0a, 0x3c, 0xaf, 0xd3, 0x8a, 0xbe, + 0x4b, 0xfb, 0x83, 0x3f, 0x48, 0x45, 0xcb, 0x3e, 0x67, 0x7e, 0xf2, 0x3e, 0x53, 0xde, 0x2b, 0x3f, + 0xc7, 0xec, 0x1a, 0x3d, 0x15, 0x3a, 0xad, 0x3e, 0x09, 0x7e, 0xaa, 0x3e, 0xf2, 0xa6, 0x89, 0xbd, + 0xa4, 0x0c, 0xb9, 0xbe, 0xb1, 0x65, 0x31, 0x3e, 0x51, 0x9e, 0x29, 0xbf, 0xd5, 0x74, 0x6b, 0x3f, + 0x69, 0x68, 0x52, 0x3e, 0xeb, 0xc3, 0x21, 0xbf, 0x72, 0xa0, 0xf3, 0x3d, 0x74, 0x2f, 0x31, 0xbe, + 0x1c, 0xf3, 0x21, 0x3e, 0x70, 0xce, 0xe7, 0x3e, 0xb3, 0x88, 0x7a, 0x3e, 0x94, 0x86, 0x8d, 0xbf, + 0x0a, 0x11, 0x15, 0x3f, 0x57, 0xfc, 0x24, 0x3f, 0x5f, 0x2c, 0x3c, 0x3f, 0xbc, 0xb4, 0xcb, 0xbf, + 0x71, 0x91, 0xd6, 0xbf, 0x46, 0x77, 0xa2, 0xbd, 0xa7, 0x30, 0x8b, 0xbf, 0x5b, 0xfb, 0x51, 0xbf, + 0xc6, 0x06, 0xaf, 0xbd, 0x65, 0xb8, 0x5a, 0x3e, 0xb5, 0x0d, 0xb4, 0xbf, 0xe6, 0xa1, 0xa5, 0xbe, + 0x15, 0xaa, 0xb5, 0xbe, 0x0a, 0x1d, 0xd2, 0xbf, 0x4e, 0x6e, 0x1c, 0xbf, 0x35, 0xec, 0x50, 0x3d, + 0xe1, 0x1b, 0x32, 0x3f, 0xee, 0xe0, 0x0c, 0xbd, 0x78, 0x81, 0xdc, 0x3e, 0x32, 0xa0, 0x4d, 0x3e, + 0x49, 0xa3, 0x0c, 0xc0, 0x0b, 0xa0, 0x38, 0xbf, 0x1f, 0x78, 0x4a, 0xbf, 0xa2, 0xef, 0x18, 0xbf, + 0x1b, 0x81, 0xb2, 0x3f, 0x4d, 0x72, 0x98, 0x3f, 0x61, 0xbe, 0x12, 0xbf, 0xc7, 0x6f, 0xdf, 0xbd, + 0x4e, 0x87, 0x98, 0x3f, 0x3d, 0x23, 0x1d, 0x3d, 0x8f, 0x10, 0x41, 0xbf, 0x6b, 0x4c, 0x63, 0x3f, + 0x0d, 0x64, 0xf9, 0xbe, 0xc7, 0xdd, 0x20, 0xbf, 0xe8, 0x2b, 0xa7, 0xbf, 0x2d, 0xb4, 0x7c, 0xbe, + 0xa0, 0x5a, 0xe8, 0x3e, 0xd2, 0xd3, 0x55, 0x3f, 0x2d, 0x60, 0x91, 0xbe, 0xc2, 0x9f, 0xb5, 0x3f, + 0xf5, 0x63, 0x3c, 0x3f, 0xca, 0x48, 0x92, 0xbf, 0xc5, 0xf8, 0x0a, 0x3f, 0x0a, 0x6a, 0x31, 0x3d, + 0xea, 0x1a, 0x43, 0x3f, 0x2a, 0x48, 0xa6, 0xbf, 0x62, 0x30, 0x31, 0x3f, 0xcc, 0x53, 0x93, 0xbf, + 0x12, 0x96, 0x3b, 0x3f, 0x6e, 0xa1, 0xc4, 0x3f, 0xd2, 0xae, 0x06, 0xbc, 0xd1, 0xdd, 0xbb, 0xbf, + 0xea, 0x3a, 0x7e, 0xbf, 0xcb, 0x67, 0x9c, 0x3e, 0x1a, 0x9f, 0x44, 0xbf, 0x6c, 0xd5, 0x2f, 0xbf, + 0xc9, 0xe9, 0x8f, 0xbe, 0xe6, 0xf1, 0x90, 0x3c, 0x35, 0x83, 0xac, 0xbf, 0x6c, 0xc0, 0xca, 0x3f, + 0x81, 0x21, 0x90, 0x3f, 0x51, 0x96, 0xdc, 0xbf, 0xd6, 0x4a, 0xa4, 0xbf, 0x5d, 0x9e, 0x77, 0xbf, + 0x49, 0x63, 0x2d, 0x3f, 0xf0, 0x1e, 0xc8, 0xbf, 0x17, 0xf7, 0xd9, 0x3f, 0xdc, 0xbb, 0xe4, 0x3f, + 0x31, 0x5e, 0x38, 0x3f, 0xf8, 0xc1, 0xa5, 0xbf, 0x33, 0x50, 0xe2, 0xbe, 0xb0, 0x33, 0x80, 0x3f, + 0x1b, 0xd2, 0x45, 0x3e, 0x31, 0x16, 0xc4, 0x3f, 0x2e, 0x45, 0x2d, 0xbf, 0xc9, 0x3f, 0x8a, 0xbe, + 0x4b, 0x6e, 0x7c, 0xbe, 0x78, 0xbf, 0x39, 0xbe, 0x72, 0x8d, 0x3f, 0xbf, 0x66, 0x0a, 0xd9, 0x3e, + 0x17, 0xe3, 0x47, 0x3f, 0x50, 0x01, 0x58, 0x3f, 0x00, 0x56, 0x1c, 0xbf, 0xd9, 0xcd, 0x5f, 0x3f, + 0x7e, 0x31, 0xd3, 0xbf, 0xf3, 0x4e, 0x5f, 0xbf, 0x49, 0xdd, 0x9c, 0xbf, 0x17, 0xb7, 0x32, 0x3d, + 0x28, 0xfe, 0xa9, 0x3e, 0x0a, 0xc5, 0x33, 0x3c, 0x46, 0x83, 0xec, 0x3f, 0xcf, 0x56, 0x9b, 0xbf, + 0xe1, 0xf2, 0x0e, 0x3d, 0x52, 0xfe, 0x6c, 0x3f, 0xe0, 0x3c, 0x92, 0xbe, 0x88, 0xed, 0x8c, 0xbf, + 0x53, 0x61, 0xf6, 0x3e, 0xe9, 0xe7, 0x02, 0x3e, 0xf1, 0x9d, 0x93, 0xbd, 0xa5, 0x17, 0x74, 0xbf, + 0x78, 0x1e, 0xda, 0x3f, 0xc7, 0x7d, 0x00, 0x3f, 0x8a, 0xbd, 0x47, 0x3e, 0x3d, 0xcb, 0xac, 0xbf, + 0x30, 0xcc, 0x96, 0x3f, 0x22, 0x5c, 0x9c, 0xbf, 0xf3, 0xec, 0x26, 0x40, 0xe3, 0x7d, 0xaa, 0x3f, + 0x22, 0xdb, 0x04, 0x3f, 0x33, 0x03, 0x97, 0x3f, 0xce, 0x27, 0xdf, 0xbe, 0x03, 0x0d, 0xec, 0x3e, + 0xad, 0xb0, 0x33, 0x3f, 0x65, 0x39, 0x4e, 0xbf, 0xc2, 0xac, 0x8f, 0xbe, 0x6a, 0xe8, 0xd7, 0xbf, + 0xd1, 0xae, 0x99, 0x3f, 0x6d, 0x13, 0x3e, 0x3f, 0x15, 0x4f, 0xb6, 0xbf, 0xd0, 0x38, 0x5c, 0xbf, + 0xc3, 0xb8, 0xae, 0x3f, 0x30, 0xd3, 0xf2, 0xbe, 0xce, 0x78, 0x7d, 0x3d, 0x40, 0x01, 0xce, 0x3d, + 0x61, 0x55, 0xc5, 0xbe, 0x8a, 0xb0, 0x9d, 0x3f, 0x5d, 0x8e, 0x59, 0x3f, 0xca, 0xf9, 0x95, 0xbf, + 0x68, 0xd8, 0xd9, 0xbf, 0x8a, 0x9e, 0xa2, 0x3f, 0x42, 0x18, 0xe6, 0xbf, 0xda, 0xf7, 0xed, 0x3f, + 0x5b, 0x02, 0xf2, 0x3f, 0x1d, 0x80, 0x99, 0xbf, 0x05, 0x6f, 0x0e, 0x40, 0x86, 0xa9, 0xa2, 0x3e, + 0x7e, 0x3d, 0xe7, 0x3f, 0x24, 0x13, 0x9b, 0xbf, 0x79, 0x66, 0xaa, 0x3f, 0xed, 0x09, 0x31, 0xbf, + 0x90, 0x3f, 0xc0, 0x3f, 0x05, 0xfc, 0x9d, 0x3f, 0xd4, 0x9f, 0x9c, 0xbf, 0x45, 0x84, 0x22, 0x3f, + 0xbc, 0x6b, 0x4d, 0xbf, 0xdb, 0x8c, 0x8c, 0xbf, 0xcb, 0xdf, 0x7d, 0xbf, 0xd5, 0xb7, 0xb7, 0xbf, + 0x1e, 0xf5, 0xb8, 0xbf, 0xe9, 0x64, 0x94, 0xbf, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0xc4, 0x03, 0x56, 0xbe, + 0x11, 0x52, 0x42, 0xbf, 0xe6, 0xd6, 0x1a, 0xbe, 0xf6, 0xe7, 0x9e, 0xbd, 0x64, 0x6a, 0xc9, 0x3e, + 0xc3, 0x73, 0xd6, 0x3c, 0x31, 0x19, 0x1b, 0x3e, 0x9c, 0x6f, 0x97, 0x3f, 0x9c, 0x48, 0x73, 0xbe, + 0x6c, 0x01, 0xcc, 0xbe, 0x94, 0x04, 0x79, 0xbf, 0xd2, 0x1b, 0x92, 0xbf, 0x8b, 0xee, 0xdb, 0xbf, + 0x87, 0x3a, 0x36, 0xbe, 0xec, 0x19, 0x39, 0x3f, 0x73, 0xe8, 0xb8, 0x3f, 0xda, 0x91, 0xed, 0x3f, + 0xa9, 0xf3, 0x3a, 0xbf, 0xad, 0x10, 0x39, 0x3f, 0x62, 0x46, 0xab, 0xbf, 0xe5, 0xd6, 0xa7, 0x3f, + 0x97, 0xb8, 0x99, 0xbe, 0x22, 0x1c, 0xd7, 0xbe, 0x30, 0xfb, 0x14, 0x40, 0xce, 0x87, 0x8a, 0xbe, + 0xfa, 0xc6, 0x8a, 0xbf, 0xbf, 0x9d, 0xab, 0xbf, 0x25, 0xb7, 0x00, 0x40, 0xca, 0xdf, 0x5d, 0xbf, + 0xd0, 0xd5, 0xb7, 0xbf, 0x64, 0xb4, 0x5b, 0xbe, 0x8e, 0xd3, 0x3e, 0xc0, 0xa2, 0x75, 0xb9, 0x3e, + 0x8b, 0x23, 0x84, 0x3e, 0xb5, 0xb7, 0xcf, 0x3f, 0xbc, 0xcb, 0xdc, 0x3e, 0xbe, 0x8d, 0x35, 0x3f, + 0x93, 0x12, 0xb2, 0x3e, 0xd4, 0x32, 0x5c, 0xbb, 0x81, 0x4d, 0xce, 0x3f, 0x77, 0x79, 0x0e, 0xbf, + 0xed, 0x9e, 0xa4, 0xbf, 0x25, 0x26, 0x86, 0xbe, 0x76, 0xb3, 0x8b, 0x3f, 0x6f, 0xf4, 0x58, 0xbf, + 0xb8, 0x1b, 0xfa, 0x3e, 0xbe, 0x72, 0x58, 0xbf, 0x4f, 0xaf, 0x61, 0x3f, 0x01, 0x84, 0x8f, 0xbf, + 0xe7, 0xc1, 0x64, 0x3f, 0xe2, 0x63, 0xb1, 0xbf, 0xc9, 0xad, 0x5c, 0x3f, 0xca, 0x88, 0xd9, 0x3f, + 0xd8, 0x70, 0x04, 0x3f, 0xdd, 0x06, 0xd0, 0xbe, 0x4a, 0xac, 0x91, 0xbe, 0x6a, 0x8e, 0x00, 0x3f, + 0x5b, 0x9a, 0xd1, 0x3f, 0xba, 0x37, 0xda, 0xbb, 0x58, 0x93, 0x12, 0x3e, 0xee, 0xbe, 0x57, 0xbf, + 0x0c, 0x6b, 0x26, 0x40, 0x64, 0x64, 0x85, 0x3d, 0x0a, 0x86, 0xd0, 0xbf, 0xa0, 0xa5, 0xe2, 0xbf, + 0x6f, 0xe5, 0xb5, 0x3f, 0x58, 0xa1, 0x10, 0x3c, 0x87, 0x14, 0xb2, 0xbf, 0x81, 0x11, 0xa8, 0x3e, + 0x28, 0x3d, 0x32, 0x3f, 0x57, 0x26, 0x86, 0xbf, 0xd6, 0x6f, 0x16, 0x3f, 0x16, 0x2f, 0xa4, 0x3f, + 0xc9, 0x13, 0x9b, 0x3f, 0xb1, 0x4e, 0xa2, 0xbf, 0x47, 0x0e, 0x7c, 0x3e, 0x98, 0xdd, 0xe5, 0xbe, + 0xab, 0x11, 0xd1, 0x3f, 0xd9, 0x67, 0x00, 0xc0, 0xae, 0xbc, 0x9d, 0x3f, 0x93, 0x4e, 0x42, 0xc0, + 0xb7, 0x1b, 0xfa, 0x3f, 0xef, 0xd6, 0xe3, 0xbf, 0x3a, 0x3c, 0x57, 0x3e, 0x57, 0x1b, 0x97, 0xbf, + 0x88, 0x83, 0xb5, 0xbf, 0x03, 0x60, 0xe6, 0x3e, 0x4a, 0x5d, 0x99, 0xbe, 0xb9, 0x4d, 0xa4, 0xbc, + 0x82, 0x99, 0x1c, 0xbf, 0xb7, 0x08, 0x80, 0xbf, 0x88, 0xb5, 0x9d, 0xbf, 0x22, 0x75, 0xff, 0xbd, + 0xaa, 0x4d, 0x35, 0x3e, 0x3a, 0xba, 0xfe, 0xbe, 0xe7, 0x38, 0x8f, 0xbf, 0x3e, 0xc3, 0xb3, 0x3d, + 0x35, 0xff, 0xb6, 0xbf, 0xdd, 0xdd, 0x98, 0xbf, 0x4f, 0xb9, 0xd4, 0x3f, 0xd2, 0xeb, 0xe2, 0x3e, + 0xa0, 0xfc, 0xaf, 0xbf, 0x60, 0x49, 0x06, 0xc0, 0x2b, 0x97, 0xf9, 0xbe, 0x23, 0x94, 0xef, 0xbc, + 0xe8, 0xf9, 0x9f, 0xbe, 0x66, 0x00, 0x85, 0xbf, 0x7b, 0x74, 0x21, 0x3f, 0xba, 0xe4, 0x1c, 0xbe, + 0x9a, 0x89, 0x17, 0xbe, 0xaa, 0xeb, 0x42, 0xbe, 0x17, 0xd7, 0xb1, 0xbf, 0x24, 0x9a, 0xe4, 0xbe, + 0x44, 0x5f, 0xba, 0x3e, 0xeb, 0x0c, 0x27, 0xbf, 0x86, 0xa9, 0xae, 0xbe, 0x9d, 0x0f, 0xe2, 0x3e, + 0xe3, 0xce, 0xb1, 0x3e, 0xc2, 0x09, 0xbc, 0xbc, 0xe0, 0xa4, 0x0a, 0x3f, 0xac, 0x7c, 0xd9, 0x3e, + 0x57, 0x9d, 0x45, 0x3f, 0xb1, 0xc0, 0x43, 0xbf, 0x7a, 0x23, 0x22, 0x3f, 0xd1, 0x82, 0x2d, 0x3f, + 0x70, 0x7c, 0x3a, 0xbf, 0xc5, 0x47, 0xad, 0x3f, 0x13, 0x7c, 0x2d, 0xbf, 0x7a, 0x6a, 0x85, 0x3f, + 0xf0, 0x8d, 0xe6, 0x3f, 0xd4, 0x6b, 0x9c, 0x3f, 0x25, 0x8d, 0x71, 0x3f, 0x77, 0x3b, 0x91, 0x3f, + 0x31, 0x8e, 0xfb, 0x3e, 0xd8, 0xcd, 0xda, 0x3f, 0xdc, 0x12, 0x9c, 0x3f, 0x58, 0xb6, 0x9e, 0xbf, + 0xc8, 0xe0, 0x9b, 0x3f, 0xf0, 0xcb, 0xc5, 0x3d, 0x15, 0xbc, 0x9b, 0xbf, 0xd5, 0x43, 0xdf, 0x3f, + 0x61, 0xfb, 0xb9, 0x3e, 0xbf, 0x41, 0xbf, 0x3d, 0x3d, 0x36, 0x33, 0x3d, 0xbc, 0x8a, 0xa5, 0x3c, + 0xa6, 0x74, 0x42, 0xbf, 0x8b, 0xf6, 0x4b, 0xbe, 0xb7, 0x70, 0xea, 0xbf, 0x99, 0xd3, 0x40, 0x3f, + 0xa2, 0x8e, 0x7f, 0x3e, 0x69, 0xc6, 0x46, 0x3f, 0x68, 0x08, 0xae, 0xbe, 0x30, 0x2e, 0xb6, 0xbf, + 0xd5, 0x34, 0x9d, 0xbf, 0x4a, 0x66, 0x22, 0xbd, 0x70, 0x85, 0x40, 0x3f, 0x93, 0xb6, 0x71, 0xbe, + 0x96, 0xdc, 0xbc, 0x3f, 0x7b, 0x83, 0x8a, 0xbf, 0x6a, 0x89, 0x8f, 0x3f, 0x57, 0xe0, 0xe2, 0x3e, + 0x12, 0xf1, 0xfc, 0x3f, 0x20, 0x6c, 0x91, 0x3f, 0x7a, 0x19, 0x0d, 0x3f, 0xcc, 0x2c, 0x66, 0x3f, + 0x91, 0x6b, 0x86, 0xbe, 0x9b, 0xe0, 0x9b, 0x3f, 0x29, 0xd5, 0xfa, 0x3e, 0xe2, 0x25, 0xe9, 0x3c, + 0x8d, 0x3d, 0x12, 0xc0, 0x55, 0xe5, 0xb4, 0x3d, 0x17, 0x13, 0xa2, 0x3e, 0x75, 0xc0, 0x9c, 0xbf, + 0x5f, 0xa0, 0xf1, 0xbd, 0x4a, 0x61, 0x09, 0x3d, 0x28, 0xef, 0x1b, 0x3f, 0xd4, 0x3b, 0x28, 0xbf, + 0x61, 0xf3, 0x24, 0x40, 0x44, 0x7f, 0xd5, 0xbf, 0x36, 0xc8, 0x53, 0xbf, 0x9c, 0x28, 0x27, 0x3e, + 0x85, 0xf9, 0x70, 0xbf, 0xcc, 0xed, 0x89, 0x3e, 0x63, 0x81, 0x87, 0xbf, 0x1f, 0xe6, 0xea, 0x3d, + 0x97, 0xbd, 0xf8, 0x3e, 0x14, 0xbc, 0x37, 0xbf, 0xba, 0xaf, 0x31, 0xbf, 0x6d, 0x46, 0x15, 0x3e, + 0xd8, 0x04, 0x4e, 0xbf, 0x45, 0x76, 0x2d, 0xbf, 0x28, 0xe9, 0xfb, 0x3f, 0x9e, 0x67, 0xbd, 0xbf, + 0xb8, 0x4c, 0x59, 0x40, 0x91, 0xda, 0x4c, 0x3f, 0x58, 0x88, 0x6e, 0x3d, 0xfd, 0xaf, 0x29, 0xbd, + 0xff, 0xe6, 0x39, 0xbf, 0x71, 0x82, 0x84, 0x3e, 0x5c, 0xf3, 0x8c, 0xbf, 0x16, 0x1b, 0x3a, 0x3f, + 0x31, 0x06, 0x8e, 0x3f, 0x2a, 0x22, 0x99, 0xbd, 0xf9, 0x44, 0x32, 0xbf, 0xa4, 0x47, 0xae, 0x3e, + 0x9c, 0x76, 0xd8, 0xbe, 0xf9, 0xae, 0x40, 0xbf, 0xd6, 0xb4, 0x97, 0x3f, 0xb4, 0xa9, 0x52, 0xbe, + 0x25, 0x7f, 0x44, 0xbf, 0xff, 0xc4, 0xa4, 0xbf, 0x59, 0x65, 0x8f, 0x3f, 0x2a, 0xaa, 0x46, 0xbf, + 0xc0, 0x3f, 0xdb, 0xbe, 0x7e, 0xbc, 0xb3, 0xbe, 0x1b, 0x1a, 0x24, 0x3f, 0xf5, 0xa7, 0xf1, 0x3e, + 0x72, 0x28, 0x9e, 0x3e, 0x85, 0xb8, 0xc8, 0x3e, 0xf0, 0x0f, 0x08, 0xbf, 0xbd, 0xcf, 0x26, 0xbe, + 0x78, 0x4b, 0xe6, 0xbe, 0x29, 0x7d, 0xc5, 0x3e, 0x68, 0xf6, 0x98, 0x3e, 0xbd, 0xf9, 0xac, 0x3f, + 0x00, 0xbf, 0x3e, 0xbe, 0xf6, 0x7a, 0x0e, 0xc0, 0x9d, 0xb7, 0x3e, 0xbf, 0x05, 0x35, 0x6c, 0x3f, + 0xcd, 0x8f, 0x46, 0x3f, 0x23, 0xd6, 0xb0, 0x3f, 0x3c, 0xec, 0x14, 0xbf, 0x18, 0x98, 0x32, 0x3b, + 0x6c, 0x5a, 0x56, 0xbf, 0xae, 0xe0, 0xa8, 0xbf, 0xfe, 0xad, 0xaf, 0xbe, 0x7d, 0x3f, 0x99, 0x3e, + 0xf5, 0x21, 0x5b, 0xbc, 0xec, 0xf1, 0xbf, 0x3e, 0x0d, 0xae, 0x67, 0x3f, 0xb7, 0xb3, 0xa8, 0x3d, + 0xc9, 0x64, 0xdf, 0xbf, 0xeb, 0xaa, 0xcb, 0xbd, 0x8c, 0x1c, 0xc1, 0x3e, 0xbd, 0xb0, 0x72, 0xbf, + 0x88, 0x99, 0x03, 0xbf, 0x64, 0x43, 0x60, 0xbf, 0xef, 0xc2, 0x8c, 0xbd, 0xff, 0x6a, 0xa4, 0xbf, + 0x39, 0xff, 0x96, 0x3f, 0xb6, 0x67, 0x66, 0xbf, 0xba, 0x5f, 0xe6, 0xbf, 0x29, 0x19, 0x2a, 0xbe, + 0x5e, 0x60, 0xa1, 0x3e, 0xb8, 0xfd, 0x7c, 0x3f, 0x68, 0xd0, 0x56, 0x3f, 0xe6, 0x1e, 0xf9, 0xbf, + 0xe0, 0x4b, 0x86, 0x3f, 0xd9, 0xf7, 0x88, 0x3e, 0x88, 0x17, 0x87, 0x3f, 0x2a, 0x5d, 0x95, 0xbf, + 0xd0, 0xaf, 0x50, 0x3f, 0x78, 0xe4, 0xfb, 0xbe, 0x75, 0xa1, 0x88, 0xbf, 0x86, 0xdc, 0x93, 0xbe, + 0xbf, 0x66, 0xa3, 0xbf, 0x83, 0xf3, 0xbd, 0xbe, 0x39, 0x86, 0x99, 0xbe, 0xd9, 0xb5, 0x29, 0x40, + 0xf8, 0x67, 0xa3, 0xbf, 0xd6, 0x9d, 0xb7, 0xbf, 0x71, 0x74, 0x81, 0xbf, 0x12, 0x7a, 0x5b, 0xbf, + 0xa2, 0xc0, 0xe6, 0x3e, 0x37, 0xc6, 0x36, 0x3f, 0x24, 0xf5, 0xd1, 0xbf, 0xdf, 0xa6, 0x82, 0xbe, + 0x5c, 0x71, 0xea, 0xbd, 0x09, 0x5b, 0xab, 0xbd, 0xf5, 0x26, 0xce, 0x3f, 0xe7, 0xe2, 0x7a, 0x3f, + 0x3a, 0x39, 0xe0, 0x3e, 0x34, 0x5c, 0x26, 0xbf, 0xb1, 0x30, 0x1b, 0x3f, 0x31, 0xf9, 0xd4, 0x3e, + 0x48, 0xc1, 0x44, 0xbf, 0x1c, 0xf3, 0x92, 0xbf, 0x7e, 0x0d, 0x53, 0x3f, 0xc2, 0x80, 0x25, 0xbf, + 0x02, 0x3c, 0x17, 0x3e, 0x95, 0x61, 0x84, 0xbe, 0x89, 0x55, 0xe0, 0x3e, 0x8e, 0xa1, 0xd3, 0x3f, + 0x90, 0xa7, 0xee, 0xbe, 0x8f, 0xd2, 0x9b, 0xbe, 0x56, 0x39, 0x07, 0xbf, 0x19, 0x67, 0xda, 0x3f, + 0x16, 0x68, 0x9a, 0xbf, 0x71, 0xb6, 0x11, 0x3f, 0x64, 0x3f, 0xb5, 0x3f, 0x6c, 0x01, 0x1d, 0xbf, + 0x23, 0x94, 0x85, 0xbf, 0x31, 0x56, 0xb8, 0xbf, 0xd7, 0x92, 0x29, 0xbf, 0xb0, 0x14, 0x70, 0x3f, + 0x4f, 0x6b, 0xbd, 0xbe, 0x4e, 0xe9, 0x88, 0xbf, 0xd5, 0xa3, 0xf8, 0xbd, 0xa3, 0xa2, 0x84, 0x3f, + 0x48, 0x39, 0x04, 0x3e, 0xe2, 0x65, 0x8f, 0xbe, 0xa9, 0x43, 0x64, 0xbf, 0xdc, 0x72, 0x8d, 0xbf, + 0xb1, 0x21, 0x68, 0x3f, 0x25, 0x73, 0xd8, 0xbe, 0xdb, 0x94, 0x24, 0x3f, 0xe9, 0x18, 0x33, 0xbe, + 0x03, 0xb1, 0x31, 0xbf, 0x93, 0xf8, 0xa2, 0xbd, 0x31, 0x65, 0xd3, 0xbf, 0x8e, 0xcc, 0x44, 0xbd, + 0xc6, 0x5e, 0x38, 0xbf, 0x03, 0x74, 0x33, 0xc0, 0x08, 0x37, 0x57, 0x3e, 0x40, 0xc3, 0x19, 0xbe, + 0xe1, 0x18, 0x7a, 0xbe, 0x23, 0xe2, 0x18, 0xbf, 0xef, 0x0e, 0x2c, 0x3f, 0x1b, 0x2d, 0x77, 0xbf, + 0x3d, 0xa2, 0xe3, 0x3d, 0xb9, 0x23, 0x26, 0x3f, 0x66, 0x32, 0xee, 0x3f, 0xfb, 0xe5, 0xed, 0xbe, + 0x97, 0x06, 0xec, 0xbe, 0x79, 0x50, 0xf2, 0x3e, 0x1d, 0xbd, 0x93, 0xbf, 0xf3, 0x29, 0xdd, 0xbd, + 0xa0, 0x78, 0x90, 0x3f, 0x01, 0x2b, 0xa4, 0xbf, 0x01, 0x44, 0xd5, 0x3e, 0xbc, 0x26, 0x5e, 0x3f, + 0x37, 0xf2, 0x6b, 0x3e, 0x14, 0x5a, 0x98, 0x3e, 0x94, 0xe3, 0x0f, 0x40, 0x6c, 0x3a, 0xec, 0x3f, + 0x28, 0x0e, 0xcb, 0x3f, 0x1f, 0xf0, 0x85, 0x3f, 0xc8, 0x86, 0x87, 0xbf, 0xed, 0x86, 0xa0, 0xbe, + 0xb4, 0x41, 0xf3, 0x3d, 0x73, 0xb1, 0x9a, 0xbe, 0x30, 0xce, 0xb1, 0x3f, 0x44, 0x3e, 0xcd, 0xbf, + 0x81, 0x19, 0xc9, 0xbe, 0x4e, 0x14, 0x7e, 0xbf, 0x8e, 0x00, 0x7c, 0x3f, 0x54, 0xaf, 0x2b, 0x3f, + 0xc4, 0xa4, 0x11, 0x3f, 0xa8, 0x1b, 0xe4, 0x3e, 0xc8, 0x01, 0xf3, 0x3f, 0xfd, 0xdb, 0x48, 0x3f, + 0xb2, 0x38, 0x07, 0x3e, 0xbe, 0xfa, 0xf3, 0xbf, 0x5d, 0xdb, 0x19, 0xc0, 0xf2, 0xd9, 0x98, 0xbe, + 0x35, 0x97, 0xd9, 0x3e, 0x59, 0x28, 0x41, 0xbf, 0xc5, 0x56, 0x90, 0x3e, 0xdb, 0xc6, 0x54, 0xbf, + 0x6c, 0xa9, 0xbc, 0x3e, 0xd7, 0x20, 0x14, 0xbf, 0xea, 0xe3, 0x7f, 0xbd, 0xb6, 0xdf, 0x04, 0x3f, + 0x50, 0x66, 0x5c, 0x3e, 0x87, 0xa7, 0x83, 0xbe, 0x44, 0x0a, 0x28, 0x3e, 0x3c, 0x05, 0x30, 0x3e, + 0x44, 0x3d, 0x09, 0x3f, 0x4d, 0x64, 0x9a, 0xbf, 0x4f, 0xd4, 0x82, 0xbd, 0x68, 0x62, 0x69, 0x3e, + 0x54, 0x0f, 0x9a, 0x3f, 0x3b, 0x24, 0x3c, 0xbf, 0x80, 0x89, 0x8a, 0xbe, 0xab, 0x1a, 0x82, 0x3f, + 0x9a, 0x80, 0xe3, 0x3e, 0x93, 0xe0, 0x3b, 0x3f, 0xe4, 0x87, 0xc0, 0x3e, 0x1f, 0xa9, 0x3e, 0x3f, + 0x18, 0x8b, 0x56, 0xbe, 0xc5, 0xff, 0xcb, 0xbe, 0xb5, 0xc7, 0x7e, 0x3d, 0x67, 0xfe, 0x51, 0x3e, + 0x74, 0x59, 0x80, 0x3f, 0xbb, 0x71, 0x75, 0x3f, 0x4e, 0x8b, 0x8a, 0x3f, 0xb9, 0x19, 0x82, 0x3f, + 0x51, 0x16, 0xdd, 0xbf, 0x8d, 0x7b, 0x90, 0x3d, 0xc4, 0xcd, 0x56, 0xbf, 0x4d, 0xd9, 0xff, 0xbe, + 0xa9, 0x8f, 0x1b, 0xbf, 0x76, 0x50, 0xbe, 0x3e, 0x7a, 0x25, 0xf1, 0xbf, 0x6a, 0x42, 0x9f, 0xbe, + 0xe4, 0x58, 0x66, 0x3f, 0xd5, 0xad, 0x49, 0x3f, 0x29, 0xeb, 0x2f, 0x3f, 0x1b, 0x8e, 0xeb, 0xbf, + 0x4f, 0x75, 0x6e, 0x3f, 0x03, 0x16, 0x11, 0xbe, 0xa2, 0x35, 0xa2, 0xbc, 0xba, 0x67, 0x64, 0xbf, + 0x66, 0x3a, 0x1c, 0xbf, 0xfc, 0xb5, 0xc1, 0x3e, 0xca, 0x46, 0xf9, 0x3f, 0xd0, 0xa7, 0x03, 0x3f, + 0x45, 0xde, 0x87, 0xbf, 0xde, 0x93, 0x04, 0x3f, 0x98, 0x2d, 0x19, 0x40, 0x70, 0x8e, 0x99, 0x3f, + 0x98, 0xb8, 0xf9, 0xbf, 0xf1, 0x7e, 0xb1, 0x3d, 0x7d, 0x7e, 0x3b, 0xbf, 0x50, 0xc2, 0xc6, 0xbe, + 0xe8, 0xb4, 0x8d, 0xbf, 0xdb, 0x6a, 0x1c, 0xc0, 0x85, 0x23, 0xd4, 0xbe, 0xea, 0x03, 0xf2, 0xbe, + 0xc4, 0x51, 0xf9, 0x3e, 0x5d, 0xd5, 0x9c, 0xbc, 0x30, 0x93, 0x9f, 0x3e, 0x0b, 0x8c, 0x24, 0xbf, + 0xf9, 0x6f, 0x0c, 0xc0, 0x19, 0x92, 0x27, 0x40, 0x7e, 0xe5, 0x8d, 0xbf, 0x1b, 0xed, 0x60, 0xbd, + 0x36, 0x80, 0xba, 0xbf, 0xda, 0xb1, 0x60, 0xbf, 0x0b, 0xe7, 0x47, 0xbf, 0xd7, 0x50, 0x14, 0x3f, + 0xab, 0x11, 0x85, 0xbf, 0xd8, 0x58, 0x15, 0x3e, 0x46, 0x8e, 0x01, 0xbf, 0x25, 0x96, 0x5c, 0xbf, + 0x23, 0xe2, 0xcc, 0xbe, 0xa5, 0x97, 0x3f, 0xbf, 0xa0, 0xec, 0x9a, 0xbf, 0x60, 0x54, 0x9b, 0x3f, + 0x6d, 0x92, 0x41, 0x3f, 0x74, 0xeb, 0x03, 0xbd, 0x49, 0xe2, 0x9b, 0x3f, 0x22, 0x80, 0x1b, 0x3f, + 0x9d, 0xa2, 0xfe, 0xbe, 0xb6, 0x93, 0xec, 0x3f, 0x6a, 0x38, 0x09, 0xc0, 0x27, 0x72, 0x89, 0xbe, + 0xe6, 0x0e, 0x33, 0xbe, 0xbd, 0x5c, 0x92, 0x3f, 0x13, 0x3b, 0xa1, 0xbf, 0xab, 0x05, 0x13, 0x3f, + 0x30, 0x84, 0x8c, 0x3c, 0xd7, 0xca, 0x02, 0x3f, 0xb0, 0x17, 0x6b, 0xbf, 0x5d, 0x34, 0x9a, 0xbf, + 0xa3, 0x50, 0x1b, 0x40, 0x9f, 0x12, 0xbd, 0x3e, 0xfa, 0x5d, 0x82, 0x3f, 0x86, 0xf6, 0x7e, 0x3f, + 0x1e, 0x8e, 0xf2, 0xbf, 0xfc, 0xbc, 0x15, 0xbf, 0xe4, 0xf7, 0xe8, 0xbe, 0xde, 0x5b, 0xb6, 0xbe, + 0x1f, 0x4d, 0x8d, 0xbe, 0x2b, 0x51, 0x30, 0xbf, 0xc1, 0xd0, 0xd8, 0x3f, 0x51, 0x5e, 0x4f, 0xbf, + 0x99, 0xca, 0xf4, 0x3e, 0xe0, 0xe8, 0xb4, 0x3f, 0x5b, 0xf0, 0x31, 0xbf, 0x77, 0xed, 0x66, 0xbf, + 0x55, 0x9b, 0xc7, 0xbf, 0x05, 0xbc, 0x35, 0xbf, 0xed, 0x67, 0x6c, 0x3f, 0x9f, 0x4d, 0x7a, 0x3f, + 0x2e, 0x4e, 0x18, 0x3f, 0x19, 0x3f, 0x26, 0x3c, 0x74, 0x0a, 0x4d, 0xbf, 0x57, 0x10, 0x71, 0xbf, + 0xf0, 0x01, 0x7b, 0x3e, 0x38, 0x3a, 0xa6, 0xbf, 0x4e, 0x95, 0x9c, 0xbe, 0x6b, 0xcd, 0xad, 0x3e, + 0x54, 0xe2, 0x91, 0x3e, 0x3b, 0xef, 0x18, 0x3e, 0x63, 0x20, 0x5d, 0xbf, 0x68, 0xc6, 0xe4, 0xbe, + 0x4c, 0xee, 0x1c, 0x3f, 0x1e, 0xce, 0x5c, 0x3d, 0x0b, 0xd5, 0xc9, 0x3f, 0x49, 0x9e, 0x01, 0x3f, + 0x22, 0x5c, 0x91, 0xbe, 0x34, 0x9a, 0x86, 0x3f, 0x0a, 0xf1, 0x85, 0x3e, 0x75, 0xd2, 0x6b, 0x3f, + 0x13, 0x96, 0xcf, 0x3f, 0x43, 0xe1, 0x28, 0x3f, 0xa9, 0xb1, 0x78, 0xbf, 0xaa, 0x0d, 0x3a, 0xbf, + 0xfe, 0x86, 0x8b, 0x3f, 0x9e, 0x0a, 0x38, 0x3e, 0x69, 0x55, 0x9a, 0xbf, 0x6e, 0x3d, 0x57, 0xbf, + 0xb0, 0x75, 0x01, 0x40, 0x55, 0x6b, 0xfc, 0x3f, 0xde, 0xe8, 0xa1, 0xbf, 0x68, 0x05, 0x79, 0xbf, + 0xac, 0xe1, 0xc1, 0xbf, 0x99, 0x8c, 0x6f, 0x3f, 0x29, 0x8a, 0x18, 0xbe, 0xba, 0xa2, 0x88, 0x3e, + 0x9d, 0xc3, 0x3e, 0x3f, 0xea, 0x41, 0x13, 0xbf, 0x2f, 0xa6, 0xb9, 0xbf, 0xdf, 0x95, 0xda, 0x3e, + 0x2e, 0x29, 0x5f, 0xbf, 0x3d, 0x86, 0x9c, 0x3f, 0x4b, 0x6f, 0x4b, 0xbf, 0x15, 0xd1, 0x16, 0xbc, + 0x76, 0x39, 0xb7, 0x3f, 0xf1, 0x0e, 0x96, 0xbd, 0xa7, 0x55, 0xf1, 0x3a, 0x2c, 0x0e, 0xa3, 0x3e, + 0x1e, 0x94, 0x2b, 0x3f, 0x98, 0xf8, 0x4a, 0xbe, 0x95, 0x99, 0xc3, 0x3f, 0x99, 0x9b, 0xa8, 0xbf, + 0x08, 0xd0, 0x1b, 0xbf, 0x64, 0xeb, 0xfb, 0x3e, 0xb9, 0x2e, 0xc4, 0x3e, 0x9d, 0x41, 0xb1, 0xbf, + 0x51, 0xbd, 0xc0, 0x3f, 0x44, 0x15, 0x0f, 0xbf, 0x1a, 0xf1, 0x0f, 0xbf, 0xef, 0xa0, 0x1c, 0x40, + 0xdb, 0xdc, 0x50, 0xbf, 0xfe, 0x0a, 0x37, 0xbf, 0x96, 0xef, 0xe4, 0x3e, 0xdb, 0x5b, 0x97, 0x3e, + 0x8d, 0xcf, 0x96, 0xbf, 0x4f, 0xe8, 0xe3, 0x3f, 0x32, 0xd8, 0xe6, 0xbf, 0xe3, 0x1f, 0x9e, 0x3f, + 0x08, 0xeb, 0x6d, 0x3e, 0x2e, 0xf7, 0x9d, 0xbf, 0x03, 0x8e, 0x81, 0x3f, 0xa2, 0xdc, 0x80, 0xbf, + 0x7e, 0x21, 0x08, 0xbf, 0x4c, 0xa2, 0x5c, 0xbf, 0xec, 0xdd, 0x25, 0xbd, 0x22, 0xcd, 0x9a, 0xbf, + 0x4f, 0x87, 0x36, 0x3f, 0x43, 0xb9, 0x24, 0x3f, 0x76, 0x26, 0x47, 0xbf, 0xf0, 0xf3, 0xae, 0xbf, + 0x46, 0x25, 0xd3, 0xbe, 0x9a, 0x22, 0x0a, 0x3f, 0x01, 0x51, 0x94, 0xbf, 0x82, 0x37, 0xd7, 0xbe, + 0x18, 0xd0, 0xb4, 0x3f, 0x76, 0xf8, 0x0a, 0x3f, 0x6e, 0xd7, 0x98, 0xbf, 0xd5, 0x11, 0x86, 0xbf, + 0x0f, 0x31, 0xf3, 0xbd, 0xa7, 0x95, 0xe1, 0xbf, 0x9e, 0xab, 0x78, 0xbf, 0x89, 0xa5, 0xe2, 0xbe, + 0x9f, 0x09, 0xf5, 0xbe, 0xa1, 0x39, 0x52, 0x3f, 0x2f, 0x8c, 0x6b, 0x3f, 0xfd, 0x89, 0xaa, 0x3e, + 0xbd, 0x17, 0xb5, 0xbf, 0x5d, 0xff, 0x8a, 0xbd, 0xe9, 0x3f, 0x91, 0xbf, 0x0e, 0xe0, 0x11, 0x3d, + 0xca, 0x65, 0x0f, 0xc0, 0x30, 0xe9, 0x0f, 0xbf, 0xd7, 0x35, 0x85, 0x3f, 0xbe, 0x41, 0xba, 0xbf, + 0xdf, 0x3e, 0xf8, 0xbe, 0x6d, 0x2c, 0x35, 0x3f, 0x43, 0xa6, 0x11, 0x3f, 0x7d, 0x9d, 0x89, 0xbe, + 0x0f, 0xe2, 0xd8, 0x3f, 0x75, 0x3c, 0x01, 0x3f, 0xd4, 0x81, 0x90, 0x3f, 0x2e, 0x61, 0x87, 0x3f, + 0xba, 0x5c, 0x94, 0xbf, 0x1c, 0x46, 0x5f, 0x3f, 0xe2, 0x65, 0x07, 0xbf, 0xad, 0xbb, 0xa6, 0x3f, + 0x6e, 0xb7, 0x8d, 0xbf, 0x28, 0xef, 0x02, 0xbf, 0x02, 0x3f, 0x28, 0xbf, 0x15, 0xd6, 0x23, 0xbe, + 0x51, 0x9b, 0xd7, 0x3e, 0x56, 0x03, 0x95, 0x3f, 0xd7, 0x7f, 0x78, 0xbf, 0x42, 0x8c, 0x33, 0xbf, + 0x30, 0xc3, 0x31, 0x3f, 0x4c, 0xea, 0x7f, 0x3e, 0xd8, 0x64, 0xfa, 0xbe, 0x96, 0x70, 0xe4, 0xbe, + 0x95, 0xb8, 0x07, 0x3e, 0x48, 0xbd, 0xaa, 0xbc, 0x8f, 0x01, 0x4a, 0x3d, 0xa6, 0x79, 0x92, 0xbe, + 0xef, 0x6d, 0x55, 0x3f, 0x76, 0xdc, 0x5e, 0xbf, 0x93, 0x99, 0x9c, 0x3f, 0x2e, 0x6e, 0xa9, 0xbe, + 0x02, 0xae, 0x93, 0x3e, 0x33, 0xc9, 0xba, 0x3f, 0x63, 0x55, 0x76, 0xbf, 0x14, 0x02, 0xaa, 0x3e, + 0xd8, 0x72, 0x2e, 0x3c, 0xa1, 0xd3, 0x4f, 0x3e, 0x5c, 0xf8, 0x4c, 0xbf, 0xb2, 0xdf, 0x05, 0xbf, + 0xbf, 0x0e, 0x43, 0x3f, 0xdc, 0xc6, 0x65, 0x3f, 0x9b, 0x80, 0x5f, 0x3e, 0x3e, 0xca, 0x03, 0xc0, + 0xb1, 0x1d, 0xc9, 0xbf, 0x02, 0x59, 0x4e, 0x3e, 0x87, 0x94, 0x6c, 0x3d, 0xd1, 0x8e, 0x42, 0xbf, + 0x4e, 0xaa, 0xb0, 0xbf, 0x58, 0x1b, 0x40, 0x3d, 0xf9, 0x61, 0x95, 0x3f, 0x52, 0xd3, 0xc1, 0xbf, + 0xd4, 0x8e, 0x22, 0x3f, 0x10, 0x58, 0x2a, 0xbe, 0x36, 0xf0, 0xab, 0xbe, 0x0f, 0x12, 0x6a, 0xbf, + 0x12, 0xaa, 0x1d, 0x3f, 0xdf, 0x4c, 0x83, 0xbf, 0x43, 0xe7, 0x3b, 0x3e, 0x32, 0xb9, 0xc0, 0xbf, + 0x66, 0xac, 0x3d, 0x3f, 0x81, 0x4d, 0x56, 0x3f, 0x18, 0x26, 0x2a, 0xc0, 0x90, 0xe9, 0x53, 0x3e, + 0xcb, 0x52, 0x96, 0x3e, 0xb1, 0x32, 0x14, 0x3e, 0xa8, 0xcd, 0x88, 0xbf, 0x96, 0x64, 0x96, 0x3e, + 0x94, 0x44, 0xca, 0xbe, 0x85, 0xaf, 0x6e, 0xbe, 0x69, 0x20, 0x4c, 0x3f, 0xd6, 0x09, 0x0e, 0x3f, + 0xd8, 0x46, 0x44, 0x3e, 0x40, 0x42, 0x91, 0x3c, 0xa3, 0x78, 0x73, 0xbf, 0xc5, 0x38, 0x97, 0x3f, + 0x4d, 0xf4, 0x5e, 0xbf, 0x7a, 0x7f, 0x32, 0x3f, 0x5d, 0x33, 0x44, 0xbe, 0x92, 0x56, 0xa6, 0xbf, + 0xfa, 0xd7, 0x14, 0x3e, 0x18, 0xee, 0xb2, 0xbe, 0xc6, 0xb3, 0x2c, 0x3f, 0x15, 0x0d, 0xb0, 0xbf, + 0x48, 0x0a, 0x26, 0x3f, 0x72, 0x53, 0xcb, 0x3d, 0x24, 0x8e, 0x06, 0x40, 0xc8, 0xa7, 0xb2, 0xbf, + 0x6e, 0xf7, 0x30, 0x3f, 0x1f, 0x94, 0x1d, 0x40, 0x0b, 0xb4, 0x0d, 0x3e, 0xff, 0x64, 0x8a, 0xbf, + 0x4b, 0x55, 0x7b, 0xbe, 0x23, 0x00, 0xef, 0x3e, 0x33, 0xc1, 0x34, 0xbf, 0x97, 0x40, 0x81, 0xbf, + 0xc7, 0x1c, 0x9b, 0xbf, 0x66, 0xa5, 0x7c, 0xbe, 0x5b, 0xff, 0x99, 0x3e, 0xc3, 0x28, 0x6e, 0x3f, + 0x6e, 0x40, 0x5e, 0x3f, 0x73, 0x59, 0xa7, 0xbf, 0x22, 0xdc, 0x95, 0x3f, 0x63, 0xff, 0xa3, 0xbf, + 0x02, 0x7a, 0x4d, 0x3f, 0x50, 0x1e, 0xd8, 0x3d, 0x50, 0xae, 0x37, 0xbd, 0xc2, 0xd7, 0x9b, 0xbf, + 0x10, 0x98, 0x01, 0x3f, 0xda, 0xa9, 0x1f, 0x3f, 0x16, 0x29, 0x7d, 0x3e, 0x31, 0x31, 0xa4, 0xbf, + 0x0e, 0xef, 0x25, 0x3f, 0x62, 0xa2, 0x9d, 0xbf, 0xdb, 0xfe, 0x07, 0xbf, 0xfb, 0x1e, 0x79, 0xbf, + 0x82, 0xf9, 0x63, 0x3e, 0x1f, 0x20, 0x9d, 0x3c, 0xd9, 0xaf, 0x02, 0xc0, 0xb6, 0x0a, 0xb7, 0xbf, + 0xc9, 0xb4, 0xc6, 0xbe, 0x5c, 0xf3, 0x5f, 0xbf, 0xcb, 0x62, 0x9a, 0x3f, 0xf4, 0xd0, 0x7f, 0x3f, + 0x74, 0x32, 0x76, 0x3f, 0x44, 0xf4, 0x03, 0xbf, 0xc4, 0x92, 0x1c, 0x3f, 0x38, 0xec, 0x28, 0x3f, + 0x38, 0x63, 0xd6, 0xbe, 0xe5, 0x29, 0x91, 0x3f, 0x03, 0x06, 0x8e, 0x3e, 0xb6, 0x98, 0xd4, 0x3f, + 0xc4, 0x99, 0x07, 0x3f, 0x6a, 0x20, 0xd5, 0x3f, 0x46, 0xed, 0x70, 0xbf, 0x83, 0xfc, 0xd2, 0xbf, + 0x8e, 0x91, 0x87, 0xbf, 0xce, 0xe2, 0x04, 0x3f, 0x1c, 0xc2, 0x14, 0xc0, 0x2c, 0x72, 0x92, 0x3f, + 0x98, 0x41, 0x55, 0x3e, 0x91, 0x83, 0x59, 0x3d, 0xb5, 0xd4, 0x0b, 0xbf, 0x77, 0x1c, 0xd8, 0x3f, + 0xca, 0x18, 0x96, 0x3f, 0x0f, 0x95, 0x7f, 0x3e, 0x1b, 0x8e, 0x22, 0xbf, 0xe4, 0x4e, 0xc2, 0x3f, + 0x1a, 0xe6, 0x77, 0x3f, 0x10, 0x28, 0x39, 0x3f, 0xb3, 0xf7, 0x01, 0x40, 0x77, 0x39, 0xb8, 0x3f, + 0x25, 0xfb, 0xfb, 0x3e, 0x66, 0x68, 0x29, 0x3e, 0x2d, 0x4d, 0xf6, 0xbf, 0x03, 0x46, 0xbb, 0x3e, + 0xab, 0xbd, 0x96, 0xbf, 0xd5, 0xcb, 0x69, 0xbf, 0x93, 0x9d, 0xd0, 0xbe, 0x43, 0x35, 0x26, 0xbe, + 0x05, 0x87, 0x47, 0xbf, 0xe5, 0xa5, 0xad, 0x3e, 0x15, 0xe1, 0x6b, 0x3f, 0x77, 0x79, 0xfa, 0x3d, + 0x6f, 0x68, 0x87, 0xbf, 0xec, 0x4d, 0x40, 0x3f, 0xb9, 0x26, 0x88, 0xbf, 0x22, 0x3b, 0x89, 0xbf, + 0x16, 0x31, 0x21, 0x3f, 0x89, 0x16, 0xba, 0x3d, 0xeb, 0x18, 0xec, 0xbe, 0x46, 0x5e, 0x14, 0x3e, + 0x53, 0xf8, 0x04, 0xbf, 0xec, 0xd2, 0x9e, 0x3e, 0x3c, 0xe6, 0xa1, 0x3f, 0xad, 0x41, 0x8f, 0x3f, + 0xb9, 0x4d, 0xba, 0x3f, 0x11, 0xba, 0x8b, 0x3f, 0xb1, 0x1d, 0xe0, 0xbe, 0xe7, 0xcd, 0x58, 0xbd, + 0xc4, 0x30, 0x09, 0x3f, 0x3b, 0x69, 0x9e, 0x3f, 0xcc, 0xcb, 0x1d, 0x3f, 0x16, 0x6e, 0x48, 0xbd, + 0x62, 0x5e, 0x36, 0xbf, 0xf9, 0x96, 0x0f, 0x40, 0xd0, 0x45, 0xad, 0xbe, 0xd3, 0x8a, 0x9e, 0x3f, + 0xc4, 0xf6, 0x33, 0xbf, 0xc1, 0x8b, 0x23, 0x3e, 0x4f, 0x3a, 0xfd, 0xbe, 0x64, 0x7a, 0x1b, 0x3f, + 0xdb, 0xfc, 0x9b, 0x3f, 0x02, 0x53, 0x99, 0xbf, 0x2c, 0x5a, 0x42, 0x3f, 0x33, 0x3c, 0xe1, 0x3f, + 0x14, 0xfd, 0xc4, 0xbf, 0xd3, 0x51, 0xb6, 0xbf, 0xb9, 0x42, 0x8d, 0x3e, 0xfb, 0xb2, 0x8e, 0xbe, + 0xde, 0x7b, 0x16, 0x3f, 0x1c, 0x4f, 0x81, 0xbf, 0xd7, 0xd1, 0x02, 0x3e, 0x97, 0xb5, 0xea, 0xbf, + 0xec, 0x38, 0x9b, 0xbf, 0xa7, 0xa5, 0x4b, 0xbf, 0xc1, 0x99, 0x37, 0x3f, 0xe1, 0x65, 0x07, 0x3e, + 0x79, 0x06, 0x25, 0x3e, 0xbc, 0xdd, 0xcc, 0x3e, 0x80, 0x5c, 0x57, 0xbf, 0xca, 0xe7, 0x99, 0x3f, + 0x4f, 0xe8, 0xab, 0xbe, 0x91, 0xd1, 0x01, 0xc0, 0xd6, 0xa2, 0xb7, 0x3e, 0x47, 0x15, 0x4e, 0x3f, + 0x65, 0x95, 0x38, 0x3f, 0xb6, 0xad, 0x8a, 0xbe, 0xb2, 0xad, 0x1c, 0xbd, 0x40, 0x00, 0x03, 0xbe, + 0x29, 0xce, 0x54, 0xbf, 0xe4, 0x75, 0xc6, 0xbf, 0xc0, 0x83, 0x9b, 0xbf, 0x12, 0xae, 0xa0, 0x3c, + 0xe7, 0x4e, 0xd3, 0x3e, 0xec, 0x81, 0xc7, 0xbf, 0x4e, 0x80, 0x8e, 0xbf, 0x59, 0x23, 0xa2, 0xbf, + 0x28, 0x02, 0xc6, 0x3f, 0x3a, 0x0f, 0xce, 0x3e, 0x02, 0x69, 0x63, 0x3f, 0x75, 0x8a, 0x36, 0x3d, + 0x24, 0xf4, 0x1c, 0x3f, 0xd8, 0xf1, 0xc6, 0x3f, 0x55, 0x23, 0x5f, 0x3e, 0x2b, 0xdf, 0x97, 0x3e, + 0xd3, 0x22, 0x18, 0xbd, 0x70, 0xf0, 0x8e, 0x3e, 0xe3, 0xdf, 0x7c, 0x3f, 0xac, 0x4a, 0x87, 0x3f, + 0x0e, 0x3f, 0x9e, 0x3e, 0xdd, 0x55, 0xfa, 0xbf, 0x63, 0x6f, 0x8f, 0xbf, 0xd0, 0x47, 0xe1, 0x3f, + 0x75, 0x93, 0x68, 0xbf, 0xd3, 0x42, 0x36, 0x3e, 0x48, 0xc7, 0x9d, 0x3d, 0x85, 0xfd, 0x63, 0xbf, + 0x50, 0x8e, 0xb2, 0xbf, 0x6a, 0xbf, 0xc6, 0x3e, 0x98, 0x4c, 0x7e, 0x3f, 0x27, 0x46, 0x5d, 0xbe, + 0xb3, 0x2b, 0xd3, 0x3f, 0xcc, 0x3d, 0xbf, 0x3f, 0x30, 0x9f, 0x5c, 0x3f, 0xf0, 0xc3, 0x67, 0xbe, + 0x70, 0xeb, 0xa7, 0xbf, 0x92, 0xd2, 0x74, 0xbe, 0xe9, 0x72, 0x9d, 0x3f, 0xf2, 0x42, 0x9e, 0xbf, + 0x90, 0x02, 0x2d, 0x3f, 0x91, 0xd4, 0x1e, 0xbf, 0x12, 0x95, 0x7f, 0xbd, 0xdf, 0x11, 0x7c, 0xbf, + 0x81, 0x01, 0xc7, 0x3e, 0xaf, 0x26, 0xe5, 0x3e, 0xfc, 0x9d, 0xcc, 0xbf, 0xa5, 0x0d, 0xe7, 0x3e, + 0xea, 0x46, 0xc3, 0x3e, 0x04, 0xca, 0x79, 0x3e, 0xb5, 0x30, 0x13, 0x3d, 0x3f, 0x6f, 0x5d, 0x3e, + 0x48, 0x73, 0x75, 0xbe, 0x1f, 0xb3, 0x35, 0x3e, 0xfd, 0xda, 0xc6, 0xbf, 0x4a, 0x6d, 0xc6, 0x3e, + 0xd5, 0x66, 0x99, 0x3e, 0x33, 0x05, 0xb3, 0x3f, 0x1b, 0x87, 0xd8, 0xbf, 0xc2, 0x9e, 0xfc, 0x3e, + 0xac, 0x0b, 0xff, 0xbe, 0x5d, 0x2a, 0x0b, 0xc0, 0xb3, 0xdb, 0x7b, 0xbf, 0x72, 0x63, 0x34, 0xbf, + 0x71, 0xca, 0x4e, 0x3f, 0x05, 0x80, 0x4c, 0x3e, 0x41, 0x39, 0x06, 0xbf, 0x41, 0x5e, 0x18, 0x3f, + 0x4e, 0x4a, 0xf2, 0xbf, 0xa7, 0xbf, 0xce, 0x3e, 0x33, 0x12, 0x49, 0x3f, 0x1e, 0xa3, 0x4f, 0xbe, + 0x5e, 0xd5, 0x3a, 0xbe, 0x6f, 0x82, 0x10, 0xbf, 0x87, 0xf2, 0x01, 0x40, 0x42, 0x1f, 0x93, 0xbf, + 0x6a, 0xc2, 0x02, 0x3f, 0xd8, 0x50, 0xd6, 0x3f, 0xf2, 0x80, 0x76, 0xbf, 0x8d, 0xc7, 0xb2, 0xbf, + 0xb3, 0xfc, 0x5b, 0x3f, 0x6d, 0x29, 0xb6, 0x3e, 0x48, 0x03, 0x2a, 0x3f, 0xc1, 0xa5, 0xb3, 0x3e, + 0x16, 0x3d, 0xa5, 0xbe, 0x47, 0xcc, 0x3e, 0xbf, 0x87, 0xca, 0x37, 0xbf, 0x3b, 0x6a, 0x61, 0x3e, + 0x69, 0x87, 0xad, 0x3f, 0x6a, 0x4e, 0xc1, 0xbf, 0xee, 0xa9, 0x5a, 0xbf, 0x65, 0x75, 0xa6, 0x3f, + 0x8d, 0x12, 0x24, 0xbd, 0x80, 0x25, 0x37, 0xc0, 0xbd, 0x92, 0xc4, 0x3f, 0x61, 0x0c, 0xf3, 0xbe, + 0xda, 0x3e, 0x0d, 0xbf, 0xc1, 0xc4, 0xb2, 0x3e, 0x41, 0xab, 0x02, 0x3f, 0x34, 0x7e, 0x54, 0xbf, + 0x96, 0xa0, 0x96, 0x3f, 0xb7, 0x1c, 0xb3, 0xbe, 0xdf, 0x95, 0xf7, 0x3e, 0x4a, 0x41, 0x7c, 0x3e, + 0xfb, 0xc3, 0x91, 0xbf, 0x55, 0x29, 0x9b, 0x3e, 0x91, 0x67, 0xb7, 0x3e, 0xdf, 0xb1, 0x62, 0xbf, + 0xe4, 0x83, 0x4c, 0xbf, 0x5e, 0x74, 0x37, 0x3f, 0x03, 0x60, 0x11, 0x3e, 0x70, 0x4e, 0xe0, 0x3d, + 0x9c, 0x75, 0x04, 0x40, 0x3a, 0x14, 0xc4, 0x3e, 0xe1, 0x10, 0x46, 0xbe, 0xfc, 0x11, 0xb4, 0x3e, + 0x8b, 0x9d, 0xbf, 0xbe, 0xaf, 0x19, 0xca, 0xbe, 0xc4, 0x91, 0x2a, 0x3f, 0x3d, 0xc5, 0x54, 0xbf, + 0xd3, 0x11, 0x02, 0x3e, 0x0c, 0xee, 0xbf, 0x3f, 0x69, 0xa4, 0x27, 0x40, 0x17, 0x7e, 0xfc, 0x3d, + 0xa8, 0xf7, 0x8b, 0xbf, 0x39, 0xa2, 0xbb, 0xbe, 0xb8, 0x70, 0x70, 0xbe, 0x9d, 0x3f, 0xdb, 0xbf, + 0x4f, 0x7b, 0x59, 0xbe, 0xa2, 0xcb, 0x75, 0xbd, 0x4b, 0xc8, 0x14, 0x3f, 0x93, 0x57, 0xd4, 0xbf, + 0xbd, 0x08, 0xa3, 0xbf, 0x2b, 0xe2, 0x5b, 0x3e, 0x0e, 0x60, 0x73, 0xbf, 0xee, 0xd4, 0xb8, 0x3d, + 0xa5, 0x6b, 0x05, 0x3f, 0x0e, 0x5c, 0xed, 0xbf, 0x6d, 0xc7, 0x1e, 0xbe, 0x86, 0x53, 0xb4, 0x3f, + 0x5b, 0xcd, 0xc3, 0xbd, 0xdc, 0x1e, 0x44, 0xbf, 0x74, 0xea, 0xfb, 0xbe, 0xb1, 0xef, 0xc8, 0xbf, + 0xeb, 0xa2, 0x93, 0xbf, 0x4f, 0x02, 0x91, 0xbf, 0xdd, 0x61, 0xb3, 0xbe, 0xc0, 0x4b, 0x4d, 0xbf, + 0x07, 0x74, 0x0c, 0xbe, 0x1b, 0x36, 0x4a, 0xbf, 0xc5, 0x5e, 0x62, 0x3f, 0x27, 0x31, 0x15, 0xc0, + 0x30, 0xb9, 0x99, 0xbf, 0x45, 0x24, 0x86, 0xbf, 0x26, 0x35, 0xaa, 0xbf, 0xbe, 0x58, 0x8c, 0xbe, + 0xfa, 0x29, 0x0f, 0xbf, 0x36, 0xb7, 0xef, 0xbf, 0xc1, 0x41, 0x35, 0xbf, 0x70, 0x1b, 0x75, 0x3d, + 0x5a, 0x2f, 0x93, 0xbf, 0xae, 0x3a, 0x20, 0x3e, 0x9d, 0x62, 0xeb, 0x3e, 0x93, 0xd3, 0x7c, 0xbe, + 0x7f, 0x83, 0xad, 0x3f, 0xfd, 0xe1, 0x10, 0xc0, 0xcb, 0x4b, 0xc7, 0x3f, 0xa2, 0x92, 0x27, 0x3f, + 0x98, 0x6c, 0xd0, 0xbf, 0x10, 0xd2, 0xf3, 0xbe, 0xc5, 0x2f, 0xa2, 0x3f, 0x76, 0x07, 0xd8, 0x3f, + 0xed, 0xf2, 0xff, 0x3e, 0xfd, 0x93, 0xa9, 0xbf, 0x73, 0xd1, 0x92, 0xbe, 0x22, 0x57, 0x5b, 0xbf, + 0x3e, 0xc9, 0xc8, 0xbf, 0x16, 0x7d, 0x21, 0x3e, 0x78, 0x6e, 0x7d, 0xbf, 0x3c, 0x7a, 0xf2, 0x3e, + 0x92, 0x17, 0xae, 0xbf, 0x8d, 0xbf, 0x01, 0x3e, 0x9d, 0xbf, 0x40, 0x3f, 0x18, 0x72, 0x59, 0x3f, + 0xb1, 0x87, 0xdb, 0x3f, 0xba, 0xfe, 0x83, 0x3f, 0x43, 0x33, 0x34, 0xc0, 0x8e, 0x34, 0x25, 0xbf, + 0x8d, 0x61, 0xba, 0xbe, 0x85, 0xc4, 0x3a, 0xbf, 0x03, 0x42, 0xde, 0x3e, 0xb6, 0x7d, 0xed, 0x3e, + 0x8d, 0xf1, 0xc3, 0x3f, 0x0f, 0xb7, 0x77, 0x3f, 0x30, 0xa5, 0x8e, 0xbe, 0xbd, 0x8b, 0xba, 0x3f, + 0xae, 0x85, 0x1b, 0x3f, 0x19, 0x8c, 0x87, 0xbf, 0xe0, 0x76, 0x4f, 0x3d, 0x7f, 0x60, 0x03, 0x3f, + 0xdc, 0xc4, 0x83, 0xbf, 0xe4, 0xf2, 0x64, 0x3e, 0x28, 0x56, 0x9b, 0x3f, 0x26, 0xe5, 0xa2, 0x3e, + 0x71, 0x6a, 0xd9, 0xbe, 0xb4, 0xc8, 0x09, 0x3f, 0x7e, 0x99, 0xcb, 0x3f, 0xf2, 0x3f, 0x9e, 0xbe, + 0x15, 0x37, 0x2d, 0xbf, 0x4b, 0xc3, 0x22, 0xbf, 0x1d, 0x45, 0xe8, 0x3e, 0xd6, 0x07, 0xe9, 0x3f, + 0xf6, 0x20, 0xe1, 0x3f, 0x42, 0xfe, 0xc4, 0x3d, 0xf6, 0x3f, 0xcf, 0xbf, 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, + 0x78, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x80, 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, 0x06, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x07, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x24, 0x01, 0x00, 0x00, + 0xe4, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x4c, 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, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x10, 0x00, 0x14, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x0c, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x62, 0x69, 0x61, 0x73, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0xa4, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x77, 0x65, 0x69, 0x67, + 0x68, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0xd0, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x5f, 0x66, + 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 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, + 0x03, 0x00, 0x00, 0x00, 0x69, 0x66, 0x6d, 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, 0x1b, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1b, 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_svdf_kernel + +class NegTestDataInputOutputTypeMismatchSVDFKernel : public NegTestDataBase +{ +public: + NegTestDataInputOutputTypeMismatchSVDFKernel() + { + _test_kernel_model_circle = + neg_input_output_type_mismatch_svdf_kernel::test_kernel_model_circle; + } + + ~NegTestDataInputOutputTypeMismatchSVDFKernel() 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_SVDF_KERNEL_H diff --git a/onert-micro/onert-micro/include/test_models/svdf/TestDataSVDFBase.h b/onert-micro/onert-micro/include/test_models/svdf/TestDataSVDFBase.h new file mode 100644 index 00000000000..389b418eff2 --- /dev/null +++ b/onert-micro/onert-micro/include/test_models/svdf/TestDataSVDFBase.h @@ -0,0 +1,61 @@ +/* + * 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 ONERT_MICRO_TEST_MODELS_SVDF_KERNEL_BASE_H +#define ONERT_MICRO_TEST_MODELS_SVDF_KERNEL_BASE_H + +#include "test_models/TestDataBase.h" +#include + +namespace onert_micro +{ +namespace test_model +{ + +template class TestDataSVDFBase : public TestDataBase +{ +public: + TestDataSVDFBase() = 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_model +} // namespace onert_micro + +#endif // ONERT_MICRO_TEST_MODELS_SVDF_KERNEL_BASE_H diff --git a/onert-micro/onert-micro/src/execute/kernels/SVDF.cpp b/onert-micro/onert-micro/src/execute/kernels/SVDF.cpp new file mode 100644 index 00000000000..418a6b155d1 --- /dev/null +++ b/onert-micro/onert-micro/src/execute/kernels/SVDF.cpp @@ -0,0 +1,169 @@ +/* + * 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/OMDataType.h" +#include "core/OMKernelData.h" +#include "core/memory/OMMemoryManager.h" + +#include "execute/OMKernelExecutionBuilder.h" +#include "execute/OMRuntimeKernel.h" + +#include "PALSVDF.h" + +using namespace onert_micro; +using namespace onert_micro::core; +using namespace onert_micro::execute; + +namespace +{ + +constexpr int inputTensorIdx = 0; +constexpr int weightsFeatureTensorIdx = 1; +constexpr int weightsTimeTensorIdx = 2; +constexpr int biasTensorIdx = 3; +constexpr int inputActivationStateTensorIdx = + 4; // This is a variable tensor, and will be modified by this op. +constexpr int outputTensorIdx = 0; + +} // namespace + +OMStatus onert_micro::execute::execute_kernel_CircleSVDF(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 *weights_feature; + const circle::Tensor *weights_time; + const circle::Tensor *bias; + const circle::Tensor *activation_state; + + const circle::Tensor *output; + + uint8_t *input_data; + uint8_t *weights_feature_data; + uint8_t *weights_time_data; + uint8_t *bias_data; + uint8_t *activation_state_data; + uint8_t *output_data; + const circle::SVDFOptions *options = nullptr; + // Read kernel + { + execute::OMRuntimeKernel runtime_kernel; + OMStatus status = runtime_kernel.readKernel(op_index, runtime_context); + if (status != Ok) + return status; + + input = runtime_kernel.inputs[inputTensorIdx]; + weights_feature = runtime_kernel.inputs[weightsFeatureTensorIdx]; + weights_time = runtime_kernel.inputs[weightsTimeTensorIdx]; + bias = runtime_kernel.inputs[biasTensorIdx]; + activation_state = runtime_kernel.inputs[inputActivationStateTensorIdx]; + + output = runtime_kernel.outputs[outputTensorIdx]; + + assert(input != nullptr); + assert(weights_feature != nullptr); + assert(weights_time != nullptr); + // bias can be nullptr + assert(activation_state != nullptr); + assert(output != nullptr); + + status = runtime_kernel.getDataFromStorage(op_index, runtime_storage, runtime_context); + if (status != Ok) + return status; + + input_data = runtime_kernel.inputs_data[inputTensorIdx]; + weights_feature_data = runtime_kernel.inputs_data[weightsFeatureTensorIdx]; + weights_time_data = runtime_kernel.inputs_data[weightsTimeTensorIdx]; + bias_data = runtime_kernel.inputs_data[biasTensorIdx]; + activation_state_data = runtime_kernel.inputs_data[inputActivationStateTensorIdx]; + output_data = runtime_kernel.outputs_data[outputTensorIdx]; + + assert(input_data != nullptr); + assert(weights_feature_data != nullptr); + assert(weights_time_data != nullptr); + // bias can be nullptr + assert(output_data != nullptr); + + options = runtime_kernel.first_operator->builtin_options_as_SVDFOptions(); + } + + OMStatus status; + OMRuntimeShape input_shape(input); + OMRuntimeShape weights_feature_shape(weights_feature); + OMRuntimeShape weights_time_shape(weights_time); + OMRuntimeShape activation_state_shape(activation_state); + OMRuntimeShape output_shape(output); + + // Define input constants based on input tensor definition above: + const int rank = options->rank(); + const int input_size = input_shape.dims(1); + const int batch_size = input_shape.dims(0); + const int num_filters = weights_feature_shape.dims(0); + + const int num_units = num_filters / rank; + const int memory_size = weights_time_shape.dims(1); + + const auto activation_state_size = + activation_state_shape.flatSize() * sizeof(core::OMDataType(output->type())); + status = + core::memory::OMMemoryManager::allocateMemory(activation_state_size, &activation_state_data); + if (status != Ok) + return status; + + std::memset(activation_state_data, 0, activation_state_size); + // Temporary buffer + uint8_t *scratch_buffer; + status = core::memory::OMMemoryManager::allocateMemory( + batch_size * num_filters * sizeof(core::OMDataType(output->type())), &scratch_buffer); + + assert(status == Ok); + if (status != Ok) + return status; + + switch (input->type()) + { +#ifndef DIS_FLOAT + case circle::TensorType_FLOAT32: + { + status = pal::SVDF( + utils::castInputData(input_data), utils::castInputData(weights_feature_data), + utils::castInputData(weights_time_data), utils::castInputData(bias_data), + utils::castOutputData(activation_state_data), + utils::castOutputData(scratch_buffer), utils::castOutputData(output_data), + rank, input_size, batch_size, num_filters, num_units, memory_size, + options->fused_activation_function()); + } + break; +#endif // DIS_FLOAT + default: + { + status = UnsupportedActivation; + assert(false && "Unsupported type."); + break; + } + } + + status = core::memory::OMMemoryManager::deallocateMemory(activation_state_data); + status = core::memory::OMMemoryManager::deallocateMemory(scratch_buffer); + + return status; +} diff --git a/onert-micro/onert-micro/src/execute/kernels/tests/SVDF.test.cpp b/onert-micro/onert-micro/src/execute/kernels/tests/SVDF.test.cpp new file mode 100644 index 00000000000..049cab7cda5 --- /dev/null +++ b/onert-micro/onert-micro/src/execute/kernels/tests/SVDF.test.cpp @@ -0,0 +1,53 @@ +/* + * 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/svdf/FloatSVDFKernel.h" +#include "test_models/svdf/NegSVDFKernel.h" + +namespace onert_micro +{ +namespace execute +{ +namespace testing +{ + +using namespace testing; + +class SVDFTest : public ::testing::Test +{ + // Do nothing +}; + +TEST_F(SVDFTest, Float_P) +{ + onert_micro::test_model::TestDataFloatSVDF test_data_kernel; + std::vector output_data_vector = + onert_micro::execute::testing::checkKernel(1, &test_data_kernel); + EXPECT_THAT(output_data_vector, + FloatArrayNear(test_data_kernel.get_output_data_by_index(0), 0.0001f)); +} + +TEST_F(SVDFTest, Input_output_type_mismatch_NEG) +{ + onert_micro::test_model::NegTestDataInputOutputTypeMismatchSVDFKernel test_data_kernel; + + EXPECT_DEATH(checkNEGSISOKernel(&test_data_kernel), ""); +} + +} // namespace testing +} // namespace execute +} // namespace onert_micro diff --git a/onert-micro/onert-micro/src/import/kernels/SVDF.cpp b/onert-micro/onert-micro/src/import/kernels/SVDF.cpp new file mode 100644 index 00000000000..25506b4743f --- /dev/null +++ b/onert-micro/onert-micro/src/import/kernels/SVDF.cpp @@ -0,0 +1,157 @@ +/* + * 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 "import/OMKernelConfigureBuilder.h" + +#include "execute/OMRuntimeKernel.h" +#include "execute/OMUtils.h" + +using namespace onert_micro; +using namespace onert_micro::core; + +namespace +{ + +constexpr int inputTensorIdx = 0; +constexpr int weightsFeatureTensorIdx = 1; +constexpr int weightsTimeTensorIdx = 2; +constexpr int biasTensorIdx = 3; +constexpr int inputActivationStateTensorIdx = + 4; // This is a variable tensor, and will be modified by this op. +constexpr int outputTensorIdx = 0; + +} // namespace + +OMStatus onert_micro::import::configure_kernel_CircleSVDF(const OMConfigureArgs &config_args) +{ + // Validate Tensor Inputs (dtype depends on quantization): + // [0] = Input, {2, batch_size, input_size} + // [1] = Weights Feature, {2, num_filters, input_size} + // [2] = Weights Time, {2, num_filters, memory_size} + // [3] = Bias (optional), {1, num_units} + // [4] = Activation State (variable), {2, batch_size, memory_size * num_filters} + + OMRuntimeContext &runtime_context = config_args.runtime_context; + uint16_t op_index = config_args.kernel_index; + + execute::OMRuntimeKernel runtime_kernel; + runtime_kernel.readKernel(op_index, runtime_context); + + const circle::Tensor *input = runtime_kernel.inputs[inputTensorIdx]; + const circle::Tensor *weights_feature = runtime_kernel.inputs[weightsFeatureTensorIdx]; + const circle::Tensor *weights_time = runtime_kernel.inputs[weightsTimeTensorIdx]; + const circle::Tensor *bias = runtime_kernel.inputs[biasTensorIdx]; + const circle::Tensor *activation_state = runtime_kernel.inputs[inputActivationStateTensorIdx]; + + const circle::Tensor *output = runtime_kernel.outputs[outputTensorIdx]; + + assert(input != nullptr); + assert(weights_feature != nullptr); + assert(weights_time != nullptr); + // bias can be nullptr + assert(activation_state != nullptr); + assert(output != nullptr); + + OMStatus status = Ok; + + if (status != Ok) + return status; + + const auto *options = runtime_kernel.first_operator->builtin_options_as_SVDFOptions(); + status = utils::checkCondition(options != nullptr); + if (status != Ok) + return status; + + OMRuntimeShape input_shape(input); + OMRuntimeShape weights_feature_shape(weights_feature); + OMRuntimeShape weights_time_shape(weights_time); + OMRuntimeShape activation_state_shape(activation_state); + OMRuntimeShape output_shape(output); + + // Define input constants based on input tensor definition above: + const int rank = options->rank(); + const int input_size = input_shape.dims(1); + const int batch_size = input_shape.dims(0); + const int num_filters = weights_feature_shape.dims(0); + status = utils::checkCondition(num_filters % rank == 0); + if (status != Ok) + return status; + + const int num_units = num_filters / rank; + const int memory_size = weights_time_shape.dims(1); + + status = utils::checkCondition(input_shape.dimensionsCount() == 2); + if (status != Ok) + return status; + // Validate Tensor Output: + // [0] = float/int8_t, {2, batch_size, num_units} + status = + utils::checkCondition(output_shape.dimensionsCount() == 2 and + output_shape.dims(0) == batch_size and output_shape.dims(1) == num_units); + if (status != Ok) + return status; + + // Validate Weights Feature Input Tensor + status = utils::checkCondition(weights_feature_shape.dimensionsCount() == 2 and + weights_feature_shape.dims(1) == input_size); + if (status != Ok) + return status; + + // Validate Weights Time Input Tensor: + status = utils::checkCondition(weights_time_shape.dimensionsCount() == 2 and + weights_time_shape.dims(0) == num_filters and + weights_time_shape.dims(1) == memory_size); + if (status != Ok) + return status; + + // Validate Optional Bias Input Tensor: + if (bias != nullptr) + { + status = utils::checkCondition(OMRuntimeShape(bias).dims(0) == num_units); + if (status != Ok) + return status; + } + + // Validate Activation State Input Tensor: + status = utils::checkCondition(activation_state_shape.dimensionsCount() == 2 and + activation_state_shape.dims(0) == batch_size and + activation_state_shape.dims(1) == memory_size * num_filters); + if (status != Ok) + return status; + + if (input->type() == circle::TensorType_FLOAT32) + { + status = utils::checkCondition(weights_feature->type() == circle::TensorType_FLOAT32 and + weights_time->type() == circle::TensorType_FLOAT32 and + activation_state->type() == circle::TensorType_FLOAT32 and + output->type() == circle::TensorType_FLOAT32); + if (status != Ok) + return status; + if (bias) + { + status = utils::checkCondition(bias->type() == circle::TensorType_FLOAT32); + if (status != Ok) + return status; + } + } + + return status; +} From 20f03a8afb89b7c1ac6f34572243518f3c13fc39 Mon Sep 17 00:00:00 2001 From: Jan Iwaszkiewicz Date: Wed, 7 Aug 2024 11:54:15 +0200 Subject: [PATCH 08/78] [res/tfl_recipes] Add Net_FullyConnected_Mul (#13610) This commit adds Net_FullyConnectedMul tflite recipes. ONE-DCO-1.0-Signed-off-by: Jan Iwaszkiewicz --- .../Net_FullyConnected_Mul_000/test.recipe | 67 +++++++++++++++++++ .../Net_FullyConnected_Mul_000/test.rule | 12 ++++ .../Net_FullyConnected_Mul_001/test.recipe | 67 +++++++++++++++++++ .../Net_FullyConnected_Mul_001/test.rule | 12 ++++ .../Net_FullyConnected_Mul_002/test.recipe | 66 ++++++++++++++++++ .../Net_FullyConnected_Mul_002/test.rule | 12 ++++ 6 files changed, 236 insertions(+) create mode 100644 res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_000/test.recipe create mode 100644 res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_000/test.rule create mode 100644 res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_001/test.recipe create mode 100644 res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_001/test.rule create mode 100644 res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_002/test.recipe create mode 100644 res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_002/test.rule diff --git a/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_000/test.recipe b/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_000/test.recipe new file mode 100644 index 00000000000..84203a12d04 --- /dev/null +++ b/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_000/test.recipe @@ -0,0 +1,67 @@ +operand { + name: "ifm" + type: FLOAT32 + shape { dim: 1 dim: 1 dim: 6 } +} +operand { + name: "fc_wgt" + type: FLOAT32 + shape { dim: 6 dim: 6 } + filler { + tag: "gaussian" + arg: "0.0" + arg: "1.0" + } +} +operand { + name: "fc_bias" + type: FLOAT32 + shape { dim: 6 } + filler { + tag: "gaussian" + arg: "0.0" + arg: "1.0" + } +} +operand { + name: "B" + type: FLOAT32 + shape { dim: 1, dim: 1, dim: 6 } + filler { + tag: "gaussian" + arg: "0.0" + arg: "1.0" + } +} +operand { + name: "fc_out" + type: FLOAT32 + shape: { dim: 1 dim: 1 dim: 6 } +} +operand { + name: "mul_out" + type: FLOAT32 + shape: { dim: 1 dim: 1 dim: 6 } +} +operation { + type: "FullyConnected" + fullyconnected_options { + activation: NONE + keep_num_dims: true + } + input: "ifm" + input: "fc_wgt" + input: "fc_bias" + output: "fc_out" +} +operation { + type: "Mul" + mul_options { + activation: NONE + } + input: "fc_out" + input: "B" + output: "mul_out" +} +input: "ifm" +output: "mul_out" diff --git a/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_000/test.rule b/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_000/test.rule new file mode 100644 index 00000000000..c1f2a827884 --- /dev/null +++ b/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_000/test.rule @@ -0,0 +1,12 @@ +# This checks if: +# Mul(FC(input, weights, bias), other) +# is converted to: +# FC(input, Mul(weights, other), Mul(bias, other)) +# and then Mul is fused to: +# FC(input, weights', bias') +# Here Mul is in shape of (1, 1, X). + +RULE "VERIFY_FILE_FORMAT" $(verify_file_format) '=' 1 + +RULE "NO_MUL" $(op_count MUL) '=' 0 +RULE "FC_EXIST" $(op_count FULLY_CONNECTED) '=' 1 diff --git a/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_001/test.recipe b/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_001/test.recipe new file mode 100644 index 00000000000..d446424c238 --- /dev/null +++ b/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_001/test.recipe @@ -0,0 +1,67 @@ +operand { + name: "ifm" + type: FLOAT32 + shape { dim: 3 dim: 1 dim: 4 } +} +operand { + name: "fc_wgt" + type: FLOAT32 + shape { dim: 6 dim: 4 } + filler { + tag: "gaussian" + arg: "0.0" + arg: "1.0" + } +} +operand { + name: "fc_bias" + type: FLOAT32 + shape { dim: 6 } + filler { + tag: "gaussian" + arg: "0.0" + arg: "1.0" + } +} +operand { + name: "B" + type: FLOAT32 + shape { dim: 6 } + filler { + tag: "gaussian" + arg: "0.0" + arg: "1.0" + } +} +operand { + name: "fc_out" + type: FLOAT32 + shape: { dim: 3 dim: 1 dim: 6 } +} +operand { + name: "mul_out" + type: FLOAT32 + shape: { dim: 3 dim: 1 dim: 6 } +} +operation { + type: "FullyConnected" + fullyconnected_options { + activation: NONE + keep_num_dims: true + } + input: "ifm" + input: "fc_wgt" + input: "fc_bias" + output: "fc_out" +} +operation { + type: "Mul" + mul_options { + activation: RELU + } + input: "fc_out" + input: "B" + output: "mul_out" +} +input: "ifm" +output: "mul_out" diff --git a/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_001/test.rule b/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_001/test.rule new file mode 100644 index 00000000000..acdd2d6a96b --- /dev/null +++ b/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_001/test.rule @@ -0,0 +1,12 @@ +# This checks if: +# Mul(FC(input, weights, bias), other) +# is converted to: +# FC(input, Mul(weights, other), Mul(bias, other)) +# and then Mul is fused to: +# FC(input, weights', bias') +# Here Mul is in shape of (X). + +RULE "VERIFY_FILE_FORMAT" $(verify_file_format) '=' 1 + +RULE "NO_MUL" $(op_count MUL) '=' 0 +RULE "FC_EXIST" $(op_count FULLY_CONNECTED) '=' 1 diff --git a/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_002/test.recipe b/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_002/test.recipe new file mode 100644 index 00000000000..34e3cde4839 --- /dev/null +++ b/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_002/test.recipe @@ -0,0 +1,66 @@ +operand { + name: "ifm" + type: FLOAT32 + shape { dim: 1 dim: 16 } +} +operand { + name: "fc_wgt" + type: FLOAT32 + shape { dim: 4 dim: 16 } + filler { + tag: "gaussian" + arg: "0.0" + arg: "1.0" + } +} +operand { + name: "fc_bias" + type: FLOAT32 + shape { dim: 4 } + filler { + tag: "gaussian" + arg: "0.0" + arg: "1.0" + } +} +operand { + name: "B" + type: FLOAT32 + shape { dim: 1 } + filler { + tag: "constant" + arg: "2.0" + } +} +operand { + name: "fc_out" + type: FLOAT32 + shape: { dim: 1 dim: 4 } +} +operand { + name: "mul_out" + type: FLOAT32 + shape: { dim: 1 dim: 4 } +} +operation { + type: "FullyConnected" + fullyconnected_options { + activation: NONE + keep_num_dims: true + } + input: "ifm" + input: "fc_wgt" + input: "fc_bias" + output: "fc_out" +} +operation { + type: "Mul" + mul_options { + activation: NONE + } + input: "fc_out" + input: "B" + output: "mul_out" +} +input: "ifm" +output: "mul_out" diff --git a/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_002/test.rule b/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_002/test.rule new file mode 100644 index 00000000000..9cc8d5fd0a7 --- /dev/null +++ b/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_002/test.rule @@ -0,0 +1,12 @@ +# This checks if: +# Mul(FC(input, weights, bias), other) +# is converted to: +# FC(input, Mul(weights, other), Mul(bias, other)) +# and then Mul is fused to: +# FC(input, weights', bias') +# Here Mul is in shape of (1), it's a scalar. + +RULE "VERIFY_FILE_FORMAT" $(verify_file_format) '=' 1 + +RULE "NO_MUL" $(op_count MUL) '=' 0 +RULE "FC_EXIST" $(op_count FULLY_CONNECTED) '=' 1 From e4adf39603f6c7eb6c507248f2976efbf7598476 Mon Sep 17 00:00:00 2001 From: Hyeongseok Oh Date: Thu, 8 Aug 2024 11:54:01 +0900 Subject: [PATCH 09/78] [infra/onert] Rename debian package (#13599) This commit renames runtime debian package nnfw -> onert. ONE-DCO-1.0-Signed-off-by: Hyeongseok Oh --- infra/debian/runtime/control | 30 +++++++++++++++---- .../{nnfw-dev.install => onert-dev.install} | 2 +- ...n-dev.install => onert-plugin-dev.install} | 2 +- .../runtime/{nnfw.install => onert.install} | 0 infra/debian/runtime/rules | 19 ++++++------ packaging/nnfw-plugin.pc.in | 2 +- packaging/nnfw.pc.in | 2 +- 7 files changed, 39 insertions(+), 18 deletions(-) rename infra/debian/runtime/{nnfw-dev.install => onert-dev.install} (61%) rename infra/debian/runtime/{nnfw-plugin-dev.install => onert-plugin-dev.install} (54%) rename infra/debian/runtime/{nnfw.install => onert.install} (100%) diff --git a/infra/debian/runtime/control b/infra/debian/runtime/control index 86b169ebff5..baa0d029816 100644 --- a/infra/debian/runtime/control +++ b/infra/debian/runtime/control @@ -6,20 +6,40 @@ Build-Depends: cmake, debhelper (>=9) Standards-Version: 3.9.8 Homepage: https://github.com/Samsung/ONE -Package: nnfw +Package: onert +Replaces: nnfw (<< 1.29.0) +Breaks: nnfw (<< 1.29.0) Architecture: amd64 Multi-Arch: same Depends: ${shlibs:Depends}, ${misc:Depends} Description: one-runtime package -Package: nnfw-dev +Package: nnfw +Architecture: all +Priority: optional +Section: oldlibs +Depends: onert, ${shlibs:Depends}, ${misc:Depends} +Description: one-runtime transitional package + This is a transitional package. It can safely be removed. + +Package: onert-dev +Replaces: nnfw-dev (<< 1.29.0) +Breaks: nnfw-dev (<< 1.29.0) Architecture: amd64 Multi-Arch: same -Depends: nnfw, ${shlibs:Depends}, ${misc:Depends} +Depends: onert, ${shlibs:Depends}, ${misc:Depends} Description: one-runtime development package -Package: nnfw-plugin-dev +Package: nnfw-dev +Architecture: all +Priority: optional +Section: oldlibs +Depends: onert-dev, ${shlibs:Depends}, ${misc:Depends} +Description: one-runtime development transitional package + This is a transitional package. It can safely be removed. + +Package: onert-plugin-dev Architecture: amd64 Multi-Arch: same -Depends: nnfw, nnfw-dev, ${shlibs:Depends}, ${misc:Depends} +Depends: onert, onert-dev, ${shlibs:Depends}, ${misc:Depends} Description: one-runtime development package diff --git a/infra/debian/runtime/nnfw-dev.install b/infra/debian/runtime/onert-dev.install similarity index 61% rename from infra/debian/runtime/nnfw-dev.install rename to infra/debian/runtime/onert-dev.install index f246e7c24ea..5aab8f5800a 100644 --- a/infra/debian/runtime/nnfw-dev.install +++ b/infra/debian/runtime/onert-dev.install @@ -1,4 +1,4 @@ # {FILES_TO_INSTALL} {DEST_DIR} # include usr/include/nnfw usr/include/ -usr/lib/pkgconfig/*.pc usr/lib/pkgconfig/ +usr/lib/pkgconfig/onert.pc usr/lib/pkgconfig/ diff --git a/infra/debian/runtime/nnfw-plugin-dev.install b/infra/debian/runtime/onert-plugin-dev.install similarity index 54% rename from infra/debian/runtime/nnfw-plugin-dev.install rename to infra/debian/runtime/onert-plugin-dev.install index 1f19e54d8de..7db4391bf9a 100644 --- a/infra/debian/runtime/nnfw-plugin-dev.install +++ b/infra/debian/runtime/onert-plugin-dev.install @@ -1,3 +1,3 @@ # {FILES_TO_INSTALL} {DEST_DIR} usr/include/onert usr/include/ -usr/lib/pkgconfig/nnfw-plugin.pc usr/lib/pkgconfig/ +usr/lib/pkgconfig/onert-plugin.pc usr/lib/pkgconfig/ diff --git a/infra/debian/runtime/nnfw.install b/infra/debian/runtime/onert.install similarity index 100% rename from infra/debian/runtime/nnfw.install rename to infra/debian/runtime/onert.install diff --git a/infra/debian/runtime/rules b/infra/debian/runtime/rules index 47a6d51dbe3..ffe3d04d42a 100755 --- a/infra/debian/runtime/rules +++ b/infra/debian/runtime/rules @@ -24,13 +24,14 @@ override_dh_auto_install: ./nnfw install --prefix $(NNFW_INSTALL_PREFIX) --strip override_dh_install: install -d $(NNFW_INSTALL_PREFIX)/lib/pkgconfig - sed -i 's:@libdir@:\/usr\/lib:g' ./packaging/nnfw.pc.in - sed -i 's:@includedir@:\/usr\/include:g' ./packaging/nnfw.pc.in - sed -i 's:@version@:${DEBVER}:g' ./packaging/nnfw.pc.in - sed -i 's:@libdir@:\/usr\/lib:g' ./packaging/nnfw-plugin.pc.in - sed -i 's:@includedir@:\/usr\/include:g' ./packaging/nnfw-plugin.pc.in - sed -i 's:@version@:${DEBVER}:g' ./packaging/nnfw-plugin.pc.in - - install -m 0644 packaging/nnfw.pc.in -T $(NNFW_INSTALL_PREFIX)/lib/pkgconfig/nnfw.pc - install -m 0644 packaging/nnfw-plugin.pc.in -T $(NNFW_INSTALL_PREFIX)/lib/pkgconfig/nnfw-plugin.pc + install -m 0644 packaging/nnfw.pc.in -T $(NNFW_INSTALL_PREFIX)/lib/pkgconfig/onert.pc + install -m 0644 packaging/nnfw-plugin.pc.in -T $(NNFW_INSTALL_PREFIX)/lib/pkgconfig/onert-plugin.pc + sed -i 's:@libdir@:\/usr\/lib:g' $(NNFW_INSTALL_PREFIX)/lib/pkgconfig/onert.pc + sed -i 's:@includedir@:\/usr\/include:g' $(NNFW_INSTALL_PREFIX)/lib/pkgconfig/onert.pc + sed -i 's:@version@:${DEBVER}:g' $(NNFW_INSTALL_PREFIX)/lib/pkgconfig/onert.pc + sed -i 's:Name\: nnfw:Name\: onert:g' $(NNFW_INSTALL_PREFIX)/lib/pkgconfig/onert.pc + sed -i 's:@libdir@:\/usr\/lib:g' $(NNFW_INSTALL_PREFIX)/lib/pkgconfig/onert-plugin.pc + sed -i 's:@includedir@:\/usr\/include:g' $(NNFW_INSTALL_PREFIX)/lib/pkgconfig/onert-plugin.pc + sed -i 's:@version@:${DEBVER}:g' $(NNFW_INSTALL_PREFIX)/lib/pkgconfig/onert-plugin.pc + sed -i 's:Name\: nnfw:Name\: onert:g' $(NNFW_INSTALL_PREFIX)/lib/pkgconfig/onert-plugin.pc dh_install diff --git a/packaging/nnfw-plugin.pc.in b/packaging/nnfw-plugin.pc.in index e0d9271b725..ef3f42cab2d 100644 --- a/packaging/nnfw-plugin.pc.in +++ b/packaging/nnfw-plugin.pc.in @@ -1,5 +1,5 @@ Name: nnfw-plugin -Description: NNFW API for tizen +Description: onert plugin API Version: @version@ Libs: -L@libdir@ -lonert_core Cflags: -I@includedir@/nnfw -I@includedir@/onert diff --git a/packaging/nnfw.pc.in b/packaging/nnfw.pc.in index d72b81b33b4..4252b83cda4 100644 --- a/packaging/nnfw.pc.in +++ b/packaging/nnfw.pc.in @@ -1,5 +1,5 @@ Name: nnfw -Description: NNFW API for tizen +Description: onert API Version: @version@ Libs: -L@libdir@ -lnnfw-dev Cflags: -I@includedir@/nnfw From cc1dbe5cbe2b92722e7f4866d20a32d88231715c Mon Sep 17 00:00:00 2001 From: SaeHie Park Date: Thu, 8 Aug 2024 13:38:48 +0900 Subject: [PATCH 10/78] [luci-interpreter] Revise MirrorPad to use LUCI_INTERPRETER_CHECK (#13614) This will revise MirrorPad kernel to use LUCI_INTERPRETER_CHECK instead of assert. ONE-DCO-1.0-Signed-off-by: SaeHie Park --- compiler/luci-interpreter/src/kernels/MirrorPad.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/luci-interpreter/src/kernels/MirrorPad.cpp b/compiler/luci-interpreter/src/kernels/MirrorPad.cpp index c0d23882da3..6fef9ebca49 100644 --- a/compiler/luci-interpreter/src/kernels/MirrorPad.cpp +++ b/compiler/luci-interpreter/src/kernels/MirrorPad.cpp @@ -40,12 +40,12 @@ void MirrorPad::configure() if (num_dims > 4) throw std::runtime_error("Unsupported number of dimensions."); - assert(output()->element_type() == input()->element_type()); - assert(paddings()->element_type() == DataType::S32); + LUCI_INTERPRETER_CHECK(output()->element_type() == input()->element_type()); + LUCI_INTERPRETER_CHECK(paddings()->element_type() == DataType::S32); // Paddings shape should be [N, 2]. - assert(paddings()->shape().num_dims() == 2); - assert(paddings()->shape().dim(0) == num_dims); - assert(paddings()->shape().dim(1) == 2); + LUCI_INTERPRETER_CHECK(paddings()->shape().num_dims() == 2); + LUCI_INTERPRETER_CHECK(paddings()->shape().dim(0) == num_dims); + LUCI_INTERPRETER_CHECK(paddings()->shape().dim(1) == 2); Shape output_shape(num_dims); const auto *paddings_data = getTensorData(paddings()); @@ -53,7 +53,7 @@ void MirrorPad::configure() { const int32_t padding_before = paddings_data[i * 2]; const int32_t padding_after = paddings_data[i * 2 + 1]; - assert(padding_before >= 0 && padding_after >= 0); + LUCI_INTERPRETER_CHECK(padding_before >= 0 && padding_after >= 0); output_shape.dim(i) = input_shape.dim(i) + padding_before + padding_after; } From 0a104d340b1337315696b91d7cb0aa2f48b5f317 Mon Sep 17 00:00:00 2001 From: SaeHie Park Date: Thu, 8 Aug 2024 13:47:48 +0900 Subject: [PATCH 11/78] [luci-interpreter] Fix MirrorPad implementation (#13613) This will fix MirrorPad kernel implementation and unit tests. - implementation is from onert-micro ONE-DCO-1.0-Signed-off-by: SaeHie Park --- .../src/kernels/MirrorPad.cpp | 133 ++++++++++++++++-- .../src/kernels/MirrorPad.test.cpp | 56 +++++--- 2 files changed, 157 insertions(+), 32 deletions(-) diff --git a/compiler/luci-interpreter/src/kernels/MirrorPad.cpp b/compiler/luci-interpreter/src/kernels/MirrorPad.cpp index 6fef9ebca49..bed74fa14db 100644 --- a/compiler/luci-interpreter/src/kernels/MirrorPad.cpp +++ b/compiler/luci-interpreter/src/kernels/MirrorPad.cpp @@ -19,7 +19,7 @@ #include "kernels/Utils.h" -#include +#include namespace luci_interpreter { @@ -60,32 +60,138 @@ void MirrorPad::configure() output()->resize(output_shape); } +namespace +{ + +// Helper method that fills the left and right pads. template -inline void MirrorPadImpl(const Tensor &input, const Tensor &paddings, MirrorPadMode mode, - Tensor &output); +inline void getPadding(const T *data, int offset, int64_t *left_pad, int64_t *right_pad) +{ + *left_pad = static_cast(*(data + offset * 2)); + *right_pad = static_cast(*(data + offset * 2 + 1)); +} + +// Given dimension index and the left/right padding. +// Returns the corresponding dimension in the input array. +inline int getInputDimension(int padded_dimension, int left_pad, int right_pad, int input_dim_size, + int offset) +{ + (void)right_pad; + + if (padded_dimension < left_pad) + { + const int original_ind = left_pad + offset - 1; + return original_ind - (std::min(padded_dimension, original_ind - offset)); + } + padded_dimension -= left_pad; + if (padded_dimension >= input_dim_size) + { + padded_dimension -= input_dim_size; + const int original_ind = input_dim_size - (1 + offset); + return original_ind - std::min(padded_dimension, original_ind); + } + return padded_dimension; +} + +// Given and index in output array, returns the index of the value +// in input array. +int getFlatIndex(int index, int num_dims, const DataType padding_matrix_type, + const uint8_t *padding_matrix_data, const int32_t *input_dims, + int *output_dims_num_elements, int *input_dims_num_elements, const int offset) +{ + int flat_index = 0; + int64_t left_pad = 0, right_pad = 0, dimension_index, index_in_input; + + for (int i = 0; i < num_dims; ++i) + { + switch (padding_matrix_type) + { + case DataType::S32: + getPadding(reinterpret_cast(padding_matrix_data), i, &left_pad, + &right_pad); + break; + case DataType::S64: + getPadding(reinterpret_cast(padding_matrix_data), i, &left_pad, + &right_pad); + break; + default: + break; + } + dimension_index = index / output_dims_num_elements[i]; + + index_in_input = getInputDimension(dimension_index, left_pad, right_pad, input_dims[i], offset); + + flat_index += index_in_input * input_dims_num_elements[i]; + index %= output_dims_num_elements[i]; + } + + return flat_index; +} + +template +void eval(const DataType padding_matrix_type, const uint8_t *padding_matrix_data, + const int32_t *input_dims, int *output_dims_num_elements, int *input_dims_num_elements, + const T *input_data, T *output_data, const int offset, const int num_dims, + const int output_size) +{ + for (int i = 0; i < output_size; ++i) + { + int index = getFlatIndex(i, num_dims, padding_matrix_type, padding_matrix_data, input_dims, + output_dims_num_elements, input_dims_num_elements, offset); + output_data[i] = input_data[index]; + } +} + +} // namespace void MirrorPad::execute() const { - switch (input()->element_type()) + const Tensor &t_input = *input(); + const Tensor &t_paddings = *paddings(); + Tensor &t_output = *output(); + + const auto offset = params().mode != MirrorPadMode::REFLECT ? 0 : 1; + const auto input_dims = t_input.shape().num_dims(); + const auto output_size = t_output.shape().num_elements(); + + int output_dims_num_elements[5]; + int input_dims_num_elements[5]; + int32_t input_shape_dim[5]; + + for (int i = 0; i < input_dims; i++) + { + output_dims_num_elements[i] = 1; + input_dims_num_elements[i] = 1; + input_shape_dim[i] = t_input.shape().dim(i); + } + + for (int i = input_dims - 2; i >= 0; i--) + { + output_dims_num_elements[i] = output_dims_num_elements[i + 1] * t_output.shape().dim(i + 1); + input_dims_num_elements[i] = input_dims_num_elements[i + 1] * t_input.shape().dim(i + 1); + } + + switch (t_input.element_type()) { case DataType::FLOAT32: - { - MirrorPadImpl(*input(), *paddings(), params().mode, *output()); + eval(t_paddings.element_type(), t_paddings.data(), input_shape_dim, + output_dims_num_elements, input_dims_num_elements, t_input.data(), + t_output.data(), offset, input_dims, output_size); break; - } - case DataType::U8: - { - assert(output()->zero_point() >= std::numeric_limits::min()); - assert(output()->zero_point() <= std::numeric_limits::max()); - MirrorPadImpl(*input(), *paddings(), params().mode, *output()); + case DataType::U8: + eval(t_paddings.element_type(), t_paddings.data(), input_shape_dim, + output_dims_num_elements, input_dims_num_elements, t_input.data(), + t_output.data(), offset, input_dims, output_size); break; - } + default: throw std::runtime_error("luci-intp MirrorPad Unsupported type."); } } +#if 0 +// delete this template inline void MirrorPadImpl(const Tensor &input, const Tensor &paddings, MirrorPadMode mode, Tensor &output) @@ -167,6 +273,7 @@ inline void MirrorPadImpl(const Tensor &input, const Tensor &paddings, MirrorPad } } } +#endif } // namespace kernels } // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/kernels/MirrorPad.test.cpp b/compiler/luci-interpreter/src/kernels/MirrorPad.test.cpp index 740d8cb2272..cef7d83da5c 100644 --- a/compiler/luci-interpreter/src/kernels/MirrorPad.test.cpp +++ b/compiler/luci-interpreter/src/kernels/MirrorPad.test.cpp @@ -48,12 +48,12 @@ class MirrorPadTest : public ::testing::Test TEST_F(MirrorPadTest, FloatReflect) { - Shape input_shape = {1, 2, 2, 1}; + Shape input_shape = {1, 2, 3, 1}; Shape padding_shape = {4, 2}; - std::vector input_data{1.0f, 2.0f, // - 3.0f, 4.0f}; // - std::vector padding_data{0, 0, 2, 1, 1, 2, 0, 0}; + std::vector input_data{1.0f, 2.0f, 3.0f, // + 4.0f, 5.0f, 6.0f}; // + std::vector padding_data{0, 0, 1, 1, 1, 1, 0, 0}; Tensor input_tensor = makeInputTensor(input_shape, input_data, _memory_manager.get()); @@ -64,12 +64,35 @@ TEST_F(MirrorPadTest, FloatReflect) Execute(input_tensor, padding_tensor, output_tensor, MirrorPadMode::REFLECT); - std::vector ref_output_data{2.0f, 1.0f, 2.0f, 1.0f, 2.0f, // - 4.0f, 3.0f, 4.0f, 3.0f, 4.0f, // - 2.0f, 1.0f, 2.0f, 1.0f, 2.0f, // - 4.0f, 3.0f, 4.0f, 3.0f, 4.0f, // - 2.0f, 1.0f, 2.0f, 1.0f, 2.0f}; // - std::initializer_list ref_output_shape{1, 5, 5, 1}; + std::vector ref_output_data{5, 4, 5, 6, 5, 2, 1, 2, 3, 2, // + 5, 4, 5, 6, 5, 2, 1, 2, 3, 2}; // + std::initializer_list ref_output_shape{1, 4, 5, 1}; + + EXPECT_THAT(extractTensorData(output_tensor), FloatArrayNear(ref_output_data)); + EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape)); +} + +TEST_F(MirrorPadTest, FloatReflect2) +{ + Shape input_shape = {2, 3}; + Shape padding_shape = {2, 2}; + + std::vector input_data{1, 2, 3, 4, 5, 6}; + std::vector padding_data{1, 1, 2, 2}; + + Tensor input_tensor = + makeInputTensor(input_shape, input_data, _memory_manager.get()); + Tensor padding_tensor = + makeInputTensor(padding_shape, padding_data, _memory_manager.get()); + + Tensor output_tensor = makeOutputTensor(DataType::FLOAT32); + + Execute(input_tensor, padding_tensor, output_tensor, MirrorPadMode::REFLECT); + + std::vector ref_output_data{6, 5, 4, 5, 6, 5, 4, 3, 2, 1, 2, 3, 2, 1, + 6, 5, 4, 5, 6, 5, 4, 3, 2, 1, 2, 3, 2, 1}; + + std::initializer_list ref_output_shape{4, 7}; EXPECT_THAT(extractTensorData(output_tensor), FloatArrayNear(ref_output_data)); EXPECT_THAT(extractTensorShape(output_tensor), ::testing::ElementsAreArray(ref_output_shape)); @@ -138,7 +161,7 @@ TEST_F(MirrorPadTest, Uint8Reflect) std::vector input_data{1.0f, 2.0f, 3.0f, // 4.0f, 5.0f, 6.0f}; // - std::vector padding_data{0, 0, 2, 1, 1, 3, 0, 0}; + std::vector padding_data{0, 0, 1, 1, 1, 1, 0, 0}; Tensor input_tensor = makeInputTensor( input_shape, quant_param.first, quant_param.second, input_data, _memory_manager.get()); @@ -150,14 +173,9 @@ TEST_F(MirrorPadTest, Uint8Reflect) Execute(input_tensor, padding_tensor, output_tensor, MirrorPadMode::REFLECT); - std::vector ref_output_data{ - 3.0f, 1.0f, 2.0f, 3.0f, 1.0f, 2.0f, 3.0f, // - 6.0f, 4.0f, 5.0f, 6.0f, 4.0f, 5.0f, 6.0f, // - 3.0f, 1.0f, 2.0f, 3.0f, 1.0f, 2.0f, 3.0f, // - 6.0f, 4.0f, 5.0f, 6.0f, 4.0f, 5.0f, 6.0f, // - 3.0f, 1.0f, 2.0f, 3.0f, 1.0f, 2.0f, 3.0f, // - }; - std::initializer_list ref_output_shape{1, 5, 7, 1}; + std::vector ref_output_data{5, 4, 5, 6, 5, 2, 1, 2, 3, 2, // + 5, 4, 5, 6, 5, 2, 1, 2, 3, 2}; // + std::initializer_list ref_output_shape{1, 4, 5, 1}; EXPECT_THAT(dequantizeTensorData(output_tensor), FloatArrayNear(ref_output_data, quant_tolerance)); From 036cb5df40fefcbabff19d3b4b330100e18d930e Mon Sep 17 00:00:00 2001 From: SeungHui Youn <61981457+zetwhite@users.noreply.github.com> Date: Thu, 8 Aug 2024 14:37:40 +0900 Subject: [PATCH 12/78] [onert] Introduce ExtraTensorIndex (#13605) This PR introduces ExtraTensorIndex. ExtraTensorIndex will be used to identify extra tensor in tensor registry. ONE-DCO-1.0-Signed-off-by: seunghui youn --- .../onert/backend/train/ExtraTensorIndex.h | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 runtime/onert/backend/train/ExtraTensorIndex.h diff --git a/runtime/onert/backend/train/ExtraTensorIndex.h b/runtime/onert/backend/train/ExtraTensorIndex.h new file mode 100644 index 00000000000..84fbf6c1c6e --- /dev/null +++ b/runtime/onert/backend/train/ExtraTensorIndex.h @@ -0,0 +1,85 @@ +/* + * 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_BACKEND_TRAIN_EXTRA_TENSOR_INDEX_H__ +#define __ONERT_BACKEND_TRAIN_EXTRA_TENSOR_INDEX_H__ + +#include + +#include + +namespace onert +{ +namespace backend +{ +namespace train +{ + +class ExtraTensorIndex +{ +public: + ExtraTensorIndex(const ir::OperationIndex &op_index, uint32_t sub_index) + : _op_index{op_index}, _sub_index{sub_index} + { + assert(op_index.valid()); + } + +public: + const ir::OperationIndex &op_index() const { return _op_index; } + uint32_t sub_index() const { return _sub_index; } + + bool operator==(const ExtraTensorIndex &other) const + { + return _op_index == other.op_index() && _sub_index == other.sub_index(); + } + bool operator!=(const ExtraTensorIndex &other) const { return !(*this == other); } + +private: + ir::OperationIndex _op_index; + uint32_t _sub_index; +}; + +inline std::ostream &operator<<(std::ostream &o, const ExtraTensorIndex &i) +{ + o << i.op_index() << "-" << i.sub_index(); + return o; +} + +} // namespace train +} // namespace backend +} // namespace onert + +namespace std +{ + +template <> struct hash +{ + size_t operator()(const onert::backend::train::ExtraTensorIndex &index) const noexcept + { + const auto op_index = index.op_index(); + const auto sub_index = index.sub_index(); + + assert(sizeof(op_index) <= sizeof(uint32_t)); + static_assert(sizeof(size_t) >= sizeof(uint32_t), + "ExtraTensorIndex's hash creation error, size_t size is less than uint32_t"); + + return (static_cast(op_index.value())) << 16 | static_cast(sub_index); + } +}; + +} // namespace std + +#endif // __ONERT_BACKEND_TRAIN_EXTRA_TENSOR_INDEX_H__ From 393c10b2af128cbf1968ed8e0d53334852351580 Mon Sep 17 00:00:00 2001 From: SaeHie Park Date: Thu, 8 Aug 2024 15:57:03 +0900 Subject: [PATCH 13/78] [luci/value-test] Enable MirrorPad (#13617) This will enable MirrorPad_000 in luci value test. ONE-DCO-1.0-Signed-off-by: SaeHie Park --- compiler/luci-value-py-test/test.lst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/luci-value-py-test/test.lst b/compiler/luci-value-py-test/test.lst index 2c928fb8d95..f7f3b86b163 100644 --- a/compiler/luci-value-py-test/test.lst +++ b/compiler/luci-value-py-test/test.lst @@ -93,7 +93,7 @@ eval(Mean_000) eval(Mean_001) eval(Mean_U8_000) eval(Minimum_000) -#eval(MirrorPad_000) +eval(MirrorPad_000) eval(Mul_000) #eval(Mul_U8_000) eval(Neg_000) From 917edfc19df77f9876dbab937c797441edd9fa9c Mon Sep 17 00:00:00 2001 From: SaeHie Park Date: Thu, 8 Aug 2024 15:57:39 +0900 Subject: [PATCH 14/78] [luci-interpreter] Tidy unused in MirrorPad (#13621) This will tidy disabled unused codes in MirrorPad kernel. ONE-DCO-1.0-Signed-off-by: SaeHie Park --- .../src/kernels/MirrorPad.cpp | 85 ------------------- 1 file changed, 85 deletions(-) diff --git a/compiler/luci-interpreter/src/kernels/MirrorPad.cpp b/compiler/luci-interpreter/src/kernels/MirrorPad.cpp index bed74fa14db..aa3c4df6ed8 100644 --- a/compiler/luci-interpreter/src/kernels/MirrorPad.cpp +++ b/compiler/luci-interpreter/src/kernels/MirrorPad.cpp @@ -190,90 +190,5 @@ void MirrorPad::execute() const } } -#if 0 -// delete this -template -inline void MirrorPadImpl(const Tensor &input, const Tensor &paddings, MirrorPadMode mode, - Tensor &output) -{ - auto const input_dims = input.shape().num_dims(); - auto const input_data = input.data(); - auto const paddings_data = paddings.data(); - auto const output_data = output.data(); - - auto const input_b = input_dims > 3 ? input.shape().dim(input_dims - 4) : 1; - auto const input_h = input_dims > 2 ? input.shape().dim(input_dims - 3) : 1; - auto const input_w = input_dims > 1 ? input.shape().dim(input_dims - 2) : 1; - auto const input_d = input.shape().dim(input_dims - 1); - - auto const input_h_offset = input_d * input_w; - auto const input_b_offset = input_h_offset * input_h; - - auto const output_b = input_dims > 3 ? output.shape().dim(input_dims - 4) : 1; - auto const output_h = input_dims > 2 ? output.shape().dim(input_dims - 3) : 1; - auto const output_w = input_dims > 1 ? output.shape().dim(input_dims - 2) : 1; - auto const output_d = output.shape().dim(input_dims - 1); - - auto const left_b_pad = paddings_data[2 * (input_dims - 4)]; - auto const left_h_pad = paddings_data[2 * (input_dims - 3)]; - auto const left_w_pad = paddings_data[2 * (input_dims - 2)]; - auto const left_d_pad = paddings_data[2 * (input_dims - 1)]; - - auto const right_b_pad = paddings_data[2 * (input_dims - 4) + 1]; - auto const right_h_pad = paddings_data[2 * (input_dims - 3) + 1]; - auto const right_w_pad = paddings_data[2 * (input_dims - 2) + 1]; - auto const right_d_pad = paddings_data[2 * (input_dims - 1) + 1]; - - const auto positive_mod = [](auto a, auto b) { return (a % b + b) % b; }; - const auto offset_index = [input_d, input_h_offset, input_b_offset](auto d, auto w, auto h, - auto b) { - return d + w * input_d + h * input_h_offset + b * input_b_offset; - }; - - const auto symmetric_dim = [&positive_mod](auto i, auto left_pad, auto input) { - bool reflected = (((i < left_pad ? i + 1 - input : i) - left_pad) / input & 1) == 1; - return positive_mod(reflected ? input + left_pad - i - 1 : i - left_pad, input); - }; - - const T *in_ptr = input_data; - T *out_ptr = output_data; - - for (int32_t b = 0; b < output_b; ++b) - { - for (int32_t h = 0; h < output_h; ++h) - { - for (int32_t w = 0; w < output_w; ++w) - { - for (int32_t d = 0; d < output_d; ++d) - { - if (b < left_b_pad || b >= output_b - right_b_pad || // - h < left_h_pad || h >= output_h - right_h_pad || // - w < left_w_pad || w >= output_w - right_w_pad || // - d < left_d_pad || d >= output_d - right_d_pad) - { - if (mode == MirrorPadMode::REFLECT) - { - *out_ptr++ = input_data[offset_index( - positive_mod(d - left_d_pad, input_d), positive_mod(w - left_w_pad, input_w), - positive_mod(h - left_h_pad, input_h), positive_mod(b - left_b_pad, input_b))]; - } - else - { - *out_ptr++ = input_data[offset_index( - symmetric_dim(d, left_d_pad, input_d), symmetric_dim(w, left_w_pad, input_w), - symmetric_dim(h, left_h_pad, input_h), symmetric_dim(b, left_b_pad, input_b))]; - } - } - else - { - *out_ptr++ = *in_ptr++; - } - } - } - } - } -} -#endif - } // namespace kernels } // namespace luci_interpreter From 4934752a079682183ab2fe6e43a85e9d86bc75cd Mon Sep 17 00:00:00 2001 From: Hyeongseok Oh Date: Thu, 8 Aug 2024 18:27:15 +0900 Subject: [PATCH 15/78] [onert] Remove type in Permute IR (#13589) This commit removes type in Permute IR. Permute IR represent copy operation in compilation phase, and can be changed dynamically on execution phase. ONE-DCO-1.0-Signed-off-by: Hyeongseok Oh --- .../onert/core/include/ir/operation/Permute.h | 34 +++++++++++-------- .../src/compiler/pass/ConstantOutputPass.cc | 2 +- .../core/src/compiler/pass/OddOutputPass.cc | 2 +- .../compiler/pass/PermutationInsertionPass.cc | 3 +- runtime/onert/core/src/ir/OperationDumper.cc | 14 +------- .../onert/core/src/ir/operation/Permute.cc | 4 +-- .../core/src/ir/train/operation/Permute.cc | 3 +- .../operation/UntrainableOperation.test.cc | 2 +- 8 files changed, 27 insertions(+), 37 deletions(-) diff --git a/runtime/onert/core/include/ir/operation/Permute.h b/runtime/onert/core/include/ir/operation/Permute.h index 10f09b9a03b..4866e9d1613 100644 --- a/runtime/onert/core/include/ir/operation/Permute.h +++ b/runtime/onert/core/include/ir/operation/Permute.h @@ -34,28 +34,32 @@ namespace ir namespace operation { +/** + * @brief Class to represent Permute operation + * @note Permute operation reorders the dimensions of a tensor. + * + * This operation is virtual operation, which is not used on real model, but used internally. + * It was introduced to support various model layout (NHWC, NCHW, etc) and backend layout. + * But currently, model layout and backend layout are always same as NHWC. + * So this operation is used for below cases. + * 1) Handle model output buffer's special case + * 1-1) Model output is comes from model constant + * 1-2) Model output is comes from model input + * 1-3) Model output shares tensor with other model output(s) + * 2) Handle shared tensor between different backend + * + * Q) Why name is still 'Permute'? + * A) It is handled as copy operation on compile phase, + * but it can be permute operation if output buffer layout is changed by API call + */ class Permute : public Operation { -public: - enum class Type - { - NHWC_TO_NCHW, - NCHW_TO_NHWC, - COPY - }; - public: void accept(OperationVisitor &v) const override; OpCode opcode() const final { return OpCode::Permute; } public: - Permute(const OperandIndex &input, const OperandIndex &output, Type type); - -public: - Type getPermuteType() const { return _type; } - -private: - Type _type; + Permute(const OperandIndex &input, const OperandIndex &output); }; } // namespace operation diff --git a/runtime/onert/core/src/compiler/pass/ConstantOutputPass.cc b/runtime/onert/core/src/compiler/pass/ConstantOutputPass.cc index 1448de47354..0e961c62316 100644 --- a/runtime/onert/core/src/compiler/pass/ConstantOutputPass.cc +++ b/runtime/onert/core/src/compiler/pass/ConstantOutputPass.cc @@ -41,7 +41,7 @@ void ConstantOutputPass::callback(const ir::OperandIndex &ind, ir::Operand &obj) obj.info().setAsNonConst(); using ir::operation::Permute; - auto permute_obj = std::make_unique(permute_input_ind, ind, Permute::Type::COPY); + auto permute_obj = std::make_unique(permute_input_ind, ind); auto permute_ind = _graph.operations().push(std::move(permute_obj)); permute_input_obj.insertUse(permute_ind); diff --git a/runtime/onert/core/src/compiler/pass/OddOutputPass.cc b/runtime/onert/core/src/compiler/pass/OddOutputPass.cc index e2b3f6111ed..5aabd2aa202 100644 --- a/runtime/onert/core/src/compiler/pass/OddOutputPass.cc +++ b/runtime/onert/core/src/compiler/pass/OddOutputPass.cc @@ -71,7 +71,7 @@ ir::OperandIndex OddOutputPass::insertPermute(ir::OperandIndex ind) auto &output_obj = _graph.operands().at(output_ind); using ir::operation::Permute; - auto permute_obj = std::make_unique(ind, output_ind, Permute::Type::COPY); + auto permute_obj = std::make_unique(ind, output_ind); auto permute_ind = _graph.operations().push(std::move(permute_obj)); output_obj.setDef(permute_ind); diff --git a/runtime/onert/core/src/compiler/pass/PermutationInsertionPass.cc b/runtime/onert/core/src/compiler/pass/PermutationInsertionPass.cc index c95d07b421e..68ee497b36e 100644 --- a/runtime/onert/core/src/compiler/pass/PermutationInsertionPass.cc +++ b/runtime/onert/core/src/compiler/pass/PermutationInsertionPass.cc @@ -150,8 +150,7 @@ ir::OperationIndex PermutationInsertionPass::insertPermute(const ir::OperandInde // Insert permute operation to the graph using Permute = ir::operation::Permute; - auto insert_node = - std::make_unique(operand_index, out_operand_index, Permute::Type::COPY); + auto insert_node = std::make_unique(operand_index, out_operand_index); auto node_index = _graph.operations().push(std::move(insert_node)); diff --git a/runtime/onert/core/src/ir/OperationDumper.cc b/runtime/onert/core/src/ir/OperationDumper.cc index 5aa4693adaf..e0f28795b9d 100644 --- a/runtime/onert/core/src/ir/OperationDumper.cc +++ b/runtime/onert/core/src/ir/OperationDumper.cc @@ -268,20 +268,8 @@ void OperationDumper::visit(const Pad &node) void OperationDumper::visit(const Permute &node) { std::string permute_type = "Unknown"; - switch (node.getPermuteType()) - { - case Permute::Type::COPY: - permute_type = "Copy"; - break; - case Permute::Type::NHWC_TO_NCHW: - permute_type = "NHWC to NCHW"; - break; - case Permute::Type::NCHW_TO_NHWC: - permute_type = "NCHW to NHWC"; - break; - } - VERBOSE(LIR) << "* Permute(" + permute_type + ")" << std::endl; + VERBOSE(LIR) << "* " << node.name() << std::endl; VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(0) << ")" << std::endl; VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0) << ")" << std::endl; } diff --git a/runtime/onert/core/src/ir/operation/Permute.cc b/runtime/onert/core/src/ir/operation/Permute.cc index 813fbaf30ad..77ec42125c7 100644 --- a/runtime/onert/core/src/ir/operation/Permute.cc +++ b/runtime/onert/core/src/ir/operation/Permute.cc @@ -26,8 +26,8 @@ namespace operation void Permute::accept(OperationVisitor &v) const { v.visit(*this); } -Permute::Permute(const OperandIndex &input, const OperandIndex &output, Type type) - : Operation{OperandConstraint::createExact(1u)}, _type{type} +Permute::Permute(const OperandIndex &input, const OperandIndex &output) + : Operation{OperandConstraint::createExact(1u)} { setInputs({input}); setOutputs({output}); diff --git a/runtime/onert/core/src/ir/train/operation/Permute.cc b/runtime/onert/core/src/ir/train/operation/Permute.cc index adc23aa49b7..b1dfcec0336 100644 --- a/runtime/onert/core/src/ir/train/operation/Permute.cc +++ b/runtime/onert/core/src/ir/train/operation/Permute.cc @@ -38,8 +38,7 @@ void Permute::accept(OperationVisitor &v) const { v.visit(*this); } void Permute::accept(TrainableOperationVisitor &v) const { v.visit(*this); } Permute::Permute(const OperationType &operation) - : OperationType{operation.getInputs().at(0), operation.getOutputs().at(0), - operation.getPermuteType()} + : OperationType{operation.getInputs().at(0), operation.getOutputs().at(0)} { // DO NOTHING } diff --git a/runtime/onert/core/src/ir/train/operation/UntrainableOperation.test.cc b/runtime/onert/core/src/ir/train/operation/UntrainableOperation.test.cc index e3472ec51e9..4a6267b0a34 100644 --- a/runtime/onert/core/src/ir/train/operation/UntrainableOperation.test.cc +++ b/runtime/onert/core/src/ir/train/operation/UntrainableOperation.test.cc @@ -332,7 +332,7 @@ operation::Pad generatePad() operation::Permute generatePermute() { - return operation::Permute{OperandIndex{1}, OperandIndex{0}, operation::Permute::Type::COPY}; + return operation::Permute{OperandIndex{1}, OperandIndex{0}}; } operation::Pool2D generatePool2D() From d1149f435595ca2f974bf31516f47f8485a95b2b Mon Sep 17 00:00:00 2001 From: Hyeongseok Oh Date: Thu, 8 Aug 2024 20:29:30 +0900 Subject: [PATCH 16/78] [github] Update android build workflow (#13618) This commit updates android build workflow - Trigger on push event - Revise path to trigger workflow - Add hash for external cache key matching ONE-DCO-1.0-Signed-off-by: Hyeongseok Oh --- .github/workflows/run-onert-android-build.yml | 38 ++++++++++++------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/.github/workflows/run-onert-android-build.yml b/.github/workflows/run-onert-android-build.yml index bfbbe857dac..16d40e90c6f 100644 --- a/.github/workflows/run-onert-android-build.yml +++ b/.github/workflows/run-onert-android-build.yml @@ -1,29 +1,38 @@ name: Run ONERT Android Release Build on: + push: + branches: + - master + - release/* + paths: + - '.github/workflows/run-onert-android-build.yml' + - 'nn*' + - 'Makefile.template' + - 'compute/**' + - 'infra/buildtool/**' + - 'infra/cmake/**' + - 'infra/nncc/**' + - 'infra/nnfw/**' + - 'runtime/**' + - 'tests/**' + - '!**/*.md' pull_request: branches: - master - release/* paths: - '.github/workflows/run-onert-android-build.yml' - - 'nnas' - - 'nnfw' + - 'nn*' - 'Makefile.template' - 'compute/**' - - 'infra/**' - - '!infra/debian/**' - - '!infra/docker/**' - - '!infra/doxygen/**' - - '!infra/git-hooks/**' - - '!infra/nncc/**' - - '!infra/onert-micro/**' - - '!infra/packaging/**' - - 'nnpackage/**' - - '!nnpackage/spec/**' + - 'infra/buildtool/**' + - 'infra/cmake/**' + - 'infra/nncc/**' + - 'infra/nnfw/**' - 'runtime/**' - 'tests/**' - - '!**.md' + - '!**/*.md' defaults: run: @@ -45,8 +54,9 @@ jobs: uses: actions/cache@v4 with: path: externals - key: external-onert-ndk26 + key: external-onert-ndk26-${{ hashFiles('infra/cmake/packages/**/*.cmake') }}-${{ hashFiles('infra/nnfw/cmake/packages/**/*.cmake') }} restore-keys: | + external-onert-ndk26- external-onert-ndk external-onert- external- From 8cc010346bf6c65c223dc0563e5dc0f3c631e8eb Mon Sep 17 00:00:00 2001 From: SaeHie Park Date: Fri, 9 Aug 2024 13:25:07 +0900 Subject: [PATCH 17/78] [res] Introduce tflite schema 2.16.1 (#13633) This will introduce tflite schema 2.16.1. ONE-DCO-1.0-Signed-off-by: SaeHie Park --- res/TensorFlowLiteSchema/2.16.1/schema.fbs | 1642 ++++++++++++++++++++ 1 file changed, 1642 insertions(+) create mode 100644 res/TensorFlowLiteSchema/2.16.1/schema.fbs diff --git a/res/TensorFlowLiteSchema/2.16.1/schema.fbs b/res/TensorFlowLiteSchema/2.16.1/schema.fbs new file mode 100644 index 00000000000..382462f938d --- /dev/null +++ b/res/TensorFlowLiteSchema/2.16.1/schema.fbs @@ -0,0 +1,1642 @@ +// 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. + +// Revision History +// Version 0: Initial version. +// Version 1: Add subgraphs to schema. +// Version 2: Rename operators to conform to NN API. +// Version 3: Move buffer data from Model.Subgraph.Tensors to Model.Buffers. +// Version 3a: Add new builtin op code field. Has backward compatibility with +// version 3. +// Version 3b: Rename fields in SignatureDef. Has backward compatibility with +// version 3 and 3a. +// Version 3c: Move constant tensor buffers & custom op buffers outside from +// Flatbuffers. Has backward compatibility with version 3, 3a and +// 3b. + +namespace tflite; + +// This corresponds to the version. +file_identifier "TFL3"; +// File extension of any written files. +file_extension "tflite"; + +// IMPORTANT: All new members of tables, enums and unions must be added at the +// end to ensure backwards compatibility. + +// The type of data stored in a tensor. +enum TensorType : byte { + FLOAT32 = 0, + FLOAT16 = 1, + INT32 = 2, + UINT8 = 3, + INT64 = 4, + STRING = 5, + BOOL = 6, + INT16 = 7, + COMPLEX64 = 8, + INT8 = 9, + FLOAT64 = 10, + COMPLEX128 = 11, + UINT64 = 12, + // Experimental: Resource and variant types are experimental, that are subject + // to change. Do not implement custom kernels using resource & variant types + // now. + RESOURCE = 13, + VARIANT = 14, + UINT32 = 15, + UINT16 = 16, + INT4 = 17, +} + +// Custom quantization parameters for experimenting with new quantization +// techniques. +table CustomQuantization { + custom:[ubyte] (force_align: 16); +} + +// Represents a specific quantization technique's parameters. +union QuantizationDetails { + CustomQuantization, +} + +// Parameters for converting a quantized tensor back to float. +table QuantizationParameters { + // These four parameters are the asymmetric linear quantization parameters. + // Given a quantized value q, the corresponding float value f should be: + // f = scale * (q - zero_point) + // For other quantization types, the QuantizationDetails below is used. + min:[float]; // For importing back into tensorflow. + max:[float]; // For importing back into tensorflow. + scale:[float]; // For dequantizing the tensor's values. + zero_point:[long]; + + // If this is not none, the other quantization parameters (i.e. min, max, + // scale, zero_point fields above) are ignored and the value of the + // QuantizationDetails union should be used. + details:QuantizationDetails; + + // Specifies the dimension of the Tensor's shape that the scales and + // zero_points correspond to. For example, a tensor t, with dims=[4, 3, 2, 1] + // with quantization params: + // scale=[1.0, 2.0, 3.0], zero_point=[1, 2, 3], quantization_dimension=1 + // will be quantized across the second dimension of t. + // t[:, 0, :, :] will have scale[0]=1.0, zero_point[0]=1 + // t[:, 1, :, :] will have scale[1]=2.0, zero_point[0]=2 + // t[:, 2, :, :] will have scale[2]=3.0, zero_point[0]=3 + quantized_dimension:int; +} + +// Sparse tensors. +// We use a modification of the TACO format. +// Reference: http://tensor-compiler.org/kjolstad-oopsla17-tensor-compiler.pdf +// +// To encode a conceptual n-dimensional dense tensor with dims (d0, ..., dn-1), +// potentially with a k-dimensional block (0 <= k <= n) with dims +// (dn, ..., dn+k-1), the format needs to specify: +// 1. In what order to traverse these dimensions. For example, to store a 2-D +// matrix in row major order, the traversal order would be (d0, d1), +// whereas to store it in column major order, the traversal order would be +// (d1, d0). If the 2-D matrix has a 2-D inner block, the traversal order +// could be (d0, d1, d2, d3). +// 2. How each block dimension in (dn, ..., dn+k-1) maps to the original +// tensor dimension in (d0, ..., dn-1). +// 3. In the traversal order defined above, the format (dense vs. sparse) and +// index metadata for each dimension. For a dense dimension, this is just +// the size of that dimension. For a sparse dimension, it's the same as +// the compressed index defined in the Compressed Sparse Row (CSR) format. +// (http://scipy-lectures.org/advanced/scipy_sparse/csr_matrix.html) + +// The storage type for a dimension. Currently we support: +// 1. DENSE: each coordinate in this dimension is stored implicitly. +// 2. SPARSE_CSR: only the coordinates with non-zero elements are stored. The +// compression technique is the same what CSR uses. +// More types like a sparse dimension with a different compression technique +// could be added to the list in the future. +enum DimensionType : byte { + DENSE = 0, + SPARSE_CSR = 1, +} + +table Int32Vector { + values:[int]; +} + +table Uint16Vector { + values:[ushort] (force_align: 4); +} + +table Uint8Vector { + values:[ubyte] (force_align: 4); +} + +// Variable-typed buffer to store the index metadata for a sparse dimension. +// The widest type is Int32 instead of UInt32 because tensor's shape is a int32 +// vector. We don't want the per-dimensional index to overflow that range. +union SparseIndexVector { + Int32Vector, + Uint16Vector, + Uint8Vector +} + +table DimensionMetadata { + // Whether a dimension is dense or sparse. + format:DimensionType; + // Index metadata used for a dimension. + // - If format is DimensionType.DENSE then we use the dense_size field to + // store the size of that dimension. Each index in that dimension is + // stored implicitly. + // - If format is DimensionType.SPARSE_CSR then we use array_segments and + // array_indices to encode that dimension. array_segments represents how + // to segment the indices array, each segment corresponds to one element + // in the previous dimension. array_indices represents the index of the + // non-zero elements within this dimension (as those in the CSR matrix + // format, where the first array is row pointers and the second array is + // column indices). + dense_size:int; + array_segments:SparseIndexVector; + array_indices:SparseIndexVector; +} + +// Parameters to encode a sparse TfLite tensor. +table SparsityParameters { + // The traversal order of the dimensions defined in the `shape` field of the + // conceptual dense tensor. For a n-dimensional tensors with dims (d0, d1, + // ..., dn-1), + // - if not block sparse, the traversal_order is just a permutation of (d0, + // ..., dn-1). For example, a 2-D matrix stored in row-major order would + // have traversal_order = (d0, d1). + // - if block sparse with a k-dimensional block (0 <= k <= n), the + // traversal_order has n + k elements. The first n elements are still a + // permutation of (d0, ..., dn-1). The lask k elements are a permutation + // of (dn, ..., dn+k-1), defining how to traverse a block internally. For + // example, a 2-D matrix with 2-D blocks, both stored in row-major order + // would have traversal_order = (d0, d1, d2, d3). + traversal_order:[int]; + // For an n-dimensional tensor with a k-dimensional block (0 <= k <= n), + // stores how a block dimension in (dn, ..., dn+k-1) maps to the original + // tensor dimension in (d0, ..., dn). + // It's stored in the order of (dn, ..., dn+k-1). + // If not block-sparse, this field is NULL. + block_map:[int]; + // In the traversal order defined above, the metadata needed for + // each dimension to locate the non-zero values in the original dense tensor. + // The size of the dim_metadata array = the size of the traversal_order array + // = n + k. + dim_metadata:[DimensionMetadata]; +} + +// The nested tensor type for VARIANT type. +table VariantSubType { + // The tensor shape. + shape:[int]; + type:TensorType; + // If false, the rank or the number of tensor dimensions is unknown. + // If false, "shape" must be []. + has_rank: bool = false; +} + +table Tensor { + // The tensor shape. The meaning of each entry is operator-specific but + // builtin ops use: [batch size, height, width, number of channels] (That's + // Tensorflow's NHWC). + shape:[int]; + type:TensorType; + // An index that refers to the buffers table at the root of the model. Or, + // if there is no data buffer associated (i.e. intermediate results), then + // this is 0 (which refers to an always existent empty buffer). + // + // The data_buffer itself is an opaque container, with the assumption that the + // target device is little-endian. In addition, all builtin operators assume + // the memory is ordered such that if `shape` is [4, 3, 2], then index + // [i, j, k] maps to data_buffer[i*3*2 + j*2 + k]. + buffer:uint; + name:string; // For debugging and importing back into tensorflow. + quantization:QuantizationParameters; // Optional. + + is_variable:bool = false; + + // Parameters to encode a sparse tensor. See the example in + // tensorflow/lite/testdata/sparse_tensor.json. + sparsity:SparsityParameters; // Optional. + + // Encodes `shape` with unknown dimensions. Unknown dimensions are + // represented with -1. + shape_signature:[int]; // Optional. + + // This field is added to distinguish between scalars and tensors of unknown + // ranks (both of which shape is []). + // For scalars (rank = 0), shape = [] and has_rank = true. + // For tensors with known rank (rank > 0) and shape, shape = [...] and + // has_rank = true. + // For tensors with unknown rank and shape, shape = [] and has_rank = false. + has_rank: bool = false; + + // The nested Tensor types for VARIANT type. This is always empty for + // non-VARIANT types. This is optional because the nested type can be omitted. + // Currently only 1 subtype is supported. The field is defined as an array for + // flexibility of supporting multiple subtypes in the future. + variant_tensors:[VariantSubType]; +} + +// A list of builtin operators. Builtin operators are slightly faster than custom +// ones, but not by much. Moreover, while custom operators accept an opaque +// object containing configuration parameters, builtins have a predetermined +// set of acceptable options. +// LINT.IfChange +enum BuiltinOperator : int32 { + ADD = 0, + AVERAGE_POOL_2D = 1, + CONCATENATION = 2, + CONV_2D = 3, + DEPTHWISE_CONV_2D = 4, + DEPTH_TO_SPACE = 5, + DEQUANTIZE = 6, + EMBEDDING_LOOKUP = 7, + FLOOR = 8, + FULLY_CONNECTED = 9, + HASHTABLE_LOOKUP = 10, + L2_NORMALIZATION = 11, + L2_POOL_2D = 12, + LOCAL_RESPONSE_NORMALIZATION = 13, + LOGISTIC = 14, + LSH_PROJECTION = 15, + LSTM = 16, + MAX_POOL_2D = 17, + MUL = 18, + RELU = 19, + // NOTE(aselle): RELU_N1_TO_1 used to be called RELU1, but it was renamed + // since different model developers use RELU1 in different ways. Never + // create another op called RELU1. + RELU_N1_TO_1 = 20, + RELU6 = 21, + RESHAPE = 22, + RESIZE_BILINEAR = 23, + RNN = 24, + SOFTMAX = 25, + SPACE_TO_DEPTH = 26, + SVDF = 27, + TANH = 28, + CONCAT_EMBEDDINGS = 29, + SKIP_GRAM = 30, + CALL = 31, + CUSTOM = 32, + EMBEDDING_LOOKUP_SPARSE = 33, + PAD = 34, + UNIDIRECTIONAL_SEQUENCE_RNN = 35, + GATHER = 36, + BATCH_TO_SPACE_ND = 37, + SPACE_TO_BATCH_ND = 38, + TRANSPOSE = 39, + MEAN = 40, + SUB = 41, + DIV = 42, + SQUEEZE = 43, + UNIDIRECTIONAL_SEQUENCE_LSTM = 44, + STRIDED_SLICE = 45, + BIDIRECTIONAL_SEQUENCE_RNN = 46, + EXP = 47, + TOPK_V2 = 48, + SPLIT = 49, + LOG_SOFTMAX = 50, + // DELEGATE is a special op type for the operations which are delegated to + // other backends. + // WARNING: Experimental interface, subject to change + DELEGATE = 51, + BIDIRECTIONAL_SEQUENCE_LSTM = 52, + CAST = 53, + PRELU = 54, + MAXIMUM = 55, + ARG_MAX = 56, + MINIMUM = 57, + LESS = 58, + NEG = 59, + PADV2 = 60, + GREATER = 61, + GREATER_EQUAL = 62, + LESS_EQUAL = 63, + SELECT = 64, + SLICE = 65, + SIN = 66, + TRANSPOSE_CONV = 67, + SPARSE_TO_DENSE = 68, + TILE = 69, + EXPAND_DIMS = 70, + EQUAL = 71, + NOT_EQUAL = 72, + LOG = 73, + SUM = 74, + SQRT = 75, + RSQRT = 76, + SHAPE = 77, + POW = 78, + ARG_MIN = 79, + FAKE_QUANT = 80, + REDUCE_PROD = 81, + REDUCE_MAX = 82, + PACK = 83, + LOGICAL_OR = 84, + ONE_HOT = 85, + LOGICAL_AND = 86, + LOGICAL_NOT = 87, + UNPACK = 88, + REDUCE_MIN = 89, + FLOOR_DIV = 90, + REDUCE_ANY = 91, + SQUARE = 92, + ZEROS_LIKE = 93, + FILL = 94, + FLOOR_MOD = 95, + RANGE = 96, + RESIZE_NEAREST_NEIGHBOR = 97, + LEAKY_RELU = 98, + SQUARED_DIFFERENCE = 99, + MIRROR_PAD = 100, + ABS = 101, + SPLIT_V = 102, + UNIQUE = 103, + CEIL = 104, + REVERSE_V2 = 105, + ADD_N = 106, + GATHER_ND = 107, + COS = 108, + WHERE = 109, + RANK = 110, + ELU = 111, + REVERSE_SEQUENCE = 112, + MATRIX_DIAG = 113, + QUANTIZE = 114, + MATRIX_SET_DIAG = 115, + ROUND = 116, + HARD_SWISH = 117, + IF = 118, + WHILE = 119, + NON_MAX_SUPPRESSION_V4 = 120, + NON_MAX_SUPPRESSION_V5 = 121, + SCATTER_ND = 122, + SELECT_V2 = 123, + DENSIFY = 124, + SEGMENT_SUM = 125, + BATCH_MATMUL = 126, + PLACEHOLDER_FOR_GREATER_OP_CODES = 127, + CUMSUM = 128, + CALL_ONCE = 129, + BROADCAST_TO = 130, + RFFT2D = 131, + CONV_3D = 132, + IMAG=133, + REAL=134, + COMPLEX_ABS=135, + HASHTABLE = 136, + HASHTABLE_FIND = 137, + HASHTABLE_IMPORT = 138, + HASHTABLE_SIZE = 139, + REDUCE_ALL = 140, + CONV_3D_TRANSPOSE = 141, + VAR_HANDLE = 142, + READ_VARIABLE = 143, + ASSIGN_VARIABLE = 144, + BROADCAST_ARGS = 145, + RANDOM_STANDARD_NORMAL = 146, + BUCKETIZE = 147, + RANDOM_UNIFORM = 148, + MULTINOMIAL = 149, + GELU = 150, + DYNAMIC_UPDATE_SLICE = 151, + RELU_0_TO_1 = 152, + UNSORTED_SEGMENT_PROD = 153, + UNSORTED_SEGMENT_MAX = 154, + UNSORTED_SEGMENT_SUM = 155, + ATAN2 = 156, + UNSORTED_SEGMENT_MIN = 157, + SIGN = 158, + BITCAST = 159, + BITWISE_XOR = 160, + RIGHT_SHIFT = 161, + // All Operators start with STABLEHLO_ prefixes are subject to change + // Many of the ops below can not be executed by TFlite runtime + STABLEHLO_LOGISTIC = 162, // WARNING: Do not have runtime support + STABLEHLO_ADD = 163, + STABLEHLO_DIVIDE = 164, // WARNING: No runtime support yet + STABLEHLO_MULTIPLY = 165, + STABLEHLO_MAXIMUM = 166, + STABLEHLO_RESHAPE = 167, // WARNING: No runtime support yet + STABLEHLO_CLAMP = 168, // WARNING: No runtime support + STABLEHLO_CONCATENATE = 169, // WARNING: No runtime support + STABLEHLO_BROADCAST_IN_DIM = 170, // WARNING: No runtime support + STABLEHLO_CONVOLUTION = 171, // WARNING: No runtime support + STABLEHLO_SLICE = 172, // WARNING: No runtime support + STABLEHLO_CUSTOM_CALL = 173, // WARNING: No runtime support + STABLEHLO_REDUCE = 174, // WARNING: No runtime support + STABLEHLO_ABS = 175, // WARNING: No runtime support + STABLEHLO_AND = 176, // WARNING: No runtime support + STABLEHLO_COSINE = 177, // WARNING: No runtime support + STABLEHLO_EXPONENTIAL = 178, // WARNING: No runtime support + STABLEHLO_FLOOR = 179, // WARNING: No runtime support + STABLEHLO_LOG = 180, // WARNING: No runtime support + STABLEHLO_MINIMUM = 181, + STABLEHLO_NEGATE = 182, // WARNING: No runtime support + STABLEHLO_OR = 183, // WARNING: No runtime support + STABLEHLO_POWER = 184, // WARNING: No runtime support + STABLEHLO_REMAINDER = 185, // WARNING: No runtime support + STABLEHLO_RSQRT = 186, // WARNING: No runtime support + STABLEHLO_SELECT = 187, // WARNING: No runtime support + STABLEHLO_SUBTRACT = 188, // WARNING: No runtime support + STABLEHLO_TANH = 189, // WARNING: No runtime support + STABLEHLO_SCATTER = 190, + STABLEHLO_COMPARE = 191, // WARNING: No runtime support + STABLEHLO_CONVERT = 192, // WARNING: No runtime support + STABLEHLO_DYNAMIC_SLICE = 193, // WARNING: No runtime support + STABLEHLO_DYNAMIC_UPDATE_SLICE = 194, // WARNING: No runtime support + STABLEHLO_PAD = 195, + STABLEHLO_IOTA = 196, // WARNING: No runtime support + STABLEHLO_DOT_GENERAL = 197, // WARNING: No runtime support + STABLEHLO_REDUCE_WINDOW = 198, + STABLEHLO_SORT = 199, // WARNING: No runtime support + STABLEHLO_WHILE = 200, // WARNING: No runtime support + STABLEHLO_GATHER = 201, + STABLEHLO_TRANSPOSE = 202, // WARNING: No runtime support + DILATE = 203, + STABLEHLO_RNG_BIT_GENERATOR = 204, + REDUCE_WINDOW = 205 (deprecated), +} +// LINT.ThenChange(nnapi_linter/linter.proto) + +// Options for the builtin operators. +union BuiltinOptions { + Conv2DOptions, + DepthwiseConv2DOptions, + ConcatEmbeddingsOptions, + LSHProjectionOptions, + Pool2DOptions, + SVDFOptions, + RNNOptions, + FullyConnectedOptions, + SoftmaxOptions, + ConcatenationOptions, + AddOptions, + L2NormOptions, + LocalResponseNormalizationOptions, + LSTMOptions, + ResizeBilinearOptions, + CallOptions, + ReshapeOptions, + SkipGramOptions, + SpaceToDepthOptions, + EmbeddingLookupSparseOptions, + MulOptions, + PadOptions, + GatherOptions, + BatchToSpaceNDOptions, + SpaceToBatchNDOptions, + TransposeOptions, + ReducerOptions, + SubOptions, + DivOptions, + SqueezeOptions, + SequenceRNNOptions, + StridedSliceOptions, + ExpOptions, + TopKV2Options, + SplitOptions, + LogSoftmaxOptions, + CastOptions, + DequantizeOptions, + MaximumMinimumOptions, + ArgMaxOptions, + LessOptions, + NegOptions, + PadV2Options, + GreaterOptions, + GreaterEqualOptions, + LessEqualOptions, + SelectOptions, + SliceOptions, + TransposeConvOptions, + SparseToDenseOptions, + TileOptions, + ExpandDimsOptions, + EqualOptions, + NotEqualOptions, + ShapeOptions, + PowOptions, + ArgMinOptions, + FakeQuantOptions, + PackOptions, + LogicalOrOptions, + OneHotOptions, + LogicalAndOptions, + LogicalNotOptions, + UnpackOptions, + FloorDivOptions, + SquareOptions, + ZerosLikeOptions, + FillOptions, + BidirectionalSequenceLSTMOptions, + BidirectionalSequenceRNNOptions, + UnidirectionalSequenceLSTMOptions, + FloorModOptions, + RangeOptions, + ResizeNearestNeighborOptions, + LeakyReluOptions, + SquaredDifferenceOptions, + MirrorPadOptions, + AbsOptions, + SplitVOptions, + UniqueOptions, + ReverseV2Options, + AddNOptions, + GatherNdOptions, + CosOptions, + WhereOptions, + RankOptions, + ReverseSequenceOptions, + MatrixDiagOptions, + QuantizeOptions, + MatrixSetDiagOptions, + HardSwishOptions, + IfOptions, + WhileOptions, + DepthToSpaceOptions, + NonMaxSuppressionV4Options, + NonMaxSuppressionV5Options, + ScatterNdOptions, + SelectV2Options, + DensifyOptions, + SegmentSumOptions, + BatchMatMulOptions, + CumsumOptions, + CallOnceOptions, + BroadcastToOptions, + Rfft2dOptions, + Conv3DOptions, + HashtableOptions, + HashtableFindOptions, + HashtableImportOptions, + HashtableSizeOptions, + VarHandleOptions, + ReadVariableOptions, + AssignVariableOptions, + RandomOptions, + BucketizeOptions, + GeluOptions, + DynamicUpdateSliceOptions, + UnsortedSegmentProdOptions, + UnsortedSegmentMaxOptions, + UnsortedSegmentMinOptions, + UnsortedSegmentSumOptions, + ATan2Options, + SignOptions, + BitcastOptions, + BitwiseXorOptions, + RightShiftOptions, + // DO NOT add new options this union, will cause failure in Java api + // generation otherwise + // Add new builtin options into builtin options 2 instead +} + +union BuiltinOptions2{ + StablehloConcatenateOptions, + StablehloBroadcastInDimOptions, + StablehloSliceOptions, + StablehloConvolutionOptions, + StablehloCustomCallOptions, + StablehloReduceOptions, + StablehloScatterOptions, + StablehloCompareOptions, + StablehloDynamicSliceOptions, + StablehloPadOptions, + StablehloIotaOptions, + StablehloDotGeneralOptions, + StablehloReduceWindowOptions, + StablehloSortOptions, + StablehloWhileOptions, + StablehloGatherOptions, + StablehloTransposeOptions, + DilateOptions, + StablehloRngBitGeneratorOptions, + ReduceWindowOptions (deprecated), +} + +table StablehloGatherOptions{ + offset_dims : [long]; + collapsed_slice_dims : [long]; + start_index_map : [long]; + index_vector_dim : long; + slice_sizes : [long]; + indices_are_sorted : bool; +} + +table StablehloTransposeOptions{ + permutation : [long]; +} + +enum StablehloPrecisionConfig : uint { + DEFAULT, + HIGH, + HIGHEST, +} + +table StablehloDotGeneralOptions{ + lhs_batching_dimensions : [long]; + rhs_batching_dimensions : [long]; + lhs_contracting_dimensions : [long]; + rhs_contracting_dimensions : [long]; + precision_config : [StablehloPrecisionConfig]; +} + +table StablehloReduceWindowOptions{ + window_dimensions : [long]; + window_strides : [long]; + base_dilations : [long]; + window_dilations : [long]; + padding : [long]; + body_subgraph_index : int; +} + +table StablehloWhileOptions{ + cond_subgraph_index : int; + body_subgraph_index : int; +} + +table StablehloSortOptions{ + dimension : long; + is_stable : bool; + comparator_subgraph_index : int; +} + +table StablehloConcatenateOptions { + dimension : long; +} + +table StablehloBroadcastInDimOptions{ + broadcast_dimensions : [long]; +} + +enum StablehloComparisonDirection : uint { + STABLEHLO_COMPARISON_DIRECTION_EQ, + STABLEHLO_COMPARISON_DIRECTION_NE, + STABLEHLO_COMPARISON_DIRECTION_GE, + STABLEHLO_COMPARISON_DIRECTION_GT, + STABLEHLO_COMPARISON_DIRECTION_LE, + STABLEHLO_COMPARISON_DIRECTION_LT, + +} + +enum StablehloComparisonType : uint { + STABLEHLO_COMPARISON_TYPE_NOTYPE, + STABLEHLO_COMPARISON_TYPE_FLOAT, + STABLEHLO_COMPARISON_TYPE_FLOAT_TOTAL_ORDER, + STABLEHLO_COMPARISON_TYPE_SIGNED, + STABLEHLO_COMPARISON_TYPE_UNSIGNED, +} + +table StablehloCompareOptions{ + comparison_direction : StablehloComparisonDirection; + compare_type : StablehloComparisonType; +} + +table StablehloDynamicSliceOptions{ + slice_sizes : [long]; +} + +table StablehloPadOptions{ + edge_padding_low : [long]; + edge_padding_high : [long]; + interior_padding : [long]; +} + +table StablehloIotaOptions{ + iota_dimension : long; +} + +table StablehloCustomCallOptions { + call_target_name : string; + has_side_effect : bool; + backend_config: string; + api_version : int; // will be decprecated + called_computations: [int]; // should point to subgraphs of the computations + custom_attributes : [ubyte]; +} + +table StablehloReduceOptions { + dimensions : [long]; + body_subgraph_index : int; +} + +table StablehloSliceOptions{ + start_indices : [long]; + limit_indices : [long]; + strides : [long]; +} + +table StablehloConvolutionOptions{ + window_strides : [long]; + padding : [long]; + lhs_dilation : [long]; + rhs_dilation : [long]; + window_reversal : [bool]; + input_batch_dimension : long; + input_feature_dimension : long; + input_spatial_dimensions : [long]; + kernel_input_feature_dimension : long; + kernel_output_feature_dimension : long; + kernel_spatial_dimensions : [long]; + output_batch_dimension : long; + output_feature_dimension : long; + output_spatial_dimensions : [long]; + feature_group_count : long; + batch_group_count : long; + precision_config : [StablehloPrecisionConfig]; +} + +table StablehloScatterOptions { + indices_are_sorted: bool; + update_window_dims: [long]; + inserted_window_dims: [long]; + scatter_dims_to_operand_dims: [long]; + index_vector_dim: long; + unique_indices: bool; + update_computation_subgraph_index: int; +} + +enum RngAlgorithm : byte { + // An algorithm auto-selected by the system according to device type. + DEFAULT = 0, + // The Philox algorithm, as described in paper + // ['Parallel Random Numbers: As Easy as 1, 2, 3'] + // (https://www.thesalmons.org/john/random123/papers/random123sc11.pdf) + PHILOX = 1, + // The ThreeFry algorithm, as described in paper + // ['Parallel Random Numbers: As Easy as 1, 2, 3'] + // (https://www.thesalmons.org/john/random123/papers/random123sc11.pdf) + THREEFRY = 2, +} + +table StablehloRngBitGeneratorOptions { + algorithm:RngAlgorithm; +} + +// LINT.IfChange +enum Padding : byte { SAME, VALID } +// LINT.ThenChange(//tensorflow/compiler/mlir/lite/ir/tfl_op_enums.td) + +// LINT.IfChange +enum ActivationFunctionType : byte { + NONE = 0, + RELU = 1, + RELU_N1_TO_1 = 2, + RELU6 = 3, + TANH = 4, + SIGN_BIT = 5, +} +// LINT.ThenChange(//tensorflow/compiler/mlir/lite/ir/tfl_op_enums.td) + +table Conv2DOptions { + padding:Padding; + stride_w:int; + stride_h:int; + fused_activation_function:ActivationFunctionType; + dilation_w_factor:int = 1; + dilation_h_factor:int = 1; + // Parameters for Conv2D version 8 or above. + // When set, quantized_bias_type defines the dtype for both bias and accumulator. + quantized_bias_type: TensorType; +} + +// Options for both Conv3D and Conv3DTranspose. +table Conv3DOptions { + padding:Padding; + stride_d:int; + stride_w:int; + stride_h:int; + fused_activation_function:ActivationFunctionType; + dilation_d_factor:int = 1; + dilation_w_factor:int = 1; + dilation_h_factor:int = 1; +} + +table Pool2DOptions { + padding:Padding; + stride_w:int; + stride_h:int; + filter_width:int; + filter_height:int; + fused_activation_function:ActivationFunctionType; +} + +table DepthwiseConv2DOptions { + // Parameters for DepthwiseConv version 1 or above. + padding:Padding; + stride_w:int; + stride_h:int; + // `depth_multiplier` is redundant. It's used by CPU kernels in + // TensorFlow 2.0 or below, but ignored in versions above. + // See comments in lite/c/builtin_op_data.h for more details. + depth_multiplier:int; + fused_activation_function:ActivationFunctionType; + // Parameters for DepthwiseConv version 2 or above. + dilation_w_factor:int = 1; + dilation_h_factor:int = 1; +} + +table ConcatEmbeddingsOptions { + num_channels:int; + num_columns_per_channel:[int]; + embedding_dim_per_channel:[int]; // This could be inferred from parameters. +} + +enum LSHProjectionType: byte { + UNKNOWN = 0, + SPARSE = 1, + DENSE = 2, +} + +table LSHProjectionOptions { + type: LSHProjectionType; +} + +table SVDFOptions { + rank:int; + fused_activation_function:ActivationFunctionType; + // For weights-only quantization, use asymmetric quantization for non + // constant inputs at evaluation time. + asymmetric_quantize_inputs:bool; +} + +// An implementation of TensorFlow RNNCell. +table RNNOptions { + fused_activation_function:ActivationFunctionType; + asymmetric_quantize_inputs:bool; +} + +// An implementation of TensorFlow dynamic_rnn with RNNCell. +table SequenceRNNOptions { + time_major:bool; + fused_activation_function:ActivationFunctionType; + asymmetric_quantize_inputs:bool; +} + +// An implementation of TensorFlow bidrectional_dynamic_rnn with RNNCell. +table BidirectionalSequenceRNNOptions { + time_major:bool; + fused_activation_function:ActivationFunctionType; + merge_outputs: bool; + asymmetric_quantize_inputs:bool; +} + +// LINT.IfChange +enum FullyConnectedOptionsWeightsFormat: byte { + DEFAULT = 0, + SHUFFLED4x16INT8 = 1, +} +// LINT.ThenChange(//tensorflow/compiler/mlir/lite/ir/tfl_op_enums.td) + +// An implementation of TensorFlow fully_connected (a.k.a Dense) layer. +table FullyConnectedOptions { + // Parameters for FullyConnected version 1 or above. + fused_activation_function:ActivationFunctionType; + + // Parameters for FullyConnected version 2 or above. + weights_format:FullyConnectedOptionsWeightsFormat = DEFAULT; + + // Parameters for FullyConnected version 5 or above. + // If set to true, then the number of dimension is preserved. Furthermore, + // all but the last dimension of the input and output shapes will be equal. + keep_num_dims: bool; + + // Parameters for FullyConnected version 7 or above. + // If set to true, then weights-only op will use asymmetric quantization for + // inputs. + asymmetric_quantize_inputs: bool; + + // Parameters for FullyConnected version 11 or above. + // When set, quantized_bias_type defines the dtype for both bias and accumulator. + quantized_bias_type: TensorType; +} + +table SoftmaxOptions { + beta: float; +} + +// An implementation of TensorFlow concat. +table ConcatenationOptions { + axis:int; + fused_activation_function:ActivationFunctionType; +} + +table AddOptions { + fused_activation_function:ActivationFunctionType; + // Parameters supported by version 3. + pot_scale_int16:bool = true; +} + +table MulOptions { + fused_activation_function:ActivationFunctionType; +} + +table L2NormOptions { + // This field is currently ignored in the L2 Norm Op. + fused_activation_function:ActivationFunctionType; +} + +table LocalResponseNormalizationOptions { + radius:int; + bias:float; + alpha:float; + beta:float; +} + +// LINT.IfChange +enum LSTMKernelType : byte { + // Full LSTM kernel which supports peephole and projection. + FULL = 0, + // Basic LSTM kernels. Equivalent to TensorFlow BasicLSTMCell. + BASIC = 1, +} +// LINT.ThenChange(//tensorflow/compiler/mlir/lite/ir/tfl_op_enums.td) + +// An implementation of TensorFlow LSTMCell and CoupledInputForgetGateLSTMCell +table LSTMOptions { + // Parameters for LSTM version 1 or above. + fused_activation_function:ActivationFunctionType; + cell_clip: float; // Optional, 0.0 means no clipping + proj_clip: float; // Optional, 0.0 means no clipping + + // Parameters for LSTM version 2 or above. + // Basic kernel is only supported in version 2 or above. + kernel_type: LSTMKernelType = FULL; + + // Parameters for LSTM version 4 or above. + asymmetric_quantize_inputs: bool; +} + +// An implementation of TensorFlow dynamic_rnn with LSTMCell. +table UnidirectionalSequenceLSTMOptions { + fused_activation_function:ActivationFunctionType; + cell_clip: float; // Optional, 0.0 means no clipping + proj_clip: float; // Optional, 0.0 means no clipping + + // If true then first dimension is sequence, otherwise batch. + time_major:bool; + + // Parameter for Unidirectional Sequence LSTM version 3. + asymmetric_quantize_inputs:bool; + + // Parameter for unidirectional sequence RNN version 4. + diagonal_recurrent_tensors:bool; +} + +table BidirectionalSequenceLSTMOptions { + // Parameters supported by version 1: + fused_activation_function:ActivationFunctionType; + cell_clip: float; // Optional, 0.0 means no clipping + proj_clip: float; // Optional, 0.0 means no clipping + + // If true, store the outputs of both directions into the first output. + merge_outputs: bool; + + // Parameters supported by version 2: + // If true then first dimension is sequence, otherwise batch. + // Version 1 implementations assumed time_major to be true, so this default + // value should never change. + time_major: bool = true; + + // Parameters for version 3 or above. + asymmetric_quantize_inputs:bool; +} + +table ResizeBilinearOptions { + new_height: int (deprecated); + new_width: int (deprecated); + align_corners: bool; + half_pixel_centers: bool; +} + +table ResizeNearestNeighborOptions { + align_corners: bool; + half_pixel_centers: bool; +} + +// A call operation options +table CallOptions { + // The subgraph index that needs to be called. + subgraph:uint; +} + +table PadOptions { +} + +table PadV2Options { +} + +table ReshapeOptions { + new_shape:[int]; +} + +table SpaceToBatchNDOptions { +} + +table BatchToSpaceNDOptions { +} + +table SkipGramOptions { + ngram_size: int; + max_skip_size: int; + include_all_ngrams: bool; +} + +table SpaceToDepthOptions { + block_size: int; +} + +table DepthToSpaceOptions { + block_size: int; +} + +table SubOptions { + fused_activation_function:ActivationFunctionType; + // Parameters supported by version 5 + pot_scale_int16:bool = true; +} + +table DivOptions { + fused_activation_function:ActivationFunctionType; +} + +table TopKV2Options { +} + +enum CombinerType : byte { + SUM = 0, + MEAN = 1, + SQRTN = 2, +} + +table EmbeddingLookupSparseOptions { + combiner:CombinerType; +} + +table GatherOptions { + axis: int; + // Parameters for Gather version 5 or above. + batch_dims: int = 0; +} + +table TransposeOptions { +} + +table ExpOptions { +} + +table CosOptions { +} + +table ReducerOptions { + keep_dims: bool; +} + +table SqueezeOptions { + squeeze_dims:[int]; +} + +table SplitOptions { + num_splits: int; +} + +table SplitVOptions { + num_splits: int; +} + +table StridedSliceOptions { + begin_mask: int; + end_mask: int; + ellipsis_mask: int; + new_axis_mask: int; + shrink_axis_mask: int; + // If true, then the end tensor is an offset of the begin tensor. + offset: bool; +} + +table LogSoftmaxOptions { +} + +table CastOptions { + in_data_type: TensorType; + out_data_type: TensorType; +} + +table DequantizeOptions { +} + +table MaximumMinimumOptions { +} + +table TileOptions { +} + +table ArgMaxOptions { + output_type : TensorType; +} + +table ArgMinOptions { + output_type : TensorType; +} + +table GreaterOptions { +} + +table GreaterEqualOptions { +} + +table LessOptions { +} + +table LessEqualOptions { +} + +table NegOptions { +} + +table SelectOptions { +} + +table SliceOptions { +} + +table TransposeConvOptions { + // Parameters supported by version 1, 2, 3: + padding:Padding; + stride_w:int; + stride_h:int; + + // Parameters supported by version 4: + fused_activation_function:ActivationFunctionType = NONE; + + // Parameters for TransposeConv version 5 or above. + // If set, use this for bias and accumulator. + // When set, quantized_bias_type defines the dtype for both bias and accumulator. + quantized_bias_type: TensorType; +} + +table ExpandDimsOptions { +} + +table SparseToDenseOptions { + validate_indices:bool; +} + +table EqualOptions { +} + +table NotEqualOptions { +} + +table ShapeOptions { + // Optional output type of the operation (int32 or int64). Defaults to int32. + out_type : TensorType; +} + +table RankOptions { +} + +table PowOptions { +} + +table FakeQuantOptions { + // Parameters supported by version 1: + min:float; + max:float; + num_bits:int; + + // Parameters supported by version 2: + narrow_range:bool; +} + +table PackOptions { + values_count:int; + axis:int; +} + +table LogicalOrOptions { +} + +table OneHotOptions { + axis:int; +} + +table AbsOptions { +} + + +table HardSwishOptions { +} + +table LogicalAndOptions { +} + +table LogicalNotOptions { +} + +table UnpackOptions { + num:int; + axis:int; +} + +table FloorDivOptions { +} + +table SquareOptions { +} + +table ZerosLikeOptions { +} + +table FillOptions { +} + +table FloorModOptions { +} + +table RangeOptions { +} + +table LeakyReluOptions { + alpha:float; +} + +table SquaredDifferenceOptions { +} + +// LINT.IfChange +enum MirrorPadMode : byte { + // Doesn't include borders. + REFLECT = 0, + // Includes borders. + SYMMETRIC = 1, +} +// LINT.ThenChange(//tensorflow/compiler/mlir/lite/ir/tfl_op_enums.td) + +table MirrorPadOptions { + mode:MirrorPadMode; +} + +table UniqueOptions { + idx_out_type:TensorType = INT32; +} + +table ReverseV2Options { +} + +table AddNOptions { +} + +table GatherNdOptions { +} + +table WhereOptions { +} + +table ReverseSequenceOptions { + seq_dim:int; + batch_dim:int = 0; +} + +table MatrixDiagOptions { +} + +table QuantizeOptions { +} + +table MatrixSetDiagOptions { +} + +table IfOptions { + then_subgraph_index:int; + else_subgraph_index:int; +} + +table CallOnceOptions { + init_subgraph_index:int; +} + +table WhileOptions { + cond_subgraph_index:int; + body_subgraph_index:int; +} + +table NonMaxSuppressionV4Options { +} + +table NonMaxSuppressionV5Options { +} + +table ScatterNdOptions { +} + +table SelectV2Options { +} + +table DensifyOptions { +} + +table SegmentSumOptions { +} + +table BatchMatMulOptions { + adj_x:bool; + adj_y:bool; + // Parameters for BatchMatMul version 4 or above. + // If set to true, then weights-only op will use asymmetric quantization for + // inputs. + asymmetric_quantize_inputs: bool; +} + +table CumsumOptions { + exclusive:bool; + reverse:bool; +} + +table BroadcastToOptions { +} + +table Rfft2dOptions { +} + +table HashtableOptions { + // The identity of hash tables. This identity will be used across different + // subgraphs in the same interpreter instance. + table_id:int; + key_dtype:TensorType; + value_dtype:TensorType; +} + +table HashtableFindOptions { +} + +table HashtableImportOptions { +} + +table HashtableSizeOptions { +} + +table VarHandleOptions { + container:string; + shared_name:string; +} + +table ReadVariableOptions { +} + +table AssignVariableOptions { +} + +table RandomOptions { + seed: long; + seed2: long; +} + +table BucketizeOptions { + boundaries: [float]; // The bucket boundaries. +} + +table GeluOptions { + approximate: bool; +} + +table DynamicUpdateSliceOptions { +} + +table UnsortedSegmentProdOptions { +} + +table UnsortedSegmentMaxOptions { +} + +table UnsortedSegmentSumOptions { +} + +table ATan2Options { +} + +table UnsortedSegmentMinOptions{ +} + +table SignOptions { +} + +table BitcastOptions { +} + +table BitwiseXorOptions { +} + +table RightShiftOptions { +} + +table DilateOptions { +} + +enum ReduceWindowFunction : int { + UNSUPPORTED, + ADD, + MUL, + MINIMUM, + MAXIMUM, + ALL, + ANY, +} + +table ReduceWindowOptions (deprecated) { + reduce_function: ReduceWindowFunction; +} + +// An OperatorCode can be an enum value (BuiltinOperator) if the operator is a +// builtin, or a string if the operator is custom. +table OperatorCode { + // This field is for backward compatibility. This field will be used when + // the value of the extended builtin_code field has less than + // BulitinOperator_PLACEHOLDER_FOR_GREATER_OP_CODES. + deprecated_builtin_code:byte; + custom_code:string; + + // The version of the operator. The version need to be bumped whenever new + // parameters are introduced into an op. + version:int = 1; + + // This field is introduced for resolving op builtin code shortage problem + // (the original BuiltinOperator enum field was represented as a byte). + // This field will be used when the value of the extended builtin_code field + // has greater than BulitinOperator_PLACEHOLDER_FOR_GREATER_OP_CODES. + builtin_code:BuiltinOperator; +} + +enum CustomOptionsFormat : byte { + FLEXBUFFERS = 0, +} + +// An operator takes tensors as inputs and outputs. The type of operation being +// performed is determined by an index into the list of valid OperatorCodes, +// while the specifics of each operations is configured using builtin_options +// or custom_options. +table Operator { + // Index into the operator_codes array. Using an integer here avoids + // complicate map lookups. + opcode_index:uint; + + // Optional input are indicated by -1. + inputs:[int]; + outputs:[int]; + + builtin_options:BuiltinOptions; + custom_options:[ubyte]; + custom_options_format:CustomOptionsFormat; + + // A list of booleans indicating the input tensors which are being mutated by + // this operator.(e.g. used by RNN and LSTM). + // For example, if the "inputs" array refers to 5 tensors and the second and + // fifth are mutable variables, then this list will contain + // [false, true, false, false, true]. + // + // If the list is empty, no variable is mutated in this operator. + // The list either has the same length as `inputs`, or is empty. + mutating_variable_inputs:[bool]; + + // A list of indices to the subgraph's "tensors" that are internal to an Op. + // Internal tensors are those that do not flow in or out of the operation, + // but instead are part of internal computation. As such, the operation's + // implementation may manage its memory more efficiently. They are needed + // however (i.e. not just an implementation detail) since they are part of the + // computation, which may require relevant metadata such as quantization + // parameters. + intermediates:[int]; + + // When an op is using custom_options in a model that is larger than 2GB, then + // we instead use the following attributes to find the buffer location which + // is stored outside of flatbuffers, the offset is calculated relative to the + // beginning of the file and is only valid if > 1 + large_custom_options_offset: ulong; + large_custom_options_size: ulong; + + // Flatbuffers union struct has a 128 elements limit in JAVA, so a second + // union is added, in the case of where BuitlinOptions2 runs out, a third + // one can be added + builtin_options_2 : BuiltinOptions2; +} + +// The root type, defining a subgraph, which typically represents an entire +// model. +table SubGraph { + // A list of all tensors used in this subgraph. + tensors:[Tensor]; + + // Indices of the tensors that are inputs into this subgraph. Note this is + // the list of non-static tensors that feed into the subgraph for inference. + inputs:[int]; + + // Indices of the tensors that are outputs out of this subgraph. Note this is + // the list of output tensors that are considered the product of the + // subgraph's inference. + outputs:[int]; + + // All operators, in execution order. + operators:[Operator]; + + // Name of this subgraph (used for debugging). + name:string; +} + +// Table of raw data buffers (used for constant tensors). Referenced by tensors +// by index. The generous alignment accommodates mmap-friendly data structures. +table Buffer { + data:[ubyte] (force_align: 16); + + // In a model that is larger than 2GB, then buffers instead uses the following + // attributes to find stored data, which is outside of flatbuffers + // the offset is calculated relative to the beginning of the file and is only + // valid if > 1. + offset: ulong; + size: ulong; +} + +table Metadata { + // A human readable string to uniquely identify a Metadata. + name:string; + // An index to the buffers table. + buffer:uint; +} + +// Map from an alias name of tensor to tensor index in the graph. +// This is used in Signature def. +table TensorMap { + // Represents the alias to use for this tensor. + name:string; + + // The actual tensor index in the primary graph, that 'name' corresponds to. + tensor_index:uint; +} + +// This corresponds to SignatureDef in Tensorflow SavedModel. +// The SignatureDef will be part of the SavedModel provided for conversion. +table SignatureDef { + // Named inputs for this signature. + inputs:[TensorMap]; + + // Named outputs for this signature. + outputs:[TensorMap]; + + // Key value which was in the Tensorflow SavedModel SignatureDef map. + signature_key:string; + + // Model tag, deprecated. + deprecated_tag:string (deprecated); + + // Index of subgraphs that corresponds to the exported method. + subgraph_index:uint; +} + +table Model { + // Version of the schema. + version:uint; + + // A list of all operator codes used in this model. This is + // kept in order because operators carry an index into this + // vector. + operator_codes:[OperatorCode]; + + // All the subgraphs of the model. The 0th is assumed to be the main + // model. + subgraphs:[SubGraph]; + + // A description of the model. + description:string; + + // Buffers of the model. + // Note the 0th entry of this array must be an empty buffer (sentinel). + // This is a convention so that tensors without a buffer can provide 0 as + // their buffer. + buffers:[Buffer]; + + // Metadata about the model. Indirects into the existings buffers list. + // Deprecated, prefer to use metadata field. + metadata_buffer:[int]; + + // Metadata about the model. + metadata:[Metadata]; + + // Optional SignatureDefs for the model. + signature_defs:[SignatureDef]; +} + +root_type Model; From 45fbbe2d161dc5aa8b291e4d055bd5e1e3a09de1 Mon Sep 17 00:00:00 2001 From: Jiyoung Giuliana Yun Date: Fri, 9 Aug 2024 13:26:18 +0900 Subject: [PATCH 18/78] [onert] Introduce DepthwiseConvOp in cpu kernel (#13574) This commit introduces DepthwiseConvOp in cpu kernel. This kernel uses depthwise_conv and bias_op eigen functions. ONE-DCO-1.0-Signed-off-by: Jiyoung Yun --- .../include/cker/operation/DepthwiseConv.h | 42 +++ compute/cker/src/DepthwiseConv.test.cc | 303 ++++++++++++++++++ 2 files changed, 345 insertions(+) create mode 100644 compute/cker/src/DepthwiseConv.test.cc diff --git a/compute/cker/include/cker/operation/DepthwiseConv.h b/compute/cker/include/cker/operation/DepthwiseConv.h index c926ec4f12d..5be36557ee8 100644 --- a/compute/cker/include/cker/operation/DepthwiseConv.h +++ b/compute/cker/include/cker/operation/DepthwiseConv.h @@ -28,6 +28,8 @@ #include "cker/operation/reference/integer_ops/DepthwiseConvUInt8.h" #include "cker/operation/reference/integer_ops/DepthwiseConvHybrid.h" #include "cker/CpuBackendThreadpool.h" +#include "cker/eigen/depthwise_conv_op.h" +#include "cker/eigen/bias_op.h" namespace nnfw { @@ -180,6 +182,46 @@ inline void DepthwiseConv(const DepthwiseConvParams ¶ms, const Shape &input_ cpu_backend_threadpool::Execute(tasks.size(), tasks.data(), ruy_context); } +void DepthwiseConvOp(const DepthwiseConvParams ¶ms, const Shape &input_shape, + const float *input_data, const Shape &filter_shape, const float *filter_data, + const Shape &bias_shape, const float *bias_data, float *padded_filter_data, + bool pad_filter, float *filter_buffers_data, const Shape &output_shape, + float *output_data) +{ + if (params.stride_height != params.stride_width) + throw std::runtime_error("Not support different length strides"); + + if (params.dilation_height_factor != 1 || params.dilation_width_factor != 1) + throw std::runtime_error{"Not support dilation other than 1."}; + + const int batch = MatchingDim(input_shape, 0, output_shape, 0); + const int input_depth = input_shape.Dims(3); + const int output_depth = output_shape.Dims(3); + const int input_height = input_shape.Dims(1); + const int input_width = input_shape.Dims(2); + const int filter_height = filter_shape.Dims(1); + const int filter_width = filter_shape.Dims(2); + const int output_height = output_shape.Dims(1); + const int output_width = output_shape.Dims(2); + const int stride = params.stride_height; + const int depth_multiplier = params.depth_multiplier; + const int pad_height = params.padding_values.height; + const int pad_width = params.padding_values.width; + const float activation_min = params.float_activation_min; + const float activation_max = params.float_activation_max; + + depthwise_conv_op::LaunchDepthwiseConvOp()( + batch, input_height, input_width, input_depth, filter_height, filter_width, depth_multiplier, + stride, pad_height, pad_width, output_height, output_width, output_depth, input_data, + filter_data, padded_filter_data, pad_filter, filter_buffers_data, output_data); + + if (bias_data != nullptr) + { + bias_op::biasHelper(bias_shape, bias_data, output_shape, output_data, activation_min, + activation_max); + } +} + } // namespace cker } // namespace nnfw diff --git a/compute/cker/src/DepthwiseConv.test.cc b/compute/cker/src/DepthwiseConv.test.cc new file mode 100644 index 00000000000..ecb7c97db97 --- /dev/null +++ b/compute/cker/src/DepthwiseConv.test.cc @@ -0,0 +1,303 @@ +/* + * 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 +#include + +#include +#include + +namespace +{ + +template class DepthwiseConvVerifier +{ +public: + DepthwiseConvVerifier() = default; + + void prepare(const nnfw::cker::Shape &output_shape, const nnfw::cker::Shape &filter_shape) + { + const int k_packet_size = nnfw::cker::eigen_support::kPacketSize(); + const int batch = output_shape.Dims(0); + const int out_depth = output_shape.Dims(3); + const int filter_rows = filter_shape.Dims(1); + const int filter_cols = filter_shape.Dims(2); + const int filter_spatial_size = filter_rows * filter_cols; + const int padded_filter_inner_dim_size = + ((out_depth + k_packet_size - 1) / k_packet_size) * k_packet_size; + + _use_padded_filter = (out_depth % k_packet_size) == 0 ? false : true; + { + nnfw::cker::Shape padded_filter_shape( + {batch, filter_spatial_size, padded_filter_inner_dim_size}); + _padded_filter.resize(padded_filter_shape.FlatSize()); + } + + { + // NOTE The Eigen library uses both main thread as well as a thread pool. + // Therefore, it needs to add an additional memory buffer for main thread. + const int thread_count = nnfw::cker::eigen_support::getThreadCount() + 1; + + nnfw::cker::Shape filter_buffer_shape( + {thread_count, filter_spatial_size, padded_filter_inner_dim_size}); + _filter_buffers.resize(filter_buffer_shape.FlatSize()); + } + } + + void run(const nnfw::cker::DepthwiseConvParams ¶ms, const nnfw::cker::Shape &input_shape, + const T *input_data, const nnfw::cker::Shape &filter_shape, const T *filter_data, + const nnfw::cker::Shape &bias_shape, const T *bias_data, + const nnfw::cker::Shape &output_shape, const T *expected) + { + std::vector output(output_shape.FlatSize()); + nnfw::cker::DepthwiseConvOp(params, input_shape, input_data, filter_shape, filter_data, + bias_shape, bias_data, _padded_filter.data(), _use_padded_filter, + _filter_buffers.data(), output_shape, output.data()); + + for (size_t i = 0; i < output.size(); ++i) + EXPECT_NEAR(output[i], expected[i], 1e-3f); + } + + void checkException(const nnfw::cker::DepthwiseConvParams ¶ms, + const nnfw::cker::Shape &input_shape, const T *input_data, + const nnfw::cker::Shape &filter_shape, const T *filter_data, + const nnfw::cker::Shape &bias_shape, const T *bias_data, + const nnfw::cker::Shape &output_shape, const T *expected) + { + std::vector output(output_shape.FlatSize()); + EXPECT_ANY_THROW( + nnfw::cker::DepthwiseConvOp(params, input_shape, input_data, filter_shape, filter_data, + bias_shape, bias_data, _padded_filter.data(), _use_padded_filter, + _filter_buffers.data(), output_shape, output.data())); + } + +private: + bool _use_padded_filter; + std::vector _padded_filter; + std::vector _filter_buffers; +}; + +} // namespace + +TEST(CKer_Operation, DepthwiseConv) +{ + { + nnfw::cker::DepthwiseConvParams params{}; + params.padding_type = nnfw::cker::PaddingType::kValid; + params.padding_values.width = 0; + params.padding_values.height = 0; + params.stride_width = 1; + params.stride_height = 1; + params.dilation_width_factor = 1; + params.dilation_height_factor = 1; + params.depth_multiplier = 1; + params.float_activation_min = std::numeric_limits::lowest(); + params.float_activation_max = std::numeric_limits::max(); + + nnfw::cker::Shape input_shape{1, 3, 2, 2}; // n, h, w, c + std::vector input = {1.0, 2.0, 7.0, 8.0, 3.0, 4.0, 9.0, 10.0, 5.0, 6.0, 11.0, 12.0}; + nnfw::cker::Shape filter_shape{1, 2, 2, 2}; // 1, h, w, c + std::vector filter = {1.0, 2.0, 3.0, 4.0, -9.0, 10.0, -11.0, 12.0}; + nnfw::cker::Shape bias_shape{2}; + std::vector bias = {0.0, 0.0}; + nnfw::cker::Shape output_shape{1, 2, 1, 2}; // n, h, w, c + std::vector expected = {-104., 196.0, -136.0, 252.0}; + + DepthwiseConvVerifier verifier; + verifier.prepare(output_shape, filter_shape); + verifier.run(params, input_shape, input.data(), filter_shape, filter.data(), bias_shape, + bias.data(), output_shape, expected.data()); + } + + // Pad + { + nnfw::cker::DepthwiseConvParams params{}; + params.padding_type = nnfw::cker::PaddingType::kSame; + params.padding_values.width = 0; + params.padding_values.height = 1; + params.stride_width = 1; + params.stride_height = 1; + params.dilation_width_factor = 1; + params.dilation_height_factor = 1; + params.depth_multiplier = 1; + params.float_activation_min = std::numeric_limits::lowest(); + params.float_activation_max = std::numeric_limits::max(); + + nnfw::cker::Shape input_shape{1, 2, 2, 2}; // n, h, w, c + std::vector input = {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0}; + nnfw::cker::Shape filter_shape{1, 3, 1, 2}; // 1, h, w, c + std::vector filter = {0.0, 1.0, 2.0, 3.0, 4.0, 5.0}; + nnfw::cker::Shape bias_shape{2}; + std::vector bias = {0.0, 0.0}; + nnfw::cker::Shape output_shape{1, 2, 2, 2}; // n, h, w, c + std::vector expected = {16.0, 28.0, 28.0, 44.0, 8.0, 16.0, 12.0, 24.0}; + + DepthwiseConvVerifier verifier; + verifier.prepare(output_shape, filter_shape); + verifier.run(params, input_shape, input.data(), filter_shape, filter.data(), bias_shape, + bias.data(), output_shape, expected.data()); + } + + // Bias + { + nnfw::cker::DepthwiseConvParams params{}; + params.padding_type = nnfw::cker::PaddingType::kSame; + params.padding_values.width = 0; + params.padding_values.height = 1; + params.stride_width = 1; + params.stride_height = 1; + params.dilation_width_factor = 1; + params.dilation_height_factor = 1; + params.depth_multiplier = 1; + params.float_activation_min = std::numeric_limits::lowest(); + params.float_activation_max = std::numeric_limits::max(); + + nnfw::cker::Shape input_shape{1, 2, 2, 2}; // n, h, w, c + std::vector input = {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0}; + nnfw::cker::Shape filter_shape{1, 3, 1, 2}; // 1, h, w, c + std::vector filter = {0.0, 1.0, 2.0, 3.0, 4.0, 5.0}; + nnfw::cker::Shape bias_shape{2}; + std::vector bias = {0.5, -0.5}; + nnfw::cker::Shape output_shape{1, 2, 2, 2}; // n, h, w, c + std::vector expected = {16.5, 27.5, 28.5, 43.5, 8.5, 15.5, 12.5, 23.5}; + + DepthwiseConvVerifier verifier; + verifier.prepare(output_shape, filter_shape); + verifier.run(params, input_shape, input.data(), filter_shape, filter.data(), bias_shape, + bias.data(), output_shape, expected.data()); + } + + // Depth Multiplier + { + nnfw::cker::DepthwiseConvParams params{}; + params.padding_type = nnfw::cker::PaddingType::kSame; + params.padding_values.width = 0; + params.padding_values.height = 1; + params.stride_width = 1; + params.stride_height = 1; + params.dilation_width_factor = 1; + params.dilation_height_factor = 1; + params.depth_multiplier = 2; + params.float_activation_min = std::numeric_limits::lowest(); + params.float_activation_max = std::numeric_limits::max(); + + nnfw::cker::Shape input_shape{1, 2, 2, 2}; // n, h, w, c + std::vector input = {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0}; + nnfw::cker::Shape filter_shape{1, 3, 1, 4}; // 1, h, w, c + std::vector filter = {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, -5.0, -4.0, -3.0, -2.0, -1.0, 0.0}; + nnfw::cker::Shape bias_shape{4}; + std::vector bias = {0.5, -0.5, 0.3, -0.3}; + nnfw::cker::Shape output_shape{1, 2, 2, 4}; // n, h, w, c + std::vector expected = {-11.5, -8.5, -9.7, -4.3, -9.5, -2.5, -21.7, -12.3, + 16.5, 19.5, -22.7, -17.3, 24.5, 31.5, -28.7, -19.3}; + + DepthwiseConvVerifier verifier; + verifier.prepare(output_shape, filter_shape); + verifier.run(params, input_shape, input.data(), filter_shape, filter.data(), bias_shape, + bias.data(), output_shape, expected.data()); + } + + // ReLU6 + { + nnfw::cker::DepthwiseConvParams params{}; + params.padding_type = nnfw::cker::PaddingType::kSame; + params.padding_values.width = 0; + params.padding_values.height = 1; + params.stride_width = 1; + params.stride_height = 1; + params.dilation_width_factor = 1; + params.dilation_height_factor = 1; + params.depth_multiplier = 1; + params.float_activation_min = 0.0; + params.float_activation_max = 6.0; + + nnfw::cker::Shape input_shape{1, 2, 2, 2}; // n, h, w, c + std::vector input = {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0}; + nnfw::cker::Shape filter_shape{1, 3, 1, 2}; // 1, h, w, c + std::vector filter = {0.0, 1.0, 2.0, 3.0, 4.0, 5.0}; + nnfw::cker::Shape bias_shape{2}; + std::vector bias = {0.5, -0.5}; + nnfw::cker::Shape output_shape{1, 2, 2, 2}; // n, h, w, c + std::vector expected = {6.0, 6.0, 6.0, 6.0, 6.0, 6.0, 6.0, 6.0}; + + DepthwiseConvVerifier verifier; + verifier.prepare(output_shape, filter_shape); + verifier.run(params, input_shape, input.data(), filter_shape, filter.data(), bias_shape, + bias.data(), output_shape, expected.data()); + } + + // No bias + { + nnfw::cker::DepthwiseConvParams params{}; + params.padding_type = nnfw::cker::PaddingType::kSame; + params.padding_values.width = 0; + params.padding_values.height = 1; + params.stride_width = 1; + params.stride_height = 1; + params.dilation_width_factor = 1; + params.dilation_height_factor = 1; + params.depth_multiplier = 1; + params.float_activation_min = std::numeric_limits::lowest(); + params.float_activation_max = std::numeric_limits::max(); + + nnfw::cker::Shape input_shape{1, 2, 2, 2}; // n, h, w, c + std::vector input = {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0}; + nnfw::cker::Shape filter_shape{1, 3, 1, 2}; // 1, h, w, c + std::vector filter = {0.0, 1.0, 2.0, 3.0, 4.0, 5.0}; + nnfw::cker::Shape bias_shape{2}; + nnfw::cker::Shape output_shape{1, 2, 2, 2}; // n, h, w, c + std::vector expected = {16.0, 28.0, 28.0, 44.0, 8.0, 16.0, 12.0, 24.0}; + + DepthwiseConvVerifier verifier; + verifier.prepare(output_shape, filter_shape); + verifier.run(params, input_shape, input.data(), filter_shape, filter.data(), bias_shape, + nullptr, output_shape, expected.data()); + } +} + +TEST(CKer_Operation, neg_DepthwiseConv) +{ + // Not supported Dilation + { + nnfw::cker::DepthwiseConvParams params{}; + params.padding_type = nnfw::cker::PaddingType::kSame; + params.padding_values.width = 0; + params.padding_values.height = 1; + params.stride_width = 1; + params.stride_height = 1; + params.dilation_width_factor = 2; + params.dilation_height_factor = 2; + params.depth_multiplier = 1; + params.float_activation_min = std::numeric_limits::lowest(); + params.float_activation_max = std::numeric_limits::max(); + + nnfw::cker::Shape input_shape{1, 6, 6, 1}; // n, h, w, c + std::vector input = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; + nnfw::cker::Shape filter_shape{1, 2, 2, 1}; // 1, h, w, c + std::vector filter = {1.0, 2.0, 3.0, 4.0}; + nnfw::cker::Shape bias_shape{1}; + std::vector bias = {0.0}; + nnfw::cker::Shape output_shape{1, 3, 3, 1}; // n, h, w, c + std::vector expected = {4.0, 0.0, 3.0, 0.0, 0.0, 0.0, 2.0, 0.0, 1.0}; + + DepthwiseConvVerifier verifier; + verifier.prepare(output_shape, filter_shape); + verifier.checkException(params, input_shape, input.data(), filter_shape, filter.data(), + bias_shape, bias.data(), output_shape, expected.data()); + } +} From 484774f3445ce9e24e04f01167ad3c63df8192db Mon Sep 17 00:00:00 2001 From: Jang Jiseob Date: Fri, 9 Aug 2024 13:26:38 +0900 Subject: [PATCH 19/78] [onert] Unify interface for generating tensors (#13631) This commit unifies interface for generating tensors. ONE-DCO-1.0-Signed-off-by: ragmani --- runtime/onert/backend/train/BackendContext.cc | 9 +-------- runtime/onert/backend/train/BackendContext.h | 1 - .../core/include/backend/train/TrainableBackendContext.h | 1 - .../core/src/backend/builtin/train/BackendContext.cc | 8 +------- .../core/src/backend/builtin/train/BackendContext.h | 1 - runtime/onert/core/src/compiler/ExecutorFactory.cc | 6 ------ 6 files changed, 2 insertions(+), 24 deletions(-) diff --git a/runtime/onert/backend/train/BackendContext.cc b/runtime/onert/backend/train/BackendContext.cc index f5bf9999671..06a224e1ddc 100644 --- a/runtime/onert/backend/train/BackendContext.cc +++ b/runtime/onert/backend/train/BackendContext.cc @@ -139,16 +139,9 @@ getDisposableBackPropTensorList(const ir::train::TrainableGraph &tgraph, backend::ITensorRegistry *BackendContext::genTensors() { planForwardTensors(); - - _tensor_builder->allocate(); - - return _tensor_registry.get(); -} - -backend::train::ITensorRegistry *BackendContext::genTrainingTensors() -{ planBackwardTensors(); + _tensor_builder->allocate(); _tensor_builder->allocateBackward(); return _tensor_registry.get(); diff --git a/runtime/onert/backend/train/BackendContext.h b/runtime/onert/backend/train/BackendContext.h index 69d17d352c4..6ab458c437a 100644 --- a/runtime/onert/backend/train/BackendContext.h +++ b/runtime/onert/backend/train/BackendContext.h @@ -69,7 +69,6 @@ class BackendContext : public onert::backend::train::TrainableBackendContext public: backend::ITensorRegistry *genTensors() override; - backend::train::ITensorRegistry *genTrainingTensors() override; private: void planForwardTensors(); diff --git a/runtime/onert/core/include/backend/train/TrainableBackendContext.h b/runtime/onert/core/include/backend/train/TrainableBackendContext.h index b3a9cdd7d52..36492786b95 100644 --- a/runtime/onert/core/include/backend/train/TrainableBackendContext.h +++ b/runtime/onert/core/include/backend/train/TrainableBackendContext.h @@ -76,7 +76,6 @@ class TrainableBackendContext std::shared_ptr tensor_registry() { return _tensor_registry; } - virtual ITensorRegistry *genTrainingTensors() = 0; virtual backend::ITensorRegistry *genTensors() = 0; virtual FunctionMap genKernels() = 0; diff --git a/runtime/onert/core/src/backend/builtin/train/BackendContext.cc b/runtime/onert/core/src/backend/builtin/train/BackendContext.cc index 69483eade12..c415a5557f5 100644 --- a/runtime/onert/core/src/backend/builtin/train/BackendContext.cc +++ b/runtime/onert/core/src/backend/builtin/train/BackendContext.cc @@ -30,19 +30,13 @@ namespace train backend::ITensorRegistry *BackendContext::genTensors() { - // For now, there is no need to generate tensors for forwarding. + // For now, there is no need to generate tensors for forwarding and backwarding. // builtin train backend handles 3 operators: `Permute`, `IF`, `WHILE`. // `Permute`: Tensor generation is not required. // `IF`, `WHILE`: Not supported yet return tensor_registry().get(); } -backend::train::ITensorRegistry *BackendContext::genTrainingTensors() -{ - // For now, there is no need to generate tensors for backwarding. - return tensor_registry().get(); -} - backend::train::FunctionMap BackendContext::genKernels() { backend::train::FunctionMap ret; diff --git a/runtime/onert/core/src/backend/builtin/train/BackendContext.h b/runtime/onert/core/src/backend/builtin/train/BackendContext.h index 4782756c31c..c57a8020685 100644 --- a/runtime/onert/core/src/backend/builtin/train/BackendContext.h +++ b/runtime/onert/core/src/backend/builtin/train/BackendContext.h @@ -47,7 +47,6 @@ class BackendContext : public backend::train::TrainableBackendContext } backend::ITensorRegistry *genTensors() override; - backend::train::ITensorRegistry *genTrainingTensors() override; public: backend::train::FunctionMap genKernels() override; diff --git a/runtime/onert/core/src/compiler/ExecutorFactory.cc b/runtime/onert/core/src/compiler/ExecutorFactory.cc index 3cbe5f670eb..0766a72174b 100644 --- a/runtime/onert/core/src/compiler/ExecutorFactory.cc +++ b/runtime/onert/core/src/compiler/ExecutorFactory.cc @@ -746,12 +746,6 @@ exec::IExecutor *ExecutorFactory::createTrainableExecutor( pair.second->genTensors(); } - for (auto &&pair : tbackend_contexts) - { - auto tctx = pair.second.get(); - tctx->genTrainingTensors(); - } - prepareMigrantTensors(*lowered_graph, tbackend_contexts); // Give some runtime objects to builtin KernelGenerator From 06be2468e114ecfaf86384a18ac37e893ffe1fea Mon Sep 17 00:00:00 2001 From: Hyeongseok Oh Date: Fri, 9 Aug 2024 13:26:55 +0900 Subject: [PATCH 20/78] [github] Add ubuntu 22.04 test to onecc workflow (#13619) This commit adds matrix context to onecc workflow for ubuntu 22.04 test. ONE-DCO-1.0-Signed-off-by: Hyeongseok Oh --- .github/workflows/run-onecc-build.yml | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/.github/workflows/run-onecc-build.yml b/.github/workflows/run-onecc-build.yml index ded12dde929..d4e1c3c96b2 100644 --- a/.github/workflows/run-onecc-build.yml +++ b/.github/workflows/run-onecc-build.yml @@ -39,16 +39,21 @@ jobs: # Tested ubuntu version is decided by docker image, not runner runs-on: ubuntu-latest strategy: - # TODO Support various ubuntu version matrix: type: [ Debug, Release ] + ubuntu_code: [ focal, jammy ] + include: + - ubuntu_code: focal + ubuntu_ver: 20.04 + - ubuntu_code: jammy + ubuntu_ver: 22.04 container: - image: nnfw/one-devtools:focal + image: nnfw/one-devtools:${{ matrix.ubuntu_code }} options: --user root env: NNCC_WORKSPACE : build NNCC_INSTALL_PREFIX : install - name: onecc ubuntu 20.04 ${{ matrix.type }} test + name: onecc ubuntu ${{ matrix.ubuntu_ver }} ${{ matrix.type }} test steps: - name: Checkout @@ -67,7 +72,7 @@ jobs: uses: actions/cache@v4 with: path: ${{ env.NNCC_WORKSPACE }}/overlay - key: overlay-onecc-focal-${{ hashFiles('compiler/common-artifacts/CMakeLists.txt') }}-${{ hashFiles('infra/cmake/packages/**/*.cmake') }} + key: overlay-onecc-${{ matrix.ubuntu_code }}-${{ hashFiles('compiler/common-artifacts/CMakeLists.txt') }}-${{ hashFiles('infra/cmake/packages/**/*.cmake') }} - name: Build run: | From 0fc4de4b517dbf29746e2d1c56943aee4ae371ab Mon Sep 17 00:00:00 2001 From: SaeHie Park Date: Fri, 9 Aug 2024 16:07:14 +0900 Subject: [PATCH 21/78] [tflchef] Introduce ModelChef (#13632) This will introduce struct ModelChef to provide model chef functionality as beginning of refactoring to provide huge model generation. ONE-DCO-1.0-Signed-off-by: SaeHie Park --- compiler/tflchef/core/src/ModelChef.cpp | 138 ++++++++++++++---------- 1 file changed, 82 insertions(+), 56 deletions(-) diff --git a/compiler/tflchef/core/src/ModelChef.cpp b/compiler/tflchef/core/src/ModelChef.cpp index 4025ed2306f..5ccf5bdf675 100644 --- a/compiler/tflchef/core/src/ModelChef.cpp +++ b/compiler/tflchef/core/src/ModelChef.cpp @@ -47,38 +47,6 @@ using namespace souschef; namespace { -class GeneratedModelImpl final : public tflchef::GeneratedModel::Impl -{ -public: - GeneratedModelImpl(std::unique_ptr &&builder) - : _builder{std::move(builder)} - { - // DO NOTHING - } - -public: - const char *base(void) const override - { - // Return the base address of generated flatbuffer model - return reinterpret_cast(_builder->GetBufferPointer()); - } - -public: - size_t size(void) const override - { - // Return the size of generated flatbuffer model - return _builder->GetSize(); - } - -private: - std::unique_ptr _builder; -}; - -} // namespace - -namespace -{ - struct DataChefRegistry final : public Registry { }; @@ -209,6 +177,8 @@ std::set gather_customcode_set(const ::tflchef::ModelRecipe &model_ namespace { +// TODO remove +#if 0 struct CookParams { std::vector> &buffer_vec; @@ -219,6 +189,20 @@ struct CookParams std::vector &custom_code_vec; std::string noname; }; +#endif + +struct ModelChef +{ + std::unique_ptr flatbuffer_builder; + + std::vector> signdef_vec; + std::vector> buffer_vec; + std::vector> code_vec; + std::vector> subgraph_vec; + std::map builtin_code_map; + std::vector custom_code_vec; + std::string graph_name; +}; std::vector> make_dim_metadata_vec(flatbuffers::FlatBufferBuilder *flatbuffer_builder, int32_t dims_count, @@ -255,16 +239,17 @@ make_dim_metadata_vec(flatbuffers::FlatBufferBuilder *flatbuffer_builder, int32_ return dim_metadata_vec; } -template std::map cook_graph(const T &graph, CookParams &cp) +template std::map cook_graph(const T &graph, ModelChef &mc) { LOGGER(l); - std::vector> &buffer_vec = cp.buffer_vec; - std::vector> &code_vec = cp.code_vec; - std::vector> &subgraph_vec = cp.subgraph_vec; - std::unique_ptr &flatbuffer_builder = cp.flatbuffer_builder; - std::map &builtin_code_map = cp.builtin_code_map; - std::vector &custom_code_vec = cp.custom_code_vec; + // TODO remove references + std::vector> &buffer_vec = mc.buffer_vec; + std::vector> &code_vec = mc.code_vec; + std::vector> &subgraph_vec = mc.subgraph_vec; + std::unique_ptr &flatbuffer_builder = mc.flatbuffer_builder; + std::map &builtin_code_map = mc.builtin_code_map; + std::vector &custom_code_vec = mc.custom_code_vec; // Operand-related std::vector> tensor_vec; @@ -273,7 +258,7 @@ template std::map cook_graph(const T &graph, std::vector> operator_vec; // default name for graph - std::string graph_name = cp.noname; + std::string graph_name = mc.graph_name; if (graph.has_name()) graph_name = graph.name(); @@ -722,6 +707,40 @@ template std::map cook_graph(const T &graph, } // namespace +namespace +{ + +class GeneratedModelImpl final : public tflchef::GeneratedModel::Impl +{ +public: + GeneratedModelImpl() + { + // DO NOTHING + } + +public: + const char *base(void) const override + { + // Return the base address of generated flatbuffer model + return reinterpret_cast(_mc.flatbuffer_builder->GetBufferPointer()); + } + +public: + size_t size(void) const override + { + // Return the size of generated flatbuffer model + return _mc.flatbuffer_builder->GetSize(); + } + +public: + ModelChef &model_chef(void) { return _mc; } + +private: + ModelChef _mc; +}; + +} // namespace + namespace tflchef { @@ -743,26 +762,35 @@ GeneratedModel cook(const ::tflchef::ModelRecipe &model_recipe) #include "DataChef.def" #undef DATA_CHEF + std::unique_ptr gen_model(new GeneratedModelImpl()); + + ModelChef &mc = gen_model->model_chef(); + + mc.flatbuffer_builder = + std::unique_ptr(new flatbuffers::FlatBufferBuilder(1024)); + + // TODO remove references + // // Create FlatBufferBuilder // - auto flatbuffer_builder = - std::unique_ptr(new flatbuffers::FlatBufferBuilder(1024)); + std::unique_ptr &flatbuffer_builder = mc.flatbuffer_builder; // Operand-related - std::vector> buffer_vec; + std::vector> &buffer_vec = mc.buffer_vec; // Operation-related - std::vector> code_vec; + std::vector> &code_vec = mc.code_vec; // SignatureDef-related - std::vector> signdef_vec; + std::vector> &signdef_vec = mc.signdef_vec; // Graphs-related - std::vector> subgraph_vec; + std::vector> &subgraph_vec = mc.subgraph_vec; // Create OperatorCode with Builtin Operator - auto builtin_code_map = gather_builtincode_map(model_recipe); + mc.builtin_code_map = gather_builtincode_map(model_recipe); + std::map &builtin_code_map = mc.builtin_code_map; for (auto const &opcode : builtin_code_map) { tflite::OperatorCodeBuilder code_builder{*flatbuffer_builder}; @@ -788,7 +816,8 @@ GeneratedModel cook(const ::tflchef::ModelRecipe &model_recipe) // Create OperatorCode with Custom Operator std::set custom_code_set = gather_customcode_set(model_recipe); - std::vector custom_code_vec{custom_code_set.begin(), custom_code_set.end()}; + mc.custom_code_vec = {custom_code_set.begin(), custom_code_set.end()}; + std::vector &custom_code_vec = mc.custom_code_vec; for (auto opcode : custom_code_vec) { @@ -818,10 +847,9 @@ GeneratedModel cook(const ::tflchef::ModelRecipe &model_recipe) // // Create Main graph // - CookParams cp{buffer_vec, code_vec, subgraph_vec, flatbuffer_builder, - builtin_code_map, custom_code_vec, "main"}; - auto table = cook_graph<::tflchef::ModelRecipe>(model_recipe, cp); + mc.graph_name = "main"; + auto table = cook_graph<::tflchef::ModelRecipe>(model_recipe, mc); symbol_tables.push_back(table); // @@ -834,10 +862,9 @@ GeneratedModel cook(const ::tflchef::ModelRecipe &model_recipe) std::ostringstream stringStream; stringStream << "sub_" << (g + 1); - CookParams cp{buffer_vec, code_vec, subgraph_vec, flatbuffer_builder, - builtin_code_map, custom_code_vec, stringStream.str()}; + mc.graph_name = stringStream.str(); - auto table = cook_graph<::tflchef::Graph>(graph, cp); + auto table = cook_graph<::tflchef::Graph>(graph, mc); symbol_tables.push_back(table); } @@ -946,8 +973,7 @@ GeneratedModel cook(const ::tflchef::ModelRecipe &model_recipe) ::tflite::FinishModelBuffer(*flatbuffer_builder, model); // Return "GenerateModel" - return GeneratedModel{ - std::unique_ptr(new GeneratedModelImpl(std::move(flatbuffer_builder)))}; + return GeneratedModel{std::move(gen_model)}; } } // namespace tflchef From 13e895493da01e0af855c21e32659920d749c692 Mon Sep 17 00:00:00 2001 From: SaeHie Park Date: Mon, 12 Aug 2024 11:38:11 +0900 Subject: [PATCH 22/78] [tflchef] Move cook and cook_graph into ModelChef (#13639) This will revise ModelChef as to move cook and cook_graph methods into member. ONE-DCO-1.0-Signed-off-by: SaeHie Park --- compiler/tflchef/core/src/ModelChef.cpp | 207 ++++++++++++++++++++++-- 1 file changed, 196 insertions(+), 11 deletions(-) diff --git a/compiler/tflchef/core/src/ModelChef.cpp b/compiler/tflchef/core/src/ModelChef.cpp index 5ccf5bdf675..0cb03640290 100644 --- a/compiler/tflchef/core/src/ModelChef.cpp +++ b/compiler/tflchef/core/src/ModelChef.cpp @@ -193,6 +193,10 @@ struct CookParams struct ModelChef { + void cook(const ::tflchef::ModelRecipe &model_recipe); + + template std::map cook_graph(const T &graph); + std::unique_ptr flatbuffer_builder; std::vector> signdef_vec; @@ -201,7 +205,7 @@ struct ModelChef std::vector> subgraph_vec; std::map builtin_code_map; std::vector custom_code_vec; - std::string graph_name; + std::string _graph_name; }; std::vector> @@ -239,18 +243,10 @@ make_dim_metadata_vec(flatbuffers::FlatBufferBuilder *flatbuffer_builder, int32_ return dim_metadata_vec; } -template std::map cook_graph(const T &graph, ModelChef &mc) +template std::map ModelChef::cook_graph(const T &graph) { LOGGER(l); - // TODO remove references - std::vector> &buffer_vec = mc.buffer_vec; - std::vector> &code_vec = mc.code_vec; - std::vector> &subgraph_vec = mc.subgraph_vec; - std::unique_ptr &flatbuffer_builder = mc.flatbuffer_builder; - std::map &builtin_code_map = mc.builtin_code_map; - std::vector &custom_code_vec = mc.custom_code_vec; - // Operand-related std::vector> tensor_vec; @@ -258,7 +254,7 @@ template std::map cook_graph(const T &graph, std::vector> operator_vec; // default name for graph - std::string graph_name = mc.graph_name; + std::string graph_name = _graph_name; if (graph.has_name()) graph_name = graph.name(); @@ -705,6 +701,191 @@ template std::map cook_graph(const T &graph, return symbol_table; } +void ModelChef::cook(const ::tflchef::ModelRecipe &model_recipe) +{ + // Create OperatorCode with Builtin Operator + builtin_code_map = gather_builtincode_map(model_recipe); + for (auto const &opcode : builtin_code_map) + { + tflite::OperatorCodeBuilder code_builder{*flatbuffer_builder}; + // 127 is BuiltinOperator_PLACEHOLDER_FOR_GREATER_OP_CODES + // This is the way to handle deprecated builtin code + // See + // https://github.com/tensorflow/tensorflow/blob/a0afe8f9218be5eb9ed5dffc2dff652996da8c28/tensorflow/lite/schema/schema.fbs#L1061-L1077 + if (opcode.first < 127) + { + code_builder.add_deprecated_builtin_code(opcode.first); + } + else + { + code_builder.add_deprecated_builtin_code( + ::tflite::BuiltinOperator_PLACEHOLDER_FOR_GREATER_OP_CODES); + } + code_builder.add_version(opcode.second); + code_builder.add_builtin_code(opcode.first); + auto code = code_builder.Finish(); + // Update OperatorCode vector + code_vec.emplace_back(code); + } + + // Create OperatorCode with Custom Operator + std::set custom_code_set = gather_customcode_set(model_recipe); + custom_code_vec = {custom_code_set.begin(), custom_code_set.end()}; + + for (auto opcode : custom_code_vec) + { + auto custom_code = flatbuffer_builder->CreateString(opcode); + tflite::OperatorCodeBuilder code_builder{*flatbuffer_builder}; + code_builder.add_deprecated_builtin_code(tflite::BuiltinOperator_CUSTOM); + code_builder.add_custom_code(custom_code); + code_builder.add_builtin_code(tflite::BuiltinOperator_CUSTOM); + auto code = code_builder.Finish(); + // Update OperatorCode vector + code_vec.emplace_back(code); + } + + // Create an Empty Buffer + // + // Buffer 0 SHOULD be an empty buffer in TensorFlow Lite model file + // (Please refer to the comment for Tensor.buffer field in schema) + { + tflite::BufferBuilder buffer_builder{*flatbuffer_builder}; + buffer_vec.emplace_back(buffer_builder.Finish()); + } + + // symbol_tables stores symbol_table of each sub graph + // this is used to find tensor ID(index) with tensor name + std::vector> symbol_tables; + + // + // Create Main graph + // + + _graph_name = "main"; + auto table = cook_graph<::tflchef::ModelRecipe>(model_recipe); + symbol_tables.push_back(table); + + // + // Create subgraphs if exist + // + for (int g = 0; g < model_recipe.graph_size(); ++g) + { + const auto &graph = model_recipe.graph(g); + + std::ostringstream stringStream; + stringStream << "sub_" << (g + 1); + + _graph_name = stringStream.str(); + + auto table = cook_graph<::tflchef::Graph>(graph); + symbol_tables.push_back(table); + } + + // Create Signature-Def + // + for (int s = 0; s < model_recipe.signature_def_size(); ++s) + { + // load from recipe + const auto &rec_signature_def = model_recipe.signature_def(s); + + std::vector> tensormap_inputs; + std::vector> tensormap_outputs; + + // which subgraph index to cook + auto subgraph_index = 0; + if (rec_signature_def.has_subgraph_index()) + { + subgraph_index = rec_signature_def.subgraph_index(); + } + assert(subgraph_index < symbol_tables.size()); + auto &symbol_table = symbol_tables[subgraph_index]; + + // cook for inputs + for (int si = 0; si < rec_signature_def.inputs_size(); ++si) + { + // recipe for input TensorMap + auto rec_tm_input = rec_signature_def.inputs(si); + auto name = flatbuffer_builder->CreateString(rec_tm_input.name()); + uint32_t tensor_index = 0; + // either tensor or tensor_index should exist + assert(rec_tm_input.has_tensor() || rec_tm_input.has_tensor_index()); + if (rec_tm_input.has_tensor()) + { + // we can get tensor_index from symbol_table + auto tensor = rec_tm_input.tensor(); + tensor_index = symbol_table[tensor]; + } + else + { + // or we can use tensor_index itself + tensor_index = rec_tm_input.tensor_index(); + } + + ::tflite::TensorMapBuilder tensormap_builder{*flatbuffer_builder}; + tensormap_builder.add_name(name); + tensormap_builder.add_tensor_index(tensor_index); + tensormap_inputs.push_back(tensormap_builder.Finish()); + } + // cook for outputs, same as inputs + for (int so = 0; so < rec_signature_def.outputs_size(); ++so) + { + auto rec_tm_output = rec_signature_def.outputs(so); + auto name = flatbuffer_builder->CreateString(rec_tm_output.name()); + uint32_t tensor_index = 0; + assert(rec_tm_output.has_tensor() || rec_tm_output.has_tensor_index()); + if (rec_tm_output.has_tensor()) + { + auto tensor = rec_tm_output.tensor(); + tensor_index = symbol_table[tensor]; + } + else + { + tensor_index = rec_tm_output.tensor_index(); + } + + ::tflite::TensorMapBuilder tensormap_builder{*flatbuffer_builder}; + tensormap_builder.add_name(name); + tensormap_builder.add_tensor_index(tensor_index); + tensormap_outputs.push_back(tensormap_builder.Finish()); + } + + auto inputs = flatbuffer_builder->CreateVector(tensormap_inputs); + auto outputs = flatbuffer_builder->CreateVector(tensormap_outputs); + auto signature_key = flatbuffer_builder->CreateString(rec_signature_def.signature_key()); + // TODO add validation for signature_key + + ::tflite::SignatureDefBuilder signature_def_builder{*flatbuffer_builder}; + signature_def_builder.add_inputs(inputs); + signature_def_builder.add_outputs(outputs); + signature_def_builder.add_signature_key(signature_key); + signature_def_builder.add_subgraph_index(rec_signature_def.subgraph_index()); + + signdef_vec.emplace_back(signature_def_builder.Finish()); + } + + // Create "Model" arguments + auto buffers = flatbuffer_builder->CreateVector(buffer_vec); + auto signdefs = flatbuffer_builder->CreateVector(signdef_vec); + auto operator_codes = flatbuffer_builder->CreateVector(code_vec); + auto subgraphs = flatbuffer_builder->CreateVector(subgraph_vec); + auto description = flatbuffer_builder->CreateString("Generated by tflchef"); + + // Create "Model" + tflite::ModelBuilder model_builder{*flatbuffer_builder}; + + model_builder.add_version(3); + model_builder.add_operator_codes(operator_codes); + model_builder.add_signature_defs(signdefs); + model_builder.add_subgraphs(subgraphs); + model_builder.add_description(description); + model_builder.add_buffers(buffers); + + auto model = model_builder.Finish(); + + // Finalize + ::tflite::FinishModelBuffer(*flatbuffer_builder, model); +} + } // namespace namespace @@ -769,6 +950,9 @@ GeneratedModel cook(const ::tflchef::ModelRecipe &model_recipe) mc.flatbuffer_builder = std::unique_ptr(new flatbuffers::FlatBufferBuilder(1024)); + mc.cook(model_recipe); + +#if 0 // TODO remove references // @@ -971,6 +1155,7 @@ GeneratedModel cook(const ::tflchef::ModelRecipe &model_recipe) // Finalize ::tflite::FinishModelBuffer(*flatbuffer_builder, model); +#endif // Return "GenerateModel" return GeneratedModel{std::move(gen_model)}; From a1c505300ea1f1a987ec2fb7cff0cf698e38659b Mon Sep 17 00:00:00 2001 From: SaeHie Park Date: Mon, 12 Aug 2024 13:31:43 +0900 Subject: [PATCH 23/78] [tflchef] Tidy disabled codes (#13640) This will tidy disabled codes. ONE-DCO-1.0-Signed-off-by: SaeHie Park --- compiler/tflchef/core/src/ModelChef.cpp | 219 ------------------------ 1 file changed, 219 deletions(-) diff --git a/compiler/tflchef/core/src/ModelChef.cpp b/compiler/tflchef/core/src/ModelChef.cpp index 0cb03640290..5f5a16f6ca3 100644 --- a/compiler/tflchef/core/src/ModelChef.cpp +++ b/compiler/tflchef/core/src/ModelChef.cpp @@ -177,20 +177,6 @@ std::set gather_customcode_set(const ::tflchef::ModelRecipe &model_ namespace { -// TODO remove -#if 0 -struct CookParams -{ - std::vector> &buffer_vec; - std::vector> &code_vec; - std::vector> &subgraph_vec; - std::unique_ptr &flatbuffer_builder; - std::map &builtin_code_map; - std::vector &custom_code_vec; - std::string noname; -}; -#endif - struct ModelChef { void cook(const ::tflchef::ModelRecipe &model_recipe); @@ -952,211 +938,6 @@ GeneratedModel cook(const ::tflchef::ModelRecipe &model_recipe) mc.cook(model_recipe); -#if 0 - // TODO remove references - - // - // Create FlatBufferBuilder - // - std::unique_ptr &flatbuffer_builder = mc.flatbuffer_builder; - - // Operand-related - std::vector> &buffer_vec = mc.buffer_vec; - - // Operation-related - std::vector> &code_vec = mc.code_vec; - - // SignatureDef-related - std::vector> &signdef_vec = mc.signdef_vec; - - // Graphs-related - std::vector> &subgraph_vec = mc.subgraph_vec; - - // Create OperatorCode with Builtin Operator - mc.builtin_code_map = gather_builtincode_map(model_recipe); - std::map &builtin_code_map = mc.builtin_code_map; - for (auto const &opcode : builtin_code_map) - { - tflite::OperatorCodeBuilder code_builder{*flatbuffer_builder}; - // 127 is BuiltinOperator_PLACEHOLDER_FOR_GREATER_OP_CODES - // This is the way to handle deprecated builtin code - // See - // https://github.com/tensorflow/tensorflow/blob/a0afe8f9218be5eb9ed5dffc2dff652996da8c28/tensorflow/lite/schema/schema.fbs#L1061-L1077 - if (opcode.first < 127) - { - code_builder.add_deprecated_builtin_code(opcode.first); - } - else - { - code_builder.add_deprecated_builtin_code( - ::tflite::BuiltinOperator_PLACEHOLDER_FOR_GREATER_OP_CODES); - } - code_builder.add_version(opcode.second); - code_builder.add_builtin_code(opcode.first); - auto code = code_builder.Finish(); - // Update OperatorCode vector - code_vec.emplace_back(code); - } - - // Create OperatorCode with Custom Operator - std::set custom_code_set = gather_customcode_set(model_recipe); - mc.custom_code_vec = {custom_code_set.begin(), custom_code_set.end()}; - std::vector &custom_code_vec = mc.custom_code_vec; - - for (auto opcode : custom_code_vec) - { - auto custom_code = flatbuffer_builder->CreateString(opcode); - tflite::OperatorCodeBuilder code_builder{*flatbuffer_builder}; - code_builder.add_deprecated_builtin_code(tflite::BuiltinOperator_CUSTOM); - code_builder.add_custom_code(custom_code); - code_builder.add_builtin_code(tflite::BuiltinOperator_CUSTOM); - auto code = code_builder.Finish(); - // Update OperatorCode vector - code_vec.emplace_back(code); - } - - // Create an Empty Buffer - // - // Buffer 0 SHOULD be an empty buffer in TensorFlow Lite model file - // (Please refer to the comment for Tensor.buffer field in schema) - { - tflite::BufferBuilder buffer_builder{*flatbuffer_builder}; - buffer_vec.emplace_back(buffer_builder.Finish()); - } - - // symbol_tables stores symbol_table of each sub graph - // this is used to find tensor ID(index) with tensor name - std::vector> symbol_tables; - - // - // Create Main graph - // - - mc.graph_name = "main"; - auto table = cook_graph<::tflchef::ModelRecipe>(model_recipe, mc); - symbol_tables.push_back(table); - - // - // Create subgraphs if exist - // - for (int g = 0; g < model_recipe.graph_size(); ++g) - { - const auto &graph = model_recipe.graph(g); - - std::ostringstream stringStream; - stringStream << "sub_" << (g + 1); - - mc.graph_name = stringStream.str(); - - auto table = cook_graph<::tflchef::Graph>(graph, mc); - symbol_tables.push_back(table); - } - - // Create Signature-Def - // - for (int s = 0; s < model_recipe.signature_def_size(); ++s) - { - // load from recipe - const auto &rec_signature_def = model_recipe.signature_def(s); - - std::vector> tensormap_inputs; - std::vector> tensormap_outputs; - - // which subgraph index to cook - auto subgraph_index = 0; - if (rec_signature_def.has_subgraph_index()) - { - subgraph_index = rec_signature_def.subgraph_index(); - } - assert(subgraph_index < symbol_tables.size()); - auto &symbol_table = symbol_tables[subgraph_index]; - - // cook for inputs - for (int si = 0; si < rec_signature_def.inputs_size(); ++si) - { - // recipe for input TensorMap - auto rec_tm_input = rec_signature_def.inputs(si); - auto name = flatbuffer_builder->CreateString(rec_tm_input.name()); - uint32_t tensor_index = 0; - // either tensor or tensor_index should exist - assert(rec_tm_input.has_tensor() || rec_tm_input.has_tensor_index()); - if (rec_tm_input.has_tensor()) - { - // we can get tensor_index from symbol_table - auto tensor = rec_tm_input.tensor(); - tensor_index = symbol_table[tensor]; - } - else - { - // or we can use tensor_index itself - tensor_index = rec_tm_input.tensor_index(); - } - - ::tflite::TensorMapBuilder tensormap_builder{*flatbuffer_builder}; - tensormap_builder.add_name(name); - tensormap_builder.add_tensor_index(tensor_index); - tensormap_inputs.push_back(tensormap_builder.Finish()); - } - // cook for outputs, same as inputs - for (int so = 0; so < rec_signature_def.outputs_size(); ++so) - { - auto rec_tm_output = rec_signature_def.outputs(so); - auto name = flatbuffer_builder->CreateString(rec_tm_output.name()); - uint32_t tensor_index = 0; - assert(rec_tm_output.has_tensor() || rec_tm_output.has_tensor_index()); - if (rec_tm_output.has_tensor()) - { - auto tensor = rec_tm_output.tensor(); - tensor_index = symbol_table[tensor]; - } - else - { - tensor_index = rec_tm_output.tensor_index(); - } - - ::tflite::TensorMapBuilder tensormap_builder{*flatbuffer_builder}; - tensormap_builder.add_name(name); - tensormap_builder.add_tensor_index(tensor_index); - tensormap_outputs.push_back(tensormap_builder.Finish()); - } - - auto inputs = flatbuffer_builder->CreateVector(tensormap_inputs); - auto outputs = flatbuffer_builder->CreateVector(tensormap_outputs); - auto signature_key = flatbuffer_builder->CreateString(rec_signature_def.signature_key()); - // TODO add validation for signature_key - - ::tflite::SignatureDefBuilder signature_def_builder{*flatbuffer_builder}; - signature_def_builder.add_inputs(inputs); - signature_def_builder.add_outputs(outputs); - signature_def_builder.add_signature_key(signature_key); - signature_def_builder.add_subgraph_index(rec_signature_def.subgraph_index()); - - signdef_vec.emplace_back(signature_def_builder.Finish()); - } - - // Create "Model" arguments - auto buffers = flatbuffer_builder->CreateVector(buffer_vec); - auto signdefs = flatbuffer_builder->CreateVector(signdef_vec); - auto operator_codes = flatbuffer_builder->CreateVector(code_vec); - auto subgraphs = flatbuffer_builder->CreateVector(subgraph_vec); - auto description = flatbuffer_builder->CreateString("Generated by tflchef"); - - // Create "Model" - tflite::ModelBuilder model_builder{*flatbuffer_builder}; - - model_builder.add_version(3); - model_builder.add_operator_codes(operator_codes); - model_builder.add_signature_defs(signdefs); - model_builder.add_subgraphs(subgraphs); - model_builder.add_description(description); - model_builder.add_buffers(buffers); - - auto model = model_builder.Finish(); - - // Finalize - ::tflite::FinishModelBuffer(*flatbuffer_builder, model); -#endif - // Return "GenerateModel" return GeneratedModel{std::move(gen_model)}; } From 2a17490b70e00a5f6105e71e805b621d6ec225fe Mon Sep 17 00:00:00 2001 From: Hyeongseok Oh Date: Mon, 12 Aug 2024 14:00:20 +0900 Subject: [PATCH 24/78] [onert] Remove layout info in BackendContext (#13635) This commit removes layout info in BackendContext. Layout is always NHWC. If not, other backend and core assume that layout is NHWC and backend has responsibility for correctness. ONE-DCO-1.0-Signed-off-by: Hyeongseok Oh --- .../backend/cl_common/include/cl_common/BackendContext.h | 1 - runtime/onert/core/include/backend/BackendContext.h | 3 --- .../core/include/backend/basic/BackendContextHelpers.h | 5 ----- runtime/onert/core/src/compiler/ExecutorFactory.cc | 7 ------- 4 files changed, 16 deletions(-) diff --git a/runtime/onert/backend/cl_common/include/cl_common/BackendContext.h b/runtime/onert/backend/cl_common/include/cl_common/BackendContext.h index 138ce6dc0d3..79031d656a5 100644 --- a/runtime/onert/backend/cl_common/include/cl_common/BackendContext.h +++ b/runtime/onert/backend/cl_common/include/cl_common/BackendContext.h @@ -120,7 +120,6 @@ class BackendContext : public onert::backend::BackendContext { // These tensors do not exist in any operation (No use and def) const auto &info = obj.info(); - assert(_data.operand_layouts.at(ind) == ir::Layout::NHWC); registerTensorInfo(ind, info); } }); diff --git a/runtime/onert/core/include/backend/BackendContext.h b/runtime/onert/core/include/backend/BackendContext.h index a00f739cc3a..052809f7d11 100644 --- a/runtime/onert/core/include/backend/BackendContext.h +++ b/runtime/onert/core/include/backend/BackendContext.h @@ -42,8 +42,6 @@ struct ContextData std::vector op_order; /* Operands that are defined by other backends */ util::Set external_operands; - /* Operand layout info */ - ir::OperandIndexMap operand_layouts; /* Custom kernel builder */ std::shared_ptr custom_kernel_builder; /* Is linear executor or not */ @@ -64,7 +62,6 @@ class BackendContext const Backend *backend() const { return _backend; } const ir::Graph *graph() const { return _data.graph.get(); } const util::Set &external_operands() const { return _data.external_operands; } - const ir::OperandIndexMap &operand_layouts() const { return _data.operand_layouts; } const ContextData &data() const { return _data; } virtual ITensorRegistry *genTensors() = 0; diff --git a/runtime/onert/core/include/backend/basic/BackendContextHelpers.h b/runtime/onert/core/include/backend/basic/BackendContextHelpers.h index 590ae0b9919..79a535559e1 100644 --- a/runtime/onert/core/include/backend/basic/BackendContextHelpers.h +++ b/runtime/onert/core/include/backend/basic/BackendContextHelpers.h @@ -61,11 +61,6 @@ template void planTensors(const T_BackendContext &ct { // These tensors do not exist in any (No use and def) const auto &info = obj.info(); - // NOTE Currently we only support NHWC tensors for cpu-common tensors. - // There is no way to get the layout info from the backend context for now. - // When we support NCHW tensors as well, we also need to change tensor info to be - // permuted shape. - assert(ctx.operand_layouts().at(ind) == ir::Layout::NHWC); tensor_builder->registerTensorInfo(ind, info); } }); diff --git a/runtime/onert/core/src/compiler/ExecutorFactory.cc b/runtime/onert/core/src/compiler/ExecutorFactory.cc index 0766a72174b..233f5f026f7 100644 --- a/runtime/onert/core/src/compiler/ExecutorFactory.cc +++ b/runtime/onert/core/src/compiler/ExecutorFactory.cc @@ -169,9 +169,6 @@ createBackendContexts(compiler::ILoweredGraph &lgraph, bool linear_executor, init_context_data(backend); auto &partial_graph = *context_data_map[backend].graph; - auto &operand_layouts = context_data_map[backend].operand_layouts; - assert(operand_layouts.find(operand_ind) == operand_layouts.end()); - operand_layouts[operand_ind] = ir::Layout::NHWC; // Copy the operand and insert it to the partial graph auto new_operand = std::make_unique(operand); @@ -191,7 +188,6 @@ createBackendContexts(compiler::ILoweredGraph &lgraph, bool linear_executor, auto &partial_graph = *context_data_map[backend].graph; auto &external_operands = context_data_map[backend].external_operands; - auto &operand_layouts = context_data_map[backend].operand_layouts; { // Add missing operands (externals) @@ -210,8 +206,6 @@ createBackendContexts(compiler::ILoweredGraph &lgraph, bool linear_executor, UNUSED_RELEASE(new_operand_ind); assert(new_operand_ind == operand_ind); - assert(operand_layouts.find(operand_ind) == operand_layouts.end()); - operand_layouts[operand_ind] = ir::Layout::NHWC; external_operands.add(operand_ind); } @@ -708,7 +702,6 @@ exec::IExecutor *ExecutorFactory::createTrainableExecutor( tdata.tgraph = std::move(tgraph); tdata.op_order = std::move(data.op_order); tdata.external_operands = std::move(external_operands); - tdata.operand_layouts = std::move(data.operand_layouts); tdata.custom_kernel_builder = std::move(data.custom_kernel_builder); tdata.is_linear_executor = data.is_linear_executor; tdata.optim_info = training_info.optimizerInfo(); From c984690f9a955486fc4afbea2bb5754872d43f24 Mon Sep 17 00:00:00 2001 From: SaeHie Park Date: Mon, 12 Aug 2024 15:11:41 +0900 Subject: [PATCH 25/78] [tflchef] Extract init method (#13641) This will extract init method for flatbuffer_builder initialization. ONE-DCO-1.0-Signed-off-by: SaeHie Park --- compiler/tflchef/core/src/ModelChef.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/compiler/tflchef/core/src/ModelChef.cpp b/compiler/tflchef/core/src/ModelChef.cpp index 5f5a16f6ca3..9cb38d9730e 100644 --- a/compiler/tflchef/core/src/ModelChef.cpp +++ b/compiler/tflchef/core/src/ModelChef.cpp @@ -179,6 +179,7 @@ namespace struct ModelChef { + void init(void); void cook(const ::tflchef::ModelRecipe &model_recipe); template std::map cook_graph(const T &graph); @@ -194,6 +195,12 @@ struct ModelChef std::string _graph_name; }; +void ModelChef::init(void) +{ + flatbuffer_builder = + std::unique_ptr(new flatbuffers::FlatBufferBuilder(1024)); +} + std::vector> make_dim_metadata_vec(flatbuffers::FlatBufferBuilder *flatbuffer_builder, int32_t dims_count, const std::vector &traversal_order_vec, @@ -933,9 +940,7 @@ GeneratedModel cook(const ::tflchef::ModelRecipe &model_recipe) ModelChef &mc = gen_model->model_chef(); - mc.flatbuffer_builder = - std::unique_ptr(new flatbuffers::FlatBufferBuilder(1024)); - + mc.init(); mc.cook(model_recipe); // Return "GenerateModel" From d0db7a8bc6b598d642ecdb547afc5e6cfdaf7c81 Mon Sep 17 00:00:00 2001 From: SaeHie Park Date: Mon, 12 Aug 2024 16:27:52 +0900 Subject: [PATCH 26/78] [tflchef] Revise ModelChef as class (#13642) This will revise ModelChef as class - add _ prefix to member variables - introduce get_buffer_pointer() and _get_size() ONE-DCO-1.0-Signed-off-by: SaeHie Park --- compiler/tflchef/core/src/ModelChef.cpp | 227 +++++++++++++----------- 1 file changed, 124 insertions(+), 103 deletions(-) diff --git a/compiler/tflchef/core/src/ModelChef.cpp b/compiler/tflchef/core/src/ModelChef.cpp index 9cb38d9730e..842fd0e4c3a 100644 --- a/compiler/tflchef/core/src/ModelChef.cpp +++ b/compiler/tflchef/core/src/ModelChef.cpp @@ -177,27 +177,36 @@ std::set gather_customcode_set(const ::tflchef::ModelRecipe &model_ namespace { -struct ModelChef +class ModelChef { +public: + ModelChef() = default; + +public: void init(void); void cook(const ::tflchef::ModelRecipe &model_recipe); template std::map cook_graph(const T &graph); - std::unique_ptr flatbuffer_builder; +public: + const char *get_buffer_pointer(void) const; + size_t get_size(void) const; - std::vector> signdef_vec; - std::vector> buffer_vec; - std::vector> code_vec; - std::vector> subgraph_vec; - std::map builtin_code_map; - std::vector custom_code_vec; +private: + std::unique_ptr _flatbuffer_builder; + + std::vector> _signdef_vec; + std::vector> _buffer_vec; + std::vector> _code_vec; + std::vector> _subgraph_vec; + std::map _builtin_code_map; + std::vector _custom_code_vec; std::string _graph_name; }; void ModelChef::init(void) { - flatbuffer_builder = + _flatbuffer_builder = std::unique_ptr(new flatbuffers::FlatBufferBuilder(1024)); } @@ -266,22 +275,22 @@ template std::map ModelChef::cook_graph(const } }; - int32_t buffer_start = buffer_vec.size(); + int32_t buffer_start = _buffer_vec.size(); int32_t buffer_index = 0; // Create buffer(s) 1~n(I) for input(s) const auto size_input = graph.input_size(); for (int ci = 0; ci < size_input; ++ci) { - tflite::BufferBuilder buffer_builder{*flatbuffer_builder}; - buffer_vec.emplace_back(buffer_builder.Finish()); + tflite::BufferBuilder buffer_builder{*_flatbuffer_builder}; + _buffer_vec.emplace_back(buffer_builder.Finish()); } // Create buffer(s) n(I)+1~n(I)+n(O) for output(s) const auto size_output = graph.output_size(); for (int co = 0; co < size_output; ++co) { - tflite::BufferBuilder buffer_builder{*flatbuffer_builder}; - buffer_vec.emplace_back(buffer_builder.Finish()); + tflite::BufferBuilder buffer_builder{*_flatbuffer_builder}; + _buffer_vec.emplace_back(buffer_builder.Finish()); } auto input_names = as_dataset(graph.input()).vectorize(); @@ -300,10 +309,10 @@ template std::map ModelChef::cook_graph(const if (operand.has_shape()) { dims = as_dims(operand.shape()); - shape = flatbuffer_builder->CreateVector(dims); + shape = _flatbuffer_builder->CreateVector(dims); } - auto name = flatbuffer_builder->CreateString(operand.name()); + auto name = _flatbuffer_builder->CreateString(operand.name()); buffer_index = 0; @@ -354,31 +363,31 @@ template std::map ModelChef::cook_graph(const sparse_uint8.emplace_back(arr[b]); } } - auto data = flatbuffer_builder->CreateVector(sparse_uint8); + auto data = _flatbuffer_builder->CreateVector(sparse_uint8); // Create Buffer - tflite::BufferBuilder buffer_builder{*flatbuffer_builder}; + tflite::BufferBuilder buffer_builder{*_flatbuffer_builder}; buffer_builder.add_data(data); auto buffer = buffer_builder.Finish(); // Update Buffer Index & Vector - buffer_index = buffer_vec.size(); - buffer_vec.emplace_back(buffer); + buffer_index = _buffer_vec.size(); + _buffer_vec.emplace_back(buffer); // save SparsityParameters - auto traversal_order = flatbuffer_builder->CreateVector(traversal_order_vec); + auto traversal_order = _flatbuffer_builder->CreateVector(traversal_order_vec); // Create block map std::vector block_map_vec{}; - auto block_map = flatbuffer_builder->CreateVector(block_map_vec); + auto block_map = _flatbuffer_builder->CreateVector(block_map_vec); // Create dimension metadata const auto &dim_metadata_src = converter.GetDimMetadata(); auto dim_metadata_vec = - make_dim_metadata_vec(flatbuffer_builder.get(), dims_count, traversal_order_vec, + make_dim_metadata_vec(_flatbuffer_builder.get(), dims_count, traversal_order_vec, format_vec, dim_metadata_src); - auto dim_metadata = flatbuffer_builder->CreateVector(dim_metadata_vec); - sparsity_index = tflite::CreateSparsityParameters(*flatbuffer_builder, traversal_order, + auto dim_metadata = _flatbuffer_builder->CreateVector(dim_metadata_vec); + sparsity_index = tflite::CreateSparsityParameters(*_flatbuffer_builder, traversal_order, block_map, dim_metadata); } else if (operand.type() == tflchef::FLOAT16) @@ -397,31 +406,31 @@ template std::map ModelChef::cook_graph(const sparse_uint8.emplace_back(arr[b]); } } - auto data = flatbuffer_builder->CreateVector(sparse_uint8); + auto data = _flatbuffer_builder->CreateVector(sparse_uint8); // Create Buffer - tflite::BufferBuilder buffer_builder{*flatbuffer_builder}; + tflite::BufferBuilder buffer_builder{*_flatbuffer_builder}; buffer_builder.add_data(data); auto buffer = buffer_builder.Finish(); // Update Buffer Index & Vector - buffer_index = buffer_vec.size(); - buffer_vec.emplace_back(buffer); + buffer_index = _buffer_vec.size(); + _buffer_vec.emplace_back(buffer); // save SparsityParameters - auto traversal_order = flatbuffer_builder->CreateVector(traversal_order_vec); + auto traversal_order = _flatbuffer_builder->CreateVector(traversal_order_vec); // Create block map std::vector block_map_vec{}; - auto block_map = flatbuffer_builder->CreateVector(block_map_vec); + auto block_map = _flatbuffer_builder->CreateVector(block_map_vec); // Create dimension metadata const auto &dim_metadata_src = converter.GetDimMetadata(); auto dim_metadata_vec = - make_dim_metadata_vec(flatbuffer_builder.get(), dims_count, traversal_order_vec, + make_dim_metadata_vec(_flatbuffer_builder.get(), dims_count, traversal_order_vec, format_vec, dim_metadata_src); - auto dim_metadata = flatbuffer_builder->CreateVector(dim_metadata_vec); - sparsity_index = tflite::CreateSparsityParameters(*flatbuffer_builder, traversal_order, + auto dim_metadata = _flatbuffer_builder->CreateVector(dim_metadata_vec); + sparsity_index = tflite::CreateSparsityParameters(*_flatbuffer_builder, traversal_order, block_map, dim_metadata); } else @@ -446,16 +455,16 @@ template std::map ModelChef::cook_graph(const data_vec = data_packed; } - auto data = flatbuffer_builder->CreateVector(data_vec); + auto data = _flatbuffer_builder->CreateVector(data_vec); // Create Buffer - tflite::BufferBuilder buffer_builder{*flatbuffer_builder}; + tflite::BufferBuilder buffer_builder{*_flatbuffer_builder}; buffer_builder.add_data(data); auto buffer = buffer_builder.Finish(); // Update Buffer Index & Vector - buffer_index = buffer_vec.size(); - buffer_vec.emplace_back(buffer); + buffer_index = _buffer_vec.size(); + _buffer_vec.emplace_back(buffer); } } else @@ -485,10 +494,10 @@ template std::map ModelChef::cook_graph(const if (buffer_index == 0) { // we couldn't find the buffer; create an empty buffer for this tensor - buffer_index = buffer_vec.size(); + buffer_index = _buffer_vec.size(); - tflite::BufferBuilder buffer_builder{*flatbuffer_builder}; - buffer_vec.emplace_back(buffer_builder.Finish()); + tflite::BufferBuilder buffer_builder{*_flatbuffer_builder}; + _buffer_vec.emplace_back(buffer_builder.Finish()); } } assert(buffer_index != 0); @@ -516,13 +525,13 @@ template std::map ModelChef::cook_graph(const for (uint32_t i = 0; i < quant.zero_point_size(); ++i) quant_zero_point_vec.at(i) = quant.zero_point(i); - auto quant_max = flatbuffer_builder->CreateVector(quant_max_vec); - auto quant_min = flatbuffer_builder->CreateVector(quant_min_vec); - auto quant_scale = flatbuffer_builder->CreateVector(quant_scale_vec); - auto quant_zero_point = flatbuffer_builder->CreateVector(quant_zero_point_vec); + auto quant_max = _flatbuffer_builder->CreateVector(quant_max_vec); + auto quant_min = _flatbuffer_builder->CreateVector(quant_min_vec); + auto quant_scale = _flatbuffer_builder->CreateVector(quant_scale_vec); + auto quant_zero_point = _flatbuffer_builder->CreateVector(quant_zero_point_vec); // Create QuantizationParameters - tflite::QuantizationParametersBuilder quant_builder{*flatbuffer_builder}; + tflite::QuantizationParametersBuilder quant_builder{*_flatbuffer_builder}; quant_builder.add_max(quant_max); quant_builder.add_min(quant_min); quant_builder.add_scale(quant_scale); @@ -540,12 +549,12 @@ template std::map ModelChef::cook_graph(const // Create traversal order std::vector traversal_order_vec{sparsity.traversal_order().dim().begin(), sparsity.traversal_order().dim().end()}; - auto traversal_order = flatbuffer_builder->CreateVector(traversal_order_vec); + auto traversal_order = _flatbuffer_builder->CreateVector(traversal_order_vec); // Create block map std::vector block_map_vec{sparsity.block_map().dim().begin(), sparsity.block_map().dim().end()}; - auto block_map = flatbuffer_builder->CreateVector(block_map_vec); + auto block_map = _flatbuffer_builder->CreateVector(block_map_vec); // Create dimension metadata std::vector> dim_metadata_vec; @@ -554,13 +563,13 @@ template std::map ModelChef::cook_graph(const { // Create array segments auto tflite_array_segments = - as_tflite_sparse_index_vec(*flatbuffer_builder, dm.array_segments()); + as_tflite_sparse_index_vec(*_flatbuffer_builder, dm.array_segments()); // Create array indices auto tflite_array_indices = - as_tflite_sparse_index_vec(*flatbuffer_builder, dm.array_indices()); + as_tflite_sparse_index_vec(*_flatbuffer_builder, dm.array_indices()); - auto tflite_dim_metadata_builder = tflite::DimensionMetadataBuilder{*flatbuffer_builder}; + auto tflite_dim_metadata_builder = tflite::DimensionMetadataBuilder{*_flatbuffer_builder}; tflite_dim_metadata_builder.add_format(as_tflite_dimensiontype(dm.format())); tflite_dim_metadata_builder.add_dense_size(dm.dense_size()); tflite_dim_metadata_builder.add_array_segments(tflite_array_segments); @@ -572,9 +581,9 @@ template std::map ModelChef::cook_graph(const auto tflite_dim_metadata = tflite_dim_metadata_builder.Finish(); dim_metadata_vec.emplace_back(tflite_dim_metadata); } - auto dim_metadata = flatbuffer_builder->CreateVector(dim_metadata_vec); + auto dim_metadata = _flatbuffer_builder->CreateVector(dim_metadata_vec); - sparsity_index = tflite::CreateSparsityParameters(*flatbuffer_builder, traversal_order, + sparsity_index = tflite::CreateSparsityParameters(*_flatbuffer_builder, traversal_order, block_map, dim_metadata); } @@ -582,11 +591,11 @@ template std::map ModelChef::cook_graph(const if (operand.has_shape_signature()) { auto signature = as_dims(operand.shape_signature()); - shape_signature = flatbuffer_builder->CreateVector(signature); + shape_signature = _flatbuffer_builder->CreateVector(signature); } // Create Tensor - tflite::TensorBuilder tensor_builder{*flatbuffer_builder}; + tflite::TensorBuilder tensor_builder{*_flatbuffer_builder}; tensor_builder.add_shape(shape); tensor_builder.add_type(as_tflite_tensortype(operand.type())); @@ -624,39 +633,39 @@ template std::map ModelChef::cook_graph(const // Create 'inputs' std::vector input_vec = as_dataset(operation.input()).map(lookup).vectorize(); - auto inputs = flatbuffer_builder->CreateVector(input_vec); + auto inputs = _flatbuffer_builder->CreateVector(input_vec); // Create 'outputs' std::vector output_vec = as_dataset(operation.output()).map(lookup).vectorize(); - auto outputs = flatbuffer_builder->CreateVector(output_vec); + auto outputs = _flatbuffer_builder->CreateVector(output_vec); // Create Option - auto options = op_chef->value(*flatbuffer_builder); + auto options = op_chef->value(*_flatbuffer_builder); // Create Custom option - auto circle_custom_options = op_chef->custom_value(*flatbuffer_builder); + auto circle_custom_options = op_chef->custom_value(*_flatbuffer_builder); // Create Operator - tflite::OperatorBuilder op_builder{*flatbuffer_builder}; + tflite::OperatorBuilder op_builder{*_flatbuffer_builder}; // Note that opcode_index is an index into the operator_codes vector. // operator_codes consists of buildtin_code and custom_code, which is inserted sequentially. uint32_t opcode_index = 0; - auto op_it = builtin_code_map.find(op_chef->code()); + auto op_it = _builtin_code_map.find(op_chef->code()); // builtin operator - if (op_it != builtin_code_map.end()) + if (op_it != _builtin_code_map.end()) { - opcode_index = std::distance(builtin_code_map.begin(), op_it); + opcode_index = std::distance(_builtin_code_map.begin(), op_it); } // custom operator else { assert(not operation.custom_code().empty()); auto custom_code = operation.custom_code(); - auto op_it = std::find(custom_code_vec.begin(), custom_code_vec.end(), custom_code); - assert(op_it != custom_code_vec.end()); - opcode_index = builtin_code_map.size(); - opcode_index += std::distance(custom_code_vec.begin(), op_it); + auto op_it = std::find(_custom_code_vec.begin(), _custom_code_vec.end(), custom_code); + assert(op_it != _custom_code_vec.end()); + opcode_index = _builtin_code_map.size(); + opcode_index += std::distance(_custom_code_vec.begin(), op_it); } op_builder.add_opcode_index(opcode_index); @@ -675,13 +684,13 @@ template std::map ModelChef::cook_graph(const std::vector output_vec = as_dataset(graph.output()).map(lookup).vectorize(); // Create "SubGraph" arguments - auto tensors = flatbuffer_builder->CreateVector(tensor_vec); - auto inputs = flatbuffer_builder->CreateVector(input_vec); - auto outputs = flatbuffer_builder->CreateVector(output_vec); - auto operators = flatbuffer_builder->CreateVector(operator_vec); - auto name = flatbuffer_builder->CreateString(graph_name); + auto tensors = _flatbuffer_builder->CreateVector(tensor_vec); + auto inputs = _flatbuffer_builder->CreateVector(input_vec); + auto outputs = _flatbuffer_builder->CreateVector(output_vec); + auto operators = _flatbuffer_builder->CreateVector(operator_vec); + auto name = _flatbuffer_builder->CreateString(graph_name); - tflite::SubGraphBuilder subgraph_builder{*flatbuffer_builder}; + tflite::SubGraphBuilder subgraph_builder{*_flatbuffer_builder}; subgraph_builder.add_tensors(tensors); subgraph_builder.add_inputs(inputs); @@ -689,7 +698,7 @@ template std::map ModelChef::cook_graph(const subgraph_builder.add_operators(operators); subgraph_builder.add_name(name); - subgraph_vec.emplace_back(subgraph_builder.Finish()); + _subgraph_vec.emplace_back(subgraph_builder.Finish()); return symbol_table; } @@ -697,10 +706,10 @@ template std::map ModelChef::cook_graph(const void ModelChef::cook(const ::tflchef::ModelRecipe &model_recipe) { // Create OperatorCode with Builtin Operator - builtin_code_map = gather_builtincode_map(model_recipe); - for (auto const &opcode : builtin_code_map) + _builtin_code_map = gather_builtincode_map(model_recipe); + for (auto const &opcode : _builtin_code_map) { - tflite::OperatorCodeBuilder code_builder{*flatbuffer_builder}; + tflite::OperatorCodeBuilder code_builder{*_flatbuffer_builder}; // 127 is BuiltinOperator_PLACEHOLDER_FOR_GREATER_OP_CODES // This is the way to handle deprecated builtin code // See @@ -718,23 +727,23 @@ void ModelChef::cook(const ::tflchef::ModelRecipe &model_recipe) code_builder.add_builtin_code(opcode.first); auto code = code_builder.Finish(); // Update OperatorCode vector - code_vec.emplace_back(code); + _code_vec.emplace_back(code); } // Create OperatorCode with Custom Operator std::set custom_code_set = gather_customcode_set(model_recipe); - custom_code_vec = {custom_code_set.begin(), custom_code_set.end()}; + _custom_code_vec = {custom_code_set.begin(), custom_code_set.end()}; - for (auto opcode : custom_code_vec) + for (auto opcode : _custom_code_vec) { - auto custom_code = flatbuffer_builder->CreateString(opcode); - tflite::OperatorCodeBuilder code_builder{*flatbuffer_builder}; + auto custom_code = _flatbuffer_builder->CreateString(opcode); + tflite::OperatorCodeBuilder code_builder{*_flatbuffer_builder}; code_builder.add_deprecated_builtin_code(tflite::BuiltinOperator_CUSTOM); code_builder.add_custom_code(custom_code); code_builder.add_builtin_code(tflite::BuiltinOperator_CUSTOM); auto code = code_builder.Finish(); // Update OperatorCode vector - code_vec.emplace_back(code); + _code_vec.emplace_back(code); } // Create an Empty Buffer @@ -742,8 +751,8 @@ void ModelChef::cook(const ::tflchef::ModelRecipe &model_recipe) // Buffer 0 SHOULD be an empty buffer in TensorFlow Lite model file // (Please refer to the comment for Tensor.buffer field in schema) { - tflite::BufferBuilder buffer_builder{*flatbuffer_builder}; - buffer_vec.emplace_back(buffer_builder.Finish()); + tflite::BufferBuilder buffer_builder{*_flatbuffer_builder}; + _buffer_vec.emplace_back(buffer_builder.Finish()); } // symbol_tables stores symbol_table of each sub graph @@ -798,7 +807,7 @@ void ModelChef::cook(const ::tflchef::ModelRecipe &model_recipe) { // recipe for input TensorMap auto rec_tm_input = rec_signature_def.inputs(si); - auto name = flatbuffer_builder->CreateString(rec_tm_input.name()); + auto name = _flatbuffer_builder->CreateString(rec_tm_input.name()); uint32_t tensor_index = 0; // either tensor or tensor_index should exist assert(rec_tm_input.has_tensor() || rec_tm_input.has_tensor_index()); @@ -814,7 +823,7 @@ void ModelChef::cook(const ::tflchef::ModelRecipe &model_recipe) tensor_index = rec_tm_input.tensor_index(); } - ::tflite::TensorMapBuilder tensormap_builder{*flatbuffer_builder}; + ::tflite::TensorMapBuilder tensormap_builder{*_flatbuffer_builder}; tensormap_builder.add_name(name); tensormap_builder.add_tensor_index(tensor_index); tensormap_inputs.push_back(tensormap_builder.Finish()); @@ -823,7 +832,7 @@ void ModelChef::cook(const ::tflchef::ModelRecipe &model_recipe) for (int so = 0; so < rec_signature_def.outputs_size(); ++so) { auto rec_tm_output = rec_signature_def.outputs(so); - auto name = flatbuffer_builder->CreateString(rec_tm_output.name()); + auto name = _flatbuffer_builder->CreateString(rec_tm_output.name()); uint32_t tensor_index = 0; assert(rec_tm_output.has_tensor() || rec_tm_output.has_tensor_index()); if (rec_tm_output.has_tensor()) @@ -836,35 +845,35 @@ void ModelChef::cook(const ::tflchef::ModelRecipe &model_recipe) tensor_index = rec_tm_output.tensor_index(); } - ::tflite::TensorMapBuilder tensormap_builder{*flatbuffer_builder}; + ::tflite::TensorMapBuilder tensormap_builder{*_flatbuffer_builder}; tensormap_builder.add_name(name); tensormap_builder.add_tensor_index(tensor_index); tensormap_outputs.push_back(tensormap_builder.Finish()); } - auto inputs = flatbuffer_builder->CreateVector(tensormap_inputs); - auto outputs = flatbuffer_builder->CreateVector(tensormap_outputs); - auto signature_key = flatbuffer_builder->CreateString(rec_signature_def.signature_key()); + auto inputs = _flatbuffer_builder->CreateVector(tensormap_inputs); + auto outputs = _flatbuffer_builder->CreateVector(tensormap_outputs); + auto signature_key = _flatbuffer_builder->CreateString(rec_signature_def.signature_key()); // TODO add validation for signature_key - ::tflite::SignatureDefBuilder signature_def_builder{*flatbuffer_builder}; + ::tflite::SignatureDefBuilder signature_def_builder{*_flatbuffer_builder}; signature_def_builder.add_inputs(inputs); signature_def_builder.add_outputs(outputs); signature_def_builder.add_signature_key(signature_key); signature_def_builder.add_subgraph_index(rec_signature_def.subgraph_index()); - signdef_vec.emplace_back(signature_def_builder.Finish()); + _signdef_vec.emplace_back(signature_def_builder.Finish()); } // Create "Model" arguments - auto buffers = flatbuffer_builder->CreateVector(buffer_vec); - auto signdefs = flatbuffer_builder->CreateVector(signdef_vec); - auto operator_codes = flatbuffer_builder->CreateVector(code_vec); - auto subgraphs = flatbuffer_builder->CreateVector(subgraph_vec); - auto description = flatbuffer_builder->CreateString("Generated by tflchef"); + auto buffers = _flatbuffer_builder->CreateVector(_buffer_vec); + auto signdefs = _flatbuffer_builder->CreateVector(_signdef_vec); + auto operator_codes = _flatbuffer_builder->CreateVector(_code_vec); + auto subgraphs = _flatbuffer_builder->CreateVector(_subgraph_vec); + auto description = _flatbuffer_builder->CreateString("Generated by tflchef"); // Create "Model" - tflite::ModelBuilder model_builder{*flatbuffer_builder}; + tflite::ModelBuilder model_builder{*_flatbuffer_builder}; model_builder.add_version(3); model_builder.add_operator_codes(operator_codes); @@ -876,7 +885,19 @@ void ModelChef::cook(const ::tflchef::ModelRecipe &model_recipe) auto model = model_builder.Finish(); // Finalize - ::tflite::FinishModelBuffer(*flatbuffer_builder, model); + ::tflite::FinishModelBuffer(*_flatbuffer_builder, model); +} + +const char *ModelChef::get_buffer_pointer(void) const +{ + // + return reinterpret_cast(_flatbuffer_builder->GetBufferPointer()); +} + +size_t ModelChef::get_size(void) const +{ + // + return _flatbuffer_builder->GetSize(); } } // namespace @@ -896,14 +917,14 @@ class GeneratedModelImpl final : public tflchef::GeneratedModel::Impl const char *base(void) const override { // Return the base address of generated flatbuffer model - return reinterpret_cast(_mc.flatbuffer_builder->GetBufferPointer()); + return reinterpret_cast(_mc.get_buffer_pointer()); } public: size_t size(void) const override { // Return the size of generated flatbuffer model - return _mc.flatbuffer_builder->GetSize(); + return _mc.get_size(); } public: From 6fafda7522938fa36d0080a80355373c03dfa0a4 Mon Sep 17 00:00:00 2001 From: SaeHie Park Date: Mon, 12 Aug 2024 18:51:43 +0900 Subject: [PATCH 27/78] [tflchef] Tidy GeneratedModelImpl (#13644) This will tidy GeneratedModelImpl base() and size() methods. ONE-DCO-1.0-Signed-off-by: SaeHie Park --- compiler/tflchef/core/src/ModelChef.cpp | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/compiler/tflchef/core/src/ModelChef.cpp b/compiler/tflchef/core/src/ModelChef.cpp index 842fd0e4c3a..b3d3b5c836e 100644 --- a/compiler/tflchef/core/src/ModelChef.cpp +++ b/compiler/tflchef/core/src/ModelChef.cpp @@ -914,18 +914,9 @@ class GeneratedModelImpl final : public tflchef::GeneratedModel::Impl } public: - const char *base(void) const override - { - // Return the base address of generated flatbuffer model - return reinterpret_cast(_mc.get_buffer_pointer()); - } + const char *base(void) const override { return _mc.get_buffer_pointer(); } -public: - size_t size(void) const override - { - // Return the size of generated flatbuffer model - return _mc.get_size(); - } + size_t size(void) const override { return _mc.get_size(); } public: ModelChef &model_chef(void) { return _mc; } From e9d8711438d50172b599535d3bf2e5175598c5c1 Mon Sep 17 00:00:00 2001 From: SaeHie Park Date: Tue, 13 Aug 2024 07:15:30 +0900 Subject: [PATCH 28/78] [tflchef] Revise cook with symbol_table(s) (#13643) This will revise cook method to have symbol_table as parameter instead of return value and symbol_tables as ModelChef member. ONE-DCO-1.0-Signed-off-by: SaeHie Park Co-authored-by: Hyukjin Jeong --- compiler/tflchef/core/src/ModelChef.cpp | 36 +++++++++++++------------ 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/compiler/tflchef/core/src/ModelChef.cpp b/compiler/tflchef/core/src/ModelChef.cpp index b3d3b5c836e..b857e3ce5c9 100644 --- a/compiler/tflchef/core/src/ModelChef.cpp +++ b/compiler/tflchef/core/src/ModelChef.cpp @@ -186,7 +186,8 @@ class ModelChef void init(void); void cook(const ::tflchef::ModelRecipe &model_recipe); - template std::map cook_graph(const T &graph); + template + void cook_graph(const T &graph, std::map &symbol_table); public: const char *get_buffer_pointer(void) const; @@ -201,6 +202,10 @@ class ModelChef std::vector> _subgraph_vec; std::map _builtin_code_map; std::vector _custom_code_vec; + // _symbol_tables stores symbol_table of each sub graph + // this is used to find tensor ID(index) with tensor name + std::vector> _symbol_tables; + std::string _graph_name; }; @@ -245,10 +250,13 @@ make_dim_metadata_vec(flatbuffers::FlatBufferBuilder *flatbuffer_builder, int32_ return dim_metadata_vec; } -template std::map ModelChef::cook_graph(const T &graph) +template +void ModelChef::cook_graph(const T &graph, std::map &symbol_table) { LOGGER(l); + assert(symbol_table.empty()); // FIX_CALLER_UNLESS + // Operand-related std::vector> tensor_vec; @@ -260,9 +268,6 @@ template std::map ModelChef::cook_graph(const if (graph.has_name()) graph_name = graph.name(); - // Tensor Name -> Tensor ID mapping (per Graph) - std::map symbol_table; - auto lookup = [&symbol_table, &graph_name](const std::string &name) { if (symbol_table.find(name) != symbol_table.end()) return symbol_table.at(name); @@ -699,8 +704,6 @@ template std::map ModelChef::cook_graph(const subgraph_builder.add_name(name); _subgraph_vec.emplace_back(subgraph_builder.Finish()); - - return symbol_table; } void ModelChef::cook(const ::tflchef::ModelRecipe &model_recipe) @@ -755,17 +758,15 @@ void ModelChef::cook(const ::tflchef::ModelRecipe &model_recipe) _buffer_vec.emplace_back(buffer_builder.Finish()); } - // symbol_tables stores symbol_table of each sub graph - // this is used to find tensor ID(index) with tensor name - std::vector> symbol_tables; - // // Create Main graph // _graph_name = "main"; - auto table = cook_graph<::tflchef::ModelRecipe>(model_recipe); - symbol_tables.push_back(table); + // Tensor Name -> Tensor ID mapping (per Graph) + std::map symbol_table; + cook_graph<::tflchef::ModelRecipe>(model_recipe, symbol_table); + _symbol_tables.push_back(symbol_table); // // Create subgraphs if exist @@ -779,8 +780,9 @@ void ModelChef::cook(const ::tflchef::ModelRecipe &model_recipe) _graph_name = stringStream.str(); - auto table = cook_graph<::tflchef::Graph>(graph); - symbol_tables.push_back(table); + symbol_table.clear(); + cook_graph<::tflchef::Graph>(graph, symbol_table); + _symbol_tables.push_back(symbol_table); } // Create Signature-Def @@ -799,8 +801,8 @@ void ModelChef::cook(const ::tflchef::ModelRecipe &model_recipe) { subgraph_index = rec_signature_def.subgraph_index(); } - assert(subgraph_index < symbol_tables.size()); - auto &symbol_table = symbol_tables[subgraph_index]; + assert(subgraph_index < _symbol_tables.size()); + auto &symbol_table = _symbol_tables[subgraph_index]; // cook for inputs for (int si = 0; si < rec_signature_def.inputs_size(); ++si) From 4ff27c74c5b7416c957a81eab3f701884c154636 Mon Sep 17 00:00:00 2001 From: SaeHie Park Date: Tue, 13 Aug 2024 10:08:20 +0900 Subject: [PATCH 29/78] [tflchef] Extract cook_operands method (#13652) This will extract cook_operands method to gather tensors. ONE-DCO-1.0-Signed-off-by: SaeHie Park --- compiler/tflchef/core/src/ModelChef.cpp | 368 +++++++++++++++++++++++- 1 file changed, 364 insertions(+), 4 deletions(-) diff --git a/compiler/tflchef/core/src/ModelChef.cpp b/compiler/tflchef/core/src/ModelChef.cpp index b857e3ce5c9..03422a84471 100644 --- a/compiler/tflchef/core/src/ModelChef.cpp +++ b/compiler/tflchef/core/src/ModelChef.cpp @@ -186,6 +186,9 @@ class ModelChef void init(void); void cook(const ::tflchef::ModelRecipe &model_recipe); +private: + template void cook_operands(const T &graph); + template void cook_graph(const T &graph, std::map &symbol_table); @@ -206,6 +209,10 @@ class ModelChef // this is used to find tensor ID(index) with tensor name std::vector> _symbol_tables; + // per graph that needs clear afer graph is processed + // Operand-related + std::vector> _tensor_vec; + std::string _graph_name; }; @@ -250,15 +257,352 @@ make_dim_metadata_vec(flatbuffers::FlatBufferBuilder *flatbuffer_builder, int32_ return dim_metadata_vec; } +template void ModelChef::cook_operands(const T &graph) +{ + int32_t buffer_start = _buffer_vec.size(); + int32_t buffer_index = 0; + + // Create buffer(s) 1~n(I) for input(s) + const auto size_input = graph.input_size(); + for (int ci = 0; ci < size_input; ++ci) + { + tflite::BufferBuilder buffer_builder{*_flatbuffer_builder}; + _buffer_vec.emplace_back(buffer_builder.Finish()); + } + // Create buffer(s) n(I)+1~n(I)+n(O) for output(s) + const auto size_output = graph.output_size(); + for (int co = 0; co < size_output; ++co) + { + tflite::BufferBuilder buffer_builder{*_flatbuffer_builder}; + _buffer_vec.emplace_back(buffer_builder.Finish()); + } + + auto input_names = as_dataset(graph.input()).vectorize(); + auto output_names = as_dataset(graph.output()).vectorize(); + + for (const auto &operand : graph.operand()) + { + assert(operand.has_name()); + assert(operand.has_type()); + + flatbuffers::Offset sparsity_index; + + flatbuffers::Offset> shape; + std::vector dims; + if (operand.has_shape()) + { + dims = as_dims(operand.shape()); + shape = _flatbuffer_builder->CreateVector(dims); + } + + auto name = _flatbuffer_builder->CreateString(operand.name()); + + buffer_index = 0; + + // Create Buffer if filler is specified + if (operand.has_filler()) + { + const auto &filler = operand.filler(); + + assert(filler.has_tag()); + + auto args = ranged_arguments(filler.arg().begin(), filler.arg().end()); + auto chef = data_chef_registry(operand.type()).lookup(filler.tag()).create(args); + + assert(chef != nullptr); + + // Create Data + int32_t count = (element_count(dims) > 0) ? element_count(dims) : filler.arg_size(); + auto data_vec = chef->generate(count); + + if (operand.has_make_sparse() && operand.make_sparse()) + { + assert(not operand.has_sparsity()); + assert(operand.has_shape()); + assert(operand.type() != tflchef::TensorType::INT4); + + const int32_t dims_count = dims.size(); + std::vector traversal_order_vec; + std::vector format_vec; + for (int32_t o = 0; o < dims_count; ++o) + traversal_order_vec.push_back(o); + for (int32_t o = 0; o < dims_count - 1; ++o) + format_vec.push_back(sparsity::kTfLiteDimDense); + format_vec.push_back(sparsity::kTfLiteDimSparseCSR); + + if (operand.type() == tflchef::FLOAT32) + { + ::sparsity::FormatConverter converter(dims, traversal_order_vec, format_vec); + converter.DenseToSparse(reinterpret_cast(data_vec.data())); + const auto &sparse_data = converter.GetData(); + + std::vector sparse_uint8; + for (int c = 0; c < sparse_data.size(); ++c) + { + const float value = sparse_data.at(c); + const uint8_t *arr = reinterpret_cast(&value); + for (uint32_t b = 0; b < sizeof(float); ++b) + { + sparse_uint8.emplace_back(arr[b]); + } + } + auto data = _flatbuffer_builder->CreateVector(sparse_uint8); + + // Create Buffer + tflite::BufferBuilder buffer_builder{*_flatbuffer_builder}; + buffer_builder.add_data(data); + auto buffer = buffer_builder.Finish(); + + // Update Buffer Index & Vector + buffer_index = _buffer_vec.size(); + _buffer_vec.emplace_back(buffer); + + // save SparsityParameters + auto traversal_order = _flatbuffer_builder->CreateVector(traversal_order_vec); + + // Create block map + std::vector block_map_vec{}; + auto block_map = _flatbuffer_builder->CreateVector(block_map_vec); + + // Create dimension metadata + const auto &dim_metadata_src = converter.GetDimMetadata(); + auto dim_metadata_vec = + make_dim_metadata_vec(_flatbuffer_builder.get(), dims_count, traversal_order_vec, + format_vec, dim_metadata_src); + auto dim_metadata = _flatbuffer_builder->CreateVector(dim_metadata_vec); + sparsity_index = tflite::CreateSparsityParameters(*_flatbuffer_builder, traversal_order, + block_map, dim_metadata); + } + else if (operand.type() == tflchef::FLOAT16) + { + ::sparsity::FormatConverter converter(dims, traversal_order_vec, format_vec); + converter.DenseToSparse(reinterpret_cast(data_vec.data())); + const auto &sparse_data = converter.GetData(); + + std::vector sparse_uint8; + for (int c = 0; c < sparse_data.size(); ++c) + { + const uint16_t value = sparse_data.at(c); + const uint8_t *arr = reinterpret_cast(&value); + for (uint32_t b = 0; b < sizeof(uint16_t); ++b) + { + sparse_uint8.emplace_back(arr[b]); + } + } + auto data = _flatbuffer_builder->CreateVector(sparse_uint8); + + // Create Buffer + tflite::BufferBuilder buffer_builder{*_flatbuffer_builder}; + buffer_builder.add_data(data); + auto buffer = buffer_builder.Finish(); + + // Update Buffer Index & Vector + buffer_index = _buffer_vec.size(); + _buffer_vec.emplace_back(buffer); + + // save SparsityParameters + auto traversal_order = _flatbuffer_builder->CreateVector(traversal_order_vec); + + // Create block map + std::vector block_map_vec{}; + auto block_map = _flatbuffer_builder->CreateVector(block_map_vec); + + // Create dimension metadata + const auto &dim_metadata_src = converter.GetDimMetadata(); + auto dim_metadata_vec = + make_dim_metadata_vec(_flatbuffer_builder.get(), dims_count, traversal_order_vec, + format_vec, dim_metadata_src); + auto dim_metadata = _flatbuffer_builder->CreateVector(dim_metadata_vec); + sparsity_index = tflite::CreateSparsityParameters(*_flatbuffer_builder, traversal_order, + block_map, dim_metadata); + } + else + { + throw std::runtime_error{"NYI: unsupported operand type"}; + } + } + else + { + // pack for INT4 and replace data_vec + if (operand.type() == tflchef::TensorType::INT4) + { + uint32_t packed = (count + 1) / 2; + std::vector data_packed(packed); + for (uint32_t idx = 0; idx < packed; ++idx) + { + uint32_t sidx = idx * 2; + data_packed[idx] = data_vec[sidx++] & 0x0f; + if (sidx < count) + data_packed[idx] |= data_vec[sidx] << 4; + } + data_vec = data_packed; + } + + auto data = _flatbuffer_builder->CreateVector(data_vec); + + // Create Buffer + tflite::BufferBuilder buffer_builder{*_flatbuffer_builder}; + buffer_builder.add_data(data); + auto buffer = buffer_builder.Finish(); + + // Update Buffer Index & Vector + buffer_index = _buffer_vec.size(); + _buffer_vec.emplace_back(buffer); + } + } + else + { + // if this is input or output, assign to that buffer_index + int idx = 0; + for (auto it = input_names.begin(); it != input_names.end(); ++it, ++idx) + { + if (*it == operand.name()) + { + buffer_index = buffer_start + idx; + break; + } + } + if (buffer_index == 0) + { + idx = 0; + for (auto it = output_names.begin(); it != output_names.end(); ++it, ++idx) + { + if (*it == operand.name()) + { + buffer_index = buffer_start + size_input + idx; + break; + } + } + } + if (buffer_index == 0) + { + // we couldn't find the buffer; create an empty buffer for this tensor + buffer_index = _buffer_vec.size(); + + tflite::BufferBuilder buffer_builder{*_flatbuffer_builder}; + _buffer_vec.emplace_back(buffer_builder.Finish()); + } + } + assert(buffer_index != 0); + + flatbuffers::Offset quant_index; + + // Create QuantizationParameters if quant is specified + if (operand.has_quant()) + { + const auto &quant = operand.quant(); + + // Create each parameters + // NOTE if some parameters are not given, those will be set to default value + std::vector quant_max_vec(quant.max_size()); + std::vector quant_min_vec(quant.min_size()); + std::vector quant_scale_vec(quant.scale_size()); + std::vector quant_zero_point_vec(quant.zero_point_size()); + + for (uint32_t i = 0; i < quant.max_size(); ++i) + quant_max_vec.at(i) = quant.max(i); + for (uint32_t i = 0; i < quant.min_size(); ++i) + quant_min_vec.at(i) = quant.min(i); + for (uint32_t i = 0; i < quant.scale_size(); ++i) + quant_scale_vec.at(i) = quant.scale(i); + for (uint32_t i = 0; i < quant.zero_point_size(); ++i) + quant_zero_point_vec.at(i) = quant.zero_point(i); + + auto quant_max = _flatbuffer_builder->CreateVector(quant_max_vec); + auto quant_min = _flatbuffer_builder->CreateVector(quant_min_vec); + auto quant_scale = _flatbuffer_builder->CreateVector(quant_scale_vec); + auto quant_zero_point = _flatbuffer_builder->CreateVector(quant_zero_point_vec); + + // Create QuantizationParameters + tflite::QuantizationParametersBuilder quant_builder{*_flatbuffer_builder}; + quant_builder.add_max(quant_max); + quant_builder.add_min(quant_min); + quant_builder.add_scale(quant_scale); + quant_builder.add_zero_point(quant_zero_point); + quant_builder.add_quantized_dimension(quant.quantized_dimension()); + + // Update QuantizationParameters Index + quant_index = quant_builder.Finish(); + } + + if (operand.has_sparsity()) + { + const auto &sparsity = operand.sparsity(); + + // Create traversal order + std::vector traversal_order_vec{sparsity.traversal_order().dim().begin(), + sparsity.traversal_order().dim().end()}; + auto traversal_order = _flatbuffer_builder->CreateVector(traversal_order_vec); + + // Create block map + std::vector block_map_vec{sparsity.block_map().dim().begin(), + sparsity.block_map().dim().end()}; + auto block_map = _flatbuffer_builder->CreateVector(block_map_vec); + + // Create dimension metadata + std::vector> dim_metadata_vec; + auto recipe_dim_metadata = sparsity.dim_metadata(); + for (const auto &dm : recipe_dim_metadata) + { + // Create array segments + auto tflite_array_segments = + as_tflite_sparse_index_vec(*_flatbuffer_builder, dm.array_segments()); + + // Create array indices + auto tflite_array_indices = + as_tflite_sparse_index_vec(*_flatbuffer_builder, dm.array_indices()); + + auto tflite_dim_metadata_builder = tflite::DimensionMetadataBuilder{*_flatbuffer_builder}; + tflite_dim_metadata_builder.add_format(as_tflite_dimensiontype(dm.format())); + tflite_dim_metadata_builder.add_dense_size(dm.dense_size()); + tflite_dim_metadata_builder.add_array_segments(tflite_array_segments); + tflite_dim_metadata_builder.add_array_segments_type( + as_tflite_sparse_idx_vec_type(dm.array_segments().type())); + tflite_dim_metadata_builder.add_array_indices(tflite_array_indices); + tflite_dim_metadata_builder.add_array_indices_type( + as_tflite_sparse_idx_vec_type(dm.array_indices().type())); + auto tflite_dim_metadata = tflite_dim_metadata_builder.Finish(); + dim_metadata_vec.emplace_back(tflite_dim_metadata); + } + auto dim_metadata = _flatbuffer_builder->CreateVector(dim_metadata_vec); + + sparsity_index = tflite::CreateSparsityParameters(*_flatbuffer_builder, traversal_order, + block_map, dim_metadata); + } + + flatbuffers::Offset> shape_signature; + if (operand.has_shape_signature()) + { + auto signature = as_dims(operand.shape_signature()); + shape_signature = _flatbuffer_builder->CreateVector(signature); + } + + // Create Tensor + tflite::TensorBuilder tensor_builder{*_flatbuffer_builder}; + + tensor_builder.add_shape(shape); + tensor_builder.add_type(as_tflite_tensortype(operand.type())); + tensor_builder.add_buffer(buffer_index); + tensor_builder.add_name(name); + tensor_builder.add_is_variable(operand.is_variable()); + if (operand.has_quant()) + tensor_builder.add_quantization(quant_index); + tensor_builder.add_sparsity(sparsity_index); + if (operand.has_shape_signature()) + tensor_builder.add_shape_signature(shape_signature); + + // Append! + _tensor_vec.emplace_back(tensor_builder.Finish()); + } +} + template void ModelChef::cook_graph(const T &graph, std::map &symbol_table) { LOGGER(l); assert(symbol_table.empty()); // FIX_CALLER_UNLESS - - // Operand-related - std::vector> tensor_vec; + assert(_tensor_vec.empty()); // FIX_CALLER_UNLESS // Operation-related std::vector> operator_vec; @@ -280,6 +624,7 @@ void ModelChef::cook_graph(const T &graph, std::map &symbo } }; +#if 0 int32_t buffer_start = _buffer_vec.size(); int32_t buffer_index = 0; @@ -624,6 +969,20 @@ void ModelChef::cook_graph(const T &graph, std::map &symbo symbol_table[tensor_name] = tensor_index; } +#endif + + cook_operands(graph); + + for (const auto &operand : graph.operand()) + { + // Update Tensor Name -> Tensor Index Map + int32_t tensor_index = symbol_table.size(); + const auto &tensor_name = operand.name(); + + INFO(l) << "Symbol [" << tensor_name << "] = Tensor " << tensor_index << std::endl; + + symbol_table[tensor_name] = tensor_index; + } // Create Operator for (const auto &operation : graph.operation()) @@ -689,7 +1048,7 @@ void ModelChef::cook_graph(const T &graph, std::map &symbo std::vector output_vec = as_dataset(graph.output()).map(lookup).vectorize(); // Create "SubGraph" arguments - auto tensors = _flatbuffer_builder->CreateVector(tensor_vec); + auto tensors = _flatbuffer_builder->CreateVector(_tensor_vec); auto inputs = _flatbuffer_builder->CreateVector(input_vec); auto outputs = _flatbuffer_builder->CreateVector(output_vec); auto operators = _flatbuffer_builder->CreateVector(operator_vec); @@ -781,6 +1140,7 @@ void ModelChef::cook(const ::tflchef::ModelRecipe &model_recipe) _graph_name = stringStream.str(); symbol_table.clear(); + _tensor_vec.clear(); cook_graph<::tflchef::Graph>(graph, symbol_table); _symbol_tables.push_back(symbol_table); } From ded9ca6f5b37899580b511671e7623149099d848 Mon Sep 17 00:00:00 2001 From: SaeHie Park Date: Tue, 13 Aug 2024 13:41:57 +0900 Subject: [PATCH 30/78] [tflchef] Extract cook_operations (#13653) This will extract cook_operations method. ONE-DCO-1.0-Signed-off-by: SaeHie Park --- compiler/tflchef/core/src/ModelChef.cpp | 95 +++++++++++++++++++++++-- 1 file changed, 89 insertions(+), 6 deletions(-) diff --git a/compiler/tflchef/core/src/ModelChef.cpp b/compiler/tflchef/core/src/ModelChef.cpp index 03422a84471..ca59b7f7fd5 100644 --- a/compiler/tflchef/core/src/ModelChef.cpp +++ b/compiler/tflchef/core/src/ModelChef.cpp @@ -189,6 +189,9 @@ class ModelChef private: template void cook_operands(const T &graph); + template + void cook_operations(const T &graph, std::map &symbol_table); + template void cook_graph(const T &graph, std::map &symbol_table); @@ -212,6 +215,8 @@ class ModelChef // per graph that needs clear afer graph is processed // Operand-related std::vector> _tensor_vec; + // Operation-related + std::vector> _operator_vec; std::string _graph_name; }; @@ -596,16 +601,89 @@ template void ModelChef::cook_operands(const T &graph) } } +template +void ModelChef::cook_operations(const T &graph, std::map &symbol_table) +{ + auto lookup = [&](const std::string &name) { + if (symbol_table.find(name) != symbol_table.end()) + return symbol_table.at(name); + else if (name == "") + return -1; // -1 in TFLite means that optional input tensor is empty. + else + { + std::string msg = "tflchef : input not found in " + _graph_name + " graph"; + throw std::runtime_error(msg.c_str()); + } + }; + + // Create Operator + for (const auto &operation : graph.operation()) + { + assert(operation.has_type()); + + std::string op_type = operation.type(); + if (not operation.custom_code().empty()) + op_type = operation.custom_code(); + + auto op_chef = op_chef_registry().lookup(op_type).create(&operation); + + // Create 'inputs' + std::vector input_vec = as_dataset(operation.input()).map(lookup).vectorize(); + auto inputs = _flatbuffer_builder->CreateVector(input_vec); + + // Create 'outputs' + std::vector output_vec = as_dataset(operation.output()).map(lookup).vectorize(); + auto outputs = _flatbuffer_builder->CreateVector(output_vec); + + // Create Option + auto options = op_chef->value(*_flatbuffer_builder); + + // Create Custom option + auto circle_custom_options = op_chef->custom_value(*_flatbuffer_builder); + + // Create Operator + tflite::OperatorBuilder op_builder{*_flatbuffer_builder}; + + // Note that opcode_index is an index into the operator_codes vector. + // operator_codes consists of buildtin_code and custom_code, which is inserted sequentially. + uint32_t opcode_index = 0; + auto op_it = _builtin_code_map.find(op_chef->code()); + // builtin operator + if (op_it != _builtin_code_map.end()) + { + opcode_index = std::distance(_builtin_code_map.begin(), op_it); + } + // custom operator + else + { + assert(not operation.custom_code().empty()); + auto custom_code = operation.custom_code(); + auto op_it = std::find(_custom_code_vec.begin(), _custom_code_vec.end(), custom_code); + assert(op_it != _custom_code_vec.end()); + opcode_index = _builtin_code_map.size(); + opcode_index += std::distance(_custom_code_vec.begin(), op_it); + } + + op_builder.add_opcode_index(opcode_index); + op_builder.add_inputs(inputs); + op_builder.add_outputs(outputs); + op_builder.add_builtin_options_type(op_chef->type()); + op_builder.add_builtin_options(options); + op_builder.add_custom_options(circle_custom_options); + op_builder.add_custom_options_format(tflite::CustomOptionsFormat_FLEXBUFFERS); + // Append Operator + _operator_vec.emplace_back(op_builder.Finish()); + } +} + template void ModelChef::cook_graph(const T &graph, std::map &symbol_table) { LOGGER(l); - assert(symbol_table.empty()); // FIX_CALLER_UNLESS - assert(_tensor_vec.empty()); // FIX_CALLER_UNLESS - - // Operation-related - std::vector> operator_vec; + assert(symbol_table.empty()); // FIX_CALLER_UNLESS + assert(_tensor_vec.empty()); // FIX_CALLER_UNLESS + assert(_operator_vec.empty()); // FIX_CALLER_UNLESS // default name for graph std::string graph_name = _graph_name; @@ -984,6 +1062,7 @@ void ModelChef::cook_graph(const T &graph, std::map &symbo symbol_table[tensor_name] = tensor_index; } +#if 0 // Create Operator for (const auto &operation : graph.operation()) { @@ -1042,6 +1121,9 @@ void ModelChef::cook_graph(const T &graph, std::map &symbo // Append Operator operator_vec.emplace_back(op_builder.Finish()); } +#endif + + cook_operations(graph, symbol_table); // Create network input/output vector std::vector input_vec = as_dataset(graph.input()).map(lookup).vectorize(); @@ -1051,7 +1133,7 @@ void ModelChef::cook_graph(const T &graph, std::map &symbo auto tensors = _flatbuffer_builder->CreateVector(_tensor_vec); auto inputs = _flatbuffer_builder->CreateVector(input_vec); auto outputs = _flatbuffer_builder->CreateVector(output_vec); - auto operators = _flatbuffer_builder->CreateVector(operator_vec); + auto operators = _flatbuffer_builder->CreateVector(_operator_vec); auto name = _flatbuffer_builder->CreateString(graph_name); tflite::SubGraphBuilder subgraph_builder{*_flatbuffer_builder}; @@ -1141,6 +1223,7 @@ void ModelChef::cook(const ::tflchef::ModelRecipe &model_recipe) symbol_table.clear(); _tensor_vec.clear(); + _operator_vec.clear(); cook_graph<::tflchef::Graph>(graph, symbol_table); _symbol_tables.push_back(symbol_table); } From c16bef65793029866fc3c24bcf02d366361434af Mon Sep 17 00:00:00 2001 From: SaeHie Park Date: Tue, 13 Aug 2024 15:29:41 +0900 Subject: [PATCH 31/78] [tflchef] Tidy disabled codes (#13657) This will tidy disabled codes that was relocated. ONE-DCO-1.0-Signed-off-by: SaeHie Park --- compiler/tflchef/core/src/ModelChef.cpp | 408 ------------------------ 1 file changed, 408 deletions(-) diff --git a/compiler/tflchef/core/src/ModelChef.cpp b/compiler/tflchef/core/src/ModelChef.cpp index ca59b7f7fd5..14c1a35d0e6 100644 --- a/compiler/tflchef/core/src/ModelChef.cpp +++ b/compiler/tflchef/core/src/ModelChef.cpp @@ -702,353 +702,6 @@ void ModelChef::cook_graph(const T &graph, std::map &symbo } }; -#if 0 - int32_t buffer_start = _buffer_vec.size(); - int32_t buffer_index = 0; - - // Create buffer(s) 1~n(I) for input(s) - const auto size_input = graph.input_size(); - for (int ci = 0; ci < size_input; ++ci) - { - tflite::BufferBuilder buffer_builder{*_flatbuffer_builder}; - _buffer_vec.emplace_back(buffer_builder.Finish()); - } - // Create buffer(s) n(I)+1~n(I)+n(O) for output(s) - const auto size_output = graph.output_size(); - for (int co = 0; co < size_output; ++co) - { - tflite::BufferBuilder buffer_builder{*_flatbuffer_builder}; - _buffer_vec.emplace_back(buffer_builder.Finish()); - } - - auto input_names = as_dataset(graph.input()).vectorize(); - auto output_names = as_dataset(graph.output()).vectorize(); - - for (const auto &operand : graph.operand()) - { - assert(operand.has_name()); - - assert(operand.has_type()); - - flatbuffers::Offset sparsity_index; - - flatbuffers::Offset> shape; - std::vector dims; - if (operand.has_shape()) - { - dims = as_dims(operand.shape()); - shape = _flatbuffer_builder->CreateVector(dims); - } - - auto name = _flatbuffer_builder->CreateString(operand.name()); - - buffer_index = 0; - - // Create Buffer if filler is specified - if (operand.has_filler()) - { - const auto &filler = operand.filler(); - - assert(filler.has_tag()); - - auto args = ranged_arguments(filler.arg().begin(), filler.arg().end()); - auto chef = data_chef_registry(operand.type()).lookup(filler.tag()).create(args); - - assert(chef != nullptr); - - // Create Data - int32_t count = (element_count(dims) > 0) ? element_count(dims) : filler.arg_size(); - auto data_vec = chef->generate(count); - - if (operand.has_make_sparse() && operand.make_sparse()) - { - assert(not operand.has_sparsity()); - assert(operand.has_shape()); - assert(operand.type() != tflchef::TensorType::INT4); - - const int32_t dims_count = dims.size(); - std::vector traversal_order_vec; - std::vector format_vec; - for (int32_t o = 0; o < dims_count; ++o) - traversal_order_vec.push_back(o); - for (int32_t o = 0; o < dims_count - 1; ++o) - format_vec.push_back(sparsity::kTfLiteDimDense); - format_vec.push_back(sparsity::kTfLiteDimSparseCSR); - - if (operand.type() == tflchef::FLOAT32) - { - ::sparsity::FormatConverter converter(dims, traversal_order_vec, format_vec); - converter.DenseToSparse(reinterpret_cast(data_vec.data())); - const auto &sparse_data = converter.GetData(); - - std::vector sparse_uint8; - for (int c = 0; c < sparse_data.size(); ++c) - { - const float value = sparse_data.at(c); - const uint8_t *arr = reinterpret_cast(&value); - for (uint32_t b = 0; b < sizeof(float); ++b) - { - sparse_uint8.emplace_back(arr[b]); - } - } - auto data = _flatbuffer_builder->CreateVector(sparse_uint8); - - // Create Buffer - tflite::BufferBuilder buffer_builder{*_flatbuffer_builder}; - buffer_builder.add_data(data); - auto buffer = buffer_builder.Finish(); - - // Update Buffer Index & Vector - buffer_index = _buffer_vec.size(); - _buffer_vec.emplace_back(buffer); - - // save SparsityParameters - auto traversal_order = _flatbuffer_builder->CreateVector(traversal_order_vec); - - // Create block map - std::vector block_map_vec{}; - auto block_map = _flatbuffer_builder->CreateVector(block_map_vec); - - // Create dimension metadata - const auto &dim_metadata_src = converter.GetDimMetadata(); - auto dim_metadata_vec = - make_dim_metadata_vec(_flatbuffer_builder.get(), dims_count, traversal_order_vec, - format_vec, dim_metadata_src); - auto dim_metadata = _flatbuffer_builder->CreateVector(dim_metadata_vec); - sparsity_index = tflite::CreateSparsityParameters(*_flatbuffer_builder, traversal_order, - block_map, dim_metadata); - } - else if (operand.type() == tflchef::FLOAT16) - { - ::sparsity::FormatConverter converter(dims, traversal_order_vec, format_vec); - converter.DenseToSparse(reinterpret_cast(data_vec.data())); - const auto &sparse_data = converter.GetData(); - - std::vector sparse_uint8; - for (int c = 0; c < sparse_data.size(); ++c) - { - const uint16_t value = sparse_data.at(c); - const uint8_t *arr = reinterpret_cast(&value); - for (uint32_t b = 0; b < sizeof(uint16_t); ++b) - { - sparse_uint8.emplace_back(arr[b]); - } - } - auto data = _flatbuffer_builder->CreateVector(sparse_uint8); - - // Create Buffer - tflite::BufferBuilder buffer_builder{*_flatbuffer_builder}; - buffer_builder.add_data(data); - auto buffer = buffer_builder.Finish(); - - // Update Buffer Index & Vector - buffer_index = _buffer_vec.size(); - _buffer_vec.emplace_back(buffer); - - // save SparsityParameters - auto traversal_order = _flatbuffer_builder->CreateVector(traversal_order_vec); - - // Create block map - std::vector block_map_vec{}; - auto block_map = _flatbuffer_builder->CreateVector(block_map_vec); - - // Create dimension metadata - const auto &dim_metadata_src = converter.GetDimMetadata(); - auto dim_metadata_vec = - make_dim_metadata_vec(_flatbuffer_builder.get(), dims_count, traversal_order_vec, - format_vec, dim_metadata_src); - auto dim_metadata = _flatbuffer_builder->CreateVector(dim_metadata_vec); - sparsity_index = tflite::CreateSparsityParameters(*_flatbuffer_builder, traversal_order, - block_map, dim_metadata); - } - else - { - throw std::runtime_error{"NYI: unsupported operand type"}; - } - } - else - { - // pack for INT4 and replace data_vec - if (operand.type() == tflchef::TensorType::INT4) - { - uint32_t packed = (count + 1) / 2; - std::vector data_packed(packed); - for (uint32_t idx = 0; idx < packed; ++idx) - { - uint32_t sidx = idx * 2; - data_packed[idx] = data_vec[sidx++] & 0x0f; - if (sidx < count) - data_packed[idx] |= data_vec[sidx] << 4; - } - data_vec = data_packed; - } - - auto data = _flatbuffer_builder->CreateVector(data_vec); - - // Create Buffer - tflite::BufferBuilder buffer_builder{*_flatbuffer_builder}; - buffer_builder.add_data(data); - auto buffer = buffer_builder.Finish(); - - // Update Buffer Index & Vector - buffer_index = _buffer_vec.size(); - _buffer_vec.emplace_back(buffer); - } - } - else - { - // if this is input or output, assign to that buffer_index - int idx = 0; - for (auto it = input_names.begin(); it != input_names.end(); ++it, ++idx) - { - if (*it == operand.name()) - { - buffer_index = buffer_start + idx; - break; - } - } - if (buffer_index == 0) - { - idx = 0; - for (auto it = output_names.begin(); it != output_names.end(); ++it, ++idx) - { - if (*it == operand.name()) - { - buffer_index = buffer_start + size_input + idx; - break; - } - } - } - if (buffer_index == 0) - { - // we couldn't find the buffer; create an empty buffer for this tensor - buffer_index = _buffer_vec.size(); - - tflite::BufferBuilder buffer_builder{*_flatbuffer_builder}; - _buffer_vec.emplace_back(buffer_builder.Finish()); - } - } - assert(buffer_index != 0); - - flatbuffers::Offset quant_index; - - // Create QuantizationParameters if quant is specified - if (operand.has_quant()) - { - const auto &quant = operand.quant(); - - // Create each parameters - // NOTE if some parameters are not given, those will be set to default value - std::vector quant_max_vec(quant.max_size()); - std::vector quant_min_vec(quant.min_size()); - std::vector quant_scale_vec(quant.scale_size()); - std::vector quant_zero_point_vec(quant.zero_point_size()); - - for (uint32_t i = 0; i < quant.max_size(); ++i) - quant_max_vec.at(i) = quant.max(i); - for (uint32_t i = 0; i < quant.min_size(); ++i) - quant_min_vec.at(i) = quant.min(i); - for (uint32_t i = 0; i < quant.scale_size(); ++i) - quant_scale_vec.at(i) = quant.scale(i); - for (uint32_t i = 0; i < quant.zero_point_size(); ++i) - quant_zero_point_vec.at(i) = quant.zero_point(i); - - auto quant_max = _flatbuffer_builder->CreateVector(quant_max_vec); - auto quant_min = _flatbuffer_builder->CreateVector(quant_min_vec); - auto quant_scale = _flatbuffer_builder->CreateVector(quant_scale_vec); - auto quant_zero_point = _flatbuffer_builder->CreateVector(quant_zero_point_vec); - - // Create QuantizationParameters - tflite::QuantizationParametersBuilder quant_builder{*_flatbuffer_builder}; - quant_builder.add_max(quant_max); - quant_builder.add_min(quant_min); - quant_builder.add_scale(quant_scale); - quant_builder.add_zero_point(quant_zero_point); - quant_builder.add_quantized_dimension(quant.quantized_dimension()); - - // Update QuantizationParameters Index - quant_index = quant_builder.Finish(); - } - - if (operand.has_sparsity()) - { - const auto &sparsity = operand.sparsity(); - - // Create traversal order - std::vector traversal_order_vec{sparsity.traversal_order().dim().begin(), - sparsity.traversal_order().dim().end()}; - auto traversal_order = _flatbuffer_builder->CreateVector(traversal_order_vec); - - // Create block map - std::vector block_map_vec{sparsity.block_map().dim().begin(), - sparsity.block_map().dim().end()}; - auto block_map = _flatbuffer_builder->CreateVector(block_map_vec); - - // Create dimension metadata - std::vector> dim_metadata_vec; - auto recipe_dim_metadata = sparsity.dim_metadata(); - for (const auto &dm : recipe_dim_metadata) - { - // Create array segments - auto tflite_array_segments = - as_tflite_sparse_index_vec(*_flatbuffer_builder, dm.array_segments()); - - // Create array indices - auto tflite_array_indices = - as_tflite_sparse_index_vec(*_flatbuffer_builder, dm.array_indices()); - - auto tflite_dim_metadata_builder = tflite::DimensionMetadataBuilder{*_flatbuffer_builder}; - tflite_dim_metadata_builder.add_format(as_tflite_dimensiontype(dm.format())); - tflite_dim_metadata_builder.add_dense_size(dm.dense_size()); - tflite_dim_metadata_builder.add_array_segments(tflite_array_segments); - tflite_dim_metadata_builder.add_array_segments_type( - as_tflite_sparse_idx_vec_type(dm.array_segments().type())); - tflite_dim_metadata_builder.add_array_indices(tflite_array_indices); - tflite_dim_metadata_builder.add_array_indices_type( - as_tflite_sparse_idx_vec_type(dm.array_indices().type())); - auto tflite_dim_metadata = tflite_dim_metadata_builder.Finish(); - dim_metadata_vec.emplace_back(tflite_dim_metadata); - } - auto dim_metadata = _flatbuffer_builder->CreateVector(dim_metadata_vec); - - sparsity_index = tflite::CreateSparsityParameters(*_flatbuffer_builder, traversal_order, - block_map, dim_metadata); - } - - flatbuffers::Offset> shape_signature; - if (operand.has_shape_signature()) - { - auto signature = as_dims(operand.shape_signature()); - shape_signature = _flatbuffer_builder->CreateVector(signature); - } - - // Create Tensor - tflite::TensorBuilder tensor_builder{*_flatbuffer_builder}; - - tensor_builder.add_shape(shape); - tensor_builder.add_type(as_tflite_tensortype(operand.type())); - tensor_builder.add_buffer(buffer_index); - tensor_builder.add_name(name); - tensor_builder.add_is_variable(operand.is_variable()); - if (operand.has_quant()) - tensor_builder.add_quantization(quant_index); - tensor_builder.add_sparsity(sparsity_index); - if (operand.has_shape_signature()) - tensor_builder.add_shape_signature(shape_signature); - - // Append! - tensor_vec.emplace_back(tensor_builder.Finish()); - - // Update Tensor Name -> Tensor Index Map - int32_t tensor_index = symbol_table.size(); - const auto &tensor_name = operand.name(); - - INFO(l) << "Symbol [" << tensor_name << "] = Tensor " << tensor_index << std::endl; - - symbol_table[tensor_name] = tensor_index; - } -#endif - cook_operands(graph); for (const auto &operand : graph.operand()) @@ -1062,67 +715,6 @@ void ModelChef::cook_graph(const T &graph, std::map &symbo symbol_table[tensor_name] = tensor_index; } -#if 0 - // Create Operator - for (const auto &operation : graph.operation()) - { - assert(operation.has_type()); - - std::string op_type = operation.type(); - if (not operation.custom_code().empty()) - op_type = operation.custom_code(); - - auto op_chef = op_chef_registry().lookup(op_type).create(&operation); - - // Create 'inputs' - std::vector input_vec = as_dataset(operation.input()).map(lookup).vectorize(); - auto inputs = _flatbuffer_builder->CreateVector(input_vec); - - // Create 'outputs' - std::vector output_vec = as_dataset(operation.output()).map(lookup).vectorize(); - auto outputs = _flatbuffer_builder->CreateVector(output_vec); - - // Create Option - auto options = op_chef->value(*_flatbuffer_builder); - - // Create Custom option - auto circle_custom_options = op_chef->custom_value(*_flatbuffer_builder); - - // Create Operator - tflite::OperatorBuilder op_builder{*_flatbuffer_builder}; - - // Note that opcode_index is an index into the operator_codes vector. - // operator_codes consists of buildtin_code and custom_code, which is inserted sequentially. - uint32_t opcode_index = 0; - auto op_it = _builtin_code_map.find(op_chef->code()); - // builtin operator - if (op_it != _builtin_code_map.end()) - { - opcode_index = std::distance(_builtin_code_map.begin(), op_it); - } - // custom operator - else - { - assert(not operation.custom_code().empty()); - auto custom_code = operation.custom_code(); - auto op_it = std::find(_custom_code_vec.begin(), _custom_code_vec.end(), custom_code); - assert(op_it != _custom_code_vec.end()); - opcode_index = _builtin_code_map.size(); - opcode_index += std::distance(_custom_code_vec.begin(), op_it); - } - - op_builder.add_opcode_index(opcode_index); - op_builder.add_inputs(inputs); - op_builder.add_outputs(outputs); - op_builder.add_builtin_options_type(op_chef->type()); - op_builder.add_builtin_options(options); - op_builder.add_custom_options(circle_custom_options); - op_builder.add_custom_options_format(tflite::CustomOptionsFormat_FLEXBUFFERS); - // Append Operator - operator_vec.emplace_back(op_builder.Finish()); - } -#endif - cook_operations(graph, symbol_table); // Create network input/output vector From 8e993e3781cfd8141a5fcbd9baf9649fa291cf58 Mon Sep 17 00:00:00 2001 From: SaeHie Park Date: Tue, 13 Aug 2024 17:17:16 +0900 Subject: [PATCH 32/78] [tflchef] Extract more methods (#13661) This will extract more methods; - prepare_initial_buffer - gather_operator_codes - gather_signature_defs ONE-DCO-1.0-Signed-off-by: SaeHie Park --- compiler/tflchef/core/src/ModelChef.cpp | 156 ++++++++++++++++++++++++ 1 file changed, 156 insertions(+) diff --git a/compiler/tflchef/core/src/ModelChef.cpp b/compiler/tflchef/core/src/ModelChef.cpp index 14c1a35d0e6..8b50b09f986 100644 --- a/compiler/tflchef/core/src/ModelChef.cpp +++ b/compiler/tflchef/core/src/ModelChef.cpp @@ -187,6 +187,10 @@ class ModelChef void cook(const ::tflchef::ModelRecipe &model_recipe); private: + void prepare_initial_buffer(void); + void gather_operator_codes(const ::tflchef::ModelRecipe &model_recipe); + void gather_signature_defs(const ::tflchef::ModelRecipe &model_recipe); + template void cook_operands(const T &graph); template @@ -739,8 +743,153 @@ void ModelChef::cook_graph(const T &graph, std::map &symbo _subgraph_vec.emplace_back(subgraph_builder.Finish()); } +void ModelChef::gather_operator_codes(const ::tflchef::ModelRecipe &model_recipe) +{ + // Create OperatorCode with Builtin Operator + _builtin_code_map = gather_builtincode_map(model_recipe); + for (auto const &opcode : _builtin_code_map) + { + tflite::OperatorCodeBuilder code_builder{*_flatbuffer_builder}; + // 127 is BuiltinOperator_PLACEHOLDER_FOR_GREATER_OP_CODES + // This is the way to handle deprecated builtin code + // See + // https://github.com/tensorflow/tensorflow/blob/a0afe8f9218be5eb9ed5dffc2dff652996da8c28/tensorflow/lite/schema/schema.fbs#L1061-L1077 + if (opcode.first < 127) + { + code_builder.add_deprecated_builtin_code(opcode.first); + } + else + { + code_builder.add_deprecated_builtin_code( + ::tflite::BuiltinOperator_PLACEHOLDER_FOR_GREATER_OP_CODES); + } + code_builder.add_version(opcode.second); + code_builder.add_builtin_code(opcode.first); + auto code = code_builder.Finish(); + // Update OperatorCode vector + _code_vec.emplace_back(code); + } + + // Create OperatorCode with Custom Operator + { + std::set custom_code_set = gather_customcode_set(model_recipe); + std::vector custom_code_vec{custom_code_set.begin(), custom_code_set.end()}; + _custom_code_vec = custom_code_vec; + } + + for (auto opcode : _custom_code_vec) + { + auto custom_code = _flatbuffer_builder->CreateString(opcode); + tflite::OperatorCodeBuilder code_builder{*_flatbuffer_builder}; + code_builder.add_deprecated_builtin_code(tflite::BuiltinOperator_CUSTOM); + code_builder.add_custom_code(custom_code); + code_builder.add_builtin_code(tflite::BuiltinOperator_CUSTOM); + auto code = code_builder.Finish(); + // Update OperatorCode vector + _code_vec.emplace_back(code); + } +} + +void ModelChef::prepare_initial_buffer(void) +{ + // Create an Empty Buffer + // + // Buffer 0 SHOULD be an empty buffer in TensorFlow Lite model file + // (Please refer to the comment for Tensor.buffer field in schema) + tflite::BufferBuilder buffer_builder{*_flatbuffer_builder}; + _buffer_vec.emplace_back(buffer_builder.Finish()); +} + +void ModelChef::gather_signature_defs(const ::tflchef::ModelRecipe &model_recipe) +{ + for (int s = 0; s < model_recipe.signature_def_size(); ++s) + { + // load from recipe + const auto &rec_signature_def = model_recipe.signature_def(s); + + std::vector> tensormap_inputs; + std::vector> tensormap_outputs; + + // which subgraph index to cook + auto subgraph_index = 0; + if (rec_signature_def.has_subgraph_index()) + { + subgraph_index = rec_signature_def.subgraph_index(); + } + assert(subgraph_index < _symbol_tables.size()); + auto &symbol_table = _symbol_tables[subgraph_index]; + + // cook for inputs + for (int si = 0; si < rec_signature_def.inputs_size(); ++si) + { + // recipe for input TensorMap + auto rec_tm_input = rec_signature_def.inputs(si); + auto name = _flatbuffer_builder->CreateString(rec_tm_input.name()); + uint32_t tensor_index = 0; + // either tensor or tensor_index should exist + assert(rec_tm_input.has_tensor() || rec_tm_input.has_tensor_index()); + if (rec_tm_input.has_tensor()) + { + // we can get tensor_index from symbol_table + auto tensor = rec_tm_input.tensor(); + tensor_index = symbol_table[tensor]; + } + else + { + // or we can use tensor_index itself + tensor_index = rec_tm_input.tensor_index(); + } + + ::tflite::TensorMapBuilder tensormap_builder{*_flatbuffer_builder}; + tensormap_builder.add_name(name); + tensormap_builder.add_tensor_index(tensor_index); + tensormap_inputs.push_back(tensormap_builder.Finish()); + } + // cook for outputs, same as inputs + for (int so = 0; so < rec_signature_def.outputs_size(); ++so) + { + auto rec_tm_output = rec_signature_def.outputs(so); + auto name = _flatbuffer_builder->CreateString(rec_tm_output.name()); + uint32_t tensor_index = 0; + assert(rec_tm_output.has_tensor() || rec_tm_output.has_tensor_index()); + if (rec_tm_output.has_tensor()) + { + auto tensor = rec_tm_output.tensor(); + tensor_index = symbol_table[tensor]; + } + else + { + tensor_index = rec_tm_output.tensor_index(); + } + + ::tflite::TensorMapBuilder tensormap_builder{*_flatbuffer_builder}; + tensormap_builder.add_name(name); + tensormap_builder.add_tensor_index(tensor_index); + tensormap_outputs.push_back(tensormap_builder.Finish()); + } + + auto inputs = _flatbuffer_builder->CreateVector(tensormap_inputs); + auto outputs = _flatbuffer_builder->CreateVector(tensormap_outputs); + auto signature_key = _flatbuffer_builder->CreateString(rec_signature_def.signature_key()); + // TODO add validation for signature_key + + ::tflite::SignatureDefBuilder signature_def_builder{*_flatbuffer_builder}; + signature_def_builder.add_inputs(inputs); + signature_def_builder.add_outputs(outputs); + signature_def_builder.add_signature_key(signature_key); + signature_def_builder.add_subgraph_index(rec_signature_def.subgraph_index()); + + _signdef_vec.emplace_back(signature_def_builder.Finish()); + } +} + void ModelChef::cook(const ::tflchef::ModelRecipe &model_recipe) { + prepare_initial_buffer(); + + gather_operator_codes(model_recipe); + +#if 0 // Create OperatorCode with Builtin Operator _builtin_code_map = gather_builtincode_map(model_recipe); for (auto const &opcode : _builtin_code_map) @@ -781,7 +930,9 @@ void ModelChef::cook(const ::tflchef::ModelRecipe &model_recipe) // Update OperatorCode vector _code_vec.emplace_back(code); } +#endif +#if 0 // Create an Empty Buffer // // Buffer 0 SHOULD be an empty buffer in TensorFlow Lite model file @@ -790,6 +941,7 @@ void ModelChef::cook(const ::tflchef::ModelRecipe &model_recipe) tflite::BufferBuilder buffer_builder{*_flatbuffer_builder}; _buffer_vec.emplace_back(buffer_builder.Finish()); } +#endif // // Create Main graph @@ -820,6 +972,9 @@ void ModelChef::cook(const ::tflchef::ModelRecipe &model_recipe) _symbol_tables.push_back(symbol_table); } + gather_signature_defs(model_recipe); + +#if 0 // Create Signature-Def // for (int s = 0; s < model_recipe.signature_def_size(); ++s) @@ -901,6 +1056,7 @@ void ModelChef::cook(const ::tflchef::ModelRecipe &model_recipe) _signdef_vec.emplace_back(signature_def_builder.Finish()); } +#endif // Create "Model" arguments auto buffers = _flatbuffer_builder->CreateVector(_buffer_vec); From 719a6f7d8b3873b3bf06bd4c17ea7fe77288d7cd Mon Sep 17 00:00:00 2001 From: SaeHie Park Date: Tue, 13 Aug 2024 17:17:41 +0900 Subject: [PATCH 33/78] [circledump] Fix namespace closing comment (#13664) This will fix namespace closing comment and insert empty space like others. ONE-DCO-1.0-Signed-off-by: SaeHie Park --- compiler/circledump/include/circledump/Dump.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/circledump/include/circledump/Dump.h b/compiler/circledump/include/circledump/Dump.h index a129458f416..594209a5def 100644 --- a/compiler/circledump/include/circledump/Dump.h +++ b/compiler/circledump/include/circledump/Dump.h @@ -25,7 +25,8 @@ namespace circledump { void dump_model(std::ostream &os, const circle::Model *model); -} + +} // namespace circledump std::ostream &operator<<(std::ostream &os, const circle::Model *model); From 4eb499f9b98b7cbaba501521cacbb9562a6c85eb Mon Sep 17 00:00:00 2001 From: Evgenii Maltsev Date: Tue, 13 Aug 2024 18:36:22 +0400 Subject: [PATCH 34/78] [onert-micro] Fix Elu and SVDF kernels (#13672) Kernels fixing. Elu and SVDF for building on board ONE-DCO-1.0-Signed-off-by: Evgenii Maltsev e.maltsev@samsung.com --- onert-micro/onert-micro/include/pal/common/PALElu.h | 2 +- onert-micro/onert-micro/include/pal/common/PALSVDFCommon.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/onert-micro/onert-micro/include/pal/common/PALElu.h b/onert-micro/onert-micro/include/pal/common/PALElu.h index fdb46098b15..a5687562eed 100644 --- a/onert-micro/onert-micro/include/pal/common/PALElu.h +++ b/onert-micro/onert-micro/include/pal/common/PALElu.h @@ -34,7 +34,7 @@ inline OMStatus Elu(const int flat_size, const float *input_data, float *output_ for (int i = 0; i < flat_size; i++) { float val = input_data[i]; - float result = val < 0.0f ? std::expm1(val) : val; + float result = val < 0.0f ? std::exp(val) - 1 : val; output_data[i] = result; } diff --git a/onert-micro/onert-micro/include/pal/common/PALSVDFCommon.h b/onert-micro/onert-micro/include/pal/common/PALSVDFCommon.h index 673d389299f..f396a63635f 100644 --- a/onert-micro/onert-micro/include/pal/common/PALSVDFCommon.h +++ b/onert-micro/onert-micro/include/pal/common/PALSVDFCommon.h @@ -49,7 +49,7 @@ inline float activationValFloat(const circle::ActivationFunctionType act, float case circle::ActivationFunctionType_TANH: return std::tanh(a); case circle::ActivationFunctionType_SIGN_BIT: - return std::signbit(a); + return (a < 0) ? true : false; default: assert(false && "Not supported"); } From ab9a9248a6bf35e204729c9d2b0c869bb1ff515c Mon Sep 17 00:00:00 2001 From: Jan Iwaszkiewicz Date: Wed, 14 Aug 2024 00:18:33 +0200 Subject: [PATCH 35/78] [res/tfl_recipes] Add new Net_FullyConnected_Mul (#13650) This commit extends Net_FullyConnectedMul tflite recipes with 'no bias' case. ONE-DCO-1.0-Signed-off-by: Jan Iwaszkiewicz --- .../Net_FullyConnected_Mul_003/test.recipe | 57 +++++++++++++++++++ .../Net_FullyConnected_Mul_003/test.rule | 13 +++++ 2 files changed, 70 insertions(+) create mode 100644 res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_003/test.recipe create mode 100644 res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_003/test.rule diff --git a/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_003/test.recipe b/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_003/test.recipe new file mode 100644 index 00000000000..2883ebabdf0 --- /dev/null +++ b/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_003/test.recipe @@ -0,0 +1,57 @@ +operand { + name: "ifm" + type: FLOAT32 + shape { dim: 3 dim: 1 dim: 4 } +} +operand { + name: "fc_wgt" + type: FLOAT32 + shape { dim: 6 dim: 4 } + filler { + tag: "gaussian" + arg: "0.0" + arg: "1.0" + } +} +operand { + name: "scale" + type: FLOAT32 + shape { dim: 6 } + filler { + tag: "gaussian" + arg: "0.0" + arg: "1.0" + } +} +operand { + name: "fc_out" + type: FLOAT32 + shape: { dim: 3 dim: 1 dim: 6 } +} +operand { + name: "mul_out" + type: FLOAT32 + shape: { dim: 3 dim: 1 dim: 6 } +} +operation { + type: "FullyConnected" + fullyconnected_options { + activation: NONE + keep_num_dims: true + } + input: "ifm" + input: "fc_wgt" + input: "" + output: "fc_out" +} +operation { + type: "Mul" + mul_options { + activation: RELU + } + input: "fc_out" + input: "scale" + output: "mul_out" +} +input: "ifm" +output: "mul_out" diff --git a/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_003/test.rule b/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_003/test.rule new file mode 100644 index 00000000000..16bb2ff2788 --- /dev/null +++ b/res/TensorFlowLiteRecipes/Net_FullyConnected_Mul_003/test.rule @@ -0,0 +1,13 @@ +# This checks if: +# Mul(FC(input, weights, _), other) +# is converted to: +# FC(input, Mul(weights, other), _) +# and then Mul is fused to: +# FC(input, weights', _) +# Here the bias is empty/excluded "_". +# Thus Mul is only fused with weights. + +RULE "VERIFY_FILE_FORMAT" $(verify_file_format) '=' 1 + +RULE "NO_MUL" $(op_count MUL) '=' 0 +RULE "FC_EXIST" $(op_count FULLY_CONNECTED) '=' 1 From c31c280f41afc732b5ab988c5e0db3ba022dcbe2 Mon Sep 17 00:00:00 2001 From: Hyeongseok Oh Date: Wed, 14 Aug 2024 09:50:52 +0900 Subject: [PATCH 36/78] [onert] Reallocated tensor when size becomes larger (#13658) This commit updates dynamic allocator usage on basic tensor to reallocate when shape is changed to larger size. It will improve performance and reduce memory usage when tensor size is lesser by dynamic shape on inference than prepare phase. ONE-DCO-1.0-Signed-off-by: Hyeongseok Oh --- .../onert/core/include/backend/basic/Tensor.h | 5 ++- .../onert/core/src/backend/basic/Tensor.cc | 41 ++++++------------- 2 files changed, 15 insertions(+), 31 deletions(-) diff --git a/runtime/onert/core/include/backend/basic/Tensor.h b/runtime/onert/core/include/backend/basic/Tensor.h index 9271faa21a2..92d98f82e13 100644 --- a/runtime/onert/core/include/backend/basic/Tensor.h +++ b/runtime/onert/core/include/backend/basic/Tensor.h @@ -41,8 +41,8 @@ class Tensor : public IPortableTensor public: Tensor(const ir::OperandInfo &info, DynamicMemoryManager *dynamic_mem_mgr) - : IPortableTensor(info), _layout(ir::Layout::NHWC), _buffer(nullptr), _num_references(0), - _dynamic_mem_mgr(dynamic_mem_mgr), _allocator(nullptr) + : IPortableTensor(info), _layout(ir::Layout::NHWC), _buffer(nullptr), _size(info.total_size()), + _num_references(0), _dynamic_mem_mgr(dynamic_mem_mgr), _allocator(nullptr) { // DO NOTHING } @@ -128,6 +128,7 @@ class Tensor : public IPortableTensor protected: const ir::Layout _layout; uint8_t *_buffer; + size_t _size; int32_t _num_references; DynamicMemoryManager *_dynamic_mem_mgr; diff --git a/runtime/onert/core/src/backend/basic/Tensor.cc b/runtime/onert/core/src/backend/basic/Tensor.cc index 7f33d4d7432..b23624683bd 100644 --- a/runtime/onert/core/src/backend/basic/Tensor.cc +++ b/runtime/onert/core/src/backend/basic/Tensor.cc @@ -32,40 +32,23 @@ void Tensor::setShape(const ir::Shape &new_shape) { _info.shape(new_shape); } bool Tensor::applyShape(const ir::Shape &new_shape) { - bool previously_dynamic = is_dynamic(); + if (_buffer != nullptr && new_shape == _info.shape()) + return true; - auto allocTensorMem = [&]() { - auto capacity = total_size(); - assert(_dynamic_mem_mgr); - auto alloc = _dynamic_mem_mgr->allocate(this, capacity); - setBuffer(alloc); - }; - - if (!previously_dynamic || buffer() == nullptr) + // Always set shape - when buffer with same or larger size was already allocated, shape could + // differ + _info.shape(new_shape); + set_dynamic(); + if (_buffer == nullptr || _size < _info.total_size()) { - // Always set shape - when buffer with same size was already allocated, shape could differ - setShape(new_shape); - set_dynamic(); - allocTensorMem(); - } - else - { - auto previous_size = total_size(); - auto new_size = new_shape.num_elements() * ir::sizeOfDataType(data_type()); - if (previous_size != new_size) - { - assert(_dynamic_mem_mgr); + assert(_dynamic_mem_mgr); + if (_allocator) _dynamic_mem_mgr->deallocate(this); - setShape(new_shape); - set_dynamic(); - allocTensorMem(); - } - else - { // when buffer with same size was already allocated, shape could differ - setShape(new_shape); - } + _size = _info.total_size(); + setBuffer(_dynamic_mem_mgr->allocate(this, _size)); } + return true; } From 4524a72693da86b4f41fe626b0faded18c9a33e3 Mon Sep 17 00:00:00 2001 From: Hyeongseok Oh Date: Wed, 14 Aug 2024 09:51:51 +0900 Subject: [PATCH 37/78] [onert/onert_run] Allow shape_prepare and shape_run together (#13654) This commit updates argument policy to allow shape_prepare and shape_run together. ONE-DCO-1.0-Signed-off-by: Hyeongseok Oh --- tests/tools/onert_run/src/args.cc | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/tests/tools/onert_run/src/args.cc b/tests/tools/onert_run/src/args.cc index dd4857c6efb..f44ed56769f 100644 --- a/tests/tools/onert_run/src/args.cc +++ b/tests/tools/onert_run/src/args.cc @@ -342,18 +342,8 @@ void Args::Parse(const int argc, char **argv) _mem_poll = _arser.get("--mem_poll"); _write_report = _arser.get("--write_report"); - // calling, e.g., "onert_run .. -- shape_prepare .. --shape_run .." should theoretically - // work but allowing both options together on command line makes the usage and implemenation - // of onert_run too complicated. Therefore let's not allow those option together. auto shape_prepare = _arser.get("--shape_prepare"); auto shape_run = _arser.get("--shape_run"); - if (!shape_prepare.empty() && !shape_run.empty()) - { - std::cerr << "Two options '--shape_prepare' and '--shape_run' cannot be given at once" - << std::endl; - exit(1); - } - if (!shape_prepare.empty()) { #if defined(ONERT_HAVE_HDF5) && ONERT_HAVE_HDF5 == 1 From d7b3607e1e1f1e3ad6c5886e03f70e79bf827b80 Mon Sep 17 00:00:00 2001 From: Jiyoung Giuliana Yun Date: Wed, 14 Aug 2024 10:55:31 +0900 Subject: [PATCH 38/78] [onert] Use DepthwiseConvOp cpu kernel (#13669) This commit uses DepthwiseConvOp cpu kernel to improve performance using multiple threads of Eigen API. ONE-DCO-1.0-Signed-off-by: Jiyoung Yun --- .../cpu/ops/DepthwiseConvolutionLayer.cc | 62 +++++++++++++++++-- .../cpu/ops/DepthwiseConvolutionLayer.h | 6 ++ .../train/ops/DepthwiseConvolutionLayer.cc | 19 ------ .../train/ops/DepthwiseConvolutionLayer.h | 3 - 4 files changed, 64 insertions(+), 26 deletions(-) diff --git a/runtime/onert/backend/cpu/ops/DepthwiseConvolutionLayer.cc b/runtime/onert/backend/cpu/ops/DepthwiseConvolutionLayer.cc index 9e6de17f2de..6c9b0e6ec6b 100644 --- a/runtime/onert/backend/cpu/ops/DepthwiseConvolutionLayer.cc +++ b/runtime/onert/backend/cpu/ops/DepthwiseConvolutionLayer.cc @@ -28,6 +28,43 @@ namespace cpu namespace ops { +void DepthwiseConvolutionLayer::prepareF32() +{ + if (_dilationWidth != 1 || _dilationHeight != 1) + return; + + // DepthwiseConvOp cpu kernel needs additional memory to perform with multi- + // threads. So, we allocate it here and pass it to the kernel. + const int64_t k_packet_size = nnfw::cker::eigen_support::kPacketSize(); + + const auto out_shape = getShape(_output); + const auto filter_shape = getShape(_kernel); + const int batch = out_shape.Dims(0); + const int out_depth = out_shape.Dims(3); + const int filter_rows = filter_shape.Dims(1); + const int filter_cols = filter_shape.Dims(2); + + const int filter_spatial_size = filter_rows * filter_cols; + const int padded_filter_inner_dim_size = + ((out_depth + k_packet_size - 1) / k_packet_size) * k_packet_size; + + _use_padded_filter = (out_depth % k_packet_size) == 0 ? false : true; + + // prepare padded_filter buffer for cker + auto padded_filter_info = ir::OperandInfo(_kernel->get_info()); + padded_filter_info.shape({batch, filter_spatial_size, padded_filter_inner_dim_size}); + _padded_filter = std::make_unique(padded_filter_info, nullptr); + _padded_filter->setBuffer(std::make_shared(_padded_filter->total_size())); + + // prepare out_bprop and in_bprop buffer for cker + const int thread_count = nnfw::cker::eigen_support::getThreadCount() + 1; + + auto filter_buffers_info = ir::OperandInfo(_kernel->get_info()); + filter_buffers_info.shape({thread_count, filter_spatial_size, padded_filter_inner_dim_size}); + _filter_buffers = std::make_unique(filter_buffers_info, nullptr); + _filter_buffers->setBuffer(std::make_shared(_filter_buffers->total_size())); +} + void DepthwiseConvolutionLayer::convFloat32() { float output_activation_min = 0, output_activation_max = 0; @@ -44,10 +81,23 @@ void DepthwiseConvolutionLayer::convFloat32() op_params.float_activation_min = output_activation_min; op_params.float_activation_max = output_activation_max; - nnfw::cker::DepthwiseConv( - op_params, getShape(_input), getBuffer(_input), getShape(_kernel), - getBuffer(_kernel), getShape(_bias), getBuffer(_bias), getShape(_output), - getBuffer(_output), _external_context->ruy_context()); + // Since DepthwiseConvOp does not support dilation yet, it uses the existing + // kernel in this case. + if (_dilationWidth == 1 && _dilationHeight == 1) + { + nnfw::cker::DepthwiseConvOp(op_params, getShape(_input), getBuffer(_input), + getShape(_kernel), getBuffer(_kernel), getShape(_bias), + getBuffer(_bias), getBuffer(_padded_filter.get()), + _use_padded_filter, getBuffer(_filter_buffers.get()), + getShape(_output), getBuffer(_output)); + } + else + { + nnfw::cker::DepthwiseConv( + op_params, getShape(_input), getBuffer(_input), getShape(_kernel), + getBuffer(_kernel), getShape(_bias), getBuffer(_bias), getShape(_output), + getBuffer(_output), _external_context->ruy_context()); + } } void DepthwiseConvolutionLayer::convQ8uPerTensor() @@ -265,6 +315,10 @@ void DepthwiseConvolutionLayer::configure( prepareQ8iHybridPerChannel(); _prepared = true; } + else if (_input->data_type() == OperandType::FLOAT32) + { + prepareF32(); + } else if (_input->data_type() == OperandType::QUANT_INT8_ASYMM) { if (_kernel->is_constant() && !_input->is_dynamic() && !_output->is_dynamic()) diff --git a/runtime/onert/backend/cpu/ops/DepthwiseConvolutionLayer.h b/runtime/onert/backend/cpu/ops/DepthwiseConvolutionLayer.h index dca36a62a48..62eabe17849 100644 --- a/runtime/onert/backend/cpu/ops/DepthwiseConvolutionLayer.h +++ b/runtime/onert/backend/cpu/ops/DepthwiseConvolutionLayer.h @@ -20,6 +20,7 @@ #include #include "OperationUtils.h" #include "../ExternalContext.h" +#include "../Tensor.h" #include @@ -57,6 +58,7 @@ class DepthwiseConvolutionLayer : public ::onert::exec::IFunction void run() override; private: + void prepareF32(); void prepareQ8i(); void prepareQ8uPerChannel(); void prepareQ8iHybridPerChannel(); @@ -83,6 +85,10 @@ class DepthwiseConvolutionLayer : public ::onert::exec::IFunction ir::Activation _activation{ir::Activation::NONE}; + bool _use_padded_filter{false}; + std::unique_ptr _padded_filter{nullptr}; + std::unique_ptr _filter_buffers{nullptr}; + private: std::shared_ptr _external_context; diff --git a/runtime/onert/backend/train/ops/DepthwiseConvolutionLayer.cc b/runtime/onert/backend/train/ops/DepthwiseConvolutionLayer.cc index 9443d0fe0ea..6a6c8684679 100644 --- a/runtime/onert/backend/train/ops/DepthwiseConvolutionLayer.cc +++ b/runtime/onert/backend/train/ops/DepthwiseConvolutionLayer.cc @@ -34,7 +34,6 @@ namespace ops DepthwiseConvolutionLayer::DepthwiseConvolutionLayer() : cpu::ops::DepthwiseConvolutionLayer(), _grad_weights{nullptr}, _grad_bias{nullptr}, _back_prop_input{nullptr}, _back_prop_output{nullptr}, _act_back_prop_output{nullptr}, - _use_padded_filter{false}, _padded_filter{nullptr}, _filter_buffers{nullptr}, _filter_dim_buffers{nullptr} { // DO NOTHING @@ -75,34 +74,16 @@ void DepthwiseConvolutionLayer::configureBackward(IPortableTensor *back_prop_inp }(); const auto incoming_shape = getShape(_back_prop_output); - const auto filter_shape = getShape(_kernel); - const int batch = incoming_shape.Dims(0); const int out_depth = incoming_shape.Dims(3); - const int filter_rows = filter_shape.Dims(1); - const int filter_cols = filter_shape.Dims(2); - const int filter_spatial_size = filter_rows * filter_cols; const int padded_filter_inner_dim_size = ((out_depth + k_packet_size - 1) / k_packet_size) * k_packet_size; - _use_padded_filter = (out_depth % k_packet_size) == 0 ? false : true; - - // prepare padded_filter buffer for cker - auto padded_filter_info = ir::OperandInfo(_kernel->get_info()); - padded_filter_info.shape({batch, filter_spatial_size, padded_filter_inner_dim_size}); - _padded_filter = std::make_unique(padded_filter_info); - _padded_filter->setBuffer(std::make_shared(_padded_filter->total_size())); - // prepare out_bprop and in_bprop buffer for cker // NOTE The Eigen library uses both main thread as well as a thread pool. // Therefore, it needs to add an additional memory buffer for main thread. const int thread_count = nnfw::cker::eigen_support::getThreadCount() + 1; - auto filter_buffers_info = ir::OperandInfo(_kernel->get_info()); - filter_buffers_info.shape({thread_count, filter_spatial_size, padded_filter_inner_dim_size}); - _filter_buffers = std::make_unique(filter_buffers_info); - _filter_buffers->setBuffer(std::make_shared(_filter_buffers->total_size())); - auto filter_dim_buffers_info = ir::OperandInfo(_back_prop_input->get_info()); filter_dim_buffers_info.shape({thread_count, padded_filter_inner_dim_size}); _filter_dim_buffers = std::make_unique(filter_dim_buffers_info); diff --git a/runtime/onert/backend/train/ops/DepthwiseConvolutionLayer.h b/runtime/onert/backend/train/ops/DepthwiseConvolutionLayer.h index 5cd98e56721..8f286b8040d 100644 --- a/runtime/onert/backend/train/ops/DepthwiseConvolutionLayer.h +++ b/runtime/onert/backend/train/ops/DepthwiseConvolutionLayer.h @@ -56,9 +56,6 @@ class DepthwiseConvolutionLayer : public ::onert::exec::train::ITrainableFunctio // TODO Consider if these tensors should be built in TensorBuilder std::unique_ptr _act_back_prop_output; - bool _use_padded_filter; - std::unique_ptr _padded_filter; - std::unique_ptr _filter_buffers; std::unique_ptr _filter_dim_buffers; }; From 4f988a4eca77b8ab72f63012c1fce3f6cc0d75bb Mon Sep 17 00:00:00 2001 From: Jang Jiseob Date: Wed, 14 Aug 2024 10:58:10 +0900 Subject: [PATCH 39/78] [onert] Unify generating training tensors and kernels (#13656) This commit unifies interfaces for generating tensors and kernels for training. ONE-DCO-1.0-Signed-off-by: ragmani --- runtime/onert/backend/train/BackendContext.cc | 79 +++++++++---------- runtime/onert/backend/train/BackendContext.h | 4 +- .../backend/train/TrainableBackendContext.h | 3 +- .../backend/builtin/train/BackendContext.cc | 14 ++-- .../backend/builtin/train/BackendContext.h | 4 +- .../core/src/compiler/ExecutorFactory.cc | 53 ++++++++----- 6 files changed, 80 insertions(+), 77 deletions(-) diff --git a/runtime/onert/backend/train/BackendContext.cc b/runtime/onert/backend/train/BackendContext.cc index 06a224e1ddc..59fee712247 100644 --- a/runtime/onert/backend/train/BackendContext.cc +++ b/runtime/onert/backend/train/BackendContext.cc @@ -136,7 +136,7 @@ getDisposableBackPropTensorList(const ir::train::TrainableGraph &tgraph, } } // namespace -backend::ITensorRegistry *BackendContext::genTensors() +FunctionMap BackendContext::gen() { planForwardTensors(); planBackwardTensors(); @@ -144,7 +144,42 @@ backend::ITensorRegistry *BackendContext::genTensors() _tensor_builder->allocate(); _tensor_builder->allocateBackward(); - return _tensor_registry.get(); + auto fn_map = generateFunctionMap(); + + // Initialize TrainableTensors + trainable_graph()->operands().iterate( + [&](const ir::OperandIndex &ind, const ir::Operand &operand) { + if (external_operands().contains(ind) || !operand.isConstant()) + return; + + auto tensor = tensor_registry()->getNativeITensor(ind); + assert(tensor != nullptr); + + VERBOSE(FillOperandData) << "Fill data for " << ind << std::endl; + + auto data = operand.shareData(); + assert(data && data->base()); + auto trainable_tensor = dynamic_cast(tensor); + + if (trainable_tensor == nullptr) + throw std::runtime_error{"This tensor is not trainable tensor"}; + + trainable_tensor->fillBuffer(data); + }); + + // NOTE For memory optimization, we want to free some operand data + const_cast(*_tdata->tgraph) + .operands() + .iterate([&](const ir::OperandIndex &, ir::Operand &obj) { obj.releaseData(); }); + + // TODO Enable + // for (auto &&it : ret) + // { + // auto &fn_seq = it.second; + // fn_seq->iterate([&](exec::IFunction &ifunc) { ifunc.prepare(); }); + // } + + return fn_map; } void BackendContext::planForwardTensors() @@ -202,46 +237,6 @@ void BackendContext::planBackwardTensors() tensor_planner.planDisposableBackPropTensors(tensor_builder.get()); } -FunctionMap BackendContext::genKernels() -{ - auto ret = generateFunctionMap(); - - // Initialize TrainableTensors - trainable_graph()->operands().iterate( - [&](const ir::OperandIndex &ind, const ir::Operand &operand) { - if (external_operands().contains(ind) || !operand.isConstant()) - return; - - auto tensor = tensor_registry()->getNativeITensor(ind); - assert(tensor != nullptr); - - VERBOSE(FillOperandData) << "Fill data for " << ind << std::endl; - - auto data = operand.shareData(); - assert(data && data->base()); - auto trainable_tensor = dynamic_cast(tensor); - - if (trainable_tensor == nullptr) - throw std::runtime_error{"This tensor is not trainable tensor"}; - - trainable_tensor->fillBuffer(data); - }); - - // NOTE For memory optimization, we want to free some operand data - const_cast(*_tdata->tgraph) - .operands() - .iterate([&](const ir::OperandIndex &, ir::Operand &obj) { obj.releaseData(); }); - - // TODO Enable - // for (auto &&it : ret) - // { - // auto &fn_seq = it.second; - // fn_seq->iterate([&](exec::IFunction &ifunc) { ifunc.prepare(); }); - // } - - return ret; -} - FunctionMap BackendContext::generateFunctionMap() { train::FunctionMap ret; diff --git a/runtime/onert/backend/train/BackendContext.h b/runtime/onert/backend/train/BackendContext.h index 6ab458c437a..8e343aee403 100644 --- a/runtime/onert/backend/train/BackendContext.h +++ b/runtime/onert/backend/train/BackendContext.h @@ -68,15 +68,13 @@ class BackendContext : public onert::backend::train::TrainableBackendContext BackendContext &operator=(const BackendContext &) = delete; public: - backend::ITensorRegistry *genTensors() override; + FunctionMap gen() override; private: void planForwardTensors(); void planBackwardTensors(); public: - FunctionMap genKernels() override; - std::shared_ptr external_context() { return _external_context; } const exec::train::optimizer::Optimizer *optimizer() const { return _optimizer.get(); } diff --git a/runtime/onert/core/include/backend/train/TrainableBackendContext.h b/runtime/onert/core/include/backend/train/TrainableBackendContext.h index 36492786b95..c2edf0deb79 100644 --- a/runtime/onert/core/include/backend/train/TrainableBackendContext.h +++ b/runtime/onert/core/include/backend/train/TrainableBackendContext.h @@ -76,8 +76,7 @@ class TrainableBackendContext std::shared_ptr tensor_registry() { return _tensor_registry; } - virtual backend::ITensorRegistry *genTensors() = 0; - virtual FunctionMap genKernels() = 0; + virtual FunctionMap gen() = 0; private: const ITrainableBackend *_backend{nullptr}; diff --git a/runtime/onert/core/src/backend/builtin/train/BackendContext.cc b/runtime/onert/core/src/backend/builtin/train/BackendContext.cc index c415a5557f5..a0cc0f3c930 100644 --- a/runtime/onert/core/src/backend/builtin/train/BackendContext.cc +++ b/runtime/onert/core/src/backend/builtin/train/BackendContext.cc @@ -28,23 +28,19 @@ namespace builtin namespace train { -backend::ITensorRegistry *BackendContext::genTensors() +backend::train::FunctionMap BackendContext::gen() { // For now, there is no need to generate tensors for forwarding and backwarding. // builtin train backend handles 3 operators: `Permute`, `IF`, `WHILE`. // `Permute`: Tensor generation is not required. // `IF`, `WHILE`: Not supported yet - return tensor_registry().get(); -} -backend::train::FunctionMap BackendContext::genKernels() -{ - backend::train::FunctionMap ret; + backend::train::FunctionMap fn_map; for (auto &&op_ind : _tdata->op_order) { auto tn_seq = kernel_gen->generate(op_ind); - ret.emplace(op_ind, std::move(tn_seq)); + fn_map.emplace(op_ind, std::move(tn_seq)); } trainable_graph()->operands().iterate( @@ -57,13 +53,13 @@ backend::train::FunctionMap BackendContext::genKernels() }); // TODO Enable prepare() - // for (auto &&it : ret) + // for (auto &&it : fn_map) // { // auto &fn_seq = it.second; // fn_seq->iterate([&](exec::IFunction &ifunc) { ifunc.prepare(); }); // } - return ret; + return fn_map; } } // namespace train diff --git a/runtime/onert/core/src/backend/builtin/train/BackendContext.h b/runtime/onert/core/src/backend/builtin/train/BackendContext.h index c57a8020685..4b7c165f454 100644 --- a/runtime/onert/core/src/backend/builtin/train/BackendContext.h +++ b/runtime/onert/core/src/backend/builtin/train/BackendContext.h @@ -46,10 +46,8 @@ class BackendContext : public backend::train::TrainableBackendContext { } - backend::ITensorRegistry *genTensors() override; - public: - backend::train::FunctionMap genKernels() override; + backend::train::FunctionMap gen() override; std::shared_ptr external_context() { return _external_context; } diff --git a/runtime/onert/core/src/compiler/ExecutorFactory.cc b/runtime/onert/core/src/compiler/ExecutorFactory.cc index 233f5f026f7..ba307d3ae8c 100644 --- a/runtime/onert/core/src/compiler/ExecutorFactory.cc +++ b/runtime/onert/core/src/compiler/ExecutorFactory.cc @@ -268,6 +268,21 @@ std::deque> orderBackendContext( return ordered_contexts; } +void generateCodes(backend::train::FunctionMap &codes, + const compiler::train::LoweredTrainableGraph *lowered_graph, + compiler::train::TrainableCodeMap &code_map) +{ + for (auto &&[op_ind, tn_seq] : codes) + { + auto &op = lowered_graph->trainable_graph().operation(op_ind); + const auto backend = lowered_graph->lower_info().operation.at(op_ind); + + assert(code_map.find(op_ind) == code_map.end()); + code_map.insert( + {op_ind, compiler::train::TrainableCodeAndInfo{op_ind, &op, backend, std::move(tn_seq)}}); + } +} + } // namespace } // namespace onert @@ -734,9 +749,17 @@ exec::IExecutor *ExecutorFactory::createTrainableExecutor( VERBOSE(ExecutorFactory) << "Linearize for backwarding order" << std::endl; Linear::dump(*lowered_graph, backward_order); - for (auto &&pair : tbackend_contexts) + train::TrainableCodeMap code_map; + // Generate tensors and kernels + for (auto &&[backend, context] : tbackend_contexts) { - pair.second->genTensors(); + // builtin backend's kernel generator requires access to tensors in other backends. + // So, the other backends must be generated first. + if (backend->config()->id() == "builtin") + continue; + + auto fn_map = context->gen(); + generateCodes(fn_map, lowered_graph.get(), code_map); } prepareMigrantTensors(*lowered_graph, tbackend_contexts); @@ -754,6 +777,16 @@ exec::IExecutor *ExecutorFactory::createTrainableExecutor( } } + // Generate tensors and kernels for only builtin backend + for (auto &&[backend, context] : tbackend_contexts) + { + if (backend->config()->id() == "builtin") + { + auto fn_map = context->gen(); + generateCodes(fn_map, lowered_graph.get(), code_map); + } + } + // Adjust the order of backends for the upcoming iteration auto ordered_contexts = onert::orderBackendContext(tbackend_contexts); @@ -832,22 +865,6 @@ exec::IExecutor *ExecutorFactory::createTrainableExecutor( })); } - train::TrainableCodeMap code_map; - // Generate kernels - for (auto &&pair : ordered_contexts) - { - auto codes = pair.second->genKernels(); - for (auto &&[op_ind, tn_seq] : codes) - { - auto &op = lowered_graph->trainable_graph().operation(op_ind); - const auto backend = lowered_graph->lower_info().operation.at(op_ind); - - assert(code_map.find(op_ind) == code_map.end()); - code_map.insert( - {op_ind, train::TrainableCodeAndInfo{op_ind, &op, backend, std::move(tn_seq)}}); - } - } - if (order.size() != code_map.size()) { throw std::runtime_error("ExecutorFactory: Some kernels are not generated"); From 097e82cadd7b2f06f9c2de395f2853ac7e217907 Mon Sep 17 00:00:00 2001 From: Hyeongseok Oh Date: Wed, 14 Aug 2024 10:59:27 +0900 Subject: [PATCH 40/78] [onert] Revisits python API (#13583) - Rename python package: nnfwapi -> onert - Native library install path: "nnfwapi/onert" -> "nnfw_onert/natvie" - Rename binding script: "libnnfw_api_pybind.py" -> "infer.py" - Rename binding session class: "nnfw_session" -> "session" - Update documentation - Update example ONE-DCO-1.0-Signed-off-by: Hyeongseok Oh --- docs/howto/how-to-use-nnfw-python-api.md | 8 +++---- infra/nnfw/python/.gitignore | 4 ++-- infra/nnfw/python/README.md | 22 +++++++++++++------ infra/nnfw/python/setup.py | 13 ++++++----- runtime/onert/api/python/package/__init__.py | 4 ++-- .../{libnnfw_api_pybind.py => infer.py} | 4 ++-- .../sample/minimal-python/src/minimal.py | 10 +++------ 7 files changed, 34 insertions(+), 31 deletions(-) rename runtime/onert/api/python/package/{libnnfw_api_pybind.py => infer.py} (95%) diff --git a/docs/howto/how-to-use-nnfw-python-api.md b/docs/howto/how-to-use-nnfw-python-api.md index 5d5b839cc63..5a18b79aeb2 100644 --- a/docs/howto/how-to-use-nnfw-python-api.md +++ b/docs/howto/how-to-use-nnfw-python-api.md @@ -17,13 +17,11 @@ Please see [nnfw python api](https://github.com/SAMSUNG/ONE/tree/master/infra/nn 1. Initialize nnfw_session ```python +import onert + # Create session and load nnpackage -# operations is optional to assign a specific backends to each operation. # The default value of backends is "cpu". -if operations: - session = nnfw_session(nnpackage_path, backends, operations) -else: - session = nnfw_session(nnpackage_path, backends) +session = onert.infer.session(nnpackage_path, backends) ``` 2. Prepare Input diff --git a/infra/nnfw/python/.gitignore b/infra/nnfw/python/.gitignore index 15d72def6a6..52796b1b1d1 100644 --- a/infra/nnfw/python/.gitignore +++ b/infra/nnfw/python/.gitignore @@ -1,4 +1,4 @@ build/ dist/ -nnfwapi/ -nnfwapi.egg-info/ +onert/ +onert.egg-info/ diff --git a/infra/nnfw/python/README.md b/infra/nnfw/python/README.md index 2a5942e5eb3..c34acd9e4b7 100644 --- a/infra/nnfw/python/README.md +++ b/infra/nnfw/python/README.md @@ -1,12 +1,12 @@ -# nnfwapi package +# onert package -`nnfwapi` is a package to run `nnpackage` with the nnfw python API. +`onert` is a package to run `nnpackage` with the nnfw onert's python API. -This package includes the nnfw python API module resulting from runtime build. +This package includes the nnfw-onert python API module resulting from runtime build. It is provided separate package for each architecture(x86_64, armv7l, aarch64). -It uses `nnfwapi/libnnfw_api_pybind.py` interface. +It uses `onert/infer.py` interface. ## Packaging Execute this command, then the tasks such as copying modules, and packaging. @@ -39,17 +39,25 @@ $ twine upload --repository-url https://test.pypi.org/legacy/ dist/* You can install the package as follows: ``` -$ pip install -i https://test.pypi.org/simple/ nnfwapi +$ pip install -i https://test.pypi.org/simple/ nnfw-onert ``` By specifying the version, you can use a specific version of the package. (recommended) ``` -$ pip install -i https://test.pypi.org/simple/ nnfwapi==0.1.1 +$ pip install -i https://test.pypi.org/simple/ nnfw-onert==0.1.1 ``` This definition has to be set at the top of the script using nnfw python API. ``` -from nnfwapi.libnnfw_api_pybind import * +import onert ``` + +Or you can import the onert module directly. + +``` +from onert.infer import * +``` + +This can be use onert session directly. diff --git a/infra/nnfw/python/setup.py b/infra/nnfw/python/setup.py index 8217c1219fb..e3c5baf12d9 100644 --- a/infra/nnfw/python/setup.py +++ b/infra/nnfw/python/setup.py @@ -4,7 +4,8 @@ import sys architecture_directory = ['x86_64', 'armv7l', 'aarch64'] -package_directory = 'nnfwapi' +package_name = 'onert' +package_directory = 'onert' packaging_directory = ['build', package_directory + '.egg-info'] THIS_FILE_DIR = os.path.dirname(os.path.abspath(__file__)) DEFAULT_PRODUCT_DIR = "../../../Product" @@ -66,7 +67,7 @@ shutil.rmtree(arch_path) # make architecture_directory and copy .so files to the directories - arch_path = os.path.join(package_directory, 'onert') + arch_path = os.path.join(package_directory, 'native') os.makedirs(arch_path) print(f"Created directory '{arch_path}'") @@ -81,7 +82,7 @@ def get_directories(): for so in os.listdir(so_core_dir): if so.endswith(".so"): - so_list.append('onert/' + so) + so_list.append('native/' + so) src_path = os.path.join(so_core_dir, so) tgt_path = os.path.join(arch_path, so) shutil.copy(src_path, tgt_path) @@ -94,7 +95,7 @@ def get_directories(): os.makedirs(so_backend_tgt_dir) for so in os.listdir(so_backend_dir): if so.endswith(".so"): - so_list.append('onert/nnfw/backend/' + so) + so_list.append('native/nnfw/backend/' + so) src_path = os.path.join(so_backend_dir, so) tgt_path = os.path.join(so_backend_tgt_dir, so) shutil.copy(src_path, tgt_path) @@ -107,7 +108,7 @@ def get_directories(): os.makedirs(so_odc_tgt_dir) for so in os.listdir(so_odc_dir): if so.endswith(".so"): - so_list.append('onert/nnfw/odc/' + so) + so_list.append('native/nnfw/odc/' + so) src_path = os.path.join(so_odc_dir, so) tgt_path = os.path.join(so_odc_tgt_dir, so) shutil.copy(src_path, tgt_path) @@ -121,7 +122,7 @@ def get_directories(): # copy .so files to architecture directories setup( - name=package_directory, + name=package_name, version='0.1.0', description='nnfw_api binding', long_description='It provides nnfw Python api', diff --git a/runtime/onert/api/python/package/__init__.py b/runtime/onert/api/python/package/__init__.py index cd1eaccc9d3..05e235a3112 100644 --- a/runtime/onert/api/python/package/__init__.py +++ b/runtime/onert/api/python/package/__init__.py @@ -1,2 +1,2 @@ -__all__ = ['libnnfw_api_pybind'] -from . import libnnfw_api_pybind +__all__ = ['infer'] +from . import infer diff --git a/runtime/onert/api/python/package/libnnfw_api_pybind.py b/runtime/onert/api/python/package/infer.py similarity index 95% rename from runtime/onert/api/python/package/libnnfw_api_pybind.py rename to runtime/onert/api/python/package/infer.py index f9d51e91dc8..146c4b03efc 100644 --- a/runtime/onert/api/python/package/libnnfw_api_pybind.py +++ b/runtime/onert/api/python/package/infer.py @@ -2,7 +2,7 @@ import os import shutil -from .onert import libnnfw_api_pybind +from .native import libnnfw_api_pybind def num_elems(tensor_info): @@ -13,7 +13,7 @@ def num_elems(tensor_info): return n -class nnfw_session(libnnfw_api_pybind.nnfw_session): +class session(libnnfw_api_pybind.nnfw_session): """Class inherited nnfw_session for easily processing input/output""" def __init__(self, nnpackage_path, backends="cpu"): diff --git a/runtime/onert/sample/minimal-python/src/minimal.py b/runtime/onert/sample/minimal-python/src/minimal.py index 60e8569b798..2ae3f249fcd 100644 --- a/runtime/onert/sample/minimal-python/src/minimal.py +++ b/runtime/onert/sample/minimal-python/src/minimal.py @@ -1,15 +1,11 @@ -from nnfwapi.libnnfw_api_pybind import * +from onert import infer import sys -def main(nnpackage_path, backends="cpu", operations=""): +def main(nnpackage_path, backends="cpu"): # Create session and load nnpackage - # operations is optional to assign a specific backends to each operation. # The default value of backends is "cpu". - if operations: - session = nnfw_session(nnpackage_path, backends, operations) - else: - session = nnfw_session(nnpackage_path, backends) + session = infer.session(nnpackage_path, backends) # Prepare input. Here we just allocate dummy input arrays. input_size = session.input_size() From 9b81a4537e9d13d0a7aed55d677e35c53f39bdcd Mon Sep 17 00:00:00 2001 From: chunseoklee Date: Fri, 16 Aug 2024 16:25:22 +0900 Subject: [PATCH 41/78] [onert-micro] fix build error with cmsisnn (#13680) To build onert_micro_arm target with -DKERNELS=cmsisnn, we need this header. ONE-DCO-1.0-Signed-off-by: Chunseok Lee Co-authored-by: chunseoklee --- .../include/pal/cmsisnn/PALArgMax.h | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 onert-micro/onert-micro/include/pal/cmsisnn/PALArgMax.h diff --git a/onert-micro/onert-micro/include/pal/cmsisnn/PALArgMax.h b/onert-micro/onert-micro/include/pal/cmsisnn/PALArgMax.h new file mode 100644 index 00000000000..67efc055d71 --- /dev/null +++ b/onert-micro/onert-micro/include/pal/cmsisnn/PALArgMax.h @@ -0,0 +1,39 @@ +/* + * 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_ARG_MAX_H +#define ONERT_MICRO_EXECUTE_PAL_ARG_MAX_H + +#include "PALArgMinMaxCommon.h" +namespace onert_micro +{ +namespace execute +{ +namespace pal +{ + +template +OMStatus ArgMax(const core::OMRuntimeShape &input1_shape, const T1 *input1_data, + const T3 *input2_data, const core::OMRuntimeShape &output_shape, T2 *output_data) +{ + return ArgMinMax(input1_shape, input1_data, input2_data, output_shape, output_data, + std::greater()); +} +} // namespace pal +} // namespace execute +} // namespace onert_micro +#endif // ONERT_MICRO_EXECUTE_PAL_ARG_MAX_H From 2502515b5044799db98574659a6f03a503271112 Mon Sep 17 00:00:00 2001 From: chunseoklee Date: Sun, 18 Aug 2024 11:47:54 +0900 Subject: [PATCH 42/78] [onert-micro] S8 Concat Test (#13683) - S8 Concat test added DCO-1.0-Signed-off-by: Chunseok Lee --- .../concatenation/S8ConcatenationKernel.h | 112 ++++++++++++++++++ .../kernels/tests/Concatenation.test.cpp | 9 ++ 2 files changed, 121 insertions(+) create mode 100644 onert-micro/onert-micro/include/test_models/concatenation/S8ConcatenationKernel.h diff --git a/onert-micro/onert-micro/include/test_models/concatenation/S8ConcatenationKernel.h b/onert-micro/onert-micro/include/test_models/concatenation/S8ConcatenationKernel.h new file mode 100644 index 00000000000..d341c5fcb6e --- /dev/null +++ b/onert-micro/onert-micro/include/test_models/concatenation/S8ConcatenationKernel.h @@ -0,0 +1,112 @@ +/* + * 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_CONCATENATION_KERNEL_S8_H +#define ONERT_MICRO_TEST_MODELS_CONCATENATION_KERNEL_S8_H + +#include "TestDataConcatenationBase.h" + +namespace onert_micro +{ +namespace test_model +{ +namespace concatenation_s8 +{ + +/* + * Concatenation Kernel: + * + * Input_1(1, 4, 4, 1) Input_2(1, 4, 4, 2) + * \ / + * Concatenation + * | + * Output(1, 4, 4, 3) + */ +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, 0x34, 0x00, 0x00, 0x00, 0x50, 0x02, 0x00, 0x00, 0x6c, 0x02, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0xf4, 0xff, 0xff, 0xff, 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, 0x68, 0x00, 0x00, 0x00, + 0x6c, 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, + 0x16, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x08, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0a, 0x14, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x03, 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, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x78, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1a, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x48, 0x00, 0x00, 0x00, + 0x0c, 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, 0x00, 0x3f, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0x42, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 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, 0x8a, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x4c, 0x00, 0x00, 0x00, + 0x7c, 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, 0x00, 0x3f, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0x42, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x04, 0x00, 0x00, 0x00, + 0x69, 0x66, 0x6d, 0x32, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 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, 0x54, 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, 0x2c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x42, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 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, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x0c, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 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 input1_data = {-9, -22, -32, 7, -23, -8, -23, -32, + -31, -25, -8, -22, -23, 1, -24, -32}; +const std::vector input2_data = {-29, -31, -8, -23, 16, -23, -38, 7, -36, -22, -32, + -24, -23, -18, -33, -23, -38, -24, -38, -14, -16, -13, + -15, -22, -38, -53, -5, -40, -23, -22, -23, -41}; +const std::vector reference_output_data = { + -9, -29, -31, -22, -8, -23, -32, 16, -23, 7, -38, 7, -23, -36, -22, -8, + -32, -24, -23, -23, -18, -32, -33, -23, -31, -38, -24, -25, -38, -14, -8, -16, + -13, -22, -15, -22, -23, -38, -53, 1, -5, -40, -24, -23, -22, -32, -23, -41}; + +} // namespace concatenation_s8 + +class TestDataS8Concatenation : public TestDataConcatenationBase +{ +public: + TestDataS8Concatenation() + { + _input1_data = concatenation_s8::input1_data; + _input2_data = concatenation_s8::input2_data; + _reference_output_data = concatenation_s8::reference_output_data; + _test_kernel_model_circle = concatenation_s8::test_kernel_model_circle; + } + + ~TestDataS8Concatenation() override = default; +}; + +} // namespace test_model +} // namespace onert_micro + +#endif // ONERT_MICRO_TEST_MODELS_CONCATENATION_KERNEL_S8_H diff --git a/onert-micro/onert-micro/src/execute/kernels/tests/Concatenation.test.cpp b/onert-micro/onert-micro/src/execute/kernels/tests/Concatenation.test.cpp index 0d142568d53..bcf99ec2c40 100644 --- a/onert-micro/onert-micro/src/execute/kernels/tests/Concatenation.test.cpp +++ b/onert-micro/onert-micro/src/execute/kernels/tests/Concatenation.test.cpp @@ -18,6 +18,7 @@ #include "test_models/concatenation/FloatConcatenationKernel.h" #include "test_models/concatenation/NegConcatenationKernel.h" #include "test_models/concatenation/IntConcatenationKernel.h" +#include "test_models/concatenation/S8ConcatenationKernel.h" namespace onert_micro { @@ -33,6 +34,14 @@ class ConcatenationTest : public ::testing::Test // Do nothing }; +TEST_F(ConcatenationTest, S8_P) +{ + test_model::TestDataS8Concatenation test_data_kernel; + std::vector output_data_vector = + onert_micro::execute::testing::checkKernel(2, &test_data_kernel); + EXPECT_THAT(output_data_vector, test_data_kernel.get_output_data_by_index(0)); +} + TEST_F(ConcatenationTest, INT64_P) { test_model::TestDataS64Concatenation test_data_kernel; From e61c5b0915ad534d29cf018fa20dd9b581facc6d Mon Sep 17 00:00:00 2001 From: SaeHie Park Date: Mon, 19 Aug 2024 06:38:26 +0900 Subject: [PATCH 43/78] [tflchef] Remove local graph_name (#13666) This will revise to remove local graph_name variable. ONE-DCO-1.0-Signed-off-by: SaeHie Park --- compiler/tflchef/core/src/ModelChef.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/compiler/tflchef/core/src/ModelChef.cpp b/compiler/tflchef/core/src/ModelChef.cpp index 8b50b09f986..cafd39c404e 100644 --- a/compiler/tflchef/core/src/ModelChef.cpp +++ b/compiler/tflchef/core/src/ModelChef.cpp @@ -690,18 +690,17 @@ void ModelChef::cook_graph(const T &graph, std::map &symbo assert(_operator_vec.empty()); // FIX_CALLER_UNLESS // default name for graph - std::string graph_name = _graph_name; if (graph.has_name()) - graph_name = graph.name(); + _graph_name = graph.name(); - auto lookup = [&symbol_table, &graph_name](const std::string &name) { + auto lookup = [&](const std::string &name) { if (symbol_table.find(name) != symbol_table.end()) return symbol_table.at(name); else if (name == "") return -1; // -1 in TFLite means that optional input tensor is empty. else { - std::string msg = "tflchef : input not found in " + graph_name + " graph"; + std::string msg = "tflchef : input not found in " + _graph_name + " graph"; throw std::runtime_error(msg.c_str()); } }; @@ -730,7 +729,7 @@ void ModelChef::cook_graph(const T &graph, std::map &symbo auto inputs = _flatbuffer_builder->CreateVector(input_vec); auto outputs = _flatbuffer_builder->CreateVector(output_vec); auto operators = _flatbuffer_builder->CreateVector(_operator_vec); - auto name = _flatbuffer_builder->CreateString(graph_name); + auto name = _flatbuffer_builder->CreateString(_graph_name); tflite::SubGraphBuilder subgraph_builder{*_flatbuffer_builder}; From f3d7383f1c561fb83a830636fa0fcdf914a4e98e Mon Sep 17 00:00:00 2001 From: SaeHie Park Date: Mon, 19 Aug 2024 06:39:15 +0900 Subject: [PATCH 44/78] [tflchef] Tidy more disabled codes (#13667) This will tidy more disabled codes that was extract to separate methods. ONE-DCO-1.0-Signed-off-by: SaeHie Park --- compiler/tflchef/core/src/ModelChef.cpp | 138 ------------------------ 1 file changed, 138 deletions(-) diff --git a/compiler/tflchef/core/src/ModelChef.cpp b/compiler/tflchef/core/src/ModelChef.cpp index cafd39c404e..6a1e44a7db9 100644 --- a/compiler/tflchef/core/src/ModelChef.cpp +++ b/compiler/tflchef/core/src/ModelChef.cpp @@ -888,60 +888,6 @@ void ModelChef::cook(const ::tflchef::ModelRecipe &model_recipe) gather_operator_codes(model_recipe); -#if 0 - // Create OperatorCode with Builtin Operator - _builtin_code_map = gather_builtincode_map(model_recipe); - for (auto const &opcode : _builtin_code_map) - { - tflite::OperatorCodeBuilder code_builder{*_flatbuffer_builder}; - // 127 is BuiltinOperator_PLACEHOLDER_FOR_GREATER_OP_CODES - // This is the way to handle deprecated builtin code - // See - // https://github.com/tensorflow/tensorflow/blob/a0afe8f9218be5eb9ed5dffc2dff652996da8c28/tensorflow/lite/schema/schema.fbs#L1061-L1077 - if (opcode.first < 127) - { - code_builder.add_deprecated_builtin_code(opcode.first); - } - else - { - code_builder.add_deprecated_builtin_code( - ::tflite::BuiltinOperator_PLACEHOLDER_FOR_GREATER_OP_CODES); - } - code_builder.add_version(opcode.second); - code_builder.add_builtin_code(opcode.first); - auto code = code_builder.Finish(); - // Update OperatorCode vector - _code_vec.emplace_back(code); - } - - // Create OperatorCode with Custom Operator - std::set custom_code_set = gather_customcode_set(model_recipe); - _custom_code_vec = {custom_code_set.begin(), custom_code_set.end()}; - - for (auto opcode : _custom_code_vec) - { - auto custom_code = _flatbuffer_builder->CreateString(opcode); - tflite::OperatorCodeBuilder code_builder{*_flatbuffer_builder}; - code_builder.add_deprecated_builtin_code(tflite::BuiltinOperator_CUSTOM); - code_builder.add_custom_code(custom_code); - code_builder.add_builtin_code(tflite::BuiltinOperator_CUSTOM); - auto code = code_builder.Finish(); - // Update OperatorCode vector - _code_vec.emplace_back(code); - } -#endif - -#if 0 - // Create an Empty Buffer - // - // Buffer 0 SHOULD be an empty buffer in TensorFlow Lite model file - // (Please refer to the comment for Tensor.buffer field in schema) - { - tflite::BufferBuilder buffer_builder{*_flatbuffer_builder}; - _buffer_vec.emplace_back(buffer_builder.Finish()); - } -#endif - // // Create Main graph // @@ -973,90 +919,6 @@ void ModelChef::cook(const ::tflchef::ModelRecipe &model_recipe) gather_signature_defs(model_recipe); -#if 0 - // Create Signature-Def - // - for (int s = 0; s < model_recipe.signature_def_size(); ++s) - { - // load from recipe - const auto &rec_signature_def = model_recipe.signature_def(s); - - std::vector> tensormap_inputs; - std::vector> tensormap_outputs; - - // which subgraph index to cook - auto subgraph_index = 0; - if (rec_signature_def.has_subgraph_index()) - { - subgraph_index = rec_signature_def.subgraph_index(); - } - assert(subgraph_index < _symbol_tables.size()); - auto &symbol_table = _symbol_tables[subgraph_index]; - - // cook for inputs - for (int si = 0; si < rec_signature_def.inputs_size(); ++si) - { - // recipe for input TensorMap - auto rec_tm_input = rec_signature_def.inputs(si); - auto name = _flatbuffer_builder->CreateString(rec_tm_input.name()); - uint32_t tensor_index = 0; - // either tensor or tensor_index should exist - assert(rec_tm_input.has_tensor() || rec_tm_input.has_tensor_index()); - if (rec_tm_input.has_tensor()) - { - // we can get tensor_index from symbol_table - auto tensor = rec_tm_input.tensor(); - tensor_index = symbol_table[tensor]; - } - else - { - // or we can use tensor_index itself - tensor_index = rec_tm_input.tensor_index(); - } - - ::tflite::TensorMapBuilder tensormap_builder{*_flatbuffer_builder}; - tensormap_builder.add_name(name); - tensormap_builder.add_tensor_index(tensor_index); - tensormap_inputs.push_back(tensormap_builder.Finish()); - } - // cook for outputs, same as inputs - for (int so = 0; so < rec_signature_def.outputs_size(); ++so) - { - auto rec_tm_output = rec_signature_def.outputs(so); - auto name = _flatbuffer_builder->CreateString(rec_tm_output.name()); - uint32_t tensor_index = 0; - assert(rec_tm_output.has_tensor() || rec_tm_output.has_tensor_index()); - if (rec_tm_output.has_tensor()) - { - auto tensor = rec_tm_output.tensor(); - tensor_index = symbol_table[tensor]; - } - else - { - tensor_index = rec_tm_output.tensor_index(); - } - - ::tflite::TensorMapBuilder tensormap_builder{*_flatbuffer_builder}; - tensormap_builder.add_name(name); - tensormap_builder.add_tensor_index(tensor_index); - tensormap_outputs.push_back(tensormap_builder.Finish()); - } - - auto inputs = _flatbuffer_builder->CreateVector(tensormap_inputs); - auto outputs = _flatbuffer_builder->CreateVector(tensormap_outputs); - auto signature_key = _flatbuffer_builder->CreateString(rec_signature_def.signature_key()); - // TODO add validation for signature_key - - ::tflite::SignatureDefBuilder signature_def_builder{*_flatbuffer_builder}; - signature_def_builder.add_inputs(inputs); - signature_def_builder.add_outputs(outputs); - signature_def_builder.add_signature_key(signature_key); - signature_def_builder.add_subgraph_index(rec_signature_def.subgraph_index()); - - _signdef_vec.emplace_back(signature_def_builder.Finish()); - } -#endif - // Create "Model" arguments auto buffers = _flatbuffer_builder->CreateVector(_buffer_vec); auto signdefs = _flatbuffer_builder->CreateVector(_signdef_vec); From d4b32bd3ae3c6f37492ee97da67fec0b4755845e Mon Sep 17 00:00:00 2001 From: chunseoklee Date: Mon, 19 Aug 2024 11:37:48 +0900 Subject: [PATCH 45/78] [onert-micro] Quantized S8 for Sub (#13682) - Enable Sub S8 support ONE-DCO-1.0-Signed-off-by: Chunseok Lee --- .../include/pal/common/PALSubCommon.h | 30 +++++ .../onert-micro/include/pal/mcu/PALSub.h | 19 +++ .../include/test_models/sub/S8SubKernel.h | 116 ++++++++++++++++++ .../onert-micro/src/execute/kernels/Sub.cpp | 69 +++++++++++ .../src/execute/kernels/tests/Sub.test.cpp | 13 ++ 5 files changed, 247 insertions(+) create mode 100644 onert-micro/onert-micro/include/test_models/sub/S8SubKernel.h diff --git a/onert-micro/onert-micro/include/pal/common/PALSubCommon.h b/onert-micro/onert-micro/include/pal/common/PALSubCommon.h index 1df3370c020..62964a51f56 100644 --- a/onert-micro/onert-micro/include/pal/common/PALSubCommon.h +++ b/onert-micro/onert-micro/include/pal/common/PALSubCommon.h @@ -25,6 +25,26 @@ namespace execute { namespace pal { + +int8_t SubFunc(int8_t x, int8_t y, const core::ArithmeticQuantParams ¶ms) +{ + const int32_t input1_val = params.input1_offset + x; + const int32_t input2_val = params.input2_offset + y; + const int32_t shifted_input1_val = input1_val * (1 << params.left_shift); + const int32_t shifted_input2_val = input2_val * (1 << params.left_shift); + const int32_t scaled_input1_val = multiplyByQuantizedMultiplierSmallerThanOneExp( + shifted_input1_val, params.input1_multiplier, params.input1_shift); + const int32_t scaled_input2_val = multiplyByQuantizedMultiplierSmallerThanOneExp( + shifted_input2_val, params.input2_multiplier, params.input2_shift); + const int32_t raw_sum = scaled_input1_val - scaled_input2_val; + const int32_t raw_output = multiplyByQuantizedMultiplierSmallerThanOneExp( + raw_sum, params.output_multiplier, params.output_shift) + + params.output_offset; + const int32_t clamped_output = std::min(params.quantized_activation_max, + std::max(params.quantized_activation_min, raw_output)); + return static_cast(clamped_output); +} + template OMStatus Sub(const core::BinaryArithmeticBroadcastParams ¶ms, const int flat_size, const T *input1_data, const T *input2_data, T *output_data) @@ -44,6 +64,16 @@ OMStatus BroadcastSub4DSlow(const core::BinaryArithmeticBroadcastParams ¶ms, return Ok; } +OMStatus BroadcastSub4DSlow(const core::ArithmeticQuantParams ¶ms, + const core::OMRuntimeShape &input1_shape, const int8_t *input1_data, + const core::OMRuntimeShape &input2_shape, const int8_t *input2_data, + const core::OMRuntimeShape &output_shape, int8_t *output_data) +{ + BroadcastBinaryFunction6DSlow(params, input1_shape, input1_data, input2_shape, input2_data, + output_shape, output_data, SubFunc); + return Ok; +} + } // namespace pal } // namespace execute } // namespace onert_micro diff --git a/onert-micro/onert-micro/include/pal/mcu/PALSub.h b/onert-micro/onert-micro/include/pal/mcu/PALSub.h index a3bd4b7368a..60c5fb6eac8 100644 --- a/onert-micro/onert-micro/include/pal/mcu/PALSub.h +++ b/onert-micro/onert-micro/include/pal/mcu/PALSub.h @@ -19,5 +19,24 @@ #define ONERT_MICRO_EXECUTE_PAL_SUB_H #include "PALSubCommon.h" +#include "PALUtils.h" + +namespace onert_micro +{ +namespace execute +{ +namespace pal +{ + +OMStatus Sub(const core::ArithmeticQuantParams ¶ms, const uint32_t flat_size, + const int8_t *input1_data, const int8_t *input2_data, int8_t *output_data) +{ + ElementWise(flat_size, params, input1_data, input2_data, output_data, SubFunc); + return Ok; +} + +} // namespace pal +} // namespace execute +} // namespace onert_micro #endif // ONERT_MICRO_EXECUTE_PAL_MUL_H diff --git a/onert-micro/onert-micro/include/test_models/sub/S8SubKernel.h b/onert-micro/onert-micro/include/test_models/sub/S8SubKernel.h new file mode 100644 index 00000000000..276ba9eb1b9 --- /dev/null +++ b/onert-micro/onert-micro/include/test_models/sub/S8SubKernel.h @@ -0,0 +1,116 @@ +/* + * 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_SUB_KERNEL_S8_H +#define ONERT_MICRO_TEST_MODELS_SUB_KERNEL_S8_H + +#include "TestDataSubBase.h" + +namespace onert_micro +{ +namespace test_model +{ +namespace sub_s8_no_broadcasting +{ + +/* + * Sub Kernel: + * + * Input_1(2, 2) Input_2(2, 2) + * \ / + * Sub(w/o broadcast) + * | + * Output(2, 2) + */ + +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, + 0x30, 0x00, 0x00, 0x00, 0x44, 0x02, 0x00, 0x00, 0x60, 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 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, 0x60, 0x00, 0x00, 0x00, 0x64, 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, 0x1c, 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, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x78, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1a, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x48, 0x00, 0x00, 0x00, + 0x0c, 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, 0xfe, 0x42, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x03, 0x00, 0x00, 0x00, + 0x6f, 0x66, 0x6d, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x8a, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x4c, 0x00, 0x00, 0x00, + 0x7c, 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, 0xfe, 0x42, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x04, 0x00, 0x00, 0x00, + 0x69, 0x66, 0x6d, 0x32, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 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, 0x54, 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, 0x2c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 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, 0xfe, 0x42, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x04, 0x00, 0x00, 0x00, 0x69, 0x66, 0x6d, 0x31, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x02, 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, + 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x11, 0x00, 0x00, 0x00, 0x4f, 0x4e, 0x45, 0x2d, + 0x74, 0x66, 0x6c, 0x69, 0x74, 0x65, 0x32, 0x63, 0x69, 0x72, 0x63, 0x6c, 0x65, 0x00, 0x00, 0x00}; +std::vector input1_data = { + 5, + 7, + 13, + -3, +}; +std::vector input2_data = {-5, -11, 5, 5}; +std::vector reference_output_data = {10, 18, 8, -8}; +} // namespace sub_s8_no_broadcasting + +class TestDataS8Sub : public TestDataSubBase +{ +public: + explicit TestDataS8Sub(bool is_with_broadcast) : TestDataSubBase(is_with_broadcast) + { + if (is_with_broadcast) + { + std::cerr << ("Sub S8 with broadcasting not supported yet!\n"); + } + else + { + _input1_data = sub_s8_no_broadcasting::input1_data; + _input2_data = sub_s8_no_broadcasting::input2_data; + _reference_output_data = sub_s8_no_broadcasting::reference_output_data; + _test_kernel_model_circle = sub_s8_no_broadcasting::test_kernel_model_circle; + } + } + + ~TestDataS8Sub() override = default; +}; + +} // namespace test_model +} // namespace onert_micro + +#endif // ONERT_MICRO_TEST_MODELS_SUB_KERNEL_S8_H diff --git a/onert-micro/onert-micro/src/execute/kernels/Sub.cpp b/onert-micro/onert-micro/src/execute/kernels/Sub.cpp index 6e32e88f3b2..788eb6813e0 100644 --- a/onert-micro/onert-micro/src/execute/kernels/Sub.cpp +++ b/onert-micro/onert-micro/src/execute/kernels/Sub.cpp @@ -38,6 +38,50 @@ constexpr uint32_t input1TensorIdx = 0; constexpr uint32_t input2TensorIdx = 1; constexpr uint32_t outputTensorIdx = 0; +void calculateQuantParams(core::ArithmeticQuantParams ¶ms, const circle::Tensor *input1, + const circle::Tensor *input2, const circle::Tensor *output, + circle::ActivationFunctionType act) +{ + long input1_zp; + long input2_zp; + long output_zp; + + float input1_scale; + float input2_scale; + float output_scale; + + // Read input1 quant params + readQuantParams(input1, input1_zp, input1_scale); + // Read input2 quant params + readQuantParams(input2, input2_zp, input2_scale); + // Read output quant params + readQuantParams(output, output_zp, output_scale); + + params.input1_offset = -static_cast(input1_zp); + params.input2_offset = -static_cast(input2_zp); + params.output_offset = static_cast(output_zp); + params.left_shift = (output->type() == circle::TensorType_INT16) ? 15 : 20; + const double twice_max_input_scale = + 2 * static_cast(std::max(input1_scale, input2_scale)); + const double real_input1_multiplier = static_cast(input1_scale) / twice_max_input_scale; + const double real_input2_multiplier = static_cast(input2_scale) / twice_max_input_scale; + const double real_output_multiplier = + twice_max_input_scale / ((1 << params.left_shift) * static_cast(output_scale)); + + quantizeMultiplierSmallerThanOneExp(real_input1_multiplier, ¶ms.input1_multiplier, + ¶ms.input1_shift); + + quantizeMultiplierSmallerThanOneExp(real_input2_multiplier, ¶ms.input2_multiplier, + ¶ms.input2_shift); + + quantizeMultiplierSmallerThanOneExp(real_output_multiplier, ¶ms.output_multiplier, + ¶ms.output_shift); + + calculateActivationRangeQuantized(act, output_zp, output_scale, output->type(), + ¶ms.quantized_activation_min, + ¶ms.quantized_activation_max); +} + } // namespace // NOTE: doesnt currently support dynamic shapes @@ -160,6 +204,31 @@ OMStatus onert_micro::execute::execute_kernel_CircleSub(const OMExecuteArgs &exe } break; #endif // DIS_FLOAT +#ifndef DIS_QUANT + case circle::TensorType_INT8: + { + core::ArithmeticQuantParams sub_params{}; + + calculateQuantParams(sub_params, input1, input2, output, + options->fused_activation_function()); + + if (need_broadcast) + { + status = pal::BroadcastSub4DSlow( + sub_params, input1_shape, core::utils::castInputData(input1_data), input2_shape, + core::utils::castInputData(input2_data), output_shape, + core::utils::castOutputData(output_data)); + } + else + { + status = pal::Sub(sub_params, input1_shape.flatSize(), + core::utils::castInputData(input1_data), + core::utils::castInputData(input2_data), + core::utils::castOutputData(output_data)); + } + } + break; +#endif // DIF_QUANT default: { status = UnsupportedType; diff --git a/onert-micro/onert-micro/src/execute/kernels/tests/Sub.test.cpp b/onert-micro/onert-micro/src/execute/kernels/tests/Sub.test.cpp index 91d9da48a75..56b361d7f30 100644 --- a/onert-micro/onert-micro/src/execute/kernels/tests/Sub.test.cpp +++ b/onert-micro/onert-micro/src/execute/kernels/tests/Sub.test.cpp @@ -18,6 +18,7 @@ #include "test_models/sub/FloatSubKernel.h" #include "test_models/sub/NegSubKernel.h" #include "test_models/sub/IntSubKernel.h" +#include "test_models/sub/S8SubKernel.h" namespace onert_micro { @@ -53,6 +54,18 @@ TEST_F(SubTest, INT_P) } } +TEST_F(SubTest, S8_P) +{ + // No broadcast + { + const bool is_with_broadcast = false; + test_model::TestDataS8Sub test_data_add_no_broadcasting(is_with_broadcast); + std::vector output_data_vector = + onert_micro::execute::testing::checkKernel(2, &test_data_add_no_broadcasting); + EXPECT_THAT(output_data_vector, test_data_add_no_broadcasting.get_output_data_by_index(0)); + } +} + TEST_F(SubTest, Float_P) { // No broadcast From d82e145ff7ec82ce4d9c21d1c9c6d26ef782eeda Mon Sep 17 00:00:00 2001 From: Hyukjin Jeong Date: Mon, 19 Aug 2024 13:53:18 +0900 Subject: [PATCH 46/78] [luci-interpreter] Avoid Conv2D integer overflow (#13690) This adds a guard code to avoid integer overflow in optimized Conv2D kernel. ONE-DCO-1.0-Signed-off-by: Hyukjin Jeong --- .../luci-interpreter/pal/linux/PALConv2d.h | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/compiler/luci-interpreter/pal/linux/PALConv2d.h b/compiler/luci-interpreter/pal/linux/PALConv2d.h index 8ffcd864b21..0ce83fc6e35 100644 --- a/compiler/luci-interpreter/pal/linux/PALConv2d.h +++ b/compiler/luci-interpreter/pal/linux/PALConv2d.h @@ -30,14 +30,30 @@ static inline void Conv(const tflite::ConvParams ¶ms, const tflite::RuntimeS float *scratchpad_data) { (void)scratchpad_shape; - if (scratchpad_data) + + const int32_t batches = tflite::MatchingDim(input_shape, 0, output_shape, 0); + const int32_t input_depth = tflite::MatchingDim(input_shape, 3, filter_shape, 3); + const int32_t output_height = output_shape.Dims(1); + const int32_t output_width = output_shape.Dims(2); + const int32_t filter_height = filter_shape.Dims(1); + const int32_t filter_width = filter_shape.Dims(2); + + int64_t im2col_flat_size = 1; + im2col_flat_size *= batches; + im2col_flat_size *= output_height; + im2col_flat_size *= output_width; + im2col_flat_size *= input_depth; + im2col_flat_size *= filter_height; + im2col_flat_size *= filter_width; + + // This condition checks if integer overflow will occur inside the optimized kernel. + // https://github.com/tensorflow/tensorflow/blob/v2.12.1/tensorflow/lite/kernels/internal/optimized/im2col_utils.h#L81 + // If overflow is expected, we fall back to the reference kernel. + // NOTE This is just a rough check. + bool opt_kernel_overflow = im2col_flat_size > std::numeric_limits::max(); + + if (scratchpad_data and not opt_kernel_overflow) { - const int32_t batches = tflite::MatchingDim(input_shape, 0, output_shape, 0); - const int32_t input_depth = tflite::MatchingDim(input_shape, 3, filter_shape, 3); - const int32_t output_height = output_shape.Dims(1); - const int32_t output_width = output_shape.Dims(2); - const int32_t filter_height = filter_shape.Dims(1); - const int32_t filter_width = filter_shape.Dims(2); tflite::RuntimeShape im2col_shape{batches, output_height, output_width, input_depth * filter_height * filter_width}; From 8f98b9aa6b551f01dfdb0b4c38ff637876f025d9 Mon Sep 17 00:00:00 2001 From: SaeHie Park Date: Mon, 19 Aug 2024 14:44:25 +0900 Subject: [PATCH 47/78] [infra/fb] Introduce FlatBuffersMuteable_Target (#13687) This will introduce FlatBuffersMuteable_Target method to produce schema generated header with mutable methods. ONE-DCO-1.0-Signed-off-by: SaeHie Park --- .../FlatBuffersConfig.cmake | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/infra/cmake/packages/FlatBuffers-23.5.26/FlatBuffersConfig.cmake b/infra/cmake/packages/FlatBuffers-23.5.26/FlatBuffersConfig.cmake index d98882a32cc..cc77b844d1d 100644 --- a/infra/cmake/packages/FlatBuffers-23.5.26/FlatBuffersConfig.cmake +++ b/infra/cmake/packages/FlatBuffers-23.5.26/FlatBuffersConfig.cmake @@ -132,4 +132,53 @@ if(FlatBuffers_FOUND) target_include_directories(${TGT} PUBLIC "${ARG_INCLUDE_DIR}") target_link_libraries(${TGT} PUBLIC flatbuffers-23.5.26) endfunction(FlatBuffers_Target) + + function(FlatBuffersMuteable_Target TGT) + set(oneValueArgs OUTPUT_DIR SCHEMA_DIR INCLUDE_DIR) + set(multiValueArgs SCHEMA_FILES) + cmake_parse_arguments(ARG "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + # Use OUTPUT_DIR as INCLUDE_DIR if INCLUDE_DIR is not specified + if(NOT ARG_INCLUDE_DIR) + set(ARG_INCLUDE_DIR ${ARG_OUTPUT_DIR}) + endif(NOT ARG_INCLUDE_DIR) + + get_filename_component(abs_output_dir ${ARG_OUTPUT_DIR} ABSOLUTE) + get_filename_component(abs_include_dir ${ARG_INCLUDE_DIR} ABSOLUTE) + get_filename_component(abs_schema_dir ${ARG_SCHEMA_DIR} ABSOLUTE) + + # Let's reset list variables before using them + # NOTE THIS DOES NOT AFFECT parent scope + unset(SCHEMA_FILES) + unset(OUTPUT_FILES) + + foreach(schema ${ARG_SCHEMA_FILES}) + get_filename_component(schema_fn "${schema}" NAME) + get_filename_component(dir "${schema}" DIRECTORY) + + get_filename_component(schema_fn_we "${schema_fn}" NAME_WE) + + list(APPEND SCHEMA_FILES "${abs_schema_dir}/${schema}") + list(APPEND OUTPUT_FILES "${abs_output_dir}/${schema_fn_we}_generated.h") + endforeach() + + # Generate headers + add_custom_command(OUTPUT ${OUTPUT_FILES} + COMMAND ${CMAKE_COMMAND} -E make_directory "${abs_output_dir}" + COMMAND "${FLATC_PATH}" -c --no-includes + --no-union-value-namespacing + --gen-object-api + --gen-mutable + -o "${abs_output_dir}" + ${SCHEMA_FILES} + DEPENDS ${SCHEMA_FILES} + COMMENT "Generate '${TGT}' headers") + + # NOTE This header-only library is deliberately declared as STATIC library + # to avoid possible scope issues related with generated files + add_library(${TGT} STATIC ${OUTPUT_FILES}) + set_target_properties(${TGT} PROPERTIES LINKER_LANGUAGE CXX) + target_include_directories(${TGT} PUBLIC "${ARG_INCLUDE_DIR}") + target_link_libraries(${TGT} PUBLIC flatbuffers-23.5.26) + endfunction(FlatBuffersMuteable_Target) endif(FlatBuffers_FOUND) From 7d2e7815d1ee00db7931443922b3ad8b2b793b45 Mon Sep 17 00:00:00 2001 From: SaeHie Park Date: Mon, 19 Aug 2024 17:22:57 +0900 Subject: [PATCH 48/78] [mio-tflite] Revise to use new schema with mutable (#13694) This will revise to use new schema to support file size > 2G and with mutable methods. ONE-DCO-1.0-Signed-off-by: SaeHie Park --- compiler/mio-tflite2121/CMakeLists.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/mio-tflite2121/CMakeLists.txt b/compiler/mio-tflite2121/CMakeLists.txt index 371118be83c..3cd9662d460 100644 --- a/compiler/mio-tflite2121/CMakeLists.txt +++ b/compiler/mio-tflite2121/CMakeLists.txt @@ -15,7 +15,9 @@ endif(NOT TensorFlowSource_FOUND) message(STATUS "Build mio-tflite2121: TRUE") message(STATUS "Build mio-tflite2121: with ${TensorFlowSource_DIR}") -set(SCHEMA_FILE "${TensorFlowSource_DIR}/tensorflow/lite/schema/schema.fbs") +# TODO rollback to use TensorFlowSource_DIR after upgrade +#set(SCHEMA_FILE "${TensorFlowSource_DIR}/tensorflow/lite/schema/schema.fbs") +set(SCHEMA_FILE "${NNAS_PROJECT_SOURCE_DIR}/res/TensorFlowLiteSchema/2.16.1/schema.fbs") # NOTE Use copy of schema.fbs as to provide unified way for circle also add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/schema.fbs" @@ -24,7 +26,7 @@ add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/schema.fbs" DEPENDS "${SCHEMA_FILE}" ) -FlatBuffers_Target(mio_tflite2121 +FlatBuffersMuteable_Target(mio_tflite2121 OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/gen/mio/tflite" INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/gen" SCHEMA_DIR "${CMAKE_CURRENT_BINARY_DIR}" From dad984ba3ae21e14f80105a8d1962ea9b03aaaca Mon Sep 17 00:00:00 2001 From: SaeHie Park Date: Mon, 19 Aug 2024 18:31:43 +0900 Subject: [PATCH 49/78] [tflchef] Introduce finalize_ext_buffer and members (#13699) This will add finalize_ext_buffer method and members to handle data outside of limits of flatbuffres offset. ONE-DCO-1.0-Signed-off-by: SaeHie Park --- compiler/tflchef/core/src/ModelChef.cpp | 76 ++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 2 deletions(-) diff --git a/compiler/tflchef/core/src/ModelChef.cpp b/compiler/tflchef/core/src/ModelChef.cpp index 6a1e44a7db9..ccb77af2b5d 100644 --- a/compiler/tflchef/core/src/ModelChef.cpp +++ b/compiler/tflchef/core/src/ModelChef.cpp @@ -199,6 +199,8 @@ class ModelChef template void cook_graph(const T &graph, std::map &symbol_table); + bool finalize_ext_buffer(void); + public: const char *get_buffer_pointer(void) const; size_t get_size(void) const; @@ -223,6 +225,11 @@ class ModelChef std::vector> _operator_vec; std::string _graph_name; + + // store Buffer data to external of FB and use (Buffer) offset/size fields + bool _ext_offset = false; + std::map> _buffer_data_map; + std::string _ext_data; }; void ModelChef::init(void) @@ -882,6 +889,66 @@ void ModelChef::gather_signature_defs(const ::tflchef::ModelRecipe &model_recipe } } +bool ModelChef::finalize_ext_buffer(void) +{ + // NOTE modification of std::string object in the middle may reallocate it. + // we will use std::string::reserve() to prevent this. + + auto align16 = [](size_t &v) { + while (v % 16 != 0) + v++; + }; + + // get total memory for flatbuffer + all buffer_data + size_t result_size = _flatbuffer_builder->GetSize(); + align16(result_size); + for (auto &it : _buffer_data_map) + { + std::vector &buffer_data = it.second; + result_size += buffer_data.size(); + align16(result_size); + } + align16(result_size); + result_size += 16; // additional for safety + + std::string result; + auto *buff_ptr = reinterpret_cast(_flatbuffer_builder->GetBufferPointer()); + + auto padalign16 = [](std::string &str) { + while (str.size() % 16 != 0) + str += '\0'; + }; + + result.reserve(result_size); + result.append(buff_ptr, _flatbuffer_builder->GetSize()); + + auto mutable_model = tflite::GetMutableModel(result.data()); + auto mutable_buffers = mutable_model->mutable_buffers(); + bool ret = true; + + padalign16(result); + for (auto &it : _buffer_data_map) + { + int32_t buffer_index = it.first; + std::vector &buffer_data = it.second; + uint64_t offset = result.size(); + uint64_t size = buffer_data.size(); + + tflite::Buffer *mutable_buffer = mutable_buffers->GetMutableObject(buffer_index); + ret &= mutable_buffer->mutate_offset(offset); + ret &= mutable_buffer->mutate_size(size); + + result.append(buffer_data.begin(), buffer_data.end()); + padalign16(result); + } + padalign16(result); + + // use final result + _ext_data = result; + + return ret; +} + void ModelChef::cook(const ::tflchef::ModelRecipe &model_recipe) { prepare_initial_buffer(); @@ -940,17 +1007,22 @@ void ModelChef::cook(const ::tflchef::ModelRecipe &model_recipe) // Finalize ::tflite::FinishModelBuffer(*_flatbuffer_builder, model); + + if (_ext_offset) + finalize_ext_buffer(); } const char *ModelChef::get_buffer_pointer(void) const { - // + if (_ext_offset) + return _ext_data.data(); return reinterpret_cast(_flatbuffer_builder->GetBufferPointer()); } size_t ModelChef::get_size(void) const { - // + if (_ext_offset) + return _ext_data.size(); return _flatbuffer_builder->GetSize(); } From bb4aa34a63bd45aa0428858f9b6006e82653b622 Mon Sep 17 00:00:00 2001 From: Hyeongseok Oh Date: Mon, 19 Aug 2024 19:29:02 +0900 Subject: [PATCH 50/78] [onert] Fix DepthwiseConvOp kernel condition (#13689) This commit fixes DepthwiseConvOp kernel usage condition. Eigen kernel is not supproting different width-height stride yet. ONE-DCO-1.0-Signed-off-by: Hyeongseok Oh Co-authored-by: Jiyoung Giuliana Yun --- .../onert/backend/cpu/ops/DepthwiseConvolutionLayer.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/runtime/onert/backend/cpu/ops/DepthwiseConvolutionLayer.cc b/runtime/onert/backend/cpu/ops/DepthwiseConvolutionLayer.cc index 6c9b0e6ec6b..9ebaa9b14f7 100644 --- a/runtime/onert/backend/cpu/ops/DepthwiseConvolutionLayer.cc +++ b/runtime/onert/backend/cpu/ops/DepthwiseConvolutionLayer.cc @@ -30,7 +30,7 @@ namespace ops void DepthwiseConvolutionLayer::prepareF32() { - if (_dilationWidth != 1 || _dilationHeight != 1) + if (_dilationWidth != 1 || _dilationHeight != 1 || _strideWidth != _strideHeight) return; // DepthwiseConvOp cpu kernel needs additional memory to perform with multi- @@ -81,9 +81,9 @@ void DepthwiseConvolutionLayer::convFloat32() op_params.float_activation_min = output_activation_min; op_params.float_activation_max = output_activation_max; - // Since DepthwiseConvOp does not support dilation yet, it uses the existing - // kernel in this case. - if (_dilationWidth == 1 && _dilationHeight == 1) + // Since DepthwiseConvOp does not support dilation and different W/H stride yet, + // it uses the existing kernel in this case. + if (_dilationWidth == 1 && _dilationHeight == 1 && _strideWidth == _strideHeight) { nnfw::cker::DepthwiseConvOp(op_params, getShape(_input), getBuffer(_input), getShape(_kernel), getBuffer(_kernel), getShape(_bias), From 452cf4c003d90f18350663e3d5d04940fecd0fbe Mon Sep 17 00:00:00 2001 From: SaeHie Park Date: Tue, 20 Aug 2024 06:40:53 +0900 Subject: [PATCH 51/78] [tflchef] Add ext_offset field to recipe proto (#13702) This will add ext_offset field to recipe proto to generate Buffer data outside of flatbuffer region. ONE-DCO-1.0-Signed-off-by: SaeHie Park --- compiler/tflchef/core/src/ModelChef.cpp | 3 +++ compiler/tflchef/proto/tflchef.proto | 2 ++ 2 files changed, 5 insertions(+) diff --git a/compiler/tflchef/core/src/ModelChef.cpp b/compiler/tflchef/core/src/ModelChef.cpp index ccb77af2b5d..786da524051 100644 --- a/compiler/tflchef/core/src/ModelChef.cpp +++ b/compiler/tflchef/core/src/ModelChef.cpp @@ -951,6 +951,9 @@ bool ModelChef::finalize_ext_buffer(void) void ModelChef::cook(const ::tflchef::ModelRecipe &model_recipe) { + // use Custom/Buffer offset + _ext_offset = model_recipe.has_ext_offset() ? model_recipe.ext_offset() : false; + prepare_initial_buffer(); gather_operator_codes(model_recipe); diff --git a/compiler/tflchef/proto/tflchef.proto b/compiler/tflchef/proto/tflchef.proto index e4ae5d9b65b..59995f13e71 100644 --- a/compiler/tflchef/proto/tflchef.proto +++ b/compiler/tflchef/proto/tflchef.proto @@ -719,4 +719,6 @@ message ModelRecipe { optional uint32 version = 6 [default = 1]; repeated Graph graph = 7; repeated SignatureDef signature_def = 8; + // store to external and use (Buffer) offset + optional bool ext_offset = 9 [default = false]; } From 6842ca1641d00d1a23d54eea8f2f50048b9bec88 Mon Sep 17 00:00:00 2001 From: SaeHie Park Date: Tue, 20 Aug 2024 06:41:44 +0900 Subject: [PATCH 52/78] [tflchef] Revise with Buffer generation with ext_offset flag (#13703) This will revise with Buffer generation with ext_offset flag state. ONE-DCO-1.0-Signed-off-by: SaeHie Park --- compiler/tflchef/core/src/ModelChef.cpp | 82 +++++++++++++++++-------- 1 file changed, 57 insertions(+), 25 deletions(-) diff --git a/compiler/tflchef/core/src/ModelChef.cpp b/compiler/tflchef/core/src/ModelChef.cpp index 786da524051..af7255195dc 100644 --- a/compiler/tflchef/core/src/ModelChef.cpp +++ b/compiler/tflchef/core/src/ModelChef.cpp @@ -362,16 +362,26 @@ template void ModelChef::cook_operands(const T &graph) sparse_uint8.emplace_back(arr[b]); } } - auto data = _flatbuffer_builder->CreateVector(sparse_uint8); - - // Create Buffer - tflite::BufferBuilder buffer_builder{*_flatbuffer_builder}; - buffer_builder.add_data(data); - auto buffer = buffer_builder.Finish(); + if (_ext_offset) + { + buffer_index = _buffer_vec.size(); + _buffer_data_map[buffer_index] = sparse_uint8; - // Update Buffer Index & Vector - buffer_index = _buffer_vec.size(); - _buffer_vec.emplace_back(buffer); + auto buffer = tflite::CreateBuffer(*_flatbuffer_builder, 0, 1, 1); + _buffer_vec.emplace_back(buffer); + } + else + { + auto data = _flatbuffer_builder->CreateVector(sparse_uint8); + // Create Buffer + tflite::BufferBuilder buffer_builder{*_flatbuffer_builder}; + buffer_builder.add_data(data); + auto buffer = buffer_builder.Finish(); + + // Update Buffer Index & Vector + buffer_index = _buffer_vec.size(); + _buffer_vec.emplace_back(buffer); + } // save SparsityParameters auto traversal_order = _flatbuffer_builder->CreateVector(traversal_order_vec); @@ -405,16 +415,27 @@ template void ModelChef::cook_operands(const T &graph) sparse_uint8.emplace_back(arr[b]); } } - auto data = _flatbuffer_builder->CreateVector(sparse_uint8); + if (_ext_offset) + { + buffer_index = _buffer_vec.size(); + _buffer_data_map[buffer_index] = sparse_uint8; - // Create Buffer - tflite::BufferBuilder buffer_builder{*_flatbuffer_builder}; - buffer_builder.add_data(data); - auto buffer = buffer_builder.Finish(); + auto buffer = tflite::CreateBuffer(*_flatbuffer_builder, 0, 1, 1); + _buffer_vec.emplace_back(buffer); + } + else + { + auto data = _flatbuffer_builder->CreateVector(sparse_uint8); - // Update Buffer Index & Vector - buffer_index = _buffer_vec.size(); - _buffer_vec.emplace_back(buffer); + // Create Buffer + tflite::BufferBuilder buffer_builder{*_flatbuffer_builder}; + buffer_builder.add_data(data); + auto buffer = buffer_builder.Finish(); + + // Update Buffer Index & Vector + buffer_index = _buffer_vec.size(); + _buffer_vec.emplace_back(buffer); + } // save SparsityParameters auto traversal_order = _flatbuffer_builder->CreateVector(traversal_order_vec); @@ -454,16 +475,27 @@ template void ModelChef::cook_operands(const T &graph) data_vec = data_packed; } - auto data = _flatbuffer_builder->CreateVector(data_vec); + if (_ext_offset) + { + buffer_index = _buffer_vec.size(); + _buffer_data_map[buffer_index] = data_vec; - // Create Buffer - tflite::BufferBuilder buffer_builder{*_flatbuffer_builder}; - buffer_builder.add_data(data); - auto buffer = buffer_builder.Finish(); + auto buffer = tflite::CreateBuffer(*_flatbuffer_builder, 0, 1, 1); + _buffer_vec.emplace_back(buffer); + } + else + { + auto data = _flatbuffer_builder->CreateVector(data_vec); - // Update Buffer Index & Vector - buffer_index = _buffer_vec.size(); - _buffer_vec.emplace_back(buffer); + // Create Buffer + tflite::BufferBuilder buffer_builder{*_flatbuffer_builder}; + buffer_builder.add_data(data); + auto buffer = buffer_builder.Finish(); + + // Update Buffer Index & Vector + buffer_index = _buffer_vec.size(); + _buffer_vec.emplace_back(buffer); + } } } else From 59d0fcb9477b38b81fc4cd74bc87894af22ed73a Mon Sep 17 00:00:00 2001 From: chunseoklee Date: Tue, 20 Aug 2024 10:25:57 +0900 Subject: [PATCH 53/78] [onert-mico] S8 test for Unpack (#13692) - S8 Test for unpack added DCO-1.0-Signed-off-by: Chunseok Lee --- .../test_models/unpack/S8UnpackKernel.h | 107 ++++++++++++++++++ .../src/execute/kernels/Unpack.cpp | 7 ++ .../src/execute/kernels/tests/Unpack.test.cpp | 9 ++ 3 files changed, 123 insertions(+) create mode 100644 onert-micro/onert-micro/include/test_models/unpack/S8UnpackKernel.h diff --git a/onert-micro/onert-micro/include/test_models/unpack/S8UnpackKernel.h b/onert-micro/onert-micro/include/test_models/unpack/S8UnpackKernel.h new file mode 100644 index 00000000000..ad039655f0b --- /dev/null +++ b/onert-micro/onert-micro/include/test_models/unpack/S8UnpackKernel.h @@ -0,0 +1,107 @@ +/* + * 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_S8_UNPACK_KERNEL_H +#define ONERT_MICRO_TEST_MODELS_S8_UNPACK_KERNEL_H + +#include "TestDataUnpackBase.h" + +namespace onert_micro +{ +namespace test_model +{ +namespace unpack_s8 +{ +/* + * Unpack Kernel: + * + * Input(2, 2, 2) + * | + * Unpack(num=2, axis=0) + * / \ + * Output1(2, 2, 2) Output1(2, 2, 2) + */ +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, 0x34, 0x00, 0x00, 0x00, 0x30, 0x02, 0x00, 0x00, 0x4c, + 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xf4, 0xff, 0xff, 0xff, 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, 0x68, 0x00, 0x00, 0x00, 0x70, 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, 0x16, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x0c, 0x00, 0x07, 0x00, 0x08, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, + 0x14, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, + 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xe8, 0x00, 0x00, + 0x00, 0x70, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x32, 0xff, 0xff, 0xff, 0x14, 0x00, + 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x48, + 0x00, 0x00, 0x00, 0x24, 0xff, 0xff, 0xff, 0x2c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0x42, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x05, + 0x00, 0x00, 0x00, 0x6f, 0x66, 0x6d, 0x3a, 0x31, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x9a, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, + 0x00, 0x48, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x44, 0x00, + 0x00, 0x00, 0x8c, 0xff, 0xff, 0xff, 0x2c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x14, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfe, 0x42, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x03, 0x00, + 0x00, 0x00, 0x6f, 0x66, 0x6d, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, + 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, 0x54, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x50, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x14, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x2c, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x42, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x03, 0x00, 0x00, 0x00, 0x69, 0x66, 0x6d, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 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, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x58, 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, 2, 3, 4, 5, 6, 7, 8}; +const std::vector reference_output_data_1 = {1, 2, 3, 4}; +const std::vector reference_output_data_2 = {5, 6, 7, 8}; + +} // namespace unpack_s8 + +class TestDataS8Unpack : public TestDataUnpackBase +{ +public: + TestDataS8Unpack() + { + _input_data = unpack_s8::input_data; + _reference_output_data_1 = unpack_s8::reference_output_data_1; + _reference_output_data_2 = unpack_s8::reference_output_data_2; + _test_kernel_model_circle = unpack_s8::test_kernel_model_circle; + } + + ~TestDataS8Unpack() override = default; +}; + +} // namespace test_model +} // namespace onert_micro + +#endif // ONERT_MICRO_TEST_MODELS_S8_UNPACK_KERNEL_H diff --git a/onert-micro/onert-micro/src/execute/kernels/Unpack.cpp b/onert-micro/onert-micro/src/execute/kernels/Unpack.cpp index cfa61f4b537..ecb0b01e721 100644 --- a/onert-micro/onert-micro/src/execute/kernels/Unpack.cpp +++ b/onert-micro/onert-micro/src/execute/kernels/Unpack.cpp @@ -93,6 +93,13 @@ OMStatus onert_micro::execute::execute_kernel_CircleUnpack(const OMExecuteArgs & output_shape, axis_value); break; #endif // DIS_FLOAT +#ifndef DIS_QUANT + case circle::TensorType_INT8: + status = + pal::Unpack(params, input_shape, core::utils::castInputData(input_data), + output_shape, axis_value); + break; +#endif // DIS_QUANT default: { status = UnsupportedActivation; diff --git a/onert-micro/onert-micro/src/execute/kernels/tests/Unpack.test.cpp b/onert-micro/onert-micro/src/execute/kernels/tests/Unpack.test.cpp index 9c5738842a5..d0c76113ce5 100644 --- a/onert-micro/onert-micro/src/execute/kernels/tests/Unpack.test.cpp +++ b/onert-micro/onert-micro/src/execute/kernels/tests/Unpack.test.cpp @@ -16,6 +16,7 @@ #include "execute/OMTestUtils.h" #include "test_models/unpack/FloatUnpackKernel.h" +#include "test_models/unpack/S8UnpackKernel.h" #include "test_models/unpack/NegUnpackKernel.h" namespace onert_micro @@ -40,6 +41,14 @@ TEST_F(UnpackTest, Float_P) EXPECT_THAT(output_data_vector, test_data_kernel.get_output_data_by_index(0)); } +TEST_F(UnpackTest, S8_P) +{ + onert_micro::test_model::TestDataS8Unpack 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(UnpackTest, Input_output_type_mismatch_NEG) { onert_micro::test_model::NegTestDataInputOutputTypeMismatchUnpackKernel test_data_kernel; From f4159d250911145073dfaaded3fdf52a09fdc16b Mon Sep 17 00:00:00 2001 From: chunseoklee Date: Tue, 20 Aug 2024 10:26:11 +0900 Subject: [PATCH 54/78] [onert-micro] S8 Test for Pack (#13691) - S8 Test for Pack Added - Enable Pack op again DCO-1.0-Signed-off-by: Chunseok Lee --- .../include/pal/mcu/KernelsToBuild.lst | 2 +- .../include/test_models/pack/PackKernel.h | 75 +++++++++++++++++++ .../src/execute/kernels/tests/Pack.test.cpp | 8 ++ 3 files changed, 84 insertions(+), 1 deletion(-) diff --git a/onert-micro/onert-micro/include/pal/mcu/KernelsToBuild.lst b/onert-micro/onert-micro/include/pal/mcu/KernelsToBuild.lst index 83208f90cc3..2560554777a 100644 --- a/onert-micro/onert-micro/include/pal/mcu/KernelsToBuild.lst +++ b/onert-micro/onert-micro/include/pal/mcu/KernelsToBuild.lst @@ -30,7 +30,7 @@ REGISTER_KERNEL(FILL, Fill) REGISTER_KERNEL(FLOOR, Floor) REGISTER_KERNEL(FLOOR_DIV, FloorDiv) REGISTER_KERNEL(FLOOR_MOD, FloorMod) -#/*REGISTER_KERNEL(PACK, Pack)*/ +REGISTER_KERNEL(PACK, Pack) REGISTER_KERNEL(PAD, Pad) #/*REGISTER_KERNEL(PADV2, PadV2)*/ #/*REGISTER_KERNEL(PRELU, PRelu)*/ diff --git a/onert-micro/onert-micro/include/test_models/pack/PackKernel.h b/onert-micro/onert-micro/include/test_models/pack/PackKernel.h index e2896d467b7..d7de7b0eb2b 100644 --- a/onert-micro/onert-micro/include/test_models/pack/PackKernel.h +++ b/onert-micro/onert-micro/include/test_models/pack/PackKernel.h @@ -221,6 +221,67 @@ const std::vector reference_output_data = { 5, 5, 5, 5, 5, 245, 251, 5, 251, 223, 5, 251, 22, 15, 15, 15}; } // namespace pack_quant_u8 +namespace pack_s8 +{ +/* + * Pack Kernel: + * + * Input(2, 2) Input(2, 2) + * \ / + * \ / + * Pack : values_count: 2, axis: 1 + * | + * Output(2, 2, 2) + */ +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, + 0x34, 0x00, 0x00, 0x00, 0x44, 0x02, 0x00, 0x00, 0x60, 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0xf4, 0xff, 0xff, 0xff, 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, 0x6c, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x78, 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, 0x3b, + 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0c, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 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, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, + 0x78, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x22, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x4c, 0x00, 0x00, 0x00, + 0x14, 0xff, 0xff, 0xff, 0x2c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 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, 0x08, 0x00, 0x00, 0x00, 0x73, 0x74, 0x61, 0x63, + 0x6b, 0x5f, 0x34, 0x64, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x92, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0x02, 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, 0x00, 0x00, 0x80, 0x3f, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7f, 0x43, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x31, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x02, 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, 0x54, 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, 0x2c, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 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, + 0x05, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x02, 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, + 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 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 = {1, 2, 3, 4}; + +const std::vector input_data_2 = {5, 6, 7, 8}; + +const std::vector reference_output_data = {1, 2, 5, 6, 3, 4, 7, 8}; +} // namespace pack_s8 class TestDataFloatPack : public TestDataPackBase { @@ -264,6 +325,20 @@ class TestDataQuantU8Pack : public TestDataPackBase ~TestDataQuantU8Pack() override = default; }; +class TestDataS8Pack : public TestDataPackBase +{ +public: + TestDataS8Pack() + { + _input_data_1 = pack_s8::input_data_1; + _input_data_2 = pack_s8::input_data_2; + _reference_output_data = pack_s8::reference_output_data; + _test_kernel_model_circle = pack_s8::test_kernel_model_circle; + } + + ~TestDataS8Pack() override = default; +}; + } // namespace test_model } // namespace onert_micro diff --git a/onert-micro/onert-micro/src/execute/kernels/tests/Pack.test.cpp b/onert-micro/onert-micro/src/execute/kernels/tests/Pack.test.cpp index 1f63ea31794..57a8fbd8d6a 100644 --- a/onert-micro/onert-micro/src/execute/kernels/tests/Pack.test.cpp +++ b/onert-micro/onert-micro/src/execute/kernels/tests/Pack.test.cpp @@ -47,6 +47,14 @@ TEST_F(PackTest, Int_P) EXPECT_THAT(output_data_vector, test_data_kernel.get_output_data_by_index(0)); } +TEST_F(PackTest, S8_P) +{ + test_model::TestDataS8Pack test_data_kernel; + std::vector output_data_vector = + onert_micro::execute::testing::checkKernel(2, &test_data_kernel); + EXPECT_THAT(output_data_vector, test_data_kernel.get_output_data_by_index(0)); +} + // TODO: add negative tests and quant version } // namespace testing From b2ccf51a8b70cb8b5a3ee729788509119d81e4b9 Mon Sep 17 00:00:00 2001 From: chunseoklee Date: Tue, 20 Aug 2024 10:26:27 +0900 Subject: [PATCH 55/78] [onert-micro] S8 Test for Logisitic (#13688) - Add test for S8 Logistic - Fix logistic kernel by syncing with tflite DCO-1.0-Signed-off-by: Chunseok Lee --- .../include/pal/common/PALLogistic.h | 2 +- .../test_models/logistic/S8LogisticKernel.h | 93 +++++++++++++++++++ .../execute/kernels/tests/Logistic.test.cpp | 9 ++ 3 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 onert-micro/onert-micro/include/test_models/logistic/S8LogisticKernel.h diff --git a/onert-micro/onert-micro/include/pal/common/PALLogistic.h b/onert-micro/onert-micro/include/pal/common/PALLogistic.h index de0f4f94fdd..298515531bc 100644 --- a/onert-micro/onert-micro/include/pal/common/PALLogistic.h +++ b/onert-micro/onert-micro/include/pal/common/PALLogistic.h @@ -96,7 +96,7 @@ OMStatus inline Logistic(const int flat_size, const int8_t *input_data, float in result = 1.f / (1.f + std::exp(-val)); } // Requantize - int8_t output = static_cast(result / output_scale + output_zero_point); + int8_t output = static_cast(std::round(result / output_scale) + output_zero_point); output_data[i] = output; } return Ok; diff --git a/onert-micro/onert-micro/include/test_models/logistic/S8LogisticKernel.h b/onert-micro/onert-micro/include/test_models/logistic/S8LogisticKernel.h new file mode 100644 index 00000000000..333fe228ab9 --- /dev/null +++ b/onert-micro/onert-micro/include/test_models/logistic/S8LogisticKernel.h @@ -0,0 +1,93 @@ +/* + * 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_S8_LOGISTIC_KERNEL_H +#define ONERT_MICRO_TEST_MODELS_S8_LOGISTIC_KERNEL_H + +#include "TestDataLogisticBase.h" + +namespace onert_micro +{ +namespace test_model +{ +namespace logistic_s8 +{ +/* + * Logistic Kernel: + * + * Input(1, 1, 2, 2) : zp = -128, scale 1/256.0 by tflite quant spec + * | + * Logistic + * | + * Output(1, 1, 2, 2) zp = -128, scale 1/256.0 by tflite quant spec + */ +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, 0x2c, 0x00, 0x00, 0x00, 0xa8, 0x01, 0x00, 0x00, 0xc4, 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, + 0x84, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x92, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x44, 0x00, 0x00, 0x00, + 0x84, 0xff, 0xff, 0xff, 0x2c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x6f, 0x66, 0x6d, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x02, 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, + 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x3b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x69, 0x66, 0x6d, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 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, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, + 0x11, 0x00, 0x00, 0x00, 0x4f, 0x4e, 0x45, 0x2d, 0x74, 0x66, 0x6c, 0x69, 0x74, 0x65, 0x32, 0x63, + 0x69, 0x72, 0x63, 0x6c, 0x65, 0x00, 0x00, 0x00}; + +const std::vector input_data = {-10, -5, 8, 99}; +const std::vector reference_output_data = {29, 30, 33, 53}; + +} // namespace logistic_s8 + +class TestDataS8Logistic : public TestDataLogisticBase +{ +public: + TestDataS8Logistic() + { + _input_data = logistic_s8::input_data; + _reference_output_data = logistic_s8::reference_output_data; + _test_kernel_model_circle = logistic_s8::test_kernel_model_circle; + } + + ~TestDataS8Logistic() override = default; +}; + +} // namespace test_model +} // namespace onert_micro + +#endif // ONERT_MICRO_TEST_MODELS_S8_LOGISTIC_KERNEL_H diff --git a/onert-micro/onert-micro/src/execute/kernels/tests/Logistic.test.cpp b/onert-micro/onert-micro/src/execute/kernels/tests/Logistic.test.cpp index 9b82cadae50..60d2efca403 100644 --- a/onert-micro/onert-micro/src/execute/kernels/tests/Logistic.test.cpp +++ b/onert-micro/onert-micro/src/execute/kernels/tests/Logistic.test.cpp @@ -16,6 +16,7 @@ #include "execute/OMTestUtils.h" #include "test_models/logistic/FloatLogisticKernel.h" +#include "test_models/logistic/S8LogisticKernel.h" #include "test_models/logistic/NegLogisticKernel.h" namespace onert_micro @@ -40,6 +41,14 @@ TEST_F(LogisticTest, Float_P) EXPECT_THAT(output_data_vector, test_data_kernel.get_output_data_by_index(0)); } +TEST_F(LogisticTest, S8_P) +{ + onert_micro::test_model::TestDataS8Logistic 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(LogisticTest, Input_output_type_mismatch_NEG) { onert_micro::test_model::NegTestDataInputOutputTypeMismatchLogisticKernel test_data_kernel; From 90e7838481f5c70edd6d9c7fde0e93b679051eb0 Mon Sep 17 00:00:00 2001 From: SaeHie Park Date: Tue, 20 Aug 2024 11:57:44 +0900 Subject: [PATCH 56/78] [tflchef] Introduce ext_offset test recipe (#13706) This will add ext_offset enabled test recipe to generate tflite file in format to support file size > 2G. ONE-DCO-1.0-Signed-off-by: SaeHie Park --- compiler/tflchef/tests/ext_offset/test.recipe | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 compiler/tflchef/tests/ext_offset/test.recipe diff --git a/compiler/tflchef/tests/ext_offset/test.recipe b/compiler/tflchef/tests/ext_offset/test.recipe new file mode 100644 index 00000000000..fb94e9c7b26 --- /dev/null +++ b/compiler/tflchef/tests/ext_offset/test.recipe @@ -0,0 +1,44 @@ +operand { + name: "ifm" + type: FLOAT32 + shape { dim: 1 dim: 3 dim: 3 dim: 2 } +} +operand { + name: "ker" + type: FLOAT32 + shape { dim: 1 dim: 1 dim: 1 dim: 2 } + filler { + tag: "explicit" + arg: "1.1" + arg: "2.2" + } +} +operand { + name: "bias" + type: FLOAT32 + shape { dim: 1 } + filler { + tag: "constant" + arg: "3.3" + } +} +operand { + name: "ofm" + type: FLOAT32 + shape { dim: 1 dim: 3 dim: 3 dim: 1 } +} +operation { + type: "Conv2D" + conv2d_options { + padding: VALID + stride_w: 1 + stride_h: 1 + } + input: "ifm" + input: "ker" + input: "bias" + output: "ofm" +} +input: "ifm" +output: "ofm" +ext_offset: true From a1ce518018c5cf21c35db328151304df272e9435 Mon Sep 17 00:00:00 2001 From: SaeHie Park Date: Tue, 20 Aug 2024 11:58:04 +0900 Subject: [PATCH 57/78] [tfldump] Revise Reader to support ext_offset (#13707) This will revise Reader class to support Buffer offset/size attributes for file size > 2G. ONE-DCO-1.0-Signed-off-by: SaeHie Park --- compiler/tfldump/src/Read.cpp | 59 +++++++++++++++++++++++++++++++++++ compiler/tfldump/src/Read.h | 4 +++ 2 files changed, 63 insertions(+) diff --git a/compiler/tfldump/src/Read.cpp b/compiler/tfldump/src/Read.cpp index f55d86dda5b..fe921c65d16 100644 --- a/compiler/tfldump/src/Read.cpp +++ b/compiler/tfldump/src/Read.cpp @@ -18,6 +18,7 @@ #include +#include #include #include @@ -39,6 +40,23 @@ Reader::Reader(const tflite::Model *model) } } +Reader::Reader(const tflite::Model *model, const std::vector *rawdata) +{ + _rawdata = rawdata; + + _version = model->version(); + _subgraphs = model->subgraphs(); + _buffers = model->buffers(); + _metadata = model->metadata(); + _signaturedefs = model->signature_defs(); + + auto opcodes = model->operator_codes(); + for (const ::tflite::OperatorCode *opcode : *opcodes) + { + _op_codes.push_back(opcode); + } +} + size_t Reader::buffer_info(uint32_t buf_idx, const uint8_t **buff_data) { *buff_data = nullptr; @@ -61,6 +79,47 @@ size_t Reader::buffer_info(uint32_t buf_idx, const uint8_t **buff_data) return 0; } +size_t Reader::buffer_info(uint32_t buf_idx, const uint8_t **buff_data, bool &ext_offset) +{ + *buff_data = nullptr; + ext_offset = false; + + if (buf_idx == 0) + return 0; + + if (auto *buffer = (*_buffers)[buf_idx]) + { + auto buffer_offset = buffer->offset(); + if (buffer->offset() > 1) + { + assert(_rawdata); // make debug break for invalid case + if (_rawdata == nullptr) + return 0; + + ext_offset = true; + *buff_data = reinterpret_cast(&_rawdata->at(buffer_offset)); + return buffer->size(); + } + else if (auto *array = buffer->data()) + { + if (size_t size = array->size()) + { + *buff_data = reinterpret_cast(array->data()); + return size; + } + } + else + { + if (buffer->offset() == 1 && buffer->size() == 1) + { + std::cerr << "Buffer " << buf_idx << " has invalid offset/size." << std::endl; + } + } + } + + return 0; +} + tflite::BuiltinOperator Reader::builtin_code(const tflite::Operator *op) const { uint32_t index = op->opcode_index(); diff --git a/compiler/tfldump/src/Read.h b/compiler/tfldump/src/Read.h index fb4d330e70d..974f60923ce 100644 --- a/compiler/tfldump/src/Read.h +++ b/compiler/tfldump/src/Read.h @@ -51,6 +51,7 @@ class Reader public: Reader(const tflite::Model *model); + Reader(const tflite::Model *model, const std::vector *rawdata); Reader() = delete; @@ -69,6 +70,7 @@ class Reader uint32_t num_subgraph() const { return _subgraphs->size(); } size_t buffer_info(uint32_t buf_idx, const uint8_t **buff_data); + size_t buffer_info(uint32_t buf_idx, const uint8_t **buff_data, bool &ext_offset); tflite::BuiltinOperator builtin_code(const tflite::Operator *op) const; std::string opcode_name(const tflite::Operator *op) const; @@ -80,6 +82,8 @@ class Reader private: uint32_t _version; + const std::vector *_rawdata{nullptr}; + const TFliteSubGraphs_t *_subgraphs{nullptr}; const TFliteBuffers_t *_buffers{nullptr}; const TFliteTensors_t *_tensors{nullptr}; From 6b99385225e149b72bc594e31d2b4ff7ab964ca9 Mon Sep 17 00:00:00 2001 From: SaeHie Park Date: Tue, 20 Aug 2024 11:58:27 +0900 Subject: [PATCH 58/78] [mio-circle08] Revise to support ext_offset (#13708) This will revise to support ext_offset with - enable mutable methods with generated schema - enable to read Buffer offset/size attributes ONE-DCO-1.0-Signed-off-by: SaeHie Park --- compiler/mio-circle08/CMakeLists.txt | 2 +- .../mio-circle08/include/mio_circle/Reader.h | 4 ++ compiler/mio-circle08/src/Reader.cpp | 71 +++++++++++++++++++ 3 files changed, 76 insertions(+), 1 deletion(-) diff --git a/compiler/mio-circle08/CMakeLists.txt b/compiler/mio-circle08/CMakeLists.txt index 03e449d6e81..cee15c96993 100644 --- a/compiler/mio-circle08/CMakeLists.txt +++ b/compiler/mio-circle08/CMakeLists.txt @@ -19,7 +19,7 @@ add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/schema.fbs" DEPENDS "${SCHEMA_FILE}" ) -FlatBuffers_Target(mio_circle08 +FlatBuffersMuteable_Target(mio_circle08 OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/gen/mio/circle" INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/gen" SCHEMA_DIR "${CMAKE_CURRENT_BINARY_DIR}" diff --git a/compiler/mio-circle08/include/mio_circle/Reader.h b/compiler/mio-circle08/include/mio_circle/Reader.h index 723668f264e..079ef27b77f 100644 --- a/compiler/mio-circle08/include/mio_circle/Reader.h +++ b/compiler/mio-circle08/include/mio_circle/Reader.h @@ -47,6 +47,7 @@ class Reader public: Reader(const ::circle::Model *model); + Reader(const ::circle::Model *model, const std::vector *rawdata); Reader() = delete; @@ -65,6 +66,7 @@ class Reader uint32_t num_subgraph() const { return _subgraphs->size(); } size_t buffer_info(uint32_t buf_idx, const uint8_t **buff_data); + size_t buffer_info(uint32_t buf_idx, const uint8_t **buff_data, bool &ext_offset); ::circle::BuiltinOperator builtin_code(const ::circle::Operator *op) const; std::string opcode_name(const ::circle::Operator *op) const; std::vector outputs(const ::circle::Operator *op) const; @@ -79,6 +81,8 @@ class Reader private: uint32_t _version; + const std::vector *_rawdata{nullptr}; + const CircleSubGraphs_t *_subgraphs{nullptr}; const CircleBuffers_t *_buffers{nullptr}; const CircleTensors_t *_tensors{nullptr}; diff --git a/compiler/mio-circle08/src/Reader.cpp b/compiler/mio-circle08/src/Reader.cpp index e4df6d04d54..b9f17725e01 100644 --- a/compiler/mio-circle08/src/Reader.cpp +++ b/compiler/mio-circle08/src/Reader.cpp @@ -17,6 +17,7 @@ #include "mio_circle/Reader.h" #include "mio_circle/Helper.h" +#include #include #include @@ -45,6 +46,28 @@ Reader::Reader(const ::circle::Model *model) } } +Reader::Reader(const ::circle::Model *model, const std::vector *rawdata) +{ + if (model == nullptr) + { + throw std::runtime_error("Invalid model"); + } + + _rawdata = rawdata; + + _version = model->version(); + _subgraphs = model->subgraphs(); + _buffers = model->buffers(); + _metadata = model->metadata(); + _signature_defs = model->signature_defs(); + + auto opcodes = model->operator_codes(); + for (const ::circle::OperatorCode *opcode : *opcodes) + { + _op_codes.push_back(opcode); + } +} + size_t Reader::buffer_info(uint32_t buf_idx, const uint8_t **buff_data) { if (buff_data != nullptr) @@ -73,6 +96,54 @@ size_t Reader::buffer_info(uint32_t buf_idx, const uint8_t **buff_data) return 0; } +size_t Reader::buffer_info(uint32_t buf_idx, const uint8_t **buff_data, bool &ext_offset) +{ + ext_offset = false; + + if (buff_data != nullptr) + { + *buff_data = nullptr; + } + + if (buf_idx == 0) + return 0; + + if (auto *buffer = (*_buffers)[buf_idx]) + { + auto buffer_offset = buffer->offset(); + if (buffer_offset > 1) + { + assert(_rawdata); // make debug break for invalid case + if (_rawdata == nullptr) + return 0; + + ext_offset = true; + *buff_data = reinterpret_cast(&_rawdata->at(buffer_offset)); + return buffer->size(); + } + else if (auto *array = buffer->data()) + { + if (size_t size = array->size()) + { + if (buff_data != nullptr) + { + *buff_data = reinterpret_cast(array->data()); + } + return size; + } + } + else + { + if (buffer->offset() == 1 && buffer->size() == 1) + { + std::cerr << "Buffer " << buf_idx << " has invalid offset/size." << std::endl; + } + } + } + + return 0; +} + ::circle::BuiltinOperator Reader::builtin_code(const ::circle::Operator *op) const { uint32_t index = op->opcode_index(); From 8188194d4f4ba135227370ea260400fee0c206e9 Mon Sep 17 00:00:00 2001 From: SaeHie Park Date: Tue, 20 Aug 2024 12:17:41 +0900 Subject: [PATCH 59/78] [github] Run onecc-build only in Samsung Org. (#13709) This will revuse to run onecc-build only in Samsung Org. ONE-DCO-1.0-Signed-off-by: SaeHie Park --- .github/workflows/run-onecc-build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/run-onecc-build.yml b/.github/workflows/run-onecc-build.yml index d4e1c3c96b2..c12010d0aec 100644 --- a/.github/workflows/run-onecc-build.yml +++ b/.github/workflows/run-onecc-build.yml @@ -38,6 +38,7 @@ jobs: onecc-test: # Tested ubuntu version is decided by docker image, not runner runs-on: ubuntu-latest + if: github.repository_owner == 'Samsung' strategy: matrix: type: [ Debug, Release ] From f5ea127d8aefc57a398391b2d706e5f5319549a6 Mon Sep 17 00:00:00 2001 From: Jiyoung Giuliana Yun Date: Tue, 20 Aug 2024 16:22:47 +0900 Subject: [PATCH 60/78] [onert] Introduce checkpoint.h file (#13671) This commit introduces checkpoint.h file. This header file contains Header and Footer structure. It also has MAGIC_NUMBER and SCHEMA_VERSION for checkpoint format. ONE-DCO-1.0-Signed-off-by: Jiyoung Yun --- .../onert/core/include/ir/train/Checkpoint.h | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 runtime/onert/core/include/ir/train/Checkpoint.h diff --git a/runtime/onert/core/include/ir/train/Checkpoint.h b/runtime/onert/core/include/ir/train/Checkpoint.h new file mode 100644 index 00000000000..d62f9d69b5e --- /dev/null +++ b/runtime/onert/core/include/ir/train/Checkpoint.h @@ -0,0 +1,51 @@ +/* + * 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_IR_TRAIN_CHECKPOINT_H__ +#define __ONERT_IR_TRAIN_CHECKPOINT_H__ + +namespace onert +{ +namespace train +{ +namespace checkpoint +{ + +struct __attribute__((packed)) Header +{ + uint16_t magic; + uint8_t schema; + uint8_t reserved; + uint32_t opt1_offset; + uint32_t opt2_offset; + uint32_t other_offset; + uint32_t length; +}; + +struct __attribute__((packed)) Footer +{ + uint32_t cur_step; + uint32_t cur_epoch; +}; + +constexpr uint16_t MAGIC_NUMBER = 429; +constexpr uint8_t SCHEMA_VERSION = 1; + +} // namespace checkpoint +} // namespace train +} // namespace onert + +#endif // __ONERT_IR_TRAIN_CHECKPOINT_H__ From 5ba64666b2f139e24f22ad9b222a398de388a8c2 Mon Sep 17 00:00:00 2001 From: SaeHie Park Date: Tue, 20 Aug 2024 16:24:39 +0900 Subject: [PATCH 61/78] [tfldump] Revise to support Buffer offset (#13712) This will revise to support Buffer offset; - pass raw file data to retrieve data outside of flatbuffers area - get flag if Buffer is from outside of flatbuffers area - show with '*' for Buffers that are outside of flatbuffers area ONE-DCO-1.0-Signed-off-by: SaeHie Park --- compiler/tfldump/driver/Driver.cpp | 6 +++++- compiler/tfldump/include/tfldump/Dump.h | 13 ++++++++++--- compiler/tfldump/src/Dump.cpp | 18 +++++++++++------- 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/compiler/tfldump/driver/Driver.cpp b/compiler/tfldump/driver/Driver.cpp index a3e748be1d1..1fb5725a6de 100644 --- a/compiler/tfldump/driver/Driver.cpp +++ b/compiler/tfldump/driver/Driver.cpp @@ -49,7 +49,11 @@ int entry(int argc, char **argv) std::cout << "Dump: " << tflite_path << std::endl << std::endl; - std::cout << tflmodel << std::endl; + tfldump::ModelEx modelex; + modelex.model = tflmodel; + modelex.rawdata = &modelData; + + std::cout << modelex << std::endl; return 0; } diff --git a/compiler/tfldump/include/tfldump/Dump.h b/compiler/tfldump/include/tfldump/Dump.h index af04bb1327d..c352967887b 100644 --- a/compiler/tfldump/include/tfldump/Dump.h +++ b/compiler/tfldump/include/tfldump/Dump.h @@ -24,9 +24,16 @@ namespace tfldump { -void dump_model(std::ostream &os, const tflite::Model *model); -} +struct ModelEx +{ + const tflite::Model *model; + const std::vector *rawdata; +}; + +void dump_model(std::ostream &os, const ModelEx &model); + +} // namespace tfldump -std::ostream &operator<<(std::ostream &os, const tflite::Model *model); +std::ostream &operator<<(std::ostream &os, const tfldump::ModelEx &model); #endif // __TFLDUMP_DUMP_H__ diff --git a/compiler/tfldump/src/Dump.cpp b/compiler/tfldump/src/Dump.cpp index 7139f9ca46c..548f5878b83 100644 --- a/compiler/tfldump/src/Dump.cpp +++ b/compiler/tfldump/src/Dump.cpp @@ -340,9 +340,9 @@ void dump_sub_graph(std::ostream &os, tflread::Reader &reader) os << std::endl; } -void dump_model(std::ostream &os, const tflite::Model *model) +void dump_model(std::ostream &os, const tflite::Model *model, const std::vector *rawdata) { - tflread::Reader reader(model); + tflread::Reader reader(model, rawdata); uint32_t num_subgraph = reader.num_subgraph(); @@ -376,13 +376,17 @@ void dump_model(std::ostream &os, const tflite::Model *model) os << std::endl; // dump buffer - os << "Buffers: B(index) (length) values, if any" << std::endl; + os << "Buffers: B(index) (length) values, if any; (length *) for ext_offset" << std::endl; for (uint32_t i = 0; i < buffers->size(); ++i) { + bool ext_offset = false; const uint8_t *buff_data; - size_t size = reader.buffer_info(i, &buff_data); + size_t size = reader.buffer_info(i, &buff_data, ext_offset); - os << "B(" << i << ") (" << size << ") "; + os << "B(" << i << ") (" << size; + if (ext_offset) + os << " *"; + os << ") "; if (buff_data != nullptr) { dump_buffer(os, buff_data, size, 16); @@ -450,8 +454,8 @@ void dump_model(std::ostream &os, const tflite::Model *model) } // namespace tfldump -std::ostream &operator<<(std::ostream &os, const tflite::Model *model) +std::ostream &operator<<(std::ostream &os, const tfldump::ModelEx &modelex) { - tfldump::dump_model(os, model); + tfldump::dump_model(os, modelex.model, modelex.rawdata); return os; } From 0b14e6b9c21a7549756419e23856d5bd645c1996 Mon Sep 17 00:00:00 2001 From: SaeHie Park Date: Tue, 20 Aug 2024 17:29:31 +0900 Subject: [PATCH 62/78] [luci/export] Relocate optimize method with anonymous namespace (#13713) This will relocate optimize method with anonymous namespace into caller file. ONE-DCO-1.0-Signed-off-by: SaeHie Park --- .../luci/export/src/CircleExporterImpl.cpp | 29 ++++++++++- compiler/luci/export/src/Optimize.cpp | 48 ------------------- compiler/luci/export/src/Optimize.h | 33 ------------- 3 files changed, 28 insertions(+), 82 deletions(-) delete mode 100644 compiler/luci/export/src/Optimize.cpp delete mode 100644 compiler/luci/export/src/Optimize.h diff --git a/compiler/luci/export/src/CircleExporterImpl.cpp b/compiler/luci/export/src/CircleExporterImpl.cpp index 014ef45d71c..2a7384663ac 100644 --- a/compiler/luci/export/src/CircleExporterImpl.cpp +++ b/compiler/luci/export/src/CircleExporterImpl.cpp @@ -15,14 +15,18 @@ */ #include "CircleExporterImpl.h" -#include "Optimize.h" #include "CircleExportMetadata.h" #include "CircleTensorExporter.h" #include "CircleOperationExporter.h" #include "CircleExporterUtils.h" +#include "ProgressReporter.h" #include +#include +#include +#include +#include #include #include #include @@ -100,6 +104,29 @@ encodeOperatorCodes(FlatBufferBuilder &builder, std::unordered_map()); + phase.emplace_back(std::make_unique()); + + // TODO add more optimization passes (with a knob) + } + + logo::PhaseRunner phase_runner{g}; + + luci::ProgressReporter prog(g, logo::PhaseStrategy::Restart); + phase_runner.attach(&prog); + phase_runner.run(phase); +} + +} // namespace + namespace luci { diff --git a/compiler/luci/export/src/Optimize.cpp b/compiler/luci/export/src/Optimize.cpp deleted file mode 100644 index e59f15204a3..00000000000 --- a/compiler/luci/export/src/Optimize.cpp +++ /dev/null @@ -1,48 +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. - */ - -#include "Optimize.h" -#include "ProgressReporter.h" - -#include -#include - -#include - -#include - -namespace luci -{ - -void optimize(loco::Graph *g) -{ - logo::Phase phase; - { - // prepare type and shape before optimization - phase.emplace_back(std::make_unique()); - phase.emplace_back(std::make_unique()); - - // TODO add more optimization passes (with a knob) - } - - logo::PhaseRunner phase_runner{g}; - - ProgressReporter prog(g, logo::PhaseStrategy::Restart); - phase_runner.attach(&prog); - phase_runner.run(phase); -} - -} // namespace luci diff --git a/compiler/luci/export/src/Optimize.h b/compiler/luci/export/src/Optimize.h deleted file mode 100644 index c3af7a04cbc..00000000000 --- a/compiler/luci/export/src/Optimize.h +++ /dev/null @@ -1,33 +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 __OPTIMIZE_H__ -#define __OPTIMIZE_H__ - -#include - -namespace luci -{ - -/** - * @brief Run passes of graph transformations - * - */ -void optimize(loco::Graph *); - -} // namespace luci - -#endif // __OPTIMIZE_H__ From 3a7974fb5b9023cf07b78d84067b81c4368bea59 Mon Sep 17 00:00:00 2001 From: SaeHie Park Date: Tue, 20 Aug 2024 17:29:55 +0900 Subject: [PATCH 63/78] [luci/export] Fix typo of SerializedGraphData (#13714) This will fix typo of disabled CTOR of SerializedGraphData. ONE-DCO-1.0-Signed-off-by: SaeHie Park --- compiler/luci/export/src/SerializedData.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/luci/export/src/SerializedData.h b/compiler/luci/export/src/SerializedData.h index 136a8ac490e..044593691ba 100644 --- a/compiler/luci/export/src/SerializedData.h +++ b/compiler/luci/export/src/SerializedData.h @@ -139,7 +139,7 @@ struct SerializedModelData final struct SerializedGraphData final : public SubGraphContext { SerializedGraphData() = default; - SerializedGraphData(const SerializedModelData &) = delete; + SerializedGraphData(const SerializedGraphData &) = delete; std::vector> _operators; std::vector> _tensors; From 7c603264ab1c7c512e27de3b364416cd883e6289 Mon Sep 17 00:00:00 2001 From: Jan Iwaszkiewicz Date: Tue, 20 Aug 2024 11:45:22 +0200 Subject: [PATCH 64/78] [luci/pass] Introduce FuseMulWithFullyConnectedPass (#13607) * [luci/pass] Introduce FuseMulWithFullyConnectedPass This commit introduce FuseMulWithFullyConnectedPass which will fuse Mul to previous FullyConnected if possible. ONE-DCO-1.0-Signed-off-by: Jan Iwaszkiewicz * Change constness of args, move tests and move FuseMulWithFC after FuseMulWithDiv * Fix codestyle * Remove default arguments * Refactor solution and apply comments * Add handling of no bias case to pass * Apply comments, refactor tests and add proper handling of OUTPUTEXCLUDE * Handle rank 0 and 1 * Update names from scalar to single element * Update tests * Fix codestyle * Search from mul, update tests * Annotate requirement of one successor and refactor checks * Fix graph in explanation --- .../luci/pass/include/luci/CircleOptimizer.h | 1 + .../luci/Pass/FuseMulWithFullyConnectedPass.h | 37 +++ compiler/luci/pass/src/CircleOptimizer.cpp | 5 + .../src/FuseMulWithFullyConnectedPass.cpp | 242 ++++++++++++++ .../FuseMulWithFullyConnectedPass.test.cpp | 306 ++++++++++++++++++ 5 files changed, 591 insertions(+) create mode 100644 compiler/luci/pass/include/luci/Pass/FuseMulWithFullyConnectedPass.h create mode 100644 compiler/luci/pass/src/FuseMulWithFullyConnectedPass.cpp create mode 100644 compiler/luci/pass/src/FuseMulWithFullyConnectedPass.test.cpp diff --git a/compiler/luci/pass/include/luci/CircleOptimizer.h b/compiler/luci/pass/include/luci/CircleOptimizer.h index 9cbd26f0da5..8a1eb6d4f78 100644 --- a/compiler/luci/pass/include/luci/CircleOptimizer.h +++ b/compiler/luci/pass/include/luci/CircleOptimizer.h @@ -49,6 +49,7 @@ class CircleOptimizer final FuseMeanWithMean, FuseMulWithConv, FuseMulWithDiv, + FuseMulWithFullyConnected, FuseTransposeWithMean, ResolveCustomOpAdd, ResolveCustomOpBatchMatMul, diff --git a/compiler/luci/pass/include/luci/Pass/FuseMulWithFullyConnectedPass.h b/compiler/luci/pass/include/luci/Pass/FuseMulWithFullyConnectedPass.h new file mode 100644 index 00000000000..718039f1c69 --- /dev/null +++ b/compiler/luci/pass/include/luci/Pass/FuseMulWithFullyConnectedPass.h @@ -0,0 +1,37 @@ +/* + * 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 __LUCI_FUSE_MUL_WITH_FULLYCONNECTED_PASS_H__ +#define __LUCI_FUSE_MUL_WITH_FULLYCONNECTED_PASS_H__ + +#include + +namespace luci +{ + +/** + * @brief Class to fuse Mul into CircleFullyConnected + */ +struct FuseMulWithFullyConnectedPass final : public logo::Pass +{ + const char *name(void) const final { return "luci::FuseMulWithFullyConnectedPass"; } + + bool run(loco::Graph *g) final; +}; + +} // namespace luci + +#endif // __LUCI_FUSE_MUL_WITH_FULLYCONNECTED_PASS_H__ diff --git a/compiler/luci/pass/src/CircleOptimizer.cpp b/compiler/luci/pass/src/CircleOptimizer.cpp index 840c8dd25dd..246d4f36e78 100644 --- a/compiler/luci/pass/src/CircleOptimizer.cpp +++ b/compiler/luci/pass/src/CircleOptimizer.cpp @@ -48,6 +48,7 @@ #include "luci/Pass/FuseMeanWithMeanPass.h" #include "luci/Pass/FuseMulWithConvPass.h" #include "luci/Pass/FuseMulWithDivPass.h" +#include "luci/Pass/FuseMulWithFullyConnectedPass.h" #include "luci/Pass/FusePreActivationBatchNormPass.h" #include "luci/Pass/FusePReluPass.h" #include "luci/Pass/FuseGeluPass.h" @@ -310,6 +311,10 @@ void CircleOptimizer::optimize(loco::Graph *g) const { phase.emplace_back(std::make_unique()); } + if (_options->query(Options::Algorithm::FuseMulWithFullyConnected)) + { + phase.emplace_back(std::make_unique()); + } if (_options->query(Options::Algorithm::ResolveCustomOpMaxPoolWithArgmax)) { phase.emplace_back(std::make_unique()); diff --git a/compiler/luci/pass/src/FuseMulWithFullyConnectedPass.cpp b/compiler/luci/pass/src/FuseMulWithFullyConnectedPass.cpp new file mode 100644 index 00000000000..3049862e216 --- /dev/null +++ b/compiler/luci/pass/src/FuseMulWithFullyConnectedPass.cpp @@ -0,0 +1,242 @@ +/* + * 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 "luci/Pass/FuseMulWithFullyConnectedPass.h" + +#include "helpers/NodeFiller.h" + +#include +#include +#include + +namespace +{ + +#define RETURN_FALSE_UNLESS(cond) \ + if (not(cond)) \ + return false; + +inline bool is_single_element(const luci::CircleConst *node) +{ + return ((node->rank() == 1 || node->rank() == 0) && node->size() == 1); +} + +inline void update_with_single_element(luci::CircleConst *fused_node, + const luci::CircleConst *multiplication) +{ + for (uint32_t i = 0; i < fused_node->size(); i++) + { + fused_node->at(i) *= multiplication->at(0); + } +} + +luci::CircleConst *gen_fused_weights(luci::CircleConst *weights, + const luci::CircleConst *multiplication) +{ + auto fused_weights = luci::clone(weights); + // Single element multiplication: + if (is_single_element(multiplication)) + { + update_with_single_element(fused_weights, multiplication); + } + // N-size multiplication: + else + { + // Go along channels, multiplication size is ensured to be compatible with channels. + auto count = fused_weights->dim(0).value(); + auto size = fused_weights->dim(fused_weights->rank() - 1).value(); + float val; + for (uint32_t c = 0; c < count; c++) + { + val = multiplication->at(c); + for (uint32_t i = 0; i < size; i++) + { + fused_weights->at(c * size + i) *= val; + } + } + } + return fused_weights; +} + +luci::CircleConst *gen_fused_bias(luci::CircleConst *bias, const luci::CircleConst *multiplication) +{ + auto fused_bias = luci::clone(bias); + // Single element multiplication: + if (is_single_element(multiplication)) + { + update_with_single_element(fused_bias, multiplication); + } + // N-size multiplication: + else + { + // Go along channels, multiplication size is ensured to be compatible with channels. + for (uint32_t i = 0; i < fused_bias->size(); i++) + { + fused_bias->at(i) *= multiplication->at(i); + } + } + return fused_bias; +} + +/** + * Fuse Mul to FullyConnected if the multiplied value is a channel(last dimension)-wise constant + * + * BEFORE + * | + * [CircleFullyConnected] + * | + * [CircleMul] + * | + * + * AFTER + * | + * [CircleFullyConnected] [CircleMul] (dead) + * | + * + */ +bool fuse_mul_with_fc(luci::CircleMul *mul) +{ + // Sanity check: + RETURN_FALSE_UNLESS(mul); + // Allow Mul node only with FLOAT32 data type: + RETURN_FALSE_UNLESS(mul->dtype() == loco::DataType::FLOAT32); + // Check if any FC node connects to Mul. + // Find the pattern of Mul(FC, CircleConst): + luci::CircleFullyConnected *fc = nullptr; + luci::CircleConst *multiplication = nullptr; + RETURN_FALSE_UNLESS(luci::fill(&fc, &multiplication).with_commutative_args_of(mul)); + /** + * Make sure that FullyConnected has only one successor. + * + * If the FullyConnected output is connected to more nodes, + * this pass will replace node with new fused FullyConnected. + * Thus pass success will only introduce extra FullyConnected + * without reducing overall number of nodes. + * Which tends to increase model's size and degrades model's performance. + * Thus one successor is required to benefit from this pass. + * + * Example graph that illustrates the described scenario: + * + * BEFORE + * | + * [CircleFullyConnected] + * | + * +-------+----------------+ + * | | + * | | + * [Other Node] [CircleMul] + * | | + * + * AFTER + * | + * +-----------------------+ + * | | + * | | + * [CircleFullyConnected] | + * | | + * +-------+ | + * | | + * | | + * [Other Node] [New CircleFullyConnected Fused with Mul] + * | | + * + */ + RETURN_FALSE_UNLESS(loco::succs(fc).size() == 1); + // Allow only FLOAT32 data type: + RETURN_FALSE_UNLESS(fc->dtype() == loco::DataType::FLOAT32); + // Allow only without activation functions as values are going to + // be multiplied before activation function. + RETURN_FALSE_UNLESS(fc->fusedActivationFunction() == luci::FusedActFunc::NONE); + // Check for weights being Constant: + auto weights = dynamic_cast(fc->weights()); + RETURN_FALSE_UNLESS(weights); + // Get rank of multiplication: + auto rank = multiplication->rank(); + // Check that all dimensions are ones, checks broadcast capabilites. + // Last dimesion of multiplication must be compatible with FC. + // N-D case (N>1): + if (multiplication->rank() > 1) + { + // Check channel-wise broadcasting: + for (uint32_t i = 0; i < rank - 1; i++) + RETURN_FALSE_UNLESS(multiplication->dim(i).value() == 1); + // Check the last dimesion of Mul is the same with the first dimension of FullyConnected + RETURN_FALSE_UNLESS(multiplication->dim(rank - 1) == weights->dim(0)); + } + // 1-D or scalar case: + else if (multiplication->rank() == 1) + { + RETURN_FALSE_UNLESS(multiplication->size() == 1 || + multiplication->size() == weights->dim(0)); + } + else if (multiplication->rank() == 0) + { + RETURN_FALSE_UNLESS(multiplication->size() == 1); + } + + // Only supports: + // (1) constant bias + // (2) no bias + auto bias = loco::must_cast(fc->bias()); + if (bias->opcode() == luci::CircleOpcode::CIRCLECONST) + { + // Create new bias to be updated with values: + auto const_bias = dynamic_cast(fc->bias()); + RETURN_FALSE_UNLESS(const_bias) + RETURN_FALSE_UNLESS(const_bias->dtype() == loco::DataType::FLOAT32); + // Create new bias with updated values and replace: + auto fused_bias = gen_fused_bias(const_bias, multiplication); + fc->bias(fused_bias); + } + else if (bias->opcode() != luci::CircleOpcode::CIRCLEOUTPUTEXCLUDE) + { + return false; + } + + // Create new weights with updated values and replace: + auto fused_weights = gen_fused_weights(weights, multiplication); + fc->weights(fused_weights); + + // Set origin and copy Activation Function if exisitng: + fc->fusedActivationFunction(mul->fusedActivationFunction()); + luci::add_origin(fc, luci::get_origin(mul)); + + replace(mul).with(fc); + + return true; +} + +} // namespace + +namespace luci +{ + +bool FuseMulWithFullyConnectedPass::run(loco::Graph *g) +{ + bool changed = false; + for (auto node : loco::active_nodes(loco::output_nodes(g))) + { + if (auto mul = dynamic_cast(node)) + { + if (fuse_mul_with_fc(mul)) + changed = true; + } + } + + return changed; +} + +} // namespace luci diff --git a/compiler/luci/pass/src/FuseMulWithFullyConnectedPass.test.cpp b/compiler/luci/pass/src/FuseMulWithFullyConnectedPass.test.cpp new file mode 100644 index 00000000000..a4f9d6bf087 --- /dev/null +++ b/compiler/luci/pass/src/FuseMulWithFullyConnectedPass.test.cpp @@ -0,0 +1,306 @@ +/* + * 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 "luci/Pass/FuseMulWithFullyConnectedPass.h" +#include "helpers/CreateCircleConst.h" + +#include +#include + +#include + +#define DIM_ONE 8 +#define DIM_TWO 4 +#define MUL_VAL 2.0f + +namespace +{ + +using namespace luci::test; + +/** + * Graph for this test + * + * BEFORE (without extra_fc_successor) + * + * [FC] + * | + * [Mul w/ Relu] + * + * BEFORE (with extra_fc_successor) + * + * [FC] + * | + * |------------------- + * | | + * | | + * [Mul w/ Relu] [other FC] + * + * AFTER (if pass applied) + * + * [FC w/ Relu] (weights and bias updated) + * + */ +class FCMulGraphlet +{ +public: + void init(loco::Graph *g, luci::FusedActFunc fc_activation, bool is_mul_scalar, bool use_bias, + bool extra_successor) + { + _fc = g->nodes()->create(); + + std::vector weights_val(DIM_ONE * DIM_TWO); + for (uint32_t i = 0; i < DIM_ONE * DIM_TWO; i++) + weights_val.at(i) = i; + + _fc_f = luci::create_const_node(g, loco::DataType::FLOAT32, {DIM_ONE, DIM_TWO}, weights_val); + _fc->weights(_fc_f); + + if (use_bias) + { + std::vector bias_val(DIM_ONE); + for (uint32_t i = 0; i < DIM_ONE; i++) + bias_val.at(i) = i; + + _fc_b = luci::create_const_node(g, loco::DataType::FLOAT32, {DIM_ONE}, bias_val); + } + else + { + // Create CircleOutputExclude -- no bias + _fc_b = g->nodes()->create(); + } + _fc->bias(_fc_b); + + _fc->fusedActivationFunction(fc_activation); + _fc->dtype(loco::DataType::FLOAT32); + _fc->shape({1, DIM_ONE}); + _fc->name("fc"); + + if (extra_successor) + { + _extra_succ = g->nodes()->create(); + // Set previous FC as input to bump number of successors for it: + _extra_succ->input(_fc); + std::vector weights_val(DIM_ONE * DIM_TWO); + _extra_f = + luci::create_const_node(g, loco::DataType::FLOAT32, {DIM_ONE, DIM_TWO}, weights_val); + _extra_succ->weights(_extra_f); + _extra_succ->bias(nullptr); + _extra_succ->fusedActivationFunction(luci::FusedActFunc::NONE); + _extra_succ->dtype(loco::DataType::FLOAT32); + _extra_succ->shape({1, DIM_ONE}); + _extra_succ->name("extra_fc"); + } + + std::vector mul_values; + + if (is_mul_scalar) + { + mul_values.push_back(static_cast(MUL_VAL)); + _mul_c = luci::create_const_node(g, loco::DataType::FLOAT32, {}, mul_values); + } + else + { + for (uint32_t i = 0; i < DIM_ONE; i++) + { + mul_values.push_back(static_cast(i)); + } + _mul_c = luci::create_const_node(g, loco::DataType::FLOAT32, {1, 1, 1, DIM_ONE}, mul_values); + } + + _mul = g->nodes()->create(); + _mul->x(_fc); + _mul->y(_mul_c); + _mul->fusedActivationFunction(luci::FusedActFunc::RELU); + _mul->dtype(loco::DataType::FLOAT32); + if (is_mul_scalar) + { + _mul->shape({1, DIM_ONE}); + } + else + { + _mul->shape({1, 1, 1, DIM_ONE}); + } + _mul->name("mul"); + } + +public: + luci::CircleFullyConnected *fc() { return _fc; } + + void to_fm_bias(void) + { + assert(_fc != nullptr); + + auto new_fc = _fc->graph()->nodes()->create(); + _fc->bias(new_fc); + } + +protected: + luci::CircleFullyConnected *_fc = nullptr; + luci::CircleMul *_mul = nullptr; + luci::CircleConst *_fc_f = nullptr; + luci::CircleNode *_fc_b = nullptr; + luci::CircleConst *_mul_c = nullptr; + luci::CircleFullyConnected *_extra_succ = nullptr; + luci::CircleConst *_extra_f = nullptr; +}; + +class FuseMulWithFCTestGraph : public TestIOGraph, public FCMulGraphlet +{ +public: + void init(luci::FusedActFunc fc_activation, bool is_mul_scalar, bool use_bias, + bool extra_successor) + { + TestIOGraph::init({1, DIM_TWO}, {1, DIM_ONE}); + FCMulGraphlet::init(g(), fc_activation, is_mul_scalar, use_bias, extra_successor); + + _fc->input(input()); + + output()->from(_mul); + } +}; + +class FuseMulWithFullyConnectedPassTest : public ::testing::Test +{ +public: + FuseMulWithFCTestGraph g; + luci::FuseMulWithFullyConnectedPass pass; +}; + +} // namespace + +TEST_F(FuseMulWithFullyConnectedPassTest, fc_mul_tensor) +{ + g.init(luci::FusedActFunc::NONE, false /* is_mul_scalar */, true /* use_bias */, + false /* extra_successor */); + + EXPECT_EQ(true, pass.run(g.g())); + + auto fc = dynamic_cast(g.output()->from()); + EXPECT_NE(nullptr, fc); + + auto weights = loco::must_cast(g.fc()->weights()); + auto weights_n = weights->dim(0).value(); + auto weights_m = weights->dim(1).value(); + uint32_t offset = 0; + for (uint32_t i = 0; i < weights_n; i++) + { + for (uint32_t j = 0; j < weights_m; j++) + { + offset = i * weights_m + j; + EXPECT_EQ(i * offset, weights->at(offset)); + } + } + + auto bias = loco::must_cast(g.fc()->bias()); + for (uint32_t i = 0; i < bias->size(); i++) + { + EXPECT_EQ(i * i, bias->at(i)); + } +} + +TEST_F(FuseMulWithFullyConnectedPassTest, fc_mul_scalar) +{ + g.init(luci::FusedActFunc::NONE, true /* is_mul_scalar */, true /* use_bias */, + false /* extra_successor */); + + EXPECT_EQ(true, pass.run(g.g())); + + auto fc = dynamic_cast(g.output()->from()); + EXPECT_NE(nullptr, fc); + + auto weights = loco::must_cast(g.fc()->weights()); + auto weights_n = weights->dim(0).value(); + auto weights_m = weights->dim(1).value(); + uint32_t offset = 0; + for (uint32_t i = 0; i < weights_n; i++) + { + for (uint32_t j = 0; j < weights_m; j++) + { + offset = i * weights_m + j; + EXPECT_EQ(MUL_VAL * offset, weights->at(offset)); + } + } + + auto bias = loco::must_cast(g.fc()->bias()); + for (uint32_t i = 0; i < bias->size(); i++) + { + EXPECT_EQ(MUL_VAL * i, bias->at(i)); + } +} + +TEST_F(FuseMulWithFullyConnectedPassTest, fc_no_bias) +{ + g.init(luci::FusedActFunc::NONE, false /* is_mul_scalar */, false /* use_bias */, + false /* extra_successor */); + + EXPECT_EQ(true, pass.run(g.g())); + + auto fc = dynamic_cast(g.output()->from()); + EXPECT_NE(nullptr, fc); + auto no_bias = dynamic_cast(fc->bias()); + ASSERT_NE(nullptr, no_bias); + + auto weights = loco::must_cast(g.fc()->weights()); + auto weights_n = weights->dim(0).value(); + auto weights_m = weights->dim(1).value(); + uint32_t offset = 0; + for (uint32_t i = 0; i < weights_n; i++) + { + for (uint32_t j = 0; j < weights_m; j++) + { + offset = i * weights_m + j; + EXPECT_EQ(i * offset, weights->at(offset)); + } + } +} + +TEST_F(FuseMulWithFullyConnectedPassTest, bias_feature_map_NEG) +{ + g.init(luci::FusedActFunc::NONE, false /* is_mul_scalar */, true /* use_bias */, + false /* extra_successor */); + + // Bias cannot be fused as it's passed as feature map. + g.to_fm_bias(); + + EXPECT_EQ(false, pass.run(g.g())); +} + +TEST_F(FuseMulWithFullyConnectedPassTest, fc_with_activation_NEG) +{ + g.init(luci::FusedActFunc::RELU, false /* is_mul_scalar */, true /* use_bias */, + false /* extra_successor */); + + EXPECT_EQ(false, pass.run(g.g())); +} + +TEST_F(FuseMulWithFullyConnectedPassTest, fc_with_null_weights_NEG) +{ + g.init(luci::FusedActFunc::NONE, false /* is_mul_scalar */, true /* use_bias */, + false /* extra_successor */); + + g.fc()->weights(nullptr); + + EXPECT_EQ(false, pass.run(g.g())); +} + +TEST_F(FuseMulWithFullyConnectedPassTest, fc_with_extra_successor_NEG) +{ + g.init(luci::FusedActFunc::NONE, false /* is_mul_scalar */, true /* use_bias */, + true /* extra_successor */); + + EXPECT_EQ(false, pass.run(g.g())); +} From aa9ebd201e79dc0c6ea9f67b57f7830a03e32075 Mon Sep 17 00:00:00 2001 From: Jiyoung Giuliana Yun Date: Tue, 20 Aug 2024 19:34:04 +0900 Subject: [PATCH 65/78] [doc] Add ONERT Training document (#13704) This commit adds ONERT Training document. ONE-DCO-1.0-Signed-off-by: Jiyoung Yun --- docs/runtime/training.md | 59 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 docs/runtime/training.md diff --git a/docs/runtime/training.md b/docs/runtime/training.md new file mode 100644 index 00000000000..31ab2bdd410 --- /dev/null +++ b/docs/runtime/training.md @@ -0,0 +1,59 @@ +# Training + +## Overview + +ONERT supports model training. In particular, it supports training not only in the Host environment but also in the On-device environment and provides features for on-device training. Training is an important part of developing and improving models. While general learning in the Host environment involves training with a large amount of data using many resources, in the on-device environment there is limited space to store data, and the resources that can be used are also limited. Therefore, efficient learning using less data and small resources is required for on-devcie training. ONERT provides various features to meet these requirements. + +It supports on-device training based on existing trained models and supports transfer learning to learn new data added to the trained model. It also provides supervised fine-tuning to improve the accuracy of the trained model. This allows ONERT to support efficient learning with less data. + +In order to efficiently learn models with limited resources, ONERT not only uses less memory by reusing it memory space during training but also quickly improves accuracy of trained model by performing optimized kernel for each operation. + +Trained model can be saved to be deployed using ONERT API. This allows users to redeploy it to other environments or real applications to perform inference and retraining. + +## Training in ONERT + +### Training options + +ONERT supports the following options: + +- Loss function + - w/ loss reduction type +- Optimizer + - w/ learning rate +- Batch size +- Num of trainable operations + +### Training process + +Prerequisites: + +- Prepare a circle model to be trained. +- Prepare your dataset and preprocess it if necessary. + +Training process in ONERT consists of the following steps: + +1. Create a session. +2. Load a circle model. + - (optional) Load the checkpoint. (for fine-tuning) +3. Set training information. +4. Prepare training a model. +5. Set input and expected data. +6. Run training. + - (optional) Get loss and accuracy. + - (optional) Save the checkpoint. +7. Validate the model. +8. Export the trained model for inference. + +### Training tools + +- [onert_train](tests/tools/onert_train): A tool to train neural networks with ONERT. +- [generate_datafile](tools/generate_datafile): A tool to generate data files for ONERT training. +- [circle_plus_gen](tools/circle_plus_gen): A tool to generate Circle+ model from circle model. + +## Example + +### Training well-known models using ONERT + +### Advanced Topics + +- [Transfer Learning](docs/runtime/transfer_learning.md) From dec3d680708d45bf6ae75a61226b4fb0dfa96d75 Mon Sep 17 00:00:00 2001 From: Hyeongseok Oh Date: Tue, 20 Aug 2024 19:41:47 +0900 Subject: [PATCH 66/78] [onert] Remove PermuteFactor (#13716) This commit removes PermuteFactor class and usage. Layout between backends is always same. ONE-DCO-1.0-Signed-off-by: Hyeongseok Oh --- .../core/include/compiler/PermuteFactor.h | 130 ------------------ .../onert/core/src/compiler/PermuteFactor.cc | 28 ---- .../compiler/pass/ConstantInsertionPass.cc | 21 ++- .../src/compiler/pass/ConstantInsertionPass.h | 33 +---- .../src/compiler/pass/ConstantLoweringPass.cc | 7 +- .../compiler/pass/PermutationInsertionPass.h | 1 - 6 files changed, 17 insertions(+), 203 deletions(-) delete mode 100644 runtime/onert/core/include/compiler/PermuteFactor.h delete mode 100644 runtime/onert/core/src/compiler/PermuteFactor.cc diff --git a/runtime/onert/core/include/compiler/PermuteFactor.h b/runtime/onert/core/include/compiler/PermuteFactor.h deleted file mode 100644 index 67ce957bb08..00000000000 --- a/runtime/onert/core/include/compiler/PermuteFactor.h +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) 2019 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. - */ - -/** - * @file PermuteFactor.h - * @brief This file contains PermuteFactor class - * @ingroup COM_AI_RUNTIME - */ - -#ifndef __ONERT_COMPILER_OPERAND_PERMUTE_FACTOR_H__ -#define __ONERT_COMPILER_OPERAND_PERMUTE_FACTOR_H__ - -#include - -#include "ir/Layout.h" - -namespace onert -{ -namespace backend -{ -class Backend; -} // namespace backend -} // namespace onert - -namespace onert -{ -namespace compiler -{ - -/** - * @brief Class that has factors of permutation - */ -class PermuteFactor -{ -public: - /** - * @brief Construct PermuteFactor object. - * @param backend The backend factor - * @param layout The layout factor - */ - PermuteFactor(const backend::Backend *backend, ir::Layout layout) - : _backend{backend}, _layout{layout} - { - // DO NOTHING - } - /** - * @brief Construct PermuteFactor object by copy semantics. - */ - PermuteFactor(const PermuteFactor &f) : _backend{f._backend}, _layout{f._layout} - { - // DO NOTHING - } - /** - * @brief Construct PermuteFactor object by move semantics. - */ - PermuteFactor(PermuteFactor &&) = default; - -public: - /** - * @brief Get backend - * - * @return Backend factor - */ - const backend::Backend *backend() const { return _backend; } - /** - * @brief Get layout - * - * @return Layout factor - */ - ir::Layout layout() const { return _layout; } - -public: - /** - * @brief operator overloading function for `==` - * - * @return Whether two PermuteFactor are the same - */ - bool operator==(const PermuteFactor &other) const - { - return _backend == other.backend() && _layout == other.layout(); - } - /** - * @brief operator overloading function for `!=` - * - * @return Whether two PermuteFactor are differenct - */ - bool operator!=(const PermuteFactor &other) const { return !(*this == other); } - -private: - const backend::Backend *_backend{nullptr}; - ir::Layout _layout{ir::Layout::UNKNOWN}; -}; - -} // namespace compiler -} // namespace onert - -namespace std -{ - -/** - * @brief Structure that provides hash value of PermuteFactor - */ -template <> struct hash -{ - size_t operator()(const onert::compiler::PermuteFactor &factor) const noexcept - { - hash b_hash{}; - hash l_hash{}; - return b_hash(factor.backend()) ^ (l_hash(factor.layout()) << 1); - } -}; - -} // namespace std - -std::ostream &operator<<(std::ostream &os, const onert::compiler::PermuteFactor &obj); - -#endif // __ONERT_COMPILER_OPERAND_PERMUTE_FACTOR_H__ diff --git a/runtime/onert/core/src/compiler/PermuteFactor.cc b/runtime/onert/core/src/compiler/PermuteFactor.cc deleted file mode 100644 index f0081a2a46f..00000000000 --- a/runtime/onert/core/src/compiler/PermuteFactor.cc +++ /dev/null @@ -1,28 +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. - */ - -#include "compiler/PermuteFactor.h" - -#include -#include - -#include "backend/Backend.h" - -std::ostream &operator<<(std::ostream &os, const onert::compiler::PermuteFactor &obj) -{ - assert(obj.backend() && obj.backend()->config()); - return os << "(" << obj.backend()->config()->id() << "/" << to_string(obj.layout()) << ")"; -} diff --git a/runtime/onert/core/src/compiler/pass/ConstantInsertionPass.cc b/runtime/onert/core/src/compiler/pass/ConstantInsertionPass.cc index e2224eaf3fc..b9fa3d79aca 100644 --- a/runtime/onert/core/src/compiler/pass/ConstantInsertionPass.cc +++ b/runtime/onert/core/src/compiler/pass/ConstantInsertionPass.cc @@ -16,7 +16,6 @@ #include "ConstantInsertionPass.h" -#include "backend/Backend.h" #include "ir/Graph.h" #include "util/Utils.h" #include "util/logging.h" @@ -31,7 +30,6 @@ namespace pass void ConstantInsertionPass::callback(const ir::OperationIndex &node_index, ir::IOperation &node) { const auto backend = _lowered_graph.lower_info().operation.at(node_index); - const auto factor = PermuteFactor{backend, ir::Layout::NHWC}; for (const auto &input : node.getInputs() | ir::Remove::DUPLICATED | ir::Remove::UNDEFINED) { @@ -42,34 +40,33 @@ void ConstantInsertionPass::callback(const ir::OperationIndex &node_index, ir::I continue; // 1st use of shared constant operand. Keep using original operand without insertion of new one - // Register original operand into keep_operand map for later reuse on same PermuteFactor + // Register original operand into keep_operand map for later reuse on same backend if (_keep_operands_map.find(input) == _keep_operands_map.end()) { - _keep_operands_map.emplace(input, factor); + _keep_operands_map.emplace(input, backend); continue; } // Same PermuteFactor with original operand usage. Keep using original operand - if (_keep_operands_map.at(input) == factor) + if (_keep_operands_map.at(input) == backend) continue; - // Different PermuteFactor with original operand + // Different backend with original operand // Check operand is already created for current input's PermuteFactor // If not, create new operand and register to _replace_operands_map - const auto key = ReplaceKey{input, factor}; - if (_replace_operands_map.count(key) == 0) + if (_replace_operands_map.count(backend) == 0) { ir::Operand new_object(object); new_object.clearDefUse(); const auto new_index = _graph.operands().emplace(new_object); - _replace_operands_map[key] = new_index; + _replace_operands_map[backend] = new_index; } - const auto replaced_input = _replace_operands_map[key]; + const auto replaced_input = _replace_operands_map[backend]; // Update the same inputs of a node at once because inputs of an operation have the same - // PermuteFactor + // backend node.replaceInputs(input, replaced_input); // Update operand @@ -77,7 +74,7 @@ void ConstantInsertionPass::callback(const ir::OperationIndex &node_index, ir::I replaced_object.insertUse(node_index); VERBOSE(ConstInsertPass) << "New operand " << replaced_input << " added(copy of " << input - << ") for " << factor << std::endl; + << ") for " << backend->config()->id() << std::endl; // Remove this node from uses of origin operand // Constant operand has no def. assert(!object.getDef().valid()); diff --git a/runtime/onert/core/src/compiler/pass/ConstantInsertionPass.h b/runtime/onert/core/src/compiler/pass/ConstantInsertionPass.h index d816240c6c5..0606511e902 100644 --- a/runtime/onert/core/src/compiler/pass/ConstantInsertionPass.h +++ b/runtime/onert/core/src/compiler/pass/ConstantInsertionPass.h @@ -17,11 +17,11 @@ #ifndef __ONERT_COMPILER_PASS_CONSTANT_INSERTION_PASS_H__ #define __ONERT_COMPILER_PASS_CONSTANT_INSERTION_PASS_H__ -#include -#include #include "LoweredOperationPass.h" +#include "backend/Backend.h" +#include "ir/Index.h" + #include -#include namespace onert { @@ -42,31 +42,8 @@ class ConstantInsertionPass : public LoweredOperationPass void callback(const ir::OperationIndex &index, ir::IOperation &node) final; private: - struct ReplaceKey - { - ir::OperandIndex index; - PermuteFactor factor; - - bool operator==(const ReplaceKey &other) const - { - return index == other.index && factor == other.factor; - } - }; - - /** - * @brief Structure that provides hash function of ReplaceKey - */ - struct KeyHasher - { - std::size_t operator()(const ReplaceKey &key) const noexcept - { - using std::hash; - return hash()(key.index) ^ (hash()(key.factor) << 1); - } - }; - - std::unordered_map _replace_operands_map; - std::unordered_map _keep_operands_map; + std::unordered_map _replace_operands_map; + std::unordered_map _keep_operands_map; }; } // namespace pass diff --git a/runtime/onert/core/src/compiler/pass/ConstantLoweringPass.cc b/runtime/onert/core/src/compiler/pass/ConstantLoweringPass.cc index 86bacf15a24..108e607ac1b 100644 --- a/runtime/onert/core/src/compiler/pass/ConstantLoweringPass.cc +++ b/runtime/onert/core/src/compiler/pass/ConstantLoweringPass.cc @@ -17,10 +17,9 @@ #include "ConstantLoweringPass.h" #include "backend/Backend.h" -#include -#include -#include +#include "ir/Graph.h" #include "util/logging.h" +#include "util/Utils.h" namespace onert { @@ -40,7 +39,7 @@ void ConstantLoweringPass::callback(const ir::OperationIndex &node_index, ir::IO if (object.isConstant()) { // All constant operand are already assinged at each backend by ContantInsertionPass. So a - // constant has `def` and `use` as the same PermuteFactor + // constant has `def` and `use` as the same backend auto operand_li = std::make_unique(); operand_li->addDefBackend(backend); operand_li->addUseBackend(backend); diff --git a/runtime/onert/core/src/compiler/pass/PermutationInsertionPass.h b/runtime/onert/core/src/compiler/pass/PermutationInsertionPass.h index 250cfb4480d..ed3515b07a3 100644 --- a/runtime/onert/core/src/compiler/pass/PermutationInsertionPass.h +++ b/runtime/onert/core/src/compiler/pass/PermutationInsertionPass.h @@ -20,7 +20,6 @@ #include "LoweredOperandPass.h" #include "compiler/BackendManager.h" #include "ir/Operand.h" -#include "compiler/PermuteFactor.h" namespace onert { From 34257bfe11c57c51ef0a1c9c5fe98712a4d100a8 Mon Sep 17 00:00:00 2001 From: Jiyoung Giuliana Yun Date: Wed, 21 Aug 2024 10:07:29 +0900 Subject: [PATCH 67/78] [onert] Add ir namespace to checkpoint header file (#13722) This commit adds the missing ir namespace to checkpoint header file. ONE-DCO-1.0-Signed-off-by: Jiyoung Yun --- runtime/onert/core/include/ir/train/Checkpoint.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/runtime/onert/core/include/ir/train/Checkpoint.h b/runtime/onert/core/include/ir/train/Checkpoint.h index d62f9d69b5e..8edc8a0aad5 100644 --- a/runtime/onert/core/include/ir/train/Checkpoint.h +++ b/runtime/onert/core/include/ir/train/Checkpoint.h @@ -19,6 +19,8 @@ namespace onert { +namespace ir +{ namespace train { namespace checkpoint @@ -46,6 +48,7 @@ constexpr uint8_t SCHEMA_VERSION = 1; } // namespace checkpoint } // namespace train +} // namespace ir } // namespace onert #endif // __ONERT_IR_TRAIN_CHECKPOINT_H__ From 41ea171543c9dcf5acfcb2e7b55e0cc64eaa9ec4 Mon Sep 17 00:00:00 2001 From: SaeHie Park Date: Wed, 21 Aug 2024 10:52:39 +0900 Subject: [PATCH 68/78] [luci/export] Tidy export with graph (#13727) This will tidy export with graph as this is not used anymore. ONE-DCO-1.0-Signed-off-by: SaeHie Park --- .../luci/export/include/luci/CircleExporter.h | 7 +-- .../include/luci/CircleFileExpContract.h | 1 - compiler/luci/export/src/CircleExporter.cpp | 16 +----- .../luci/export/src/CircleExporter.test.cpp | 19 ++++--- .../luci/export/src/CircleExporterImpl.cpp | 56 ------------------- compiler/luci/export/src/CircleExporterImpl.h | 7 --- compiler/luci/tester/src/WriteTester.cpp | 8 --- 7 files changed, 15 insertions(+), 99 deletions(-) diff --git a/compiler/luci/export/include/luci/CircleExporter.h b/compiler/luci/export/include/luci/CircleExporter.h index 0584c623cfa..de064ea8444 100644 --- a/compiler/luci/export/include/luci/CircleExporter.h +++ b/compiler/luci/export/include/luci/CircleExporter.h @@ -36,14 +36,9 @@ class CircleExporter virtual ~Contract() = default; public: // Client -> Exporter - // Input Graph (to be exported) - // Exporter expects a loco graph that consists of Circle nodes - virtual loco::Graph *graph(void) const = 0; - // Input Module (to be exported) // Exporter expects a luci module that consists of loco graphs - // TODO make this pure virtual - virtual luci::Module *module(void) const; + virtual luci::Module *module(void) const = 0; public: // Exporter -> Client // Exporter calls store for export data diff --git a/compiler/luci/export/include/luci/CircleFileExpContract.h b/compiler/luci/export/include/luci/CircleFileExpContract.h index 8ef1b5e0cf6..a06ebe9963e 100644 --- a/compiler/luci/export/include/luci/CircleFileExpContract.h +++ b/compiler/luci/export/include/luci/CircleFileExpContract.h @@ -40,7 +40,6 @@ struct CircleFileExpContract : public luci::CircleExporter::Contract virtual ~CircleFileExpContract() = default; public: - loco::Graph *graph(void) const final { return nullptr; } luci::Module *module(void) const final { return _module; } public: diff --git a/compiler/luci/export/src/CircleExporter.cpp b/compiler/luci/export/src/CircleExporter.cpp index 125df780212..6f5066823c2 100644 --- a/compiler/luci/export/src/CircleExporter.cpp +++ b/compiler/luci/export/src/CircleExporter.cpp @@ -26,9 +26,6 @@ namespace luci { -// TODO remove this -Module *CircleExporter::Contract::module(void) const { return nullptr; } - CircleExporter::CircleExporter() { // NOTHING TO DO @@ -48,17 +45,10 @@ bool CircleExporter::invoke(Contract *contract) const return contract->store(ptr, size); } - auto graph = contract->graph(); - if (graph == nullptr) - return false; - - CircleExporterImpl impl(graph); - - const char *ptr = impl.getBufferPointer(); - const size_t size = impl.getBufferSize(); + // NOTE some unit tests calls with nullptr module, cannot add assert here + // TODO fix those unit tests and add assert(false) - // we just send one time - return contract->store(ptr, size); + return false; } } // namespace luci diff --git a/compiler/luci/export/src/CircleExporter.test.cpp b/compiler/luci/export/src/CircleExporter.test.cpp index 5898f9d653e..c76d983972d 100644 --- a/compiler/luci/export/src/CircleExporter.test.cpp +++ b/compiler/luci/export/src/CircleExporter.test.cpp @@ -33,12 +33,12 @@ class SampleGraphContract : public luci::CircleExporter::Contract SampleGraphContract() : luci::CircleExporter::Contract(), _buffer(new std::vector) { // create needed entities - _g = loco::make_graph(); - auto graph_input = _g->inputs()->create(); - auto graph_output = _g->outputs()->create(); - input_node = _g->nodes()->create(); - output_node = _g->nodes()->create(); - relu_node = _g->nodes()->create(); + auto g = loco::make_graph(); + auto graph_input = g->inputs()->create(); + auto graph_output = g->outputs()->create(); + input_node = g->nodes()->create(); + output_node = g->nodes()->create(); + relu_node = g->nodes()->create(); // link nodes and link them to graph relu_node->features(input_node); @@ -57,9 +57,12 @@ class SampleGraphContract : public luci::CircleExporter::Contract graph_output->shape({1, 2, 3, 4}); graph_output->dtype(loco::DataType::FLOAT32); + + _m = std::unique_ptr{new luci::Module}; + _m->add(std::move(g)); } - loco::Graph *graph(void) const override { return _g.get(); } + luci::Module *module(void) const override { return _m.get(); } public: bool store(const char *ptr, const size_t size) const override @@ -77,7 +80,7 @@ class SampleGraphContract : public luci::CircleExporter::Contract luci::CircleRelu *relu_node; private: - std::unique_ptr _g; + std::unique_ptr _m; std::unique_ptr> _buffer; }; diff --git a/compiler/luci/export/src/CircleExporterImpl.cpp b/compiler/luci/export/src/CircleExporterImpl.cpp index 2a7384663ac..c8f2aa06529 100644 --- a/compiler/luci/export/src/CircleExporterImpl.cpp +++ b/compiler/luci/export/src/CircleExporterImpl.cpp @@ -133,7 +133,6 @@ namespace luci using namespace circle; using namespace flatbuffers; -CircleExporterImpl::CircleExporterImpl(loco::Graph *graph) { exportGraph(graph); } CircleExporterImpl::CircleExporterImpl(Module *module) { exportModule(module); } ::flatbuffers::Offset<::circle::SubGraph> @@ -148,61 +147,6 @@ CircleExporterImpl::exportSubgraph(SerializedGraphData &gd) return subgraph; } -void CircleExporterImpl::exportGraph(loco::Graph *graph) -{ - // do graph optimization - optimize(graph); - - _builder.Clear(); - - SerializedModelData md; - SerializedGraphData gd; - - // This version is taken from comment in fbs - constexpr uint32_t version = 0; - - // set Subgraph name - gd._name = graph->name(); - - // TODO set this value properly - gd._data_format = circle::DataFormat::DataFormat_CHANNELS_LAST; - - // prepare model data - prepareModelData(_builder, md); - - // parse graph into SerializedModelData structure - exportOpDefinedTensors(graph, _builder, md, gd); - - // NOTE Invoke these register functions only after each node is annotated with its tensor_index - registerGraphInputTensors(graph, gd); - registerGraphOutputTensors(graph, gd); - - exportNodes(graph, _builder, md, gd); - - // encode operator codes - auto operator_codes = encodeOperatorCodes(_builder, md._operator_codes); - - // Subgraphs - Offset subgraph = exportSubgraph(gd); - auto subgraphs = _builder.CreateVector(std::vector>{subgraph}); - - // Description - std::string description_str = "nnpackage"; - auto description = _builder.CreateString(description_str); - - // Metadata - auto metadata_vec = createCircleMetadataVector(_builder, md); - auto metadata = _builder.CreateVector(std::vector>(metadata_vec)); - - // create array of buffers - auto buffers = _builder.CreateVector(md._buffers); - - // Model - auto model_offset = CreateModel(_builder, version, operator_codes, subgraphs, description, - buffers, 0 /* metadata_buffer */, metadata); - FinishModelBuffer(_builder, model_offset); -} - void CircleExporterImpl::exportModule(Module *module) { assert(module->size() > 0); diff --git a/compiler/luci/export/src/CircleExporterImpl.h b/compiler/luci/export/src/CircleExporterImpl.h index 069f62afd4a..5911fadba43 100644 --- a/compiler/luci/export/src/CircleExporterImpl.h +++ b/compiler/luci/export/src/CircleExporterImpl.h @@ -38,7 +38,6 @@ class CircleExporterImpl CircleExporterImpl() = delete; ~CircleExporterImpl() = default; - explicit CircleExporterImpl(loco::Graph *graph); explicit CircleExporterImpl(Module *module); /** @@ -59,12 +58,6 @@ class CircleExporterImpl */ flatbuffers::Offset exportSubgraph(SerializedGraphData &gd); - /** - * @brief root function that writes graph into internal buffer - * @param graph - */ - void exportGraph(loco::Graph *graph); - /** * @brief root function that writes Module into internal buffer * @param module diff --git a/compiler/luci/tester/src/WriteTester.cpp b/compiler/luci/tester/src/WriteTester.cpp index 0d3a1efa220..e5b31e16dc6 100644 --- a/compiler/luci/tester/src/WriteTester.cpp +++ b/compiler/luci/tester/src/WriteTester.cpp @@ -42,11 +42,6 @@ void show_error_message(const char *progname, std::ostream &os, const std::strin struct CircleExpContract : public luci::CircleExporter::Contract { public: - CircleExpContract(loco::Graph *graph, const std::string &filename) - : _graph(graph), _filepath(filename) - { - // NOTHING TO DO - } CircleExpContract(luci::Module *module, const std::string &filename) : _module(module), _filepath(filename) { @@ -55,15 +50,12 @@ struct CircleExpContract : public luci::CircleExporter::Contract virtual ~CircleExpContract() = default; public: - loco::Graph *graph(void) const final { return _graph; } - luci::Module *module(void) const final { return _module; } public: bool store(const char *ptr, const size_t size) const final; private: - loco::Graph *_graph{nullptr}; luci::Module *_module{nullptr}; const std::string _filepath; }; From 93f0960ac54e65c19fcff13885af83c2bd04f357 Mon Sep 17 00:00:00 2001 From: SaeHie Park Date: Wed, 21 Aug 2024 10:53:17 +0900 Subject: [PATCH 69/78] [luci/export] Revise file description (#13729) This will revise file description to "ONE-luci/export". ONE-DCO-1.0-Signed-off-by: SaeHie Park --- compiler/luci/export/src/CircleExporterImpl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/luci/export/src/CircleExporterImpl.cpp b/compiler/luci/export/src/CircleExporterImpl.cpp index c8f2aa06529..00e7ace2c99 100644 --- a/compiler/luci/export/src/CircleExporterImpl.cpp +++ b/compiler/luci/export/src/CircleExporterImpl.cpp @@ -192,7 +192,7 @@ void CircleExporterImpl::exportModule(Module *module) auto operator_codes = encodeOperatorCodes(_builder, md._operator_codes); // Description - std::string description_str = "nnpackage"; + std::string description_str = "ONE-luci/export"; auto description = _builder.CreateString(description_str); // Metadata From 2158eb77a41d4b78ec23038b3ef7cb1045b7e993 Mon Sep 17 00:00:00 2001 From: chunseoklee Date: Wed, 21 Aug 2024 11:14:45 +0900 Subject: [PATCH 70/78] [onert-micro] S8 Test for Less (#13715) - S8 test for Less added - Fix wrong accumulator type DCO-1.0-Signed-off-by: Chunseok Lee --- .../execute/kernels/ComparisonCommon.h | 4 +- .../include/pal/common/PALComparisons.h | 8 +- .../include/test_models/less/S8LessKernel.h | 192 ++++++++++++++++++ .../onert-micro/src/execute/kernels/Less.cpp | 7 +- .../src/execute/kernels/tests/Less.test.cpp | 21 ++ 5 files changed, 225 insertions(+), 7 deletions(-) create mode 100644 onert-micro/onert-micro/include/test_models/less/S8LessKernel.h diff --git a/onert-micro/onert-micro/include/execute/kernels/ComparisonCommon.h b/onert-micro/onert-micro/include/execute/kernels/ComparisonCommon.h index 5aea894d47f..fc08257f156 100644 --- a/onert-micro/onert-micro/include/execute/kernels/ComparisonCommon.h +++ b/onert-micro/onert-micro/include/execute/kernels/ComparisonCommon.h @@ -110,8 +110,8 @@ template void evalComparisonGeneric(OMRuntimeKernel *runtime_kernel } } -template -void evalQuantizedComparisonGeneric(OMRuntimeKernel *runtime_kernel, bool F(T, T)) +template +void evalQuantizedComparisonGeneric(OMRuntimeKernel *runtime_kernel, bool F(AccType, AccType)) { const circle::Tensor *input1 = nullptr; const circle::Tensor *input2 = nullptr; diff --git a/onert-micro/onert-micro/include/pal/common/PALComparisons.h b/onert-micro/onert-micro/include/pal/common/PALComparisons.h index 0f37d2f19c8..0770196ff32 100644 --- a/onert-micro/onert-micro/include/pal/common/PALComparisons.h +++ b/onert-micro/onert-micro/include/pal/common/PALComparisons.h @@ -71,11 +71,11 @@ inline void ComparisonNoScaling(const int64_t flat_size, const T *input1_data, c } } -template +template inline void BroadcastComparison4DSlowWithScaling( const core::ComparisonParams &op_params, const core::OMRuntimeShape &unextended_input1_shape, const T *input1_data, const core::OMRuntimeShape &unextended_input2_shape, const T *input2_data, - const core::OMRuntimeShape &unextended_output_shape, bool *output_data, bool F(T, T)) + const core::OMRuntimeShape &unextended_output_shape, bool *output_data, bool F(AccType, AccType)) { const BroadcastComparison4DSlowCommon dims = BroadcastComparison4DSlowPreprocess( unextended_input1_shape, unextended_input2_shape, unextended_output_shape); @@ -118,10 +118,10 @@ inline void BroadcastComparison4DSlowWithScaling( } } -template +template inline void ComparisonWithScaling(const core::ComparisonParams &op_params, const int64_t flat_size, const T *input1_data, const T *input2_data, bool *output_data, - bool F(T, T)) + bool F(AccType, AccType)) { int left_shift = op_params.left_shift; int32_t input1_offset = op_params.input1_offset; diff --git a/onert-micro/onert-micro/include/test_models/less/S8LessKernel.h b/onert-micro/onert-micro/include/test_models/less/S8LessKernel.h new file mode 100644 index 00000000000..f2762487cd9 --- /dev/null +++ b/onert-micro/onert-micro/include/test_models/less/S8LessKernel.h @@ -0,0 +1,192 @@ +/* + * 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_LESS_KERNEL_S8_H +#define ONERT_MICRO_TEST_MODELS_LESS_KERNEL_S8_H + +#include "TestDataLessBase.h" + +namespace onert_micro +{ +namespace test_model +{ +namespace less_s8_with_no_broadcasting +{ + +/* + * Less Kernel: + * + * Input_1(1, 1, 4, 3) Input_2(1, 1, 4, 3) + * scale: 0.0078431373 scale: 0.008431373 + * \ / + * Less(no broadcast) + * | + * Output(1, 1, 4, 3) + */ + +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, 0x30, 0x00, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x2c, + 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 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, + 0x60, 0x00, 0x00, 0x00, 0x64, 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, 0x29, 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, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0xcc, 0x00, 0x00, 0x00, 0x44, 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, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0c, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x6f, 0x66, 0x6d, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x8a, 0xff, 0xff, + 0xff, 0x14, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x09, 0x4c, 0x00, 0x00, 0x00, 0x7c, 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, 0xbe, 0x23, 0x0a, 0x3c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x42, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x04, 0x00, 0x00, 0x00, 0x69, 0x66, 0x6d, 0x32, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x03, 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, 0x54, 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, 0x2c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x81, 0x80, 0x00, 0x3c, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfe, 0x42, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x04, 0x00, 0x00, 0x00, + 0x69, 0x66, 0x6d, 0x31, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x01, 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, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, + 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 input1_data = {36, 4, 49, 84, 22, 40, 74, 97, 25, 26, 69, 37}; + +const std::vector input2_data = {66, 62, 58, 89, 2, 29, 37, 88, 64, 83, 73, 33}; + +const std::vector reference_output_data = {true, true, true, true, false, false, + false, false, true, true, true, false}; + +} // namespace less_s8_with_no_broadcasting + +namespace neg_less_s8_with_no_broadcasting +{ + +/* + * Less Kernel with input type mismatch: + * + * Input_1(1, 2, 2, 3) INT8 Input_2(1, 2, 2, 3) UINT8 + * \ / + * Less(no broadcast) + * | + * Output(1, 2, 2, 3) + */ + +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, 0x30, 0x00, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x2c, 0x02, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 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, 0x60, 0x00, 0x00, 0x00, 0x64, 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, 0x29, + 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, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0xcc, 0x00, 0x00, 0x00, 0x44, 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, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x6f, 0x66, 0x6d, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x8a, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x4c, 0x00, 0x00, 0x00, + 0x7c, 0xff, 0xff, 0xff, 0x30, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xbe, 0x23, 0x0a, 0x3c, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x43, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x69, 0x66, 0x6d, 0x32, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 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, 0x54, 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, 0x2c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x81, 0x80, 0x00, 0x3c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x42, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x04, 0x00, 0x00, 0x00, 0x69, 0x66, 0x6d, 0x31, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 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, + 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 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 input1_data = {36, 4, 49, 84, 22, 40, 74, 97, 25, 26, 69, 37}; + +const std::vector input2_data = {66, 62, 58, 89, 2, 29, 37, 88, 64, 83, 73, 33}; + +const std::vector reference_output_data = {true, true, true, true, false, false, + false, false, true, true, true, false}; + +} // namespace neg_less_s8_with_no_broadcasting + +class TestDataS8Less : public TestDataLessBase +{ +public: + explicit TestDataS8Less(bool is_with_broadcast, bool is_neg) + : TestDataLessBase(is_with_broadcast) + { + if (is_with_broadcast) + { + assert(false && "Not impl yet"); + } + else + { + if (is_neg) + { + _input1_data = neg_less_s8_with_no_broadcasting::input1_data; + _input2_data = neg_less_s8_with_no_broadcasting::input2_data; + _reference_output_data = neg_less_s8_with_no_broadcasting::reference_output_data; + _test_kernel_model_circle = neg_less_s8_with_no_broadcasting::test_kernel_model_circle; + } + else + { + _input1_data = less_s8_with_no_broadcasting::input1_data; + _input2_data = less_s8_with_no_broadcasting::input2_data; + _reference_output_data = less_s8_with_no_broadcasting::reference_output_data; + _test_kernel_model_circle = less_s8_with_no_broadcasting::test_kernel_model_circle; + } + } + } + + ~TestDataS8Less() override = default; +}; + +} // namespace test_model +} // namespace onert_micro + +#endif // ONERT_MICRO_TEST_MODELS_LESS_KERNEL_QUANT_H diff --git a/onert-micro/onert-micro/src/execute/kernels/Less.cpp b/onert-micro/onert-micro/src/execute/kernels/Less.cpp index 6d27f66abd3..b815849cf6f 100644 --- a/onert-micro/onert-micro/src/execute/kernels/Less.cpp +++ b/onert-micro/onert-micro/src/execute/kernels/Less.cpp @@ -73,7 +73,12 @@ OMStatus onert_micro::execute::execute_kernel_CircleLess(const OMExecuteArgs &ex break; #ifndef DIS_QUANT case circle::TensorType_UINT8: - evalQuantizedComparisonGeneric(&runtime_kernel, onert_micro::execute::pal::LessFn); + evalQuantizedComparisonGeneric(&runtime_kernel, + onert_micro::execute::pal::LessFn); + break; + case circle::TensorType_INT8: + evalQuantizedComparisonGeneric(&runtime_kernel, + onert_micro::execute::pal::LessFn); break; #endif // DIS_QUANT diff --git a/onert-micro/onert-micro/src/execute/kernels/tests/Less.test.cpp b/onert-micro/onert-micro/src/execute/kernels/tests/Less.test.cpp index f7b8b8f08bb..61aa5419c8d 100644 --- a/onert-micro/onert-micro/src/execute/kernels/tests/Less.test.cpp +++ b/onert-micro/onert-micro/src/execute/kernels/tests/Less.test.cpp @@ -19,6 +19,7 @@ #include "test_models/less/FloatLessKernel.h" #include "test_models/less/IntLessKernel.h" #include "test_models/less/QuantLessKernel.h" +#include "test_models/less/S8LessKernel.h" #include "test_models/less/NegTestDataLessKernel.h" namespace onert_micro @@ -124,6 +125,26 @@ TEST_F(LessTest, Quant_P) EXPECT_THAT(output_data_vector, test_data_kernel.get_output_data_by_index(0)); } +TEST_F(LessTest, S8_P) +{ + const bool is_with_broadcast = false; + onert_micro::test_model::TestDataS8Less test_data_kernel(is_with_broadcast, false); + + std::vector output_data_vector = + onert_micro::execute::testing::checkKernel(2, &test_data_kernel); + + EXPECT_THAT(output_data_vector, test_data_kernel.get_output_data_by_index(0)); +} + +TEST_F(LessTest, S8_NEG) +{ + const bool is_with_broadcast = false; + onert_micro::test_model::TestDataS8Less test_data_kernel(is_with_broadcast, true); + + EXPECT_DEATH((onert_micro::execute::testing::checkKernel(2, &test_data_kernel)), + ""); +} + TEST_F(LessTest, Quant_NEG) { const bool is_with_broadcast = false; From 01c23cbbf35fb63bdc84dc3f288ddff4356d63d0 Mon Sep 17 00:00:00 2001 From: SaeHie Park Date: Wed, 21 Aug 2024 11:31:51 +0900 Subject: [PATCH 71/78] [circledump] Resive to support Buffer offsset (#13728) This will revise to support Buffer offset for file size > 2G. ONE-DCO-1.0-Signed-off-by: SaeHie Park --- compiler/circledump/driver/Driver.cpp | 6 +++++- compiler/circledump/include/circledump/Dump.h | 10 ++++++++-- compiler/circledump/src/Dump.cpp | 18 +++++++++++------- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/compiler/circledump/driver/Driver.cpp b/compiler/circledump/driver/Driver.cpp index 5b0871a91ae..f5fd9f8268a 100644 --- a/compiler/circledump/driver/Driver.cpp +++ b/compiler/circledump/driver/Driver.cpp @@ -50,7 +50,11 @@ int entry(int argc, char **argv) std::cout << "Dump: " << circle_path << std::endl << std::endl; - std::cout << circlemodel << std::endl; + circledump::ModelEx modelex; + modelex.model = circlemodel; + modelex.rawdata = &modelData; + + std::cout << modelex << std::endl; return 0; } diff --git a/compiler/circledump/include/circledump/Dump.h b/compiler/circledump/include/circledump/Dump.h index 594209a5def..2d25a6178c6 100644 --- a/compiler/circledump/include/circledump/Dump.h +++ b/compiler/circledump/include/circledump/Dump.h @@ -24,10 +24,16 @@ namespace circledump { -void dump_model(std::ostream &os, const circle::Model *model); +struct ModelEx +{ + const circle::Model *model; + const std::vector *rawdata; +}; + +void dump_model(std::ostream &os, const circledump::ModelEx &model); } // namespace circledump -std::ostream &operator<<(std::ostream &os, const circle::Model *model); +std::ostream &operator<<(std::ostream &os, const circledump::ModelEx &model); #endif // __CIRCLEDUMP_DUMP_H__ diff --git a/compiler/circledump/src/Dump.cpp b/compiler/circledump/src/Dump.cpp index 166931648f8..999799f9bfa 100644 --- a/compiler/circledump/src/Dump.cpp +++ b/compiler/circledump/src/Dump.cpp @@ -341,9 +341,9 @@ void dump_sub_graph(std::ostream &os, mio::circle::Reader &reader) os << std::endl; } -void dump_model(std::ostream &os, const circle::Model *model) +void dump_model(std::ostream &os, const circle::Model *model, const std::vector *rawdata) { - mio::circle::Reader reader(model); + mio::circle::Reader reader(model, rawdata); uint32_t num_subgraph = reader.num_subgraph(); @@ -378,13 +378,17 @@ void dump_model(std::ostream &os, const circle::Model *model) os << std::endl; // dump buffer - os << "Buffers: B(index) (length) values, if any" << std::endl; + os << "Buffers: B(index) (length) values, if any; (length *) for ext_offset" << std::endl; for (uint32_t i = 0; i < buffers->size(); ++i) { + bool ext_offset = false; const uint8_t *buff_data; - size_t size = reader.buffer_info(i, &buff_data); + size_t size = reader.buffer_info(i, &buff_data, ext_offset); - os << "B(" << i << ") (" << size << ") "; + os << "B(" << i << ") (" << size; + if (ext_offset) + os << " *"; + os << ") "; if (buff_data != nullptr) { dump_buffer(os, buff_data, size, 16); @@ -460,8 +464,8 @@ void dump_model(std::ostream &os, const circle::Model *model) } // namespace circledump -std::ostream &operator<<(std::ostream &os, const circle::Model *model) +std::ostream &operator<<(std::ostream &os, const circledump::ModelEx &modelex) { - circledump::dump_model(os, model); + circledump::dump_model(os, modelex.model, modelex.rawdata); return os; } From 157f5eef210f25091e35fdb0de69aa948e1a1c15 Mon Sep 17 00:00:00 2001 From: Hyeongseok Oh Date: Wed, 21 Aug 2024 11:41:56 +0900 Subject: [PATCH 72/78] [github] Run workflow jobs only in Samsung org (#13718) This will revuse to run all workflow jobs only in Samsung org. ONE-DCO-1.0-Signed-off-by: Hyeongseok Oh --- .github/workflows/check-format.yml | 2 ++ .github/workflows/check-pr-commit.yml | 2 +- .github/workflows/run-onert-android-build.yml | 1 + .github/workflows/run-onert-micro-unit-tests.yml | 9 ++++++++- 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/.github/workflows/check-format.yml b/.github/workflows/check-format.yml index ba8d4bff968..6b64450d3d4 100644 --- a/.github/workflows/check-format.yml +++ b/.github/workflows/check-format.yml @@ -18,6 +18,7 @@ jobs: check-format: name: Check format runs-on: ubuntu-20.04 + if: github.repository_owner == 'Samsung' steps: - name: Checkout @@ -54,6 +55,7 @@ jobs: check-copyright: name: Check copyright runs-on: ubuntu-20.04 + if: github.repository_owner == 'Samsung' steps: - name: Checkout diff --git a/.github/workflows/check-pr-commit.yml b/.github/workflows/check-pr-commit.yml index 5dc2de1c390..9651514fd48 100644 --- a/.github/workflows/check-pr-commit.yml +++ b/.github/workflows/check-pr-commit.yml @@ -20,7 +20,7 @@ jobs: name: Check commit message runs-on: ubuntu-20.04 # Skip on draft, check on draft -> ready - if: github.event.pull_request.draft == false + if: github.repository_owner == 'Samsung' && github.event.pull_request.draft == false steps: - name: Checkout diff --git a/.github/workflows/run-onert-android-build.yml b/.github/workflows/run-onert-android-build.yml index 16d40e90c6f..ca016f2ee52 100644 --- a/.github/workflows/run-onert-android-build.yml +++ b/.github/workflows/run-onert-android-build.yml @@ -41,6 +41,7 @@ defaults: jobs: build: runs-on: ubuntu-22.04 + if: github.repository_owner == 'Samsung' env: TARGET_ARCH: aarch64 TARGET_OS: android diff --git a/.github/workflows/run-onert-micro-unit-tests.yml b/.github/workflows/run-onert-micro-unit-tests.yml index 3256c758c4d..28df490b059 100644 --- a/.github/workflows/run-onert-micro-unit-tests.yml +++ b/.github/workflows/run-onert-micro-unit-tests.yml @@ -1,6 +1,13 @@ name: Run onert-micro Unit tests on: + push: + branches: + - master + - release/* + paths: + - 'onert-micro/**' + - '.github/workflows/run-onert-micro-unit-tests.yml' pull_request: branches: - master @@ -23,7 +30,7 @@ jobs: name: Run onert-micro Unit tests runs-on: ubuntu-20.04 # Skip on draft, check on draft -> ready - if: github.event.pull_request.draft == false + if: github.repository_owner == 'Samsung' && github.event.pull_request.draft == false steps: - name: Install Arm GNU Toolchain (arm-none-eabi-gcc) From 7d461674b611cc077c4a086751bdcd00798a9285 Mon Sep 17 00:00:00 2001 From: chunseoklee Date: Wed, 21 Aug 2024 11:46:14 +0900 Subject: [PATCH 73/78] [onert-micro] S8 Test for SpaceToDepth (#13696) - S8 test added - Fix wring height/width check DCO-1.0-Signed-off-by: Chunseok Lee --- .../space_to_depth/NegSpaceToDepthKernel.h | 70 ++++++++++++++ .../space_to_depth/S8SpaceToDepthKernel.h | 96 +++++++++++++++++++ .../src/execute/kernels/SpaceToDepth.cpp | 9 ++ .../kernels/tests/SpaceToDepth.test.cpp | 16 ++++ .../src/import/kernels/SpaceToDepth.cpp | 5 +- 5 files changed, 194 insertions(+), 2 deletions(-) create mode 100644 onert-micro/onert-micro/include/test_models/space_to_depth/S8SpaceToDepthKernel.h diff --git a/onert-micro/onert-micro/include/test_models/space_to_depth/NegSpaceToDepthKernel.h b/onert-micro/onert-micro/include/test_models/space_to_depth/NegSpaceToDepthKernel.h index c36b24da231..c0d02ff2d9d 100644 --- a/onert-micro/onert-micro/include/test_models/space_to_depth/NegSpaceToDepthKernel.h +++ b/onert-micro/onert-micro/include/test_models/space_to_depth/NegSpaceToDepthKernel.h @@ -81,6 +81,76 @@ class NegTestDataInputOutputTypeMismatchSpaceToDepthKernel : public NegTestDataB const unsigned char *_test_kernel_model_circle; }; +namespace neg_input_output_shape_mismatch_space_to_depth_kernel +{ +/* + * SpaceToDepth kernel with input output shape mismatch: + * + * Input(1, 4, 4, 3) - S8 + * | + * SpaceToDepth + * | + * Output(1, 2, 3, 11) - S8 + */ +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, 0xc4, 0x01, 0x00, 0x00, 0xe0, 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, 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, 0x16, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x08, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x13, 0x14, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 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, 0x84, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x92, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x09, 0x44, 0x00, 0x00, 0x00, 0x84, 0xff, 0xff, 0xff, 0x2c, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, + 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, 0x04, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0b, + 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, + 0x7f, 0x43, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x69, + 0x66, 0x6d, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 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, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 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_shape_mismatch_space_to_depth_kernel + +class NegTestDataInputOutputShapeMismatchSpaceToDepthKernel : public NegTestDataBase +{ +public: + NegTestDataInputOutputShapeMismatchSpaceToDepthKernel() + { + _test_kernel_model_circle = + neg_input_output_shape_mismatch_space_to_depth_kernel::test_kernel_model_circle; + } + + ~NegTestDataInputOutputShapeMismatchSpaceToDepthKernel() 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 diff --git a/onert-micro/onert-micro/include/test_models/space_to_depth/S8SpaceToDepthKernel.h b/onert-micro/onert-micro/include/test_models/space_to_depth/S8SpaceToDepthKernel.h new file mode 100644 index 00000000000..8dc58e017d7 --- /dev/null +++ b/onert-micro/onert-micro/include/test_models/space_to_depth/S8SpaceToDepthKernel.h @@ -0,0 +1,96 @@ +/* + * 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_S8_SPACE_TO_DEPTH_KERNEL_H +#define ONERT_MICRO_TEST_MODELS_S8_SPACE_TO_DEPTH_KERNEL_H + +#include "TestDataSpaceToDepthBase.h" + +namespace onert_micro +{ +namespace test_model +{ +namespace space_to_depth_s8 +{ +/* + * SpaceToDepth Kernel: + * + * Input(1, 4, 4, 3) + * | + * SpaceToDepth + * | + * Output(1, 2, 2, 12) + */ +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, 0xc4, 0x01, 0x00, 0x00, 0xe0, 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, + 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, 0x16, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x08, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x14, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x02, 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, 0x84, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x92, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x09, 0x44, 0x00, 0x00, 0x00, 0x84, 0xff, 0xff, 0xff, 0x2c, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 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, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0c, 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, 0x7f, 0x43, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x69, 0x66, 0x6d, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 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, + 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 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 = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}; +const std::vector reference_output_data = { + 0, 1, 2, 3, 4, 5, 12, 13, 14, 15, 16, 17, 6, 7, 8, 9, 10, 11, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 36, 37, 38, 39, 40, 41, 30, 31, 32, 33, 34, 35, 42, 43, 44, 45, 46, 47}; +} // namespace space_to_depth_s8 + +class TestDataS8SpaceToDepth : public TestDataSpaceToDepthBase +{ +public: + TestDataS8SpaceToDepth() + { + _input_data = space_to_depth_s8::input_data; + _reference_output_data = space_to_depth_s8::reference_output_data; + _test_kernel_model_circle = space_to_depth_s8::test_kernel_model_circle; + } + + ~TestDataS8SpaceToDepth() override = default; +}; + +} // namespace test_model +} // namespace onert_micro + +#endif // ONERT_MICRO_TEST_MODELS_S8_SPACE_TO_DEPTH_KERNEL_H diff --git a/onert-micro/onert-micro/src/execute/kernels/SpaceToDepth.cpp b/onert-micro/onert-micro/src/execute/kernels/SpaceToDepth.cpp index 313b80febf7..9eef7a22f61 100644 --- a/onert-micro/onert-micro/src/execute/kernels/SpaceToDepth.cpp +++ b/onert-micro/onert-micro/src/execute/kernels/SpaceToDepth.cpp @@ -77,6 +77,15 @@ OMStatus onert_micro::execute::execute_kernel_CircleSpaceToDepth( } break; #endif // DIS_FLOAT +#ifndef DIS_QUANT + case circle::TensorType_INT8: + { + status = + pal::SpaceToDepth(block_size, input_shape, reinterpret_cast(input_data), + output_shape, reinterpret_cast(output_data)); + } + break; +#endif // DIS_QUANT default: { status = UnsupportedType; diff --git a/onert-micro/onert-micro/src/execute/kernels/tests/SpaceToDepth.test.cpp b/onert-micro/onert-micro/src/execute/kernels/tests/SpaceToDepth.test.cpp index e427e2068a5..f9c55e2d836 100644 --- a/onert-micro/onert-micro/src/execute/kernels/tests/SpaceToDepth.test.cpp +++ b/onert-micro/onert-micro/src/execute/kernels/tests/SpaceToDepth.test.cpp @@ -16,6 +16,7 @@ #include "execute/OMTestUtils.h" #include "test_models/space_to_depth/FloatSpaceToDepthKernel.h" +#include "test_models/space_to_depth/S8SpaceToDepthKernel.h" #include "test_models/space_to_depth/NegSpaceToDepthKernel.h" namespace onert_micro @@ -40,6 +41,14 @@ TEST_F(SpaceToDepthTest, Float_P) EXPECT_THAT(output_data_vector, test_data_kernel.get_output_data_by_index(0)); } +TEST_F(SpaceToDepthTest, S8_P) +{ + onert_micro::test_model::TestDataS8SpaceToDepth 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(SpaceToDepthTest, Input_output_type_mismatch_NEG) { onert_micro::test_model::NegTestDataInputOutputTypeMismatchSpaceToDepthKernel test_data_kernel; @@ -47,6 +56,13 @@ TEST_F(SpaceToDepthTest, Input_output_type_mismatch_NEG) EXPECT_DEATH(checkNEGSISOKernel(&test_data_kernel), ""); } +TEST_F(SpaceToDepthTest, Input_output_shape_mismatch_NEG) +{ + onert_micro::test_model::NegTestDataInputOutputShapeMismatchSpaceToDepthKernel test_data_kernel; + + EXPECT_DEATH(checkNEGSISOKernel(&test_data_kernel), ""); +} + } // namespace testing } // namespace execute } // namespace onert_micro diff --git a/onert-micro/onert-micro/src/import/kernels/SpaceToDepth.cpp b/onert-micro/onert-micro/src/import/kernels/SpaceToDepth.cpp index 8520ccf5de4..b8843293b9b 100644 --- a/onert-micro/onert-micro/src/import/kernels/SpaceToDepth.cpp +++ b/onert-micro/onert-micro/src/import/kernels/SpaceToDepth.cpp @@ -53,6 +53,7 @@ OMStatus onert_micro::import::configure_kernel_CircleSpaceToDepth( return status; OMRuntimeShape input_shape(input); + OMRuntimeShape output_shape(output); const auto *options = runtime_kernel.first_operator->builtin_options_as_SpaceToDepthOptions(); const int32_t block_size = options->block_size(); @@ -66,8 +67,8 @@ OMStatus onert_micro::import::configure_kernel_CircleSpaceToDepth( const int input_height = input_shape.dims(kHeightRank); const int input_width = input_shape.dims(kWidthRank); - int output_height = input_height / block_size; - int output_width = input_width / block_size; + int output_height = output_shape.dims(kHeightRank); + int output_width = output_shape.dims(kWidthRank); status = utils::checkCondition(input_height == output_height * block_size); if (status != Ok) From b22860f1ad0ac92d97a68cd8585c21436858668b Mon Sep 17 00:00:00 2001 From: Hyukjin Jeong Date: Wed, 21 Aug 2024 16:17:11 +0900 Subject: [PATCH 74/78] [luci] Infer dynamic shape for concat (#13698) This infers dynamic shape for concat Op. ONE-DCO-1.0-Signed-off-by: Hyukjin Jeong --- .../service/src/CircleShapeInferenceRule.cpp | 33 +++++- .../src/Nodes/CircleConcatenation.test.cpp | 111 ++++++++++++++++++ 2 files changed, 138 insertions(+), 6 deletions(-) diff --git a/compiler/luci/service/src/CircleShapeInferenceRule.cpp b/compiler/luci/service/src/CircleShapeInferenceRule.cpp index 63eb4fb7e37..877bd5a0ae7 100644 --- a/compiler/luci/service/src/CircleShapeInferenceRule.cpp +++ b/compiler/luci/service/src/CircleShapeInferenceRule.cpp @@ -568,14 +568,35 @@ loco::NodeShape infer_concatenation(const luci::CircleConcatenation *node) { if (j == static_cast(axis)) { - // If dimension is unknown, value() will return 0. - // This is wrong but until new inference algorithm is implemented, - // this code will not be modified to keep compatibility. - output_shape.dim(j) = output_shape.dim(j).value() + input_shape.dim(j).value(); + if (output_shape.dim(j).known() and input_shape.dim(j).known()) + { + output_shape.dim(j) = output_shape.dim(j).value() + input_shape.dim(j).value(); + } + else + { + // If any of inputs is unknown, just mark it as unknown. + output_shape.dim(j).unset(); + } } else - assert(!output_shape.dim(j).known() || !input_shape.dim(j).known() || - output_shape.dim(j) == input_shape.dim(j)); + { + if (output_shape.dim(j).known() and input_shape.dim(j).known()) + { + if (output_shape.dim(j).value() != input_shape.dim(j).value()) + { + INTERNAL_EXN_V("Input has incompatible shape.", node->name()); + } + } + else + { + if (input_shape.dim(j).known()) + { + assert(not output_shape.dim(j).known()); // FIX_ME_UNLESS + output_shape.dim(j) = input_shape.dim(j); + } + // For unknown input_shape, leave output_shape as-is + } + } } } diff --git a/compiler/luci/service/src/Nodes/CircleConcatenation.test.cpp b/compiler/luci/service/src/Nodes/CircleConcatenation.test.cpp index 270068cf0d9..7bf0268c9f4 100644 --- a/compiler/luci/service/src/Nodes/CircleConcatenation.test.cpp +++ b/compiler/luci/service/src/Nodes/CircleConcatenation.test.cpp @@ -16,6 +16,8 @@ #include "luci/Service/CircleNodeClone.h" +#include + #include TEST(CloneNodeTest, clone_Concatenation) @@ -47,3 +49,112 @@ TEST(CloneNodeTest, clone_Concatenation_NEG) auto cloned = luci::clone_node(node_concat, gc.get()); ASSERT_EQ(nullptr, cloned); } + +TEST(ShapeRuleTest, concat_dynamic_shape_axis) +{ + luci::CircleInput input_1; + luci::CircleInput input_2; + luci::CircleConcatenation concat(2); + + input_1.shape({1, 4, 3, 1}); + input_1.shape_status(luci::ShapeStatus::VALID); + + input_2.shape({1, 4, 3, 1}); + input_2.shape_status(luci::ShapeStatus::VALID); + input_2.dim(2).unset(); + + concat.values(0, &input_1); + concat.values(1, &input_2); + concat.axis(2); + + loco::TensorShape shape; + luci::sinf::Rule shape_inf_rule; + + ASSERT_TRUE(shape_inf_rule.infer(&concat, shape)); + ASSERT_EQ(4, shape.rank()); + ASSERT_TRUE(shape.dim(0).known()); + ASSERT_TRUE(shape.dim(1).known()); + ASSERT_FALSE(shape.dim(2).known()); + ASSERT_TRUE(shape.dim(3).known()); + ASSERT_EQ(1, shape.dim(0).value()); + ASSERT_EQ(4, shape.dim(1).value()); + ASSERT_EQ(0, shape.dim(2).value()); + ASSERT_EQ(1, shape.dim(3).value()); +} + +TEST(ShapeRuleTest, concat_dynamic_shape_non_axis) +{ + luci::CircleInput input_1; + luci::CircleInput input_2; + luci::CircleConcatenation concat(2); + + input_1.shape({1, 4, 3, 1}); + input_1.shape_status(luci::ShapeStatus::VALID); + + input_2.shape({1, 4, 3, 1}); + input_2.shape_status(luci::ShapeStatus::VALID); + input_2.dim(2).unset(); + + concat.values(0, &input_1); + concat.values(1, &input_2); + concat.axis(1); + + loco::TensorShape shape; + luci::sinf::Rule shape_inf_rule; + + ASSERT_TRUE(shape_inf_rule.infer(&concat, shape)); + ASSERT_EQ(4, shape.rank()); + ASSERT_TRUE(shape.dim(0).known()); + ASSERT_TRUE(shape.dim(1).known()); + ASSERT_TRUE(shape.dim(2).known()); + ASSERT_TRUE(shape.dim(3).known()); + ASSERT_EQ(1, shape.dim(0).value()); + ASSERT_EQ(8, shape.dim(1).value()); + ASSERT_EQ(3, shape.dim(2).value()); + ASSERT_EQ(1, shape.dim(3).value()); +} + +TEST(ShapeRuleTest, concat_wrong_shape_NEG) +{ + luci::CircleInput input_1; + luci::CircleInput input_2; + luci::CircleConcatenation concat(2); + + input_1.shape({1, 4, 4, 1}); + input_1.shape_status(luci::ShapeStatus::VALID); + + input_2.shape({1, 4, 3, 1}); + input_2.shape_status(luci::ShapeStatus::VALID); + + concat.values(0, &input_1); + concat.values(1, &input_2); + concat.axis(1); + + loco::TensorShape shape; + luci::sinf::Rule shape_inf_rule; + + EXPECT_ANY_THROW(shape_inf_rule.infer(&concat, shape)); +} + +TEST(ShapeRuleTest, concat_rank_mismatch_NEG) +{ + luci::CircleInput input_1; + luci::CircleInput input_2; + luci::CircleConcatenation concat(2); + + input_1.shape({1, 4, 3, 1}); + input_1.shape_status(luci::ShapeStatus::VALID); + + input_2.shape({1, 4, 1}); + input_2.shape_status(luci::ShapeStatus::VALID); + input_2.dim(2).unset(); + + concat.values(0, &input_1); + concat.values(1, &input_2); + concat.axis(2); + + loco::TensorShape shape; + luci::sinf::Rule shape_inf_rule; + + EXPECT_ANY_THROW(shape_inf_rule.infer(&concat, shape)); +} From bf43f41cb31477ef48a6a1afd4effe68567ba396 Mon Sep 17 00:00:00 2001 From: SaeHie Park Date: Wed, 21 Aug 2024 16:29:29 +0900 Subject: [PATCH 75/78] [tflite2circle] Revise interface to pass raw file data (#13732) This will revise CircleModel interface to pass raw file data to access Buffer data outside of flatbuffers range. ONE-DCO-1.0-Signed-off-by: SaeHie Park --- compiler/tflite2circle/driver/Driver.cpp | 3 ++- compiler/tflite2circle/include/CircleModel.h | 5 ++++- compiler/tflite2circle/include/TFLModel.h | 2 ++ compiler/tflite2circle/src/CircleModel.cpp | 4 ++-- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/compiler/tflite2circle/driver/Driver.cpp b/compiler/tflite2circle/driver/Driver.cpp index 6afe1b0f272..8ac630130a0 100644 --- a/compiler/tflite2circle/driver/Driver.cpp +++ b/compiler/tflite2circle/driver/Driver.cpp @@ -67,7 +67,8 @@ int entry(int argc, char **argv) auto flatbuffer_builder = std::make_unique(1024); // convert tflite to circle - tflite2circle::CircleModel circle_model{flatbuffer_builder}; + const std::vector &raw_data = tfl_model.raw_data(); + tflite2circle::CircleModel circle_model{flatbuffer_builder, raw_data}; circle_model.load_offsets(tfl_model.get_model()); circle_model.model_build(); diff --git a/compiler/tflite2circle/include/CircleModel.h b/compiler/tflite2circle/include/CircleModel.h index 189cfaff23f..719848c003c 100644 --- a/compiler/tflite2circle/include/CircleModel.h +++ b/compiler/tflite2circle/include/CircleModel.h @@ -80,6 +80,8 @@ template class Offset CIRFlatBufVecOffset _circle_flatbuffer_vec_offset; // TODO revise this when Circle supports SignatureDef const SignatureDefs *_tfl_signature_def_offsets = nullptr; + // for extended buffer for size > 2G + const std::vector *_file_raw = nullptr; }; class CircleModel @@ -89,7 +91,7 @@ class CircleModel public: CircleModel(void) = delete; - CircleModel(FlatBufBuilder &fb); + CircleModel(FlatBufBuilder &fb, const std::vector &fr); public: void load_offsets(const tflite::Model *tfl_model); @@ -101,6 +103,7 @@ class CircleModel uint32_t _version; Description _description; FlatBufBuilder &_fb; + const std::vector &_file_raw; std::unique_ptr> _operator_codes_offset; std::unique_ptr> _subGraphs_offset; std::unique_ptr> _buffers_offset; diff --git a/compiler/tflite2circle/include/TFLModel.h b/compiler/tflite2circle/include/TFLModel.h index 507667bb903..111a5b9fefc 100644 --- a/compiler/tflite2circle/include/TFLModel.h +++ b/compiler/tflite2circle/include/TFLModel.h @@ -38,6 +38,8 @@ class TFLModel public: const tflite::Model *get_model(void); + // NOTE TFLModel lifetime should be longer than users + const std::vector &raw_data(void) const { return _data; } public: bool verify_data(void); diff --git a/compiler/tflite2circle/src/CircleModel.cpp b/compiler/tflite2circle/src/CircleModel.cpp index c9465a0c615..57010f20682 100644 --- a/compiler/tflite2circle/src/CircleModel.cpp +++ b/compiler/tflite2circle/src/CircleModel.cpp @@ -376,8 +376,8 @@ template <> void Offset::build(const TFLFlatBufVec *tflite_fla _circle_flatbuffer_vec_offset = _fb->CreateVector(operator_code_vec); } -CircleModel::CircleModel(FlatBufBuilder &fb) - : _version{0}, _description{fb->CreateString("ONE-tflite2circle")}, _fb{fb} +CircleModel::CircleModel(FlatBufBuilder &fb, const std::vector &fr) + : _version{0}, _description{fb->CreateString("ONE-tflite2circle")}, _fb{fb}, _file_raw{fr} { // NOTHING TODO } From 089423c715c1d1d1d8af4d19e6ab06e4c0225b5e Mon Sep 17 00:00:00 2001 From: SaeHie Park Date: Wed, 21 Aug 2024 16:29:54 +0900 Subject: [PATCH 76/78] [tflite2circle] Extract variable in Buffer build (#13731) This will extract a variable in Buffer build method. ONE-DCO-1.0-Signed-off-by: SaeHie Park --- compiler/tflite2circle/src/CircleModel.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/tflite2circle/src/CircleModel.cpp b/compiler/tflite2circle/src/CircleModel.cpp index 57010f20682..ca2778ec354 100644 --- a/compiler/tflite2circle/src/CircleModel.cpp +++ b/compiler/tflite2circle/src/CircleModel.cpp @@ -43,9 +43,10 @@ template <> void Offset::build(const TFLFlatBufVec *tflite_flatbuffe for (auto it : *tflite_flatbuffer_vec) { flatbuffers::Offset> buffer_data; - if (it->data()) + const auto *tflbuff_data = it->data(); + if (tflbuff_data) { - std::vector data_vec{it->data()->begin(), it->data()->end()}; + std::vector data_vec{tflbuff_data->begin(), tflbuff_data->end()}; buffer_data = _fb->CreateVector(data_vec); } circle::BufferBuilder circle_buffer_builder{*_fb}; From f72d1cf9e5dd2c339a47f99b931f2423f6d6a549 Mon Sep 17 00:00:00 2001 From: chunseoklee Date: Wed, 21 Aug 2024 16:38:52 +0900 Subject: [PATCH 77/78] [onert-micro] S8 Test for Gather (#13710) - S8 Test added - NEG test added DCO-1.0-Signed-off-by: Chunseok Lee --- .../test_models/gather/NegGatherKernel.h | 70 ++++++++++++ .../test_models/gather/S8GatherKernel.h | 104 ++++++++++++++++++ .../src/execute/kernels/tests/Gather.test.cpp | 16 +++ .../onert-micro/src/import/kernels/Gather.cpp | 14 +++ 4 files changed, 204 insertions(+) create mode 100644 onert-micro/onert-micro/include/test_models/gather/S8GatherKernel.h diff --git a/onert-micro/onert-micro/include/test_models/gather/NegGatherKernel.h b/onert-micro/onert-micro/include/test_models/gather/NegGatherKernel.h index a240cdfd86c..9cf0f4ebfaf 100644 --- a/onert-micro/onert-micro/include/test_models/gather/NegGatherKernel.h +++ b/onert-micro/onert-micro/include/test_models/gather/NegGatherKernel.h @@ -160,6 +160,60 @@ const unsigned char test_kernel_model_circle[] = { } // namespace neg_gather_wrong_axis +namespace neg_gather_scale_mismatch +{ +/* + * Gather Kernel with io quant scael mismatch + * + * Input(1, 2, 3, 4) - S8 (scale 0.38) Indices(1, 2) + * \ / + * Gather(axis=2) + * | + * Output(1, 2, 2, 4) (scale 0.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, + 0x44, 0x00, 0x00, 0x00, 0x1c, 0x02, 0x00, 0x00, 0x38, 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x72, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 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, 0x68, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x08, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, + 0x14, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 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, 0xc0, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x5a, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x09, 0x48, 0x00, 0x00, 0x00, 0x4c, 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, + 0xb8, 0x1e, 0x05, 0x3c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x42, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xc3, 0x03, 0x00, 0x00, 0x00, 0x6f, 0x66, 0x6d, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x65, 0x73, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 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, 0x54, 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, 0x2c, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x42, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, + 0x05, 0x00, 0x00, 0x00, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 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, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, + 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_gather_scale_mismatch + class NegTestDataInputOutputTypeMismatchGatherKernel : public NegTestDataBase { public: @@ -208,6 +262,22 @@ class NegTestDataWrongAxisGatherKernel : public NegTestDataBase const unsigned char *_test_kernel_model_circle; }; +class NegTestDataInputOutputScaleMismatchGatherKernel : public NegTestDataBase +{ +public: + NegTestDataInputOutputScaleMismatchGatherKernel() + { + _test_kernel_model_circle = neg_gather_scale_mismatch::test_kernel_model_circle; + } + + ~NegTestDataInputOutputScaleMismatchGatherKernel() 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 diff --git a/onert-micro/onert-micro/include/test_models/gather/S8GatherKernel.h b/onert-micro/onert-micro/include/test_models/gather/S8GatherKernel.h new file mode 100644 index 00000000000..a3bbc5e9127 --- /dev/null +++ b/onert-micro/onert-micro/include/test_models/gather/S8GatherKernel.h @@ -0,0 +1,104 @@ +/* + * 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_GATHER_S8_KERNEL_H +#define ONERT_MICRO_TEST_MODELS_GATHER_S8_KERNEL_H + +#include "TestDataGatherBase.h" + +namespace onert_micro +{ +namespace test_model +{ +namespace gather_s8 +{ +/* + * Gather Kernel: + * + * Input(1, 2, 3, 4) Indices(1, 2) + * \ / + * Gather(axis=2) + * | + * Output(1, 2, 2, 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, + 0x44, 0x00, 0x00, 0x00, 0x1c, 0x02, 0x00, 0x00, 0x38, 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x72, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 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, 0x68, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x08, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, + 0x14, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 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, 0xc0, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x5a, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x09, 0x48, 0x00, 0x00, 0x00, 0x4c, 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, 0x00, 0x3c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x42, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xc3, 0x03, 0x00, 0x00, 0x00, 0x6f, 0x66, 0x6d, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x65, 0x73, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 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, 0x54, 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, 0x2c, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x42, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, + 0x05, 0x00, 0x00, 0x00, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 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, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, + 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 = {4, 14, 14, 22, 5, -5, -4, -3, 5, 15, 13, 5, + -3, 5, -13, 15, -6, -13, -4, -12, -5, 5, 5, -5}; + +const std::vector reference_output_data = {5, -5, -4, -3, 5, 15, 13, 5, + -6, -13, -4, -12, -5, 5, 5, -5}; + +} // namespace gather_s8 + +class TestDataS8Gather : public TestDataGatherBase +{ +public: + TestDataS8Gather() + { + _input_data = gather_s8::input_data; + _reference_output_data = gather_s8::reference_output_data; + _test_kernel_model_circle = gather_s8::test_kernel_model_circle; + } + + ~TestDataS8Gather() override = default; +}; +} // namespace test_model +} // namespace onert_micro + +#endif // ONERT_MICRO_TEST_MODELS_GATHER_S8_KERNEL_H diff --git a/onert-micro/onert-micro/src/execute/kernels/tests/Gather.test.cpp b/onert-micro/onert-micro/src/execute/kernels/tests/Gather.test.cpp index b3a47d4f9e6..bb256cd360a 100644 --- a/onert-micro/onert-micro/src/execute/kernels/tests/Gather.test.cpp +++ b/onert-micro/onert-micro/src/execute/kernels/tests/Gather.test.cpp @@ -17,6 +17,7 @@ #include "execute/OMTestUtils.h" #include "test_models/gather/FloatGatherKernel.h" #include "test_models/gather/IntGatherKernel.h" +#include "test_models/gather/S8GatherKernel.h" #include "test_models/gather/NegGatherKernel.h" namespace onert_micro @@ -49,6 +50,14 @@ TEST_F(GatherTest, Gather_Int_P) EXPECT_THAT(output_data_vector, test_data_kernel.get_output_data_by_index(0)); } +TEST_F(GatherTest, Gather_S8_P) +{ + onert_micro::test_model::TestDataS8Gather 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(GatherTest, Input_output_type_mismatch_NEG) { onert_micro::test_model::NegTestDataInputOutputTypeMismatchGatherKernel test_data_kernel; @@ -63,6 +72,13 @@ TEST_F(GatherTest, Wrong_position_type_NEG) EXPECT_DEATH(checkNEGSISOKernel(&test_data_kernel), ""); } +TEST_F(GatherTest, Wrong_scale_mismatch_NEG) +{ + onert_micro::test_model::NegTestDataInputOutputScaleMismatchGatherKernel test_data_kernel; + + EXPECT_DEATH(checkNEGSISOKernel(&test_data_kernel), ""); +} + TEST_F(GatherTest, Wrong_axis_NEG) { onert_micro::test_model::NegTestDataWrongAxisGatherKernel test_data_kernel; diff --git a/onert-micro/onert-micro/src/import/kernels/Gather.cpp b/onert-micro/onert-micro/src/import/kernels/Gather.cpp index 622c700ddb4..709b59b38f8 100644 --- a/onert-micro/onert-micro/src/import/kernels/Gather.cpp +++ b/onert-micro/onert-micro/src/import/kernels/Gather.cpp @@ -71,6 +71,20 @@ OMStatus onert_micro::import::configure_kernel_CircleGather(const OMConfigureArg if (status != Ok) return status; +#ifndef DIS_QUANT + if (input_type == circle::TensorType_INT8) + { + status = utils::checkCondition(*output->quantization()->scale()->begin() == + *input->quantization()->scale()->begin()); + if (status != Ok) + return status; + status = utils::checkCondition(*output->quantization()->zero_point()->begin() == + *input->quantization()->zero_point()->begin()); + if (status != Ok) + return status; + } +#endif // DIS_QUANT + int32_t axis = options->axis(); core::OMRuntimeShape input_shape(input); From ac4d588dc4620f4e084ff041e523606de6c17206 Mon Sep 17 00:00:00 2001 From: chunseoklee Date: Wed, 21 Aug 2024 16:39:42 +0900 Subject: [PATCH 78/78] [onert-micro] S8 Test for Reshape (#13701) - S8 test addded - NEG test also added DCO-1.0-Signed-off-by: Chunseok Lee --- .../test_models/reshape/ReshapeKernel.h | 166 ++++++++++++++++++ .../execute/kernels/tests/Reshape.test.cpp | 14 ++ 2 files changed, 180 insertions(+) diff --git a/onert-micro/onert-micro/include/test_models/reshape/ReshapeKernel.h b/onert-micro/onert-micro/include/test_models/reshape/ReshapeKernel.h index d0c9c762be6..d6b14f6db3f 100644 --- a/onert-micro/onert-micro/include/test_models/reshape/ReshapeKernel.h +++ b/onert-micro/onert-micro/include/test_models/reshape/ReshapeKernel.h @@ -169,6 +169,172 @@ template class TestDataReshapeKernel : public TestDataBase const unsigned char *_test_kernel_model_circle; }; +namespace reshape_kernel_s8 +{ +/* + * Reshape Kernel: + * + * Input(1, 1, 1, 10) Const([1,10]) + * \ / + * Reshape + * | + * Output(1,10) + */ +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, 0x44, 0x00, 0x00, 0x00, 0x18, 0x02, 0x00, 0x00, 0x34, 0x02, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x72, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0a, 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, 0x6c, 0x00, 0x00, 0x00, + 0x70, 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, + 0x16, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x08, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x11, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 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, 0xb8, 0x00, 0x00, 0x00, + 0x7c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x62, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x48, 0x00, 0x00, 0x00, + 0x54, 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, 0xfe, 0x42, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x03, 0x00, 0x00, 0x00, + 0x6f, 0x66, 0x6d, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x73, 0x68, 0x61, 0x70, 0x65, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 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, 0xfe, 0x42, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xc3, 0x03, 0x00, 0x00, 0x00, 0x69, 0x66, 0x6d, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0a, 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, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, + 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, 2, 3, 4, 5, 6, 7, 8, 9, 10}; +const std::vector reference_output_data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + +} // namespace reshape_kernel_s8 + +namespace neg_reshape_kernel_s8 +{ +/* + * Reshape Kernel: + * + * Input(1, 1, 1, 10) Const([1, 10]) + * \ / + * Reshape + * | + * Output(1, 20) + */ +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, 0x44, 0x00, 0x00, 0x00, 0x18, 0x02, 0x00, 0x00, 0x34, 0x02, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x72, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0a, 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, 0x6c, 0x00, 0x00, 0x00, + 0x70, 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, + 0x16, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x08, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x11, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x00, 0x08, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 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, 0xb8, 0x00, 0x00, 0x00, + 0x7c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x62, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x48, 0x00, 0x00, 0x00, + 0x54, 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, 0xfe, 0x42, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x03, 0x00, 0x00, 0x00, + 0x6f, 0x66, 0x6d, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x73, 0x68, 0x61, 0x70, 0x65, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 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, 0xfe, 0x42, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xc3, 0x03, 0x00, 0x00, 0x00, 0x69, 0x66, 0x6d, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0a, 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, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, + 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, 2, 3, 4, 5, 6, 7, 8, 9, 10}; +const std::vector reference_output_data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + +} // namespace neg_reshape_kernel_s8 + +class TestDataS8ReshapeKernel : public TestDataBase +{ +public: + TestDataS8ReshapeKernel(bool is_neg) + { + if (not is_neg) + { + _input_data = reshape_kernel_s8::input_data; + _reference_output_data = reshape_kernel_s8::reference_output_data; + _test_kernel_model_circle = reshape_kernel_s8::test_kernel_model_circle; + } + else + { + _input_data = neg_reshape_kernel_s8::input_data; + _reference_output_data = neg_reshape_kernel_s8::reference_output_data; + _test_kernel_model_circle = neg_reshape_kernel_s8::test_kernel_model_circle; + } + } + + ~TestDataS8ReshapeKernel() override = 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_model } // namespace onert_micro diff --git a/onert-micro/onert-micro/src/execute/kernels/tests/Reshape.test.cpp b/onert-micro/onert-micro/src/execute/kernels/tests/Reshape.test.cpp index dda748e54b3..873a6c18d36 100644 --- a/onert-micro/onert-micro/src/execute/kernels/tests/Reshape.test.cpp +++ b/onert-micro/onert-micro/src/execute/kernels/tests/Reshape.test.cpp @@ -39,6 +39,20 @@ TEST_F(ReshapeTest, MainTest_P) EXPECT_THAT(output_data_vector, test_data_kernel.get_output_data_by_index(0)); } +TEST_F(ReshapeTest, S8_P) +{ + onert_micro::test_model::TestDataS8ReshapeKernel test_data_kernel(false); + 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(ReshapeTest, UNMATCHED_IOTYPE_NEG) +{ + onert_micro::test_model::TestDataS8ReshapeKernel test_data_kernel(true); + EXPECT_DEATH(checkKernel(1, &test_data_kernel), ""); +} + TEST_F(ReshapeTest, MainTest_NEG) { onert_micro::test_model::TestDataReshapeKernel test_data_kernel(true);