diff --git a/runtime/onert/core/include/backend/basic/BackendContextHelpers.h b/runtime/onert/core/include/backend/basic/BackendContextHelpers.h index 46e57e925e6..ce905ce7a46 100644 --- a/runtime/onert/core/include/backend/basic/BackendContextHelpers.h +++ b/runtime/onert/core/include/backend/basic/BackendContextHelpers.h @@ -177,16 +177,31 @@ void planTensors(const std::shared_ptr &tensor_builder, const i } template -ITensorRegistry * -genTensors(const std::shared_ptr &tensor_builder, const ir::Graph &graph, - const util::Set &external_operands, - const std::shared_ptr &tensor_registry, - const std::vector &op_order, - const ir::OperandIndexMap & /*shared_memory_operand_idx*/) +ITensorRegistry *genTensors(const std::shared_ptr &tensor_builder, + const ir::Graph &graph, + const util::Set &external_operands, + const std::shared_ptr &tensor_registry, + const std::vector &op_order, + const ir::OperandIndexMap &shared_memory_operand_idx) { + // process source tensors for shared memory at first + std::vector registered_source_ind; + for (const auto &[_, source_ind] : shared_memory_operand_idx) + { + if (external_operands.contains(source_ind)) + continue; + if (tensor_builder->isRegistered(source_ind)) // some tensors can have the same source + continue; + tensor_builder->registerTensorInfo(source_ind, graph.operands().at(source_ind).info()); + registered_source_ind.emplace_back(source_ind); + } + graph.operands().iterate([&](const ir::OperandIndex &ind, const ir::Operand &obj) { if (external_operands.contains(ind)) return; + if (std::find(std::begin(registered_source_ind), std::end(registered_source_ind), ind) != + std::end(registered_source_ind)) // skip tensors already registered + return; tensor_builder->registerTensorInfo(ind, obj.info()); }); @@ -219,10 +234,14 @@ template ITensorRegistry *genTensors(T_BackendContex inline void initConsts(const ir::Operands &operands, const util::Set &external_operands, ITensorRegistry *tensor_registry, - const ir::OperandIndexMap & /*shared_memory_operands_map*/) + const ir::OperandIndexMap &shared_memory_operands_map) { operands.iterate([&](const ir::OperandIndex &ind, const ir::Operand &operand) { - if (external_operands.contains(ind) || !operand.isConstant()) + const bool has_const_shared_memory = + shared_memory_operands_map.find(ind) != std::end(shared_memory_operands_map) && + operands.at(shared_memory_operands_map.at(ind)).isConstant(); + const bool can_be_initialized_as_const = operand.isConstant() || has_const_shared_memory; + if (external_operands.contains(ind) || !can_be_initialized_as_const) return; auto tensor = tensor_registry->getNativeITensor(ind); @@ -230,14 +249,23 @@ inline void initConsts(const ir::Operands &operands, VERBOSE(FillOperandData) << "Fill data for " << ind << std::endl; - auto data = operand.shareData(); - assert(data && data->base()); ExternalTensor *ext_tensor = dynamic_cast(tensor); - if (ext_tensor == nullptr) throw std::runtime_error{"This tensor is not external tensor"}; - ext_tensor->setData(data); + if (has_const_shared_memory) + { + const auto &source_operand_ind = operands.at(shared_memory_operands_map.at(ind)); + auto memory_source_data = source_operand_ind.shareData(); + assert(memory_source_data && memory_source_data->base()); + ext_tensor->setData(memory_source_data); + } + else + { + auto data = operand.shareData(); + assert(data && data->base()); + ext_tensor->setData(data); + } }); } diff --git a/runtime/onert/core/include/backend/basic/StaticTensorManager.h b/runtime/onert/core/include/backend/basic/StaticTensorManager.h index a92af7bd45d..f9157cb2a42 100644 --- a/runtime/onert/core/include/backend/basic/StaticTensorManager.h +++ b/runtime/onert/core/include/backend/basic/StaticTensorManager.h @@ -60,6 +60,7 @@ class StaticTensorManager ir::OperandIndexMap _as_constants; DynamicTensorManager *_dynamic_tensor_manager; ir::OperandIndexMap _shared_memory_operand_indexes; + ir::OperandIndexMap _source_operand_inds_ref_counter; }; } // namespace basic diff --git a/runtime/onert/core/src/backend/basic/StaticTensorManager.cc b/runtime/onert/core/src/backend/basic/StaticTensorManager.cc index 2e5fadd8d37..f6f69d6af06 100644 --- a/runtime/onert/core/src/backend/basic/StaticTensorManager.cc +++ b/runtime/onert/core/src/backend/basic/StaticTensorManager.cc @@ -14,6 +14,8 @@ * limitations under the License. */ +#include + #include "backend/basic/StaticTensorManager.h" #include "backend/basic/DynamicTensorManager.h" @@ -54,13 +56,28 @@ void StaticTensorManager::allocateNonconsts(void) for (auto &&[ind, tensor] : _tensors->native_tensors()) { - if (!_as_constants[ind] && !tensor->is_dynamic()) + bool buffer_set = false; + if (!tensor->is_dynamic()) { - auto *buffer = _nonconst_mgr->getBuffer(ind); - tensor->setBuffer(buffer); - - VERBOSE(CPU_StaticTensorManager) - << "TENSOR " << ind << " : " << static_cast(buffer) << std::endl; + if (_shared_memory_operand_indexes.find(ind) != std::end(_shared_memory_operand_indexes)) + { + const auto &shared_memory_ind = _shared_memory_operand_indexes[ind]; + if (!_as_constants[shared_memory_ind]) + { + tensor->setBuffer(_nonconst_mgr->getBuffer(shared_memory_ind)); + buffer_set = true; + } + } + else if (!_as_constants[ind]) + { + tensor->setBuffer(_nonconst_mgr->getBuffer(ind)); + buffer_set = true; + } + if (buffer_set) + { + VERBOSE(CPU_StaticTensorManager) + << "TENSOR " << ind << " : " << static_cast(tensor->buffer()) << std::endl; + } } } } @@ -71,17 +88,30 @@ void StaticTensorManager::buildTensor(const ir::OperandIndex &ind, const ir::OperandInfo &tensor_info, bool as_const) { assert(!_tensors->getNativeTensor(ind)); + std::unique_ptr tensor = nullptr; if (as_const) { - auto tensor = std::make_unique(tensor_info); - _tensors->setNativeTensor(ind, std::move(tensor)); + tensor = std::make_unique(tensor_info); } else { - auto tensor = - std::make_unique(tensor_info, _dynamic_tensor_manager->dynamic_mem_mgr().get()); - _tensors->setNativeTensor(ind, std::move(tensor)); + const auto source_operand_ind = _shared_memory_operand_indexes.find(ind); + if (source_operand_ind != std::end(_shared_memory_operand_indexes) && + _as_constants[source_operand_ind->second]) + { + as_const = _as_constants[source_operand_ind->second]; + auto new_tensor_info = tensor_info; + new_tensor_info.setAsConstant(); + tensor = std::make_unique(new_tensor_info); + } + else + { + tensor = + std::make_unique(tensor_info, _dynamic_tensor_manager->dynamic_mem_mgr().get()); + } } + assert(tensor); + _tensors->setNativeTensor(ind, std::move(tensor)); _as_constants[ind] = as_const; } @@ -92,8 +122,26 @@ void StaticTensorManager::claimPlan(const ir::OperandIndex &ind, uint32_t size) // This method is called only when a tensor has proper shape assert(!_tensors->getNativeTensor(ind)->is_dynamic()); - if (!_as_constants[ind]) - _nonconst_mgr->claimPlan(ind, size); + ir::OperandIndex claim_ind; + const auto source_ind = _shared_memory_operand_indexes.find(ind); + if (source_ind == std::end(_shared_memory_operand_indexes)) + { + claim_ind = ind; + } + else + { + claim_ind = source_ind->second; + } + if (_as_constants[claim_ind]) + { + return; + } + ++_source_operand_inds_ref_counter[claim_ind]; + // notify only first usage + if (1 == _source_operand_inds_ref_counter[claim_ind]) + { + _nonconst_mgr->claimPlan(claim_ind, size); + } } void StaticTensorManager::releasePlan(const ir::OperandIndex &ind) @@ -103,8 +151,29 @@ void StaticTensorManager::releasePlan(const ir::OperandIndex &ind) // This method is called only when a tensor has proper shape assert(!_tensors->getNativeTensor(ind)->is_dynamic()); - if (!_as_constants[ind]) - _nonconst_mgr->releasePlan(ind); + ir::OperandIndex release_ind; + const auto source_operand_ind_ind = _shared_memory_operand_indexes.find(ind); + if (source_operand_ind_ind == std::end(_shared_memory_operand_indexes)) + { + release_ind = ind; + } + else + { + release_ind = source_operand_ind_ind->second; + } + if (_as_constants[release_ind]) + { + return; + } + if (_source_operand_inds_ref_counter[release_ind] > 0) + { + --_source_operand_inds_ref_counter[release_ind]; + } + // notify only last usage + if (0 == _source_operand_inds_ref_counter[release_ind]) + { + _nonconst_mgr->releasePlan(release_ind); + } } void StaticTensorManager::iterate(const std::function &fn) diff --git a/tests/nnfw_api/lib/CircleGen.cc b/tests/nnfw_api/lib/CircleGen.cc index 80d1fcfc870..83ab3487761 100644 --- a/tests/nnfw_api/lib/CircleGen.cc +++ b/tests/nnfw_api/lib/CircleGen.cc @@ -582,6 +582,15 @@ uint32_t CircleGen::addOperatorSquare(const OperatorParams ¶ms) circle::BuiltinOptions_SquareOptions, options); } +uint32_t CircleGen::addOperatorSqueeze(const OperatorParams ¶ms, + const std::vector &squeeze_dims) +{ + auto squeeze_dims_vec = _fbb.CreateVector(squeeze_dims.data(), squeeze_dims.size()); + auto options = circle::CreateSqueezeOptions(_fbb, squeeze_dims_vec).Union(); + return addOperatorWithOptions(params, circle::BuiltinOperator_SQUEEZE, + circle::BuiltinOptions_SqueezeOptions, options); +} + uint32_t CircleGen::addOperatorBatchToSpaceND(const OperatorParams ¶ms) { auto options = circle::CreateBatchToSpaceNDOptions(_fbb).Union(); diff --git a/tests/nnfw_api/lib/CircleGen.h b/tests/nnfw_api/lib/CircleGen.h index 6297f415c69..ac95ba9b2e1 100644 --- a/tests/nnfw_api/lib/CircleGen.h +++ b/tests/nnfw_api/lib/CircleGen.h @@ -223,6 +223,8 @@ class CircleGen uint32_t addOperatorSplit(const OperatorParams ¶ms, int32_t num_split); uint32_t addOperatorSqrt(const OperatorParams ¶ms); uint32_t addOperatorSquare(const OperatorParams ¶ms); + uint32_t addOperatorSqueeze(const OperatorParams ¶ms, + const std::vector &squeeze_dims); uint32_t addOperatorStridedSlice(const OperatorParams ¶ms, int32_t begin_mask = 0, int32_t end_mask = 0, int32_t ellipsis_mask = 0, int32_t new_axis_mask = 0, int32_t shrink_axis_mask = 0); diff --git a/tests/nnfw_api/src/GenModelTests/MemorySharingModels.test.cc b/tests/nnfw_api/src/GenModelTests/MemorySharingModels.test.cc new file mode 100644 index 00000000000..787ea53f29a --- /dev/null +++ b/tests/nnfw_api/src/GenModelTests/MemorySharingModels.test.cc @@ -0,0 +1,312 @@ +/* + * 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 "CircleGen.h" +#include "GenModelTest.h" + +TEST_F(GenModelTest, reshape_inference) +{ + CircleGen cgen; + std::vector new_shape_data{2, 2}; + uint32_t new_shape_buf = cgen.addBuffer(new_shape_data); + int input = cgen.addTensor({{4}, circle::TensorType::TensorType_FLOAT32}); + int cos1_out = cgen.addTensor({{4}, circle::TensorType::TensorType_FLOAT32}); + int new_shape = cgen.addTensor({{2}, circle::TensorType::TensorType_INT32, new_shape_buf}); + int reshape_out = cgen.addTensor({{2, 2}, circle::TensorType::TensorType_FLOAT32}); + int cos2_out = cgen.addTensor({{2, 2}, circle::TensorType::TensorType_FLOAT32}); + + cgen.addOperatorCos({{input}, {cos1_out}}); + cgen.addOperatorReshape({{cos1_out, new_shape}, {reshape_out}}, &new_shape_data); + cgen.addOperatorCos({{reshape_out}, {cos2_out}}); + cgen.setInputsAndOutputs({input}, {cos2_out}); + + _context = std::make_unique(cgen.finish()); + _context->addTestCase( + uniformTCD({{1, 2, 3, 4}}, {{0.85755322, 0.91465333, 0.54869613, 0.79387345}})); + _context->setBackends({"cpu"}); + + SUCCEED(); +} + +TEST_F(GenModelTest, expand_dims_inference) +{ + CircleGen cgen; + std::vector axes_data{0, 1}; + uint32_t axes_buf = cgen.addBuffer(axes_data); + int input = cgen.addTensor({{4}, circle::TensorType::TensorType_FLOAT32}); + int cos1_out = cgen.addTensor({{4}, circle::TensorType::TensorType_FLOAT32}); + int axes = cgen.addTensor({{2}, circle::TensorType::TensorType_INT32, axes_buf}); + int expand_dims_out = cgen.addTensor({{1, 1, 2, 2}, circle::TensorType::TensorType_FLOAT32}); + int cos2_out = cgen.addTensor({{1, 1, 2, 2}, circle::TensorType::TensorType_FLOAT32}); + + cgen.addOperatorCos({{input}, {cos1_out}}); + cgen.addOperatorExpandDims({{cos1_out, axes}, {expand_dims_out}}); + cgen.addOperatorCos({{expand_dims_out}, {cos2_out}}); + cgen.setInputsAndOutputs({input}, {cos2_out}); + + _context = std::make_unique(cgen.finish()); + _context->addTestCase( + uniformTCD({{1, 2, 3, 4}}, {{0.85755322, 0.91465333, 0.54869613, 0.79387345}})); + _context->setBackends({"cpu"}); + + SUCCEED(); +} + +TEST_F(GenModelTest, squeeze_inference) +{ + CircleGen cgen; + const std::vector squeeze_dims{0, 2}; + int input = cgen.addTensor({{1, 2, 1, 2}, circle::TensorType::TensorType_FLOAT32}); + int cos1_out = cgen.addTensor({{1, 2, 1, 2}, circle::TensorType::TensorType_FLOAT32}); + int squeeze_out = cgen.addTensor({{2, 2}, circle::TensorType::TensorType_FLOAT32}); + int cos2_out = cgen.addTensor({{2, 2}, circle::TensorType::TensorType_FLOAT32}); + + cgen.addOperatorCos({{input}, {cos1_out}}); + cgen.addOperatorSqueeze({{cos1_out}, {squeeze_out}}, squeeze_dims); + cgen.addOperatorCos({{squeeze_out}, {cos2_out}}); + cgen.setInputsAndOutputs({input}, {cos2_out}); + + _context = std::make_unique(cgen.finish()); + _context->addTestCase( + uniformTCD({{1, 2, 3, 4}}, {{0.85755322, 0.91465333, 0.54869613, 0.79387345}})); + _context->setBackends({"cpu"}); + + SUCCEED(); +} + +TEST_F(GenModelTest, reshape_const_input_inference) +{ + CircleGen cgen; + std::vector new_shape_data{2, 2}; + uint32_t new_shape_buf = cgen.addBuffer(new_shape_data); + std::vector reshape_in_data{1, 2, 3, 4}; + uint32_t reshape_in_buf = cgen.addBuffer(reshape_in_data); + int reshape_input = cgen.addTensor({{4}, circle::TensorType::TensorType_FLOAT32, reshape_in_buf}); + int new_shape = cgen.addTensor({{2}, circle::TensorType::TensorType_INT32, new_shape_buf}); + int reshape_out = cgen.addTensor({{2, 2}, circle::TensorType::TensorType_FLOAT32}); + int cos_out = cgen.addTensor({{2, 2}, circle::TensorType::TensorType_FLOAT32}); + + cgen.addOperatorReshape({{reshape_input, new_shape}, {reshape_out}}, &new_shape_data); + cgen.addOperatorCos({{reshape_out}, {cos_out}}); + cgen.setInputsAndOutputs({}, {cos_out}); + + _context = std::make_unique(cgen.finish()); + _context->addTestCase( + uniformTCD({}, {{0.54030231, -0.41614684, -0.9899925, -0.65364362}})); + _context->setBackends({"cpu"}); + + SUCCEED(); +} + +TEST_F(GenModelTest, reshape_dynamic_output) +{ + CircleGen cgen; + int cast_in = cgen.addTensor({{4}, circle::TensorType::TensorType_INT32}); + int cast_out = cgen.addTensor({{4}, circle::TensorType::TensorType_FLOAT32}); + int new_shape = cgen.addTensor({{2}, circle::TensorType::TensorType_INT32}); + int reshape_out = cgen.addTensor({{}, circle::TensorType::TensorType_FLOAT32}); + int cast2_out = cgen.addTensor({{2, 2}, circle::TensorType::TensorType_INT32}); + + cgen.addOperatorCast({{cast_in}, {cast_out}}, circle::TensorType::TensorType_INT32, + circle::TensorType::TensorType_FLOAT32); + cgen.addOperatorReshape({{cast_out, new_shape}, {reshape_out}}); + cgen.addOperatorCast({{reshape_out}, {cast2_out}}, circle::TensorType::TensorType_FLOAT32, + circle::TensorType::TensorType_INT32); + cgen.setInputsAndOutputs({cast_in, new_shape}, {cast2_out}); + + _context = std::make_unique(cgen.finish()); + _context->addTestCase(uniformTCD({{1, 2, 3, 4}, {2, 2}}, {{1, 2, 3, 4}})); + _context->setBackends({"cpu"}); + + SUCCEED(); +} + +TEST_F(GenModelTest, reshape_input_used_in_many_places_inference) +{ + CircleGen cgen; + std::vector new_shape_data{2, 2}; + uint32_t new_shape_buf = cgen.addBuffer(new_shape_data); + int input = cgen.addTensor({{4}, circle::TensorType::TensorType_FLOAT32}); + int cos1_out = cgen.addTensor({{4}, circle::TensorType::TensorType_FLOAT32}); + int new_shape = cgen.addTensor({{2}, circle::TensorType::TensorType_INT32, new_shape_buf}); + int reshape_out = cgen.addTensor({{2, 2}, circle::TensorType::TensorType_FLOAT32}); + int cos2_out = cgen.addTensor({{2, 2}, circle::TensorType::TensorType_FLOAT32}); + int cos3_out = cgen.addTensor({{2, 2}, circle::TensorType::TensorType_FLOAT32}); + + cgen.addOperatorCos({{input}, {cos1_out}}); + cgen.addOperatorReshape({{cos1_out, new_shape}, {reshape_out}}, &new_shape_data); + cgen.addOperatorCos({{reshape_out}, {cos2_out}}); + cgen.addOperatorCos({{cos1_out}, {cos3_out}}); + cgen.setInputsAndOutputs({input}, {cos2_out, cos3_out}); + + _context = std::make_unique(cgen.finish()); + _context->addTestCase( + uniformTCD({{1, 2, 3, 4}}, {{0.85755322, 0.91465333, 0.54869613, 0.79387345}, + {0.85755322, 0.91465333, 0.54869613, 0.79387345}})); + _context->setBackends({"cpu"}); + + SUCCEED(); +} + +TEST_F(GenModelTest, reshape_output_used_in_many_places_inference) +{ + CircleGen cgen; + std::vector new_shape_data{2, 2}; + uint32_t new_shape_buf = cgen.addBuffer(new_shape_data); + int input = cgen.addTensor({{4}, circle::TensorType::TensorType_FLOAT32}); + int cos1_out = cgen.addTensor({{4}, circle::TensorType::TensorType_FLOAT32}); + int new_shape = cgen.addTensor({{2}, circle::TensorType::TensorType_INT32, new_shape_buf}); + int reshape_out = cgen.addTensor({{2, 2}, circle::TensorType::TensorType_FLOAT32}); + int cos2_out = cgen.addTensor({{2, 2}, circle::TensorType::TensorType_FLOAT32}); + int cos3_out = cgen.addTensor({{2, 2}, circle::TensorType::TensorType_FLOAT32}); + + cgen.addOperatorCos({{input}, {cos1_out}}); + cgen.addOperatorReshape({{cos1_out, new_shape}, {reshape_out}}, &new_shape_data); + cgen.addOperatorCos({{reshape_out}, {cos2_out}}); + cgen.addOperatorCos({{reshape_out}, {cos3_out}}); + cgen.setInputsAndOutputs({input}, {cos2_out, cos3_out}); + + _context = std::make_unique(cgen.finish()); + _context->addTestCase( + uniformTCD({{1, 2, 3, 4}}, {{0.85755322, 0.91465333, 0.54869613, 0.79387345}, + {0.85755322, 0.91465333, 0.54869613, 0.79387345}})); + _context->setBackends({"cpu"}); + + SUCCEED(); +} + +TEST_F(GenModelTest, reshape_reshape_chain_inference) +{ + CircleGen cgen; + std::vector new_shape_data{2, 2}; + uint32_t new_shape_buf = cgen.addBuffer(new_shape_data); + int input = cgen.addTensor({{4}, circle::TensorType::TensorType_FLOAT32}); + int cos1_out = cgen.addTensor({{4}, circle::TensorType::TensorType_FLOAT32}); + int new_shape = cgen.addTensor({{2}, circle::TensorType::TensorType_INT32, new_shape_buf}); + int reshape1_out = cgen.addTensor({{2, 2}, circle::TensorType::TensorType_FLOAT32}); + int reshape2_out = cgen.addTensor({{2, 2}, circle::TensorType::TensorType_FLOAT32}); + int cos2_out = cgen.addTensor({{2, 2}, circle::TensorType::TensorType_FLOAT32}); + + cgen.addOperatorCos({{input}, {cos1_out}}); + cgen.addOperatorReshape({{cos1_out, new_shape}, {reshape1_out}}, &new_shape_data); + cgen.addOperatorReshape({{reshape1_out, new_shape}, {reshape2_out}}, &new_shape_data); + cgen.addOperatorCos({{reshape2_out}, {cos2_out}}); + cgen.setInputsAndOutputs({input}, {cos2_out}); + + _context = std::make_unique(cgen.finish()); + _context->addTestCase( + uniformTCD({{1, 2, 3, 4}}, {{0.85755322, 0.91465333, 0.54869613, 0.79387345}})); + _context->setBackends({"cpu"}); + + SUCCEED(); +} + +TEST_F(GenModelTest, reshape_reshape_reshape_chain_inference) +{ + CircleGen cgen; + std::vector new_shape_data{2, 2}; + uint32_t new_shape_buf = cgen.addBuffer(new_shape_data); + int input = cgen.addTensor({{4}, circle::TensorType::TensorType_FLOAT32}); + int cos1_out = cgen.addTensor({{4}, circle::TensorType::TensorType_FLOAT32}); + int new_shape = cgen.addTensor({{2}, circle::TensorType::TensorType_INT32, new_shape_buf}); + int reshape1_out = cgen.addTensor({{2, 2}, circle::TensorType::TensorType_FLOAT32}); + int reshape2_out = cgen.addTensor({{2, 2}, circle::TensorType::TensorType_FLOAT32}); + int reshape3_out = cgen.addTensor({{2, 2}, circle::TensorType::TensorType_FLOAT32}); + int cos2_out = cgen.addTensor({{2, 2}, circle::TensorType::TensorType_FLOAT32}); + + cgen.addOperatorCos({{input}, {cos1_out}}); + cgen.addOperatorReshape({{cos1_out, new_shape}, {reshape1_out}}, &new_shape_data); + cgen.addOperatorReshape({{reshape1_out, new_shape}, {reshape2_out}}, &new_shape_data); + cgen.addOperatorReshape({{reshape2_out, new_shape}, {reshape3_out}}, &new_shape_data); + cgen.addOperatorCos({{reshape3_out}, {cos2_out}}); + cgen.setInputsAndOutputs({input}, {cos2_out}); + + _context = std::make_unique(cgen.finish()); + _context->addTestCase( + uniformTCD({{1, 2, 3, 4}}, {{0.85755322, 0.91465333, 0.54869613, 0.79387345}})); + _context->setBackends({"cpu"}); + + SUCCEED(); +} + +TEST_F(GenModelTest, reshape_input_model_input_inference) +{ + CircleGen cgen; + std::vector new_shape_data{2, 2}; + uint32_t new_shape_buf = cgen.addBuffer(new_shape_data); + int input = cgen.addTensor({{4}, circle::TensorType::TensorType_FLOAT32}); + int new_shape = cgen.addTensor({{2}, circle::TensorType::TensorType_INT32, new_shape_buf}); + int output = cgen.addTensor({{2, 2}, circle::TensorType::TensorType_FLOAT32}); + + cgen.addOperatorReshape({{input, new_shape}, {output}}, &new_shape_data); + cgen.setInputsAndOutputs({input}, {output}); + + _context = std::make_unique(cgen.finish()); + _context->addTestCase(uniformTCD({{1, 2, 3, 4}}, {{1, 2, 3, 4}})); + _context->setBackends({"cpu"}); + + SUCCEED(); +} + +TEST_F(GenModelTest, reshape_input_model_output_inference) +{ + CircleGen cgen; + std::vector new_shape_data{2, 2}; + uint32_t new_shape_buf = cgen.addBuffer(new_shape_data); + int input = cgen.addTensor({{4}, circle::TensorType::TensorType_FLOAT32}); + int cos1_out = cgen.addTensor({{4}, circle::TensorType::TensorType_FLOAT32}); + int new_shape = cgen.addTensor({{2}, circle::TensorType::TensorType_INT32, new_shape_buf}); + int reshape_out = cgen.addTensor({{2, 2}, circle::TensorType::TensorType_FLOAT32}); + int cos2_out = cgen.addTensor({{2, 2}, circle::TensorType::TensorType_FLOAT32}); + + cgen.addOperatorCos({{input}, {cos1_out}}); + cgen.addOperatorReshape({{cos1_out, new_shape}, {reshape_out}}, &new_shape_data); + cgen.addOperatorCos({{reshape_out}, {cos2_out}}); + cgen.setInputsAndOutputs({input}, {cos1_out, cos2_out}); + + _context = std::make_unique(cgen.finish()); + _context->addTestCase( + uniformTCD({{1, 2, 3, 4}}, {{0.54030231, -0.41614684, -0.9899925, -0.65364362}, + {0.85755322, 0.91465333, 0.54869613, 0.79387345}})); + _context->setBackends({"cpu"}); + + SUCCEED(); +} + +TEST_F(GenModelTest, reshape_output_model_output_inference) +{ + CircleGen cgen; + std::vector new_shape_data{2, 2}; + uint32_t new_shape_buf = cgen.addBuffer(new_shape_data); + int input = cgen.addTensor({{4}, circle::TensorType::TensorType_FLOAT32}); + int cos1_out = cgen.addTensor({{4}, circle::TensorType::TensorType_FLOAT32}); + int new_shape = cgen.addTensor({{2}, circle::TensorType::TensorType_INT32, new_shape_buf}); + int reshape_out = cgen.addTensor({{2, 2}, circle::TensorType::TensorType_FLOAT32}); + + cgen.addOperatorCos({{input}, {cos1_out}}); + cgen.addOperatorReshape({{cos1_out, new_shape}, {reshape_out}}, &new_shape_data); + cgen.setInputsAndOutputs({input}, {reshape_out}); + + _context = std::make_unique(cgen.finish()); + _context->addTestCase( + uniformTCD({{1, 2, 3, 4}}, {{0.54030231, -0.41614684, -0.9899925, -0.65364362}})); + _context->setBackends({"cpu"}); + + SUCCEED(); +}