diff options
Diffstat (limited to 'runtimes/neurun')
230 files changed, 8449 insertions, 4966 deletions
diff --git a/runtimes/neurun/CMakeLists.txt b/runtimes/neurun/CMakeLists.txt index 2cbd702b0..92547da2c 100644 --- a/runtimes/neurun/CMakeLists.txt +++ b/runtimes/neurun/CMakeLists.txt @@ -18,29 +18,23 @@ file(GLOB SOURCES_BACKEND "src/backend/*.cc") file(GLOB_RECURSE SOURCES_INTERNAL "src/internal/*.cc") file(GLOB_RECURSE SOURCES_GRAPH "src/graph/*.cc") file(GLOB_RECURSE SOURCES_LINEAR "src/linear/*.cc") -file(GLOB_RECURSE SOURCES_CODEGEN "src/codegen/*.cc") +file(GLOB_RECURSE SOURCES_DUMPER "src/dumper/*.cc") +file(GLOB_RECURSE SOURCES_COMPILER "src/compiler/*.cc") file(GLOB_RECURSE SOURCES_VERIFIER "src/verifier/*.cc") +file(GLOB_RECURSE SOURCES_UTIL "src/util/*.cc") +file(GLOB_RECURSE SOURCES_MODEL "src/model/*.cc") -set(SOURCES ${SOURCES} ${SOURCES_FRONTEND} ${SOURCES_BACKEND} ${SOURCES_INTERNAL} ${SOURCES_GRAPH} ${SOURCES_LINEAR} ${SOURCES_CODEGEN} ${SOURCES_VERIFIER}) - -# NOTE For now ARMCompute is necessary -# TODO Remove required package below(should be optional) -nnfw_find_package(ARMCompute REQUIRED) +set(SOURCES ${SOURCES} ${SOURCES_FRONTEND} ${SOURCES_BACKEND} ${SOURCES_INTERNAL} ${SOURCES_GRAPH} ${SOURCES_LINEAR} ${SOURCES_DUMPER} ${SOURCES_COMPILER} ${SOURCES_VERIFIER} ${SOURCES_UTIL} ${SOURCES_MODEL}) add_library(${LIB_NEURUN} SHARED ${SOURCES}) target_include_directories(${LIB_NEURUN} PUBLIC ${NNFW_INCLUDE_DIR}) target_include_directories(${LIB_NEURUN} PUBLIC ${NEURUN_INCLUDE_DIR}) target_include_directories(${LIB_NEURUN} PUBLIC ${CMAKE_SOURCE_DIR}/externals/tensorflow) -target_link_libraries(${LIB_NEURUN} arm_compute) target_link_libraries(${LIB_NEURUN} tensorflow-lite) -target_link_libraries(${LIB_NEURUN} nnfw_util) -target_link_libraries(${LIB_NEURUN} nnfw_support_nnapi) - -# TODO This should be optional -target_link_libraries(${LIB_NEURUN} ${LIB_NEURUN_BACKEND_CPU}) -target_link_libraries(${LIB_NEURUN} ${LIB_NEURUN_BACKEND_ACL_CL}) +target_link_libraries(${LIB_NEURUN} nnfw_lib_misc) +target_link_libraries(${LIB_NEURUN} nnfw_lib_cpp14) -target_compile_options(${LIB_NEURUN} PRIVATE -Wall -Wextra -Werror) +target_compile_options(${LIB_NEURUN} PRIVATE -Wall -Wextra -Werror -Wno-unused-parameter) set_target_properties(${LIB_NEURUN} PROPERTIES OUTPUT_NAME neuralnetworks) @@ -58,6 +52,8 @@ target_link_libraries(${TEST_NEURUN} ${LIB_NEURUN}) target_link_libraries(${TEST_NEURUN} gtest) target_link_libraries(${TEST_NEURUN} gtest_main) target_link_libraries(${TEST_NEURUN} ${LIB_PTHREAD}) +target_link_libraries(${TEST_NEURUN} ${LIB_NEURUN_BACKEND_CPU}) +target_link_libraries(${TEST_NEURUN} ${LIB_NEURUN_BACKEND_ACL_CL}) add_test(${TEST_NEURUN} ${TEST_NEURUN}) install(TARGETS ${TEST_NEURUN} DESTINATION unittest) diff --git a/runtimes/neurun/src/backend/BackendManager.cc b/runtimes/neurun/src/backend/BackendManager.cc index fb7d69108..5d19d4015 100644 --- a/runtimes/neurun/src/backend/BackendManager.cc +++ b/runtimes/neurun/src/backend/BackendManager.cc @@ -14,36 +14,28 @@ * limitations under the License. */ +#include <dlfcn.h> #include "BackendManager.h" -#include "backend/acl_cl/BackendConfig.h" -#include "backend/acl_cl/TensorBuilder.h" -#include "backend/acl_cl/InitializerGenerator.h" -#include "backend/acl_cl/StageGenerator.h" -#include "backend/cpu/BackendConfig.h" -#include "backend/cpu/TensorBuilder.h" -#include "backend/cpu/InitializerGenerator.h" -#include "backend/cpu/StageGenerator.h" +#include "backend/interface/IConfig.h" +#include "backend/interface/ITensorBuilder.h" +#include "backend/interface/IStageGenerator.h" +#include "util/logging.h" +#include "util/config/ConfigManager.h" namespace neurun { namespace backend { -Backend::Backend(const std::shared_ptr<neurun::backend::IBackendConfig> &backend_config, - const std::shared_ptr<neurun::backend::IInitializerGenerator> &initializer_gen, +Backend::Backend(const std::shared_ptr<neurun::backend::IConfig> &backend_config, const std::shared_ptr<neurun::backend::IStageGenerator> &stage_gen) - : _config(backend_config), _initializer_gen(initializer_gen), _stage_gen(stage_gen) + : _config(backend_config), _stage_gen(stage_gen) { backend_config->initialize(); } -const std::shared_ptr<neurun::backend::IBackendConfig> Backend::config() const { return _config; } - -const std::shared_ptr<neurun::backend::IInitializerGenerator> Backend::initializer_gen() const -{ - return _initializer_gen; -} +const std::shared_ptr<neurun::backend::IConfig> Backend::config() const { return _config; } const std::shared_ptr<neurun::backend::IStageGenerator> Backend::stage_gen() const { @@ -55,34 +47,72 @@ const std::shared_ptr<neurun::backend::ITensorBuilder> Backend::tensor_builder() return _stage_gen->tensor_builder(); } -BackendManager::BackendManager(const neurun::graph::operand::Set &operands) +template <typename T, class... Types> +void BackendManager::loadObjectFromPlugin(std::shared_ptr<T> &object_of_plugin_class, + const std::string obj_creator_func_name, void *handle, + Types &&... args) +{ + T *(*allocate_obj)(Types && ... Args); + // load object creator function + allocate_obj = (T * (*)(Types && ... Args))dlsym(handle, obj_creator_func_name.c_str()); + if (allocate_obj == nullptr) + { + fprintf(stderr, "BackendManager: unable to open function %s: %s\n", + obj_creator_func_name.c_str(), dlerror()); + abort(); + } + + object_of_plugin_class.reset(allocate_obj(args...)); +} + +void BackendManager::loadBackend(const std::string &backend, + const neurun::model::operand::Set &operands) { - // Add arm_compute backend + const std::string backend_plugin = "libbackend_" + backend + ".so"; + void *handle = dlopen(backend_plugin.c_str(), RTLD_LAZY | RTLD_LOCAL); + if (handle == nullptr) { - using namespace ::neurun::backend::acl_cl; - auto acl_backend_initializer = std::make_shared<BackendConfig>(); - auto acl_tensor_builder = std::make_shared<TensorBuilder>(); - auto acl_initializer_gen = std::make_shared<InitializerGenerator>(operands); - auto acl_stage_gen = std::make_shared<StageGenerator>(operands, acl_tensor_builder); - - // TODO Do not use magic string for backend id - _gen_map["acl_cl"] = {acl_backend_initializer, acl_initializer_gen, acl_stage_gen}; + fprintf(stderr, "BackendManager::loadBackend failed to load plugin of %s backend: %s\n", + backend.c_str(), dlerror()); + abort(); } + VERBOSE(BackendManager::loadBackend) << "loaded " << backend_plugin << " as a plugin of " + << backend << " backend\n"; + + // load Config + std::shared_ptr<neurun::backend::IConfig> config; + loadObjectFromPlugin(config, std::string("allocate_Config"), handle); + + // load TensorBuilder + std::shared_ptr<neurun::backend::ITensorBuilder> tensor_builder; + loadObjectFromPlugin(tensor_builder, std::string("allocate_TensorBuilder"), handle); + + // load StageGenerator + std::shared_ptr<neurun::backend::IStageGenerator> stage_gen; + loadObjectFromPlugin(stage_gen, std::string("allocate_StageGenerator"), handle, operands, + tensor_builder); + _gen_map[config->id()] = {config, stage_gen}; +} - // Add CPU backend +BackendManager::BackendManager(const neurun::model::operand::Set &operands) +{ + const auto backends = config::ConfigManager::instance().get<std::string>("BACKENDS"); + size_t prev_pos = 0; + auto pos = backends.find(";"); + while (pos != std::string::npos) + { + loadBackend(backends.substr(prev_pos, pos - prev_pos), operands); + prev_pos = pos + 1; + pos = backends.find(";", prev_pos); + } + // if backends doesn't terminate with ";" + if (prev_pos < backends.size()) { - using namespace ::neurun::backend::cpu; - auto cpu_backend_initializer = std::make_shared<BackendConfig>(); - auto cpu_tensor_builder = std::make_shared<TensorBuilder>(); - auto cpu_initializer_gen = std::make_shared<InitializerGenerator>(operands); - auto cpu_stage_gen = std::make_shared<StageGenerator>(operands, cpu_tensor_builder); - - // TODO Do not use magic string for backend id - _gen_map["cpu"] = {cpu_backend_initializer, cpu_initializer_gen, cpu_stage_gen}; + loadBackend(backends.substr(prev_pos), operands); } } -Backend BackendManager::get(const std::string &key) { return _gen_map.at(key); } +Backend *BackendManager::get(const std::string &key) { return &_gen_map.at(key); } } // namespace backend } // namespace neurun diff --git a/runtimes/neurun/src/backend/BackendManager.h b/runtimes/neurun/src/backend/BackendManager.h index 6f862ffe6..428542b1e 100644 --- a/runtimes/neurun/src/backend/BackendManager.h +++ b/runtimes/neurun/src/backend/BackendManager.h @@ -20,51 +20,72 @@ #include <memory> #include <map> -#include "graph/operand/Set.h" +#include "model/operand/Set.h" namespace neurun { namespace backend { -struct IBackendConfig; -struct IInitializerGenerator; +struct IConfig; struct IStageGenerator; struct ITensorBuilder; class Backend { public: - Backend(const std::shared_ptr<neurun::backend::IBackendConfig> &backend_config, - const std::shared_ptr<neurun::backend::IInitializerGenerator> &initializer_gen, + Backend(const std::shared_ptr<neurun::backend::IConfig> &backend_config, const std::shared_ptr<neurun::backend::IStageGenerator> &stage_gen); - Backend(void) : _config(nullptr), _initializer_gen(nullptr), _stage_gen(nullptr) + Backend(void) : _config(nullptr), _stage_gen(nullptr) { // DO NOTHING } public: - const std::shared_ptr<neurun::backend::IBackendConfig> config() const; - const std::shared_ptr<neurun::backend::IInitializerGenerator> initializer_gen() const; + const std::shared_ptr<neurun::backend::IConfig> config() const; const std::shared_ptr<neurun::backend::IStageGenerator> stage_gen() const; const std::shared_ptr<neurun::backend::ITensorBuilder> tensor_builder() const; private: - std::shared_ptr<neurun::backend::IBackendConfig> _config; - std::shared_ptr<neurun::backend::IInitializerGenerator> _initializer_gen; + std::shared_ptr<neurun::backend::IConfig> _config; std::shared_ptr<neurun::backend::IStageGenerator> _stage_gen; }; class BackendManager { public: - BackendManager(const neurun::graph::operand::Set &operands); + BackendManager(const neurun::model::operand::Set &operands); - Backend get(const std::string &key); + Backend *get(const std::string &key); private: std::map<std::string, Backend> _gen_map; + /** + * @brief Allocate an object of a class of a plugin by loading a plugin function, that does + * allocation, and calling it + * + * @param object_of_plugin_class target object + * @param obj_creator_func_name name of the plugin function, that allocates an object + * @param handle handle of the plugin + * @param args arguments to pass to constructor of the plugin class + * + * @return + */ + template <typename T, class... Types> + void loadObjectFromPlugin(std::shared_ptr<T> &object_of_plugin_class, + const std::string obj_creator_func_name, void *handle, + Types &&... args); + + /** + * @brief load backend plugin + * + * @param backend backend to be loaded + * @param operands operands to construct StageGenerator + * + * @return + */ + void loadBackend(const std::string &backend, const neurun::model::operand::Set &operands); }; } // namespace backend diff --git a/runtimes/neurun/src/backend/IInitializerGenerator.h b/runtimes/neurun/src/backend/IInitializerGenerator.h deleted file mode 100644 index 83cf87a52..000000000 --- a/runtimes/neurun/src/backend/IInitializerGenerator.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2018 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 __INTERNAL_IINITIALIZER_GENERATOR_H__ -#define __INTERNAL_IINITIALIZER_GENERATOR_H__ - -#include "arm_compute/core/ITensor.h" - -#include "graph/operation/Conv2D.h" -#include "graph/operation/FullyConnected.h" - -using Initializer = std::function<void(::arm_compute::ITensor &)>; - -namespace neurun -{ -namespace backend -{ - -struct IInitializerGenerator -{ - virtual ~IInitializerGenerator() = default; - - virtual Initializer generateWeight(const graph::operation::Conv2D::Implicit::Node &node) = 0; - virtual Initializer generateWeight(const graph::operation::FullyConnected::Node &node) = 0; - - virtual Initializer generateBias(const graph::operation::Conv2D::Implicit::Node &node) = 0; - virtual Initializer generateBias(const graph::operation::FullyConnected::Node &node) = 0; -}; - -} // namespace backend -} // namespace neurun - -#endif // __INTERNAL_IINITIALIZER_GENERATOR_H__ diff --git a/runtimes/neurun/src/backend/IStageGenerator.h b/runtimes/neurun/src/backend/IStageGenerator.h deleted file mode 100644 index 05959e2b1..000000000 --- a/runtimes/neurun/src/backend/IStageGenerator.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2018 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 __INTERNAL_ISTAGE_GENERATOR_H__ -#define __INTERNAL_ISTAGE_GENERATOR_H__ - -#include <memory> -#include <functional> - -#include <arm_compute/runtime/IFunction.h> - -#include "backend/ITensorBuilder.h" -#include "graph/operation/Conv2D.h" -#include "graph/operation/MaxPool2D.h" -#include "graph/operation/AvgPool2D.h" -#include "graph/operation/Concat.h" -#include "graph/operation/FullyConnected.h" -#include "graph/operation/Reshape.h" -#include "graph/operation/Softmax.h" -#include "graph/operation/NOP.h" - -struct IExecutionBuilder -{ - virtual ~IExecutionBuilder() = default; - - virtual void append(std::unique_ptr<::arm_compute::IFunction> &&f) = 0; -}; - -using Stage = std::function<void(IExecutionBuilder &)>; - -namespace neurun -{ -namespace backend -{ - -struct IStageGenerator -{ - virtual ~IStageGenerator() = default; - - virtual std::shared_ptr<ITensorBuilder> tensor_builder() = 0; - - virtual Stage generate(const graph::operation::Conv2D::Implicit::Node &node) = 0; - virtual Stage generate(const graph::operation::MaxPool2D::Implicit::Node &node) = 0; - virtual Stage generate(const graph::operation::AvgPool2D::Implicit::Node &node) = 0; - virtual Stage generate(const graph::operation::Concat::Node &node) = 0; - virtual Stage generate(const graph::operation::FullyConnected::Node &node) = 0; - virtual Stage generate(const graph::operation::Reshape::Node &node) = 0; - virtual Stage generate(const graph::operation::Softmax::Node &node) = 0; - virtual Stage generate(const graph::operation::NOP::Node &node) = 0; -}; - -} // namespace backend -} // namespace neurun - -#endif // __INTERNAL_ISTAGE_GENERATOR_H__ diff --git a/runtimes/neurun/src/backend/ITensorBuilder.h b/runtimes/neurun/src/backend/ITensorBuilder.h deleted file mode 100644 index c3a07ffeb..000000000 --- a/runtimes/neurun/src/backend/ITensorBuilder.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2018 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 __INTERNAL_ITENSOR_BUILDER_H__ -#define __INTERNAL_ITENSOR_BUILDER_H__ - -#include <map> -#include <arm_compute/core/TensorInfo.h> - -#include "graph/operand/Index.h" -#include "codegen/Plan.h" - -namespace neurun -{ -namespace backend -{ - -struct ITensorBuilder -{ - virtual ~ITensorBuilder(void) = default; - virtual void mark(const ::neurun::graph::operand::Index &ind) = 0; - // TODO Add an interface for adding subsumption info - virtual void prepare(codegen::Plan &plan, - const std::map<int, ::arm_compute::TensorInfo> &tensor_info_ctx) = 0; - virtual void allocate(void) = 0; -}; - -} // namespace backend -} // namespace neurun - -#include <set> -#include <memory> - -namespace neurun -{ -namespace backend -{ - -using TensorBuilderSet = std::set<std::shared_ptr<backend::ITensorBuilder>>; - -} // namespace backend -} // namespace neurun - -#endif // __INTERNAL_ITENSOR_BUILDER_H__ diff --git a/runtimes/neurun/src/backend/acl_cl/CMakeLists.txt b/runtimes/neurun/src/backend/acl_cl/CMakeLists.txt index d64c23a80..f1ea22bc5 100644 --- a/runtimes/neurun/src/backend/acl_cl/CMakeLists.txt +++ b/runtimes/neurun/src/backend/acl_cl/CMakeLists.txt @@ -1,17 +1,15 @@ file(GLOB_RECURSE SOURCES "*.cc") -add_library(${LIB_NEURUN_BACKEND_ACL_CL} STATIC ${SOURCES}) +add_library(${LIB_NEURUN_BACKEND_ACL_CL} SHARED ${SOURCES}) target_include_directories(${LIB_NEURUN_BACKEND_ACL_CL} PUBLIC ${NNFW_INCLUDE_DIR}) target_include_directories(${LIB_NEURUN_BACKEND_ACL_CL} PUBLIC ${NEURUN_INCLUDE_DIR}) -target_include_directories(${LIB_NEURUN_BACKEND_ACL_CL} PUBLIC ${CMAKE_SOURCE_DIR}/externals/tensorflow) # TODO Remove this file. We should not need this. target_link_libraries(${LIB_NEURUN_BACKEND_ACL_CL} arm_compute) -target_link_libraries(${LIB_NEURUN_BACKEND_ACL_CL} nnfw_support_nnapi) target_link_libraries(${LIB_NEURUN_BACKEND_ACL_CL} ${LIB_NEURUN_KERNEL_ACL_CL}) +target_link_libraries(${LIB_NEURUN_BACKEND_ACL_CL} ${LIB_NEURUN}) -target_compile_options(${LIB_NEURUN_BACKEND_ACL_CL} PRIVATE -Wall -Wextra -Werror) +target_compile_options(${LIB_NEURUN_BACKEND_ACL_CL} PRIVATE -Wall -Wextra -Werror -Wno-unused-parameter) -set_target_properties(${LIB_NEURUN_BACKEND_ACL_CL} PROPERTIES POSITION_INDEPENDENT_CODE ON) set_target_properties(${LIB_NEURUN_BACKEND_ACL_CL} PROPERTIES OUTPUT_NAME backend_acl_cl) install(TARGETS ${LIB_NEURUN_BACKEND_ACL_CL} DESTINATION lib/neurun) diff --git a/runtimes/neurun/src/backend/acl_cl/BackendConfig.cc b/runtimes/neurun/src/backend/acl_cl/Config.cc index 6b3e6b3a3..cad9b8988 100644 --- a/runtimes/neurun/src/backend/acl_cl/BackendConfig.cc +++ b/runtimes/neurun/src/backend/acl_cl/Config.cc @@ -16,7 +16,7 @@ #include <arm_compute/runtime/CL/CLScheduler.h> -#include "backend/acl_cl/BackendConfig.h" +#include "backend/acl_cl/Config.h" namespace neurun { @@ -25,7 +25,7 @@ namespace backend namespace acl_cl { -void BackendConfig::initialize() { arm_compute::CLScheduler::get().default_init(); } +void Config::initialize() { arm_compute::CLScheduler::get().default_init(); } } // namespace acl_cl } // namespace backend diff --git a/runtimes/neurun/src/backend/acl_cl/BackendConfig.h b/runtimes/neurun/src/backend/acl_cl/Config.h index 8eec9e795..cb43bfbe0 100644 --- a/runtimes/neurun/src/backend/acl_cl/BackendConfig.h +++ b/runtimes/neurun/src/backend/acl_cl/Config.h @@ -14,10 +14,10 @@ * limitations under the License. */ -#ifndef __NEURUN_BACKEND_ACL_CL_BACKEND_CONFIG_H__ -#define __NEURUN_BACKEND_ACL_CL_BACKEND_CONFIG_H__ +#ifndef __NEURUN_BACKEND_ACL_CL_CONFIG_H__ +#define __NEURUN_BACKEND_ACL_CL_CONFIG_H__ -#include "backend/IBackendConfig.h" +#include "backend/interface/IConfig.h" namespace neurun { @@ -26,20 +26,22 @@ namespace backend namespace acl_cl { -class BackendConfig : public IBackendConfig +class Config : public IConfig { public: - BackendConfig() + Config() { // DO NOTHING } + virtual std::string id() override { return "acl_cl"; } virtual void initialize() override; virtual graph::operand::Layout getOperandLayout() { return graph::operand::Layout::NCHW; } + virtual bool SupportSubTensorAlloc() override { return true; } }; } // namespace acl_cl } // namespace backend } // namespace neurun -#endif // __NEURUN_BACKEND_ACL_CL_BACKEND_CONFIG_H__ +#endif // __NEURUN_BACKEND_ACL_CL_CONFIG_H__ diff --git a/runtimes/neurun/src/backend/acl_cl/Convert.cc b/runtimes/neurun/src/backend/acl_cl/Convert.cc new file mode 100644 index 000000000..ed0a089c4 --- /dev/null +++ b/runtimes/neurun/src/backend/acl_cl/Convert.cc @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2018 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 "Convert.h" + +#include "Swizzle.h" +#include "model/operand/DataType.h" + +namespace neurun +{ +namespace backend +{ +namespace acl_cl +{ + +::arm_compute::TensorShape asTensorShape(const ::neurun::model::operand::Shape &shape, + bool apply_dim_correction) +{ + const uint32_t rank = shape.rank(); + + ::arm_compute::TensorShape res{}; + + res.set_num_dimensions(rank); + + for (uint32_t axis = 0; axis < rank; ++axis) + { + // NOTE In some cases, in incorrect dimensions is required. + // For example, intput_size is 1 in LSTM. The input-to-input weights([num_units, input_size]) of + // LSTM is used as the weight of the FullyConnected. + // The FullyConnected's weight must be greater or equal than 2-dimensions. + // However, if the dimension correction is applied to input_to_input_weights with input_size + // equal to 1, it will be changed to 1-D. + // So input_to_input_weights is not used by the weight of FullyConnected. + res.set(ToARMComputeAxis(rank, axis).value(), shape.dim(axis), apply_dim_correction); + } + + return res; +} + +::arm_compute::DataType asDataType(const ::neurun::model::operand::DataType &type) +{ + switch (type) + { + case ::neurun::model::operand::DataType::SCALAR_FLOAT32: + case ::neurun::model::operand::DataType::TENSOR_FLOAT32: + return ::arm_compute::DataType::F32; + case ::neurun::model::operand::DataType::SCALAR_INT32: + case ::neurun::model::operand::DataType::TENSOR_INT32: + return ::arm_compute::DataType::S32; + case ::neurun::model::operand::DataType::SCALAR_UINT32: + return ::arm_compute::DataType::U32; + case ::neurun::model::operand::DataType::TENSOR_QUANT8_ASYMM: + return ::arm_compute::DataType::QASYMM8; + default: + throw std::runtime_error("Not supported, yet"); + break; + } +} + +::arm_compute::QuantizationInfo asQuantizationInfo(const float scale, const int32_t offset) +{ + return ::arm_compute::QuantizationInfo(scale, offset); +} + +::arm_compute::TensorInfo asTensorInfo(const ::neurun::model::operand::Shape &shape, + const ::neurun::model::operand::TypeInfo &typeInfo) +{ + return ::arm_compute::TensorInfo(asTensorShape(shape), 1, asDataType(typeInfo.type()), + asQuantizationInfo(typeInfo.scale(), typeInfo.offset())); +} + +} // namespace acl_cl +} // namespace backend +} // namespace neurun diff --git a/runtimes/neurun/src/backend/acl_cl/Convert.h b/runtimes/neurun/src/backend/acl_cl/Convert.h new file mode 100644 index 000000000..1a233fb87 --- /dev/null +++ b/runtimes/neurun/src/backend/acl_cl/Convert.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2018 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 __NEURUN_BACKEND_ACL_CL_CONVERT_H__ +#define __NEURUN_BACKEND_ACL_CL_CONVERT_H__ + +#include <arm_compute/core/TensorInfo.h> +#include <arm_compute/core/SubTensorInfo.h> +#include <arm_compute/core/TensorShape.h> + +#include "model/operand/Object.h" +#include "model/operand/Shape.h" +#include "model/operand/TypeInfo.h" +#include "misc/feature/Shape.h" +#include "misc/kernel/Shape.h" + +namespace neurun +{ +namespace backend +{ +namespace acl_cl +{ + +::arm_compute::TensorShape asTensorShape(const ::neurun::model::operand::Shape &shape, + bool apply_dim_correction = true); +::arm_compute::DataType asDataType(const ::neurun::model::operand::DataType &type); +::arm_compute::TensorInfo asTensorInfo(const ::neurun::model::operand::Shape &shape, + const ::neurun::model::operand::TypeInfo &typeInfo); + +} // namespace acl_cl +} // namespace backend +} // namespace neurun + +#endif // __NEURUN_BACKEND_ACL_CL_CONVERT_H__ diff --git a/runtimes/neurun/src/backend/acl_cl/InitializerGenerator.cc b/runtimes/neurun/src/backend/acl_cl/InitializerGenerator.cc deleted file mode 100644 index 9a681b3de..000000000 --- a/runtimes/neurun/src/backend/acl_cl/InitializerGenerator.cc +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (c) 2018 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 "backend/acl_cl/InitializerGenerator.h" - -#include <arm_compute/core/Coordinates.h> - -#include "backend/acl_cl/kernel/View.h" -#include "internal/nnapi/kernel/Reader.h" -#include "util/kernel/IndexIterator.h" - -namespace neurun -{ -namespace backend -{ -namespace acl_cl -{ - -InitializerGenerator::InitializerGenerator(const neurun::graph::operand::Set &ctx) : _ctx(ctx) -{ - // DO NOTHING -} - -Initializer -InitializerGenerator::generateWeight(const graph::operation::Conv2D::Implicit::Node &node) -{ - const ::neurun::graph::operand::Index ker_index{node.getInputs().at(1)}; - - const auto ker_shape = _ctx.at(ker_index).shape().asKernel(); - auto ker_base = _ctx.at(ker_index).data().base(); - auto ker_size = _ctx.at(ker_index).data().size(); - - return [ker_shape, ker_base, ker_size](::arm_compute::ITensor &tensor) { - const ::internal::nnapi::kernel::Reader<float> from{ker_shape, ker_base, ker_size}; - ::internal::arm_compute::kernel::View<float> into{&tensor}; - - ::nnfw::util::kernel::iterate(ker_shape) - << [&](uint32_t nth, uint32_t ch, uint32_t row, uint32_t col) { - const auto value = from.at(nth, ch, row, col); - into.at(nth, ch, row, col) = value; - }; - }; -} - -Initializer InitializerGenerator::generateWeight(const graph::operation::FullyConnected::Node &node) -{ - const ::neurun::graph::operand::Index weight_index{node.getInputs().at(1)}; - const ::neurun::graph::operand::Index input_index{node.getInputs().at(0)}; - - const auto num_output = _ctx.at(weight_index).shape().dim(0); - auto weight_base = _ctx.at(weight_index).data().base(); - auto weight_size = _ctx.at(weight_index).data().size(); - - // NOTE We assume that input is a feature map - // TODO Remove this restriction! - const auto ifm_shape = _ctx.at(input_index).shape().asFeature(); - - return [num_output, ifm_shape, weight_base, weight_size](::arm_compute::ITensor &tensor) { - const ::nnfw::util::kernel::Shape ker_shape{num_output, ifm_shape.C, ifm_shape.H, ifm_shape.W}; - const ::internal::nnapi::kernel::Reader<float> from{ker_shape, weight_base, weight_size}; - - ::nnfw::util::kernel::iterate(ker_shape) - << [&](uint32_t nth, uint32_t ch, uint32_t row, uint32_t col) { - const auto value = from.at(nth, ch, row, col); - - uint32_t offset = 0; - - // ARM Compute Library uses 'NCHW' ordering - offset += nth * ifm_shape.C * ifm_shape.H * ifm_shape.W; - offset += ch * ifm_shape.H * ifm_shape.W; - offset += row * ifm_shape.W; - offset += col; - - const ::arm_compute::Coordinates coordinate{offset}; - - auto into = reinterpret_cast<float *>(tensor.ptr_to_element(coordinate)); - - *into = value; - }; - }; -} - -Initializer InitializerGenerator::generateBias(const graph::operation::Conv2D::Implicit::Node &node) -{ - // TODO Refactor so we can reuse the common code - - const ::neurun::graph::operand::Index bias_index{node.getInputs().at(2)}; - - auto bias_base = _ctx.at(bias_index).data().base(); - const auto bias_size = _ctx.at(bias_index).shape().asVector(); - - return [bias_base, bias_size](::arm_compute::ITensor &tensor) { - for (int32_t n = 0; n < bias_size; ++n) - { - const ::arm_compute::Coordinates coordinate{n}; - - float *into = reinterpret_cast<float *>(tensor.ptr_to_element(coordinate)); - - const float *from = reinterpret_cast<const float *>(bias_base) + n; - const auto value = *from; - - *into = value; - } - }; -} - -Initializer InitializerGenerator::generateBias(const graph::operation::FullyConnected::Node &node) -{ - const ::neurun::graph::operand::Index bias_index{node.getInputs().at(2)}; - - auto bias_base = _ctx.at(bias_index).data().base(); - const auto bias_size = _ctx.at(bias_index).shape().asVector(); - - return [bias_base, bias_size](::arm_compute::ITensor &tensor) { - for (int32_t n = 0; n < bias_size; ++n) - { - const ::arm_compute::Coordinates coordinate{n}; - - float *into = reinterpret_cast<float *>(tensor.ptr_to_element(coordinate)); - - const float *from = reinterpret_cast<const float *>(bias_base) + n; - const auto value = *from; - - *into = value; - } - }; -} - -} // namespace acl_cl -} // namespace backend -} // namespace neurun diff --git a/runtimes/neurun/src/backend/acl_cl/InitializerGenerator.h b/runtimes/neurun/src/backend/acl_cl/InitializerGenerator.h deleted file mode 100644 index 78b7efb5e..000000000 --- a/runtimes/neurun/src/backend/acl_cl/InitializerGenerator.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2018 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 __NEURUN_BACKEND_ACL_CL_INITIALIZER_GENERATOR_H__ -#define __NEURUN_BACKEND_ACL_CL_INITIALIZER_GENERATOR_H__ - -#include "backend/IInitializerGenerator.h" - -#include "graph/operand/Set.h" - -namespace neurun -{ -namespace backend -{ -namespace acl_cl -{ - -class InitializerGenerator : public IInitializerGenerator -{ -public: - InitializerGenerator(const neurun::graph::operand::Set &ctx); - - Initializer generateWeight(const graph::operation::Conv2D::Implicit::Node &node) override; - Initializer generateWeight(const graph::operation::FullyConnected::Node &node) override; - - Initializer generateBias(const graph::operation::Conv2D::Implicit::Node &node) override; - Initializer generateBias(const graph::operation::FullyConnected::Node &node) override; - -private: - const neurun::graph::operand::Set &_ctx; -}; - -} // namespace acl_cl -} // namespace backend -} // namespace neurun - -#endif // __NEURUN_BACKEND_ACL_CL_INITIALIZER_GENERATOR_H__ diff --git a/runtimes/neurun/src/backend/acl_cl/PluginClassesAllocator.cc b/runtimes/neurun/src/backend/acl_cl/PluginClassesAllocator.cc new file mode 100644 index 000000000..f33e71d33 --- /dev/null +++ b/runtimes/neurun/src/backend/acl_cl/PluginClassesAllocator.cc @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2018 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 <memory> +#include "TensorBuilder.h" +#include "StageGenerator.h" +#include "Config.h" +#include "util/logging.h" + +extern "C" { +neurun::backend::acl_cl::TensorBuilder *allocate_TensorBuilder() +{ + VERBOSE(allocate_TensorBuilder) << "loaded from acl_cl\n"; + return new neurun::backend::acl_cl::TensorBuilder; +} + +neurun::backend::acl_cl::StageGenerator *allocate_StageGenerator( + const neurun::model::operand::Set &operand_ctx, + const std::shared_ptr<neurun::backend::acl_cl::TensorBuilder> &tensor_builder) +{ + VERBOSE(allocate_StageGenerator) << "loaded from acl_cl\n"; + return new neurun::backend::acl_cl::StageGenerator(operand_ctx, tensor_builder); +} + +neurun::backend::acl_cl::Config *allocate_Config() +{ + VERBOSE(allocate_Config) << "loaded from acl_cl\n"; + return new neurun::backend::acl_cl::Config; +} +} diff --git a/runtimes/neurun/src/backend/acl_cl/StageGenerator.cc b/runtimes/neurun/src/backend/acl_cl/StageGenerator.cc index c63698fd8..89bbd7bd2 100644 --- a/runtimes/neurun/src/backend/acl_cl/StageGenerator.cc +++ b/runtimes/neurun/src/backend/acl_cl/StageGenerator.cc @@ -16,6 +16,8 @@ #include "backend/acl_cl/StageGenerator.h" +#include "kernel/acl_cl/CLFunction.h" + #include <arm_compute/runtime/CL/functions/CLConvolutionLayer.h> #include <arm_compute/runtime/CL/functions/CLPoolingLayer.h> #include <arm_compute/runtime/CL/functions/CLActivationLayer.h> @@ -25,20 +27,27 @@ #include "kernel/acl_cl/ConcatLayer.h" -#include "internal/Padding.h" +#include "util/Padding.h" -#include "graph/operand/Index.h" +#include "model/operand/Index.h" -#include "logging.h" +#include "util/logging.h" #include "NeuralNetworks.h" -#include "support/nnapi/Utils.h" +#include "util/Utils.h" template <typename T> std::unique_ptr<T> make_layer(void) { return std::unique_ptr<T>{new T}; } -::arm_compute::PadStrideInfo asPadStringInfo(const ::internal::Padding &padding, - const ::internal::Stride &stride) +std::unique_ptr<::neurun::kernel::acl_cl::CLFunction> +make_cl_function(std::unique_ptr<::arm_compute::IFunction> &&layer) +{ + return std::unique_ptr<::neurun::kernel::acl_cl::CLFunction>( + new ::neurun::kernel::acl_cl::CLFunction(std::move(layer))); +} + +::arm_compute::PadStrideInfo asPadStringInfo(const neurun::util::Padding &padding, + const neurun::util::Stride &stride) { return ::arm_compute::PadStrideInfo{stride.horizontal, stride.vertical, @@ -86,7 +95,9 @@ void ActivationBuilder::appendReLU(::arm_compute::ICLTensor *ifm_alloc) fn->configure(ifm_alloc, nullptr, act_info); - _builder.append(std::move(fn)); + auto acl_fn = make_cl_function(std::move(fn)); + + _builder.append(std::move(acl_fn)); } void ActivationBuilder::append(FuseCode code, ::arm_compute::ICLTensor *ifm_alloc) @@ -113,25 +124,27 @@ void ActivationBuilder::append(FuseCode code, ::arm_compute::ICLTensor *ifm_allo // // StageGenerator // -StageGenerator::StageGenerator(const neurun::graph::operand::Set &ctx, +StageGenerator::StageGenerator(const neurun::model::operand::Set &ctx, const std::shared_ptr<TensorBuilder> &tensor_builder) : _ctx(ctx), _tensor_builder(tensor_builder) { // DO NOTHING } -Stage StageGenerator::generate(const graph::operation::Conv2D::Implicit::Node &node) +void StageGenerator::visit(const model::operation::Conv2DNode &node) { - const ::neurun::graph::operand::Index ofm_index{node.getOutputs().at(0)}; - const ::neurun::graph::operand::Index ifm_index{node.getInputs().at(0)}; - const ::neurun::graph::operand::Index ker_index{node.getInputs().at(1)}; - const ::neurun::graph::operand::Index bias_index{node.getInputs().at(2)}; + using model::operation::Conv2DNode; + + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(Conv2DNode::Input::INPUT)}; + const auto ker_index{node.getInputs().at(Conv2DNode::Input::KERNEL)}; + const auto bias_index{node.getInputs().at(Conv2DNode::Input::BIAS)}; - const ::neurun::graph::operand::Index vstride_index{node.param().vstride_index}; - const ::neurun::graph::operand::Index hstride_index{node.param().hstride_index}; + const auto vstride_index{node.param().vstride_index}; + const auto hstride_index{node.param().hstride_index}; - const ::neurun::graph::operand::Index padding_index{node.param().padding_index}; - const ::neurun::graph::operand::Index activation_index{node.param().activation_index}; + const auto padding_index{node.param().padding_index}; + const auto activation_index{node.param().activation_index}; const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(); const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(); @@ -143,7 +156,7 @@ Stage StageGenerator::generate(const graph::operation::Conv2D::Implicit::Node &n assert((ANEURALNETWORKS_PADDING_SAME == padding_type) || (ANEURALNETWORKS_PADDING_VALID == padding_type)); - ::internal::Stride stride; + neurun::util::Stride stride; stride.vertical = _ctx.at(vstride_index).asScalar<int32_t>(); stride.horizontal = _ctx.at(hstride_index).asScalar<int32_t>(); @@ -151,64 +164,67 @@ Stage StageGenerator::generate(const graph::operation::Conv2D::Implicit::Node &n // Construct operation parameters struct Param { - int ofm_index; - int ifm_index; - int ker_index; - int bias_index; + model::operand::Index ofm_index; + model::operand::Index ifm_index; + model::operand::Index ker_index; + model::operand::Index bias_index; - ::internal::Padding padding; - ::internal::Stride stride; + neurun::util::Padding padding; + neurun::util::Stride stride; FuseCode activation; }; Param param; - param.ofm_index = ofm_index.asInt(); - param.ifm_index = ifm_index.asInt(); - param.ker_index = ker_index.asInt(); - param.bias_index = bias_index.asInt(); + param.ofm_index = ofm_index; + param.ifm_index = ifm_index; + param.ker_index = ker_index; + param.bias_index = bias_index; param.stride = stride; param.padding = (padding_type == ANEURALNETWORKS_PADDING_SAME) - ? ::internal::same_padding(ifm_shape, ofm_shape, stride, ker_shape.W, ker_shape.H) - : ::internal::valid_padding(); + ? neurun::util::same_padding(ifm_shape, ofm_shape, stride, ker_shape.W, ker_shape.H) + : neurun::util::valid_padding(); param.activation = static_cast<FuseCode>(_ctx.at(activation_index).asScalar<int32_t>()); auto tensors = _tensor_builder; - return [tensors, param](IExecutionBuilder &builder) { - auto ofm_alloc = tensors->at(::neurun::graph::operand::Index{param.ofm_index}).get(); - auto ifm_alloc = tensors->at(::neurun::graph::operand::Index{param.ifm_index}).get(); - auto ker_alloc = tensors->at(::neurun::graph::operand::Index{param.ker_index}).get(); - auto bias_alloc = tensors->at(::neurun::graph::operand::Index{param.bias_index}).get(); + returnStage([tensors, param](IExecutionBuilder &builder) { + auto ofm_alloc = tensors->at(param.ofm_index).get(); + auto ifm_alloc = tensors->at(param.ifm_index).get(); + auto ker_alloc = tensors->at(param.ker_index).get(); + auto bias_alloc = tensors->at(param.bias_index).get(); const auto conv_info = asPadStringInfo(param.padding, param.stride); std::unique_ptr<::arm_compute::CLConvolutionLayer> fn{new ::arm_compute::CLConvolutionLayer}; - fn->configure(ifm_alloc, ker_alloc, bias_alloc, ofm_alloc, conv_info); + fn->configure(ifm_alloc->handle(), ker_alloc->handle(), bias_alloc->handle(), + ofm_alloc->handle(), conv_info); - builder.append(std::move(fn)); + auto acl_fn = make_cl_function(std::move(fn)); - ActivationBuilder{builder}.append(param.activation, ofm_alloc); - }; + builder.append(std::move(acl_fn)); + + ActivationBuilder{builder}.append(param.activation, ofm_alloc->handle()); + }); } -Stage StageGenerator::generate(const graph::operation::MaxPool2D::Implicit::Node &node) +void StageGenerator::visit(const model::operation::MaxPool2DNode &node) { - const ::neurun::graph::operand::Index ofm_index{node.getOutputs().at(0)}; - const ::neurun::graph::operand::Index ifm_index{node.getInputs().at(0)}; + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(model::operation::MaxPool2DNode::Input::INPUT)}; - const ::neurun::graph::operand::Index kh_index{node.param().kh_index}; - const ::neurun::graph::operand::Index kw_index{node.param().kw_index}; + const auto kh_index{node.param().kh_index}; + const auto kw_index{node.param().kw_index}; - const ::neurun::graph::operand::Index vstride_index{node.param().vstride_index}; - const ::neurun::graph::operand::Index hstride_index{node.param().hstride_index}; + const auto vstride_index{node.param().vstride_index}; + const auto hstride_index{node.param().hstride_index}; - const ::neurun::graph::operand::Index padding_index{node.param().padding_index}; + const auto padding_index{node.param().padding_index}; const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(); const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(); @@ -225,22 +241,22 @@ Stage StageGenerator::generate(const graph::operation::MaxPool2D::Implicit::Node // Construct operation parameters struct Param { - int ofm_index; - int ifm_index; + model::operand::Index ofm_index; + model::operand::Index ifm_index; uint32_t kw; uint32_t kh; - ::internal::Padding padding; - ::internal::Stride stride; + neurun::util::Padding padding; + neurun::util::Stride stride; // TODO Add 'activation' field }; Param param; - param.ofm_index = ofm_index.asInt(); - param.ifm_index = ifm_index.asInt(); + param.ofm_index = ofm_index; + param.ifm_index = ifm_index; param.kh = kh; param.kw = kw; @@ -249,8 +265,8 @@ Stage StageGenerator::generate(const graph::operation::MaxPool2D::Implicit::Node param.stride.horizontal = hstride; param.padding = (padding_type == ANEURALNETWORKS_PADDING_SAME) - ? ::internal::same_padding(ifm_shape, ofm_shape, param.stride, kw, kh) - : ::internal::valid_padding(); + ? neurun::util::same_padding(ifm_shape, ofm_shape, param.stride, kw, kh) + : neurun::util::valid_padding(); VERBOSE(MaxPool2D) << "IFM_H: " << ifm_shape.H << std::endl; VERBOSE(MaxPool2D) << "IFM_W: " << ifm_shape.W << std::endl; @@ -267,9 +283,9 @@ Stage StageGenerator::generate(const graph::operation::MaxPool2D::Implicit::Node auto tensors = _tensor_builder; - return [tensors, param](IExecutionBuilder &builder) { - auto ofm_alloc = tensors->at(::neurun::graph::operand::Index{param.ofm_index}).get(); - auto ifm_alloc = tensors->at(::neurun::graph::operand::Index{param.ifm_index}).get(); + returnStage([tensors, param](IExecutionBuilder &builder) { + auto ofm_alloc = tensors->at(param.ofm_index).get(); + auto ifm_alloc = tensors->at(param.ifm_index).get(); ::arm_compute::PoolingLayerInfo info{::arm_compute::PoolingType::MAX, ::arm_compute::Size2D{param.kw, param.kh}, @@ -277,24 +293,26 @@ Stage StageGenerator::generate(const graph::operation::MaxPool2D::Implicit::Node std::unique_ptr<::arm_compute::CLPoolingLayer> fn{new ::arm_compute::CLPoolingLayer}; - fn->configure(ifm_alloc, ofm_alloc, info); + fn->configure(ifm_alloc->handle(), ofm_alloc->handle(), info); - builder.append(std::move(fn)); - }; + auto acl_fn = make_cl_function(std::move(fn)); + + builder.append((std::move(acl_fn))); + }); } -Stage StageGenerator::generate(const graph::operation::AvgPool2D::Implicit::Node &node) +void StageGenerator::visit(const model::operation::AvgPool2DNode &node) { - const ::neurun::graph::operand::Index ofm_index{node.getOutputs().at(0)}; - const ::neurun::graph::operand::Index ifm_index{node.getInputs().at(0)}; + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(model::operation::AvgPool2DNode::Input::INPUT)}; - const ::neurun::graph::operand::Index kh_index{node.param().kh_index}; - const ::neurun::graph::operand::Index kw_index{node.param().kw_index}; + const auto kh_index{node.param().kh_index}; + const auto kw_index{node.param().kw_index}; - const ::neurun::graph::operand::Index vstride_index{node.param().vstride_index}; - const ::neurun::graph::operand::Index hstride_index{node.param().hstride_index}; + const auto vstride_index{node.param().vstride_index}; + const auto hstride_index{node.param().hstride_index}; - const ::neurun::graph::operand::Index padding_index{node.param().padding_index}; + const auto padding_index{node.param().padding_index}; const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(); const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(); @@ -314,22 +332,22 @@ Stage StageGenerator::generate(const graph::operation::AvgPool2D::Implicit::Node // Construct operation parameters struct Param { - int ofm_index; - int ifm_index; + model::operand::Index ofm_index; + model::operand::Index ifm_index; uint32_t kw; uint32_t kh; - ::internal::Padding padding; - ::internal::Stride stride; + neurun::util::Padding padding; + neurun::util::Stride stride; // TODO Add 'activation' field }; Param param; - param.ofm_index = ofm_index.asInt(); - param.ifm_index = ifm_index.asInt(); + param.ofm_index = ofm_index; + param.ifm_index = ifm_index; param.kh = kh; param.kw = kw; @@ -338,8 +356,8 @@ Stage StageGenerator::generate(const graph::operation::AvgPool2D::Implicit::Node param.stride.horizontal = hstride; param.padding = (padding_type == ANEURALNETWORKS_PADDING_SAME) - ? ::internal::same_padding(ifm_shape, ofm_shape, param.stride, kw, kh) - : ::internal::valid_padding(); + ? neurun::util::same_padding(ifm_shape, ofm_shape, param.stride, kw, kh) + : neurun::util::valid_padding(); VERBOSE(AvgPool2D) << "IFM_H: " << ifm_shape.H << std::endl; VERBOSE(AvgPool2D) << "IFM_W: " << ifm_shape.W << std::endl; @@ -349,7 +367,7 @@ Stage StageGenerator::generate(const graph::operation::AvgPool2D::Implicit::Node VERBOSE(AvgPool2D) << "KER_W: " << kw << std::endl; VERBOSE(AvgPool2D) << "STRIDE_H: " << vstride << std::endl; VERBOSE(AvgPool2D) << "STRIDE_W: " << hstride << std::endl; - VERBOSE(AvgPool2D) << "PAD: " << ::nnfw::support::nnapi::to_string(padding_type) << std::endl; + VERBOSE(AvgPool2D) << "PAD: " << neurun::util::to_string(padding_type) << std::endl; VERBOSE(AvgPool2D) << "PAD(T): " << param.padding.top << std::endl; VERBOSE(AvgPool2D) << "PAD(B): " << param.padding.bottom << std::endl; VERBOSE(AvgPool2D) << "PAD(L): " << param.padding.left << std::endl; @@ -357,9 +375,9 @@ Stage StageGenerator::generate(const graph::operation::AvgPool2D::Implicit::Node auto tensors = _tensor_builder; - return [tensors, param](IExecutionBuilder &builder) { - auto ofm_alloc = tensors->at(::neurun::graph::operand::Index{param.ofm_index}).get(); - auto ifm_alloc = tensors->at(::neurun::graph::operand::Index{param.ifm_index}).get(); + returnStage([tensors, param](IExecutionBuilder &builder) { + auto ofm_alloc = tensors->at(param.ofm_index).get(); + auto ifm_alloc = tensors->at(param.ifm_index).get(); ::arm_compute::PoolingLayerInfo info{ ::arm_compute::PoolingType::AVG, ::arm_compute::Size2D{param.kw, param.kh}, @@ -367,170 +385,207 @@ Stage StageGenerator::generate(const graph::operation::AvgPool2D::Implicit::Node std::unique_ptr<::arm_compute::CLPoolingLayer> fn{new ::arm_compute::CLPoolingLayer}; - fn->configure(ifm_alloc, ofm_alloc, info); + fn->configure(ifm_alloc->handle(), ofm_alloc->handle(), info); - builder.append(std::move(fn)); - }; + auto acl_fn = make_cl_function(std::move(fn)); + + builder.append((std::move(acl_fn))); + }); } -Stage StageGenerator::generate(const graph::operation::Concat::Node &node) +void StageGenerator::visit(const model::operation::ConcatNode &node) { - const ::neurun::graph::operand::Index ofm_index{node.getOutputs().at(0)}; - const ::neurun::graph::operand::Index axis_index{node.param().axis_index}; + const auto ofm_index{node.getOutputs().at(0)}; + const auto axis_index{node.param().axis_index}; struct Param { - int32_t output_index; - std::vector<int32_t> input_indexes; + model::operand::Index output_index; + std::vector<model::operand::Index> input_indexes; int32_t axis; }; Param param; - param.output_index = ofm_index.asInt(); + param.output_index = ofm_index; for (const auto &e : node.getInputs()) { - param.input_indexes.emplace_back(e.asInt()); + param.input_indexes.emplace_back(e); } param.axis = _ctx.at(axis_index).asScalar<int32_t>(); auto tensors = _tensor_builder; - return [tensors, param](IExecutionBuilder &builder) { - auto output_alloc = tensors->at(::neurun::graph::operand::Index{param.output_index}).get(); + returnStage([tensors, param](IExecutionBuilder &builder) { + // If tensor allocator allocate as subtensor + bool canEliminate = true; + for (auto ifm_ind : param.input_indexes) + { + if (!tensors->isSubTensorOf(param.output_index, ifm_ind)) + { + canEliminate = false; + break; + } + } + if (canEliminate) + { + // If concat eliminated, return with nothing to do + return; + } + + auto output_alloc = tensors->at(param.output_index).get(); - std::vector<::arm_compute::ICLTensor *> input_allocs; + std::vector<::neurun::backend::acl_cl::operand::ICLTensor *> input_allocs; for (auto ifm_ind : param.input_indexes) { - input_allocs.emplace_back(tensors->at(::neurun::graph::operand::Index{ifm_ind}).get()); + input_allocs.emplace_back( + dynamic_cast<::neurun::backend::acl_cl::operand::CLTensor *>(tensors->at(ifm_ind).get())); } std::unique_ptr<::neurun::kernel::acl_cl::ConcatLayer> fn{ new ::neurun::kernel::acl_cl::ConcatLayer}; - fn->configure(input_allocs, param.axis, output_alloc); + fn->configure(input_allocs, param.axis, + dynamic_cast<::neurun::backend::acl_cl::operand::CLTensor *>(output_alloc)); - builder.append(std::move(fn)); - }; + auto acl_fn = make_cl_function(std::move(fn)); + + builder.append(std::move(acl_fn)); + }); } -Stage StageGenerator::generate(const graph::operation::FullyConnected::Node &node) +void StageGenerator::visit(const model::operation::FullyConnectedNode &node) { - const ::neurun::graph::operand::Index output_index{node.getOutputs().at(0)}; - const ::neurun::graph::operand::Index input_index{node.getInputs().at(0)}; - const ::neurun::graph::operand::Index weight_index{node.getInputs().at(1)}; - const ::neurun::graph::operand::Index bias_index{node.getInputs().at(2)}; - const ::neurun::graph::operand::Index activation_index{node.param().activation_index}; + using model::operation::FullyConnectedNode; + + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(FullyConnectedNode::Input::INPUT)}; + const auto weight_index{node.getInputs().at(FullyConnectedNode::Input::WEIGHT)}; + const auto bias_index{node.getInputs().at(FullyConnectedNode::Input::BIAS)}; + const auto activation_index{node.param().activation_index}; // Construct operation parameters struct Param { - int output_index; + model::operand::Index output_index; - int input_index; - int weight_index; - int bias_index; + model::operand::Index input_index; + model::operand::Index weight_index; + model::operand::Index bias_index; FuseCode activation; }; Param param; - param.output_index = output_index.asInt(); - param.input_index = input_index.asInt(); - param.weight_index = weight_index.asInt(); - param.bias_index = bias_index.asInt(); + param.output_index = output_index; + param.input_index = input_index; + param.weight_index = weight_index; + param.bias_index = bias_index; param.activation = static_cast<FuseCode>(_ctx.at(activation_index).asScalar<int32_t>()); auto tensors = _tensor_builder; - return [tensors, param](IExecutionBuilder &builder) { - auto output_alloc = tensors->at(::neurun::graph::operand::Index{param.output_index}).get(); - auto input_alloc = tensors->at(::neurun::graph::operand::Index{param.input_index}).get(); - auto weight_alloc = tensors->at(::neurun::graph::operand::Index{param.weight_index}).get(); - auto bias_alloc = tensors->at(::neurun::graph::operand::Index{param.bias_index}).get(); + returnStage([tensors, param](IExecutionBuilder &builder) { + auto output_alloc = tensors->at(param.output_index).get(); + auto input_alloc = tensors->at(param.input_index).get(); + auto weight_alloc = tensors->at(param.weight_index).get(); + auto bias_alloc = tensors->at(param.bias_index).get(); auto fn = make_layer<::arm_compute::CLFullyConnectedLayer>(); - fn->configure(input_alloc, weight_alloc, bias_alloc, output_alloc); + fn->configure(input_alloc->handle(), weight_alloc->handle(), bias_alloc->handle(), + output_alloc->handle()); - builder.append(std::move(fn)); + auto acl_fn = make_cl_function(std::move(fn)); - ActivationBuilder{builder}.append(param.activation, output_alloc); - }; + builder.append(std::move(acl_fn)); + + ActivationBuilder{builder}.append(param.activation, output_alloc->handle()); + }); } -Stage StageGenerator::generate(const graph::operation::Reshape::Node &node) +void StageGenerator::visit(const model::operation::ReshapeNode &node) { - const ::neurun::graph::operand::Index output_index{node.getOutputs().at(0)}; - const ::neurun::graph::operand::Index input_index{node.getInputs().at(0)}; + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(model::operation::ReshapeNode::Input::INPUT)}; struct Param { - int output_index; - int input_index; + model::operand::Index output_index; + model::operand::Index input_index; }; Param param; - param.output_index = output_index.asInt(); - param.input_index = input_index.asInt(); + param.output_index = output_index; + param.input_index = input_index; auto tensors = _tensor_builder; - return [tensors, param](IExecutionBuilder &builder) { - auto output_alloc = tensors->at(::neurun::graph::operand::Index{param.output_index}).get(); - auto input_alloc = tensors->at(::neurun::graph::operand::Index{param.input_index}).get(); + returnStage([tensors, param](IExecutionBuilder &builder) { + auto output_alloc = tensors->at(param.output_index).get(); + auto input_alloc = tensors->at(param.input_index).get(); auto fn = make_layer<::arm_compute::CLReshapeLayer>(); - fn->configure(input_alloc, output_alloc); + fn->configure(input_alloc->handle(), output_alloc->handle()); - builder.append(std::move(fn)); - }; + auto acl_fn = make_cl_function(std::move(fn)); + + builder.append(std::move(acl_fn)); + }); } -Stage StageGenerator::generate(const graph::operation::Softmax::Node &node) +void StageGenerator::visit(const model::operation::SoftmaxNode &node) { - const ::neurun::graph::operand::Index output_index{node.getOutputs().at(0)}; - const ::neurun::graph::operand::Index input_index{node.getInputs().at(0)}; - const ::neurun::graph::operand::Index scale_index{node.param().scale_index}; + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(model::operation::SoftmaxNode::Input::INPUT)}; + const auto scale_index{node.param().scale_index}; assert(_ctx.at(scale_index).shape().rank() == 0); struct Param { - int output_index; - int input_index; + model::operand::Index output_index; + model::operand::Index input_index; float scale; }; Param param; - param.output_index = output_index.asInt(); - param.input_index = input_index.asInt(); + param.output_index = output_index; + param.input_index = input_index; param.scale = _ctx.at(scale_index).asScalar<float>(); auto tensors = _tensor_builder; - return [tensors, param](IExecutionBuilder &builder) { - auto output_alloc = tensors->at(::neurun::graph::operand::Index{param.output_index}).get(); - auto input_alloc = tensors->at(::neurun::graph::operand::Index{param.input_index}).get(); + returnStage([tensors, param](IExecutionBuilder &builder) { + auto output_alloc = tensors->at(param.output_index).get(); + auto input_alloc = tensors->at(param.input_index).get(); auto fn = make_layer<::arm_compute::CLSoftmaxLayer>(); - fn->configure(input_alloc, output_alloc, param.scale); + fn->configure(input_alloc->handle(), output_alloc->handle(), param.scale); - builder.append(std::move(fn)); - }; + auto acl_fn = make_cl_function(std::move(fn)); + + builder.append(std::move(acl_fn)); + }); } -Stage StageGenerator::generate(const graph::operation::NOP::Node & /* node */) +void StageGenerator::visit(const model::operation::PermuteNode & /* node */) { - // DO NOTHING - return nullptr; + throw "Unsupported"; +} + +void StageGenerator::visit(const model::operation::AddNode &) +{ + VERBOSE(Add) << "generate CPU Add" << std::endl; + + throw std::runtime_error("NYI"); } } // namespace acl_cl diff --git a/runtimes/neurun/src/backend/acl_cl/StageGenerator.h b/runtimes/neurun/src/backend/acl_cl/StageGenerator.h index 921604649..1dac2592b 100644 --- a/runtimes/neurun/src/backend/acl_cl/StageGenerator.h +++ b/runtimes/neurun/src/backend/acl_cl/StageGenerator.h @@ -17,9 +17,9 @@ #ifndef __NEURUN_BACKEND_ACL_CL_STAGE_GENERATOR_H__ #define __NEURUN_BACKEND_ACL_CL_STAGE_GENERATOR_H__ -#include "backend/IStageGenerator.h" +#include "backend/interface/IStageGenerator.h" -#include "graph/operand/Set.h" +#include "model/operand/Set.h" #include "backend/acl_cl/TensorBuilder.h" namespace neurun @@ -32,22 +32,18 @@ namespace acl_cl class StageGenerator : public IStageGenerator { public: - StageGenerator(const neurun::graph::operand::Set &ctx, + StageGenerator(const neurun::model::operand::Set &ctx, const std::shared_ptr<TensorBuilder> &tensor_builder); virtual std::shared_ptr<ITensorBuilder> tensor_builder() override { return _tensor_builder; } - virtual Stage generate(const graph::operation::Conv2D::Implicit::Node &node) override; - virtual Stage generate(const graph::operation::MaxPool2D::Implicit::Node &node) override; - virtual Stage generate(const graph::operation::AvgPool2D::Implicit::Node &node) override; - virtual Stage generate(const graph::operation::Concat::Node &node) override; - virtual Stage generate(const graph::operation::FullyConnected::Node &node) override; - virtual Stage generate(const graph::operation::Reshape::Node &node) override; - virtual Stage generate(const graph::operation::Softmax::Node &node) override; - virtual Stage generate(const graph::operation::NOP::Node &node) override; +#define OP(InternalName, IsNnApi, NnApiName) \ + virtual void visit(const model::operation::InternalName &) override; +#include "model/operation/Op.lst" +#undef OP private: - const neurun::graph::operand::Set &_ctx; + const neurun::model::operand::Set &_ctx; std::shared_ptr<TensorBuilder> _tensor_builder; }; diff --git a/runtimes/neurun/src/backend/acl_cl/Swizzle.h b/runtimes/neurun/src/backend/acl_cl/Swizzle.h new file mode 100644 index 000000000..838e57162 --- /dev/null +++ b/runtimes/neurun/src/backend/acl_cl/Swizzle.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2018 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 __NEURUN_BACKEND_ACL_CL_SWIZZLE_H__ +#define __NEURUN_BACKEND_ACL_CL_SWIZZLE_H__ + +#include <cassert> + +namespace neurun +{ +namespace backend +{ +namespace acl_cl +{ + +class ARMComputeAxis +{ +public: + ARMComputeAxis() = default; + +public: + explicit ARMComputeAxis(uint32_t value) : _value{value} + { + // DO NOTHING + } + +public: + uint32_t value(void) const { return _value; } + +private: + uint32_t _value; +}; + +// Convert T/F Lite / NNAPI axis (based on ...NHWC) to ARMCompute axis (WHCN...) +inline ARMComputeAxis ToARMComputeAxis(uint32_t rank, uint32_t axis) +{ + assert(rank > axis); + const ARMComputeAxis reversed{(rank - axis) - 1}; + + if (rank < 4) + { + return reversed; + } + + // DEPTH + if (0 == reversed.value()) + { + return ARMComputeAxis{2}; + } + // WIDTH + if (1 == reversed.value()) + { + return ARMComputeAxis{0}; + } + // HEIGHT + if (2 == reversed.value()) + { + return ARMComputeAxis{1}; + } + + // ELSE + return reversed; +} + +template <typename T> inline T ReorderBits(T in, size_t numOfBits) +{ + assert(numOfBits > 0); + T out = 0; + for (int32_t i = numOfBits - 1; i >= 0; --i) + { + const uint32_t toShift = numOfBits - ToARMComputeAxis(numOfBits, i).value() - 1; + out += ((in & 1) << toShift); + in >>= 1; + } + return out; +} + +} // namespace acl_cl +} // namespace backend +} // namespace neurun + +#endif // __NEURUN_BACKEND_ACL_CL_SWIZZLE_H__ diff --git a/runtimes/neurun/src/backend/acl_cl/TensorBuilder.cc b/runtimes/neurun/src/backend/acl_cl/TensorBuilder.cc index 05943c26a..b5c038200 100644 --- a/runtimes/neurun/src/backend/acl_cl/TensorBuilder.cc +++ b/runtimes/neurun/src/backend/acl_cl/TensorBuilder.cc @@ -17,8 +17,12 @@ #include "backend/acl_cl/TensorBuilder.h" #include <cassert> +#include <stack> #include "operand/Object.h" +#include "Convert.h" + +#include "util/logging.h" namespace neurun { @@ -32,34 +36,124 @@ TensorBuilder::TensorBuilder() // DO NOTHING } -void TensorBuilder::mark(const ::neurun::graph::operand::Index &ind) +void TensorBuilder::registerTensorInfo(const model::operand::Index &ind, + const compiler::TensorInfo &info) +{ + assert(_tensors.size() == 0); + + _tensor_info_map.insert({ind, info}); +} + +void TensorBuilder::registerSubTensorInfo(const model::operand::Index &ind, + const compiler::SubTensorInfo &info) { assert(_tensors.size() == 0); - _inds.insert(ind); + _subtensor_info_map.insert({ind, info}); +} + +void TensorBuilder::notifyFirstUse(const model::operand::Index &) +{ + // DO NOTHING +} + +void TensorBuilder::notifyLastUse(const model::operand::Index &) +{ + // DO NOTHING } -void TensorBuilder::prepare(codegen::Plan &plan, - const std::map<int, ::arm_compute::TensorInfo> &tensor_info_ctx) +void TensorBuilder::prepare(void) { assert(_tensors.size() == 0); // TODO Handle SubTensor(subsumption) // Currently this TensorBuilder does not have subsumption info yet + // Allocated subtensor will be mapped to _subtensors instead of _tensors + assert(_subtensors.size() == 0); - for (auto ind_int : _inds) + for (auto &entry : _tensor_info_map) { - ::neurun::graph::operand::Index ind{ind_int}; - auto tensor = std::make_shared<::arm_compute::CLTensor>(); - tensor->allocator()->init(tensor_info_ctx.at(ind.asInt())); - plan.operands().set(ind, std::make_shared<operand::Object>(tensor)); + auto ind = entry.first; + const auto &info = entry.second; + auto tensor = std::make_shared<::neurun::backend::acl_cl::operand::CLTensor>(info); _tensors[ind] = tensor; } + + // To make subtensor, parent tensor must be made first + // For this condition, use stack + // 1) Push one subtensor index to stack (iterate subtensors) + // 2) If tensor at stack top is already made, pop and go to 4) + // 3) If tensor pushed at 1) is not made, check parent tensor + // 3-1) If parent tensor is already made, we can make child tensor + // Make child tensor and pop, go to 4) + // 3-2) If parent tensor is not made, we can't make child tensor yet + // Push parent tensor index to stack and return to 4) + // 4) If stack is empty, return to 1), else return to 2) + for (auto &entry : _subtensor_info_map) + { + model::operand::Index ind = entry.first; + + std::stack<model::operand::Index> stack; + stack.push(ind); + + while (!stack.empty()) + { + const auto current = stack.top(); + const auto &info = _subtensor_info_map.at(current); + + // Already generated CLSubTensor + if (_subtensors.find(current) != _subtensors.end()) + { + stack.pop(); + continue; + } + + auto parent = info.parent(); + std::shared_ptr<::neurun::backend::acl_cl::operand::ICLTensor> parent_tensor; + + if (_tensors.find(parent) != _tensors.end()) + { + // Parent is allocated as tensor + parent_tensor = _tensors[parent]; + } + else if (_subtensors.find(parent) != _subtensors.end()) + { + // Parent is allocated as subtensor + parent_tensor = _subtensors[parent]; + } + else + { + // Cannot find allocated parent tensor: allocate parent first + assert(_subtensor_info_map.find(parent) != _subtensor_info_map.end()); + stack.push(parent); + continue; + } + assert(parent_tensor != nullptr); + + // Child's type should be same with parent + assert(info.type().offset() == parent_tensor->info()->quantization_info().offset); + assert(info.type().scale() == parent_tensor->info()->quantization_info().scale); + assert(asDataType(info.type().type()) == parent_tensor->info()->data_type()); + auto shape = asTensorShape(info.shape()); + + // Only support axis: 3 (channel) + ::arm_compute::Coordinates coordinates; + coordinates.set_num_dimensions(4); + assert(info.offset().h() == 0); + assert(info.offset().n() == 0); + assert(info.offset().w() == 0); + coordinates[2] = info.offset().c(); + auto tensor = std::make_shared<::neurun::backend::acl_cl::operand::CLSubTensor>( + parent_tensor.get(), shape, coordinates, true); + _subtensors[current] = tensor; + stack.pop(); + } + } } void TensorBuilder::allocate(void) { - assert(_inds.size() == _tensors.size()); + assert(_tensor_info_map.size() == _tensors.size()); for (const auto &tensor_entry : _tensors) { @@ -68,10 +162,83 @@ void TensorBuilder::allocate(void) } } -std::shared_ptr<::arm_compute::CLTensor> -TensorBuilder::at(const ::neurun::graph::operand::Index &ind) +std::shared_ptr<::neurun::backend::operand::ITensor> +TensorBuilder::tensorAt(const model::operand::Index &ind) +{ + if (_tensors.find(ind) != _tensors.end()) + { + return _tensors.at(ind); + } + else + { + return _subtensors.at(ind); + } +} + +std::shared_ptr<backend::operand::IObject> +TensorBuilder::wrapTensor(const model::operand::Index &ind) { - return _tensors.at(ind); + if (_objects.find(ind) != _objects.end()) + { + return _objects.at(ind); + } + else + { + if (_tensors.find(ind) != _tensors.end()) + { + return _objects[ind] = std::make_shared<operand::Object>(_tensors.at(ind)); + } + else + { + return _objects[ind] = std::make_shared<operand::Object>(_subtensors.at(ind)); + } + } +} + +void TensorBuilder::iterate(const IterateFunction &fn) +{ + for (auto it : _tensors) + { + fn(it.first); + } + for (auto it : _subtensors) + { + fn(it.first); + } +} + +std::shared_ptr<::neurun::backend::acl_cl::operand::ICLTensor> +TensorBuilder::at(const ::neurun::model::operand::Index &ind) +{ + if (_tensors.find(ind) != _tensors.end()) + { + return _tensors.at(ind); + } + else + { + return _subtensors.at(ind); + } +} + +bool TensorBuilder::isSubTensorOf(const model::operand::Index &parent, + const model::operand::Index &child) +{ + if (_subtensor_info_map.find(child) == _subtensor_info_map.end()) + { + return false; + } + + if (_subtensors.find(child) == _subtensors.end()) + { + return false; + } + + if (_subtensor_info_map.at(child).parent() != parent) + { + return false; + } + + return true; } } // namespace acl_cl diff --git a/runtimes/neurun/src/backend/acl_cl/TensorBuilder.h b/runtimes/neurun/src/backend/acl_cl/TensorBuilder.h index 0a0f4e9ca..64d81721a 100644 --- a/runtimes/neurun/src/backend/acl_cl/TensorBuilder.h +++ b/runtimes/neurun/src/backend/acl_cl/TensorBuilder.h @@ -17,12 +17,12 @@ #ifndef __NEURUN_BACKEND_ACL_CL_TENSOR_BUILDER_H__ #define __NEURUN_BACKEND_ACL_CL_TENSOR_BUILDER_H__ -#include "backend/ITensorBuilder.h" +#include "backend/interface/ITensorBuilder.h" +#include "backend/acl_cl/operand/CLTensor.h" +#include "backend/acl_cl/operand/CLSubTensor.h" +#include "backend/acl_cl/operand/Object.h" #include <unordered_map> -#include <unordered_set> - -#include <arm_compute/runtime/CL/CLTensor.h> namespace neurun { @@ -31,23 +31,60 @@ namespace backend namespace acl_cl { -class Plan; - class TensorBuilder : public ITensorBuilder { public: TensorBuilder(); - virtual void mark(const ::neurun::graph::operand::Index &ind) override; - virtual void prepare(codegen::Plan &plan, - const std::map<int, ::arm_compute::TensorInfo> &tensor_info_ctx) override; + /** + * @brief Register tensor information to allocate on ACL-CL backend + * @param[in] ind Operand index + * @param[in] info Tensor information + */ + virtual void registerTensorInfo(const model::operand::Index &ind, + const compiler::TensorInfo &info) override; + /** + * @brief Register subtensor information to allocate on ACL-CL backend + * @param[in] ind Operand index + * @param[in] info Tensor information + */ + virtual void registerSubTensorInfo(const model::operand::Index &ind, + const compiler::SubTensorInfo &info) override; + + virtual void notifyFirstUse(const model::operand::Index &) override; + virtual void notifyLastUse(const model::operand::Index &) override; + + virtual void prepare(void) override; virtual void allocate(void) override; - std::shared_ptr<::arm_compute::CLTensor> at(const ::neurun::graph::operand::Index &ind); + virtual std::shared_ptr<::neurun::backend::operand::ITensor> + tensorAt(const model::operand::Index &ind) override; + virtual std::shared_ptr<backend::operand::IObject> + wrapTensor(const model::operand::Index &ind) override; + virtual void iterate(const IterateFunction &fn) override; + + std::shared_ptr<::neurun::backend::acl_cl::operand::ICLTensor> + at(const ::neurun::model::operand::Index &ind); + /** + * @brief Check child tensor is allocated as subtensor of parent tensor + * @param[in] parent Index of parent + * @param[in] child Index of child + * @return @c true if child is allocated as subtensor of parent, otherwise @c false + */ + bool isSubTensorOf(const model::operand::Index &parent, const model::operand::Index &child); private: - std::unordered_set<graph::operand::Index> _inds; - std::unordered_map<graph::operand::Index, std::shared_ptr<::arm_compute::CLTensor>> _tensors; + std::unordered_map<model::operand::Index, compiler::TensorInfo> _tensor_info_map; + std::unordered_map<model::operand::Index, compiler::SubTensorInfo> _subtensor_info_map; + std::unordered_map<model::operand::Index, + std::shared_ptr<::neurun::backend::acl_cl::operand::CLTensor>> + _tensors; + std::unordered_map<model::operand::Index, + std::shared_ptr<::neurun::backend::acl_cl::operand::CLSubTensor>> + _subtensors; + std::unordered_map<model::operand::Index, + std::shared_ptr<::neurun::backend::acl_cl::operand::Object>> + _objects; }; } // namespace acl_cl diff --git a/runtimes/neurun/src/backend/acl_cl/feature/View.h b/runtimes/neurun/src/backend/acl_cl/feature/View.h deleted file mode 100644 index 12025ce01..000000000 --- a/runtimes/neurun/src/backend/acl_cl/feature/View.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2018 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 __INTERNAL_ARM_COMPUTE_FEATURE_VIEW_H__ -#define __INTERNAL_ARM_COMPUTE_FEATURE_VIEW_H__ - -#include "util/feature/Reader.h" - -#include <arm_compute/core/ITensor.h> - -#include <cassert> - -namespace internal -{ -namespace arm_compute -{ -namespace feature -{ - -template <typename T> class View; - -template <> class View<float> final : public nnfw::util::feature::Reader<float> -{ -public: - View(::arm_compute::ITensor *tensor) : _tensor{tensor} - { - assert(tensor->info()->data_type() == ::arm_compute::DataType::F32); - - // TODO Validate whether tensor is a feature map, or not - - _shape.C = tensor->info()->dimension(2); - _shape.H = tensor->info()->dimension(1); - _shape.W = tensor->info()->dimension(0); - } - -public: - const ::nnfw::util::feature::Shape &shape(void) const { return _shape; } - -public: - float at(uint32_t ch, uint32_t row, uint32_t col) const override - { - const auto offset = feature_index_to_byte_offset(ch, row, col); - - float *ptr = reinterpret_cast<float *>(_tensor->buffer() + offset); - - return *ptr; - } - float at(uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) const override - { - const auto offset = feature_index_to_byte_offset(batch, ch, row, col); - - float *ptr = reinterpret_cast<float *>(_tensor->buffer() + offset); - - return *ptr; - } - -public: - float &at(uint32_t ch, uint32_t row, uint32_t col) - { - const auto offset = feature_index_to_byte_offset(ch, row, col); - - float *ptr = reinterpret_cast<float *>(_tensor->buffer() + offset); - - return *ptr; - } - float &at(uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) - { - const auto offset = feature_index_to_byte_offset(batch, ch, row, col); - - float *ptr = reinterpret_cast<float *>(_tensor->buffer() + offset); - - return *ptr; - } - -private: - size_t feature_index_to_byte_offset(uint32_t ch, uint32_t row, uint32_t col) const - { - // ARM Compute uses CHW ordering - return _tensor->info()->offset_element_in_bytes(::arm_compute::Coordinates{col, row, ch}); - } - size_t feature_index_to_byte_offset(uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) const - { - // ARM Compute uses CHW ordering - return _tensor->info()->offset_element_in_bytes( - ::arm_compute::Coordinates{col, row, ch, batch}); - } - -private: - ::nnfw::util::feature::Shape _shape; - ::arm_compute::ITensor *_tensor; -}; - -} // namespace feature -} // namespace arm_compute -} // namespace internal - -#endif // __INTERNAL_ARM_COMPUTE_FEATURE_VIEW_H__ diff --git a/runtimes/neurun/src/backend/acl_cl/kernel/View.h b/runtimes/neurun/src/backend/acl_cl/kernel/View.h deleted file mode 100644 index aec9a8892..000000000 --- a/runtimes/neurun/src/backend/acl_cl/kernel/View.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2018 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 __INTERNAL_ARM_COMPUTE_KERNEL_VIEW_H__ -#define __INTERNAL_ARM_COMPUTE_KERNEL_VIEW_H__ - -#include "util/kernel/Shape.h" -#include "util/kernel/Reader.h" - -#include <arm_compute/core/ITensor.h> - -#include <cassert> - -namespace internal -{ -namespace arm_compute -{ -namespace kernel -{ - -template <typename T> class View; - -template <> class View<float> final : public nnfw::util::kernel::Reader<float> -{ -public: - View(::arm_compute::ITensor *tensor) : _tensor{tensor} - { - assert(tensor->info()->data_type() == ::arm_compute::DataType::F32); - - _shape.N = tensor->info()->dimension(3); - _shape.C = tensor->info()->dimension(2); - _shape.H = tensor->info()->dimension(1); - _shape.W = tensor->info()->dimension(0); - } - -public: - const ::nnfw::util::kernel::Shape &shape(void) const { return _shape; } - -public: - float at(uint32_t nth, uint32_t ch, uint32_t row, uint32_t col) const override - { - const auto offset = kernel_index_to_byte_offset(nth, ch, row, col); - - float *ptr = reinterpret_cast<float *>(_tensor->buffer() + offset); - - return *ptr; - } - -public: - float &at(uint32_t nth, uint32_t ch, uint32_t row, uint32_t col) - { - const auto offset = kernel_index_to_byte_offset(nth, ch, row, col); - - float *ptr = reinterpret_cast<float *>(_tensor->buffer() + offset); - - return *ptr; - } - -private: - size_t kernel_index_to_byte_offset(uint32_t nth, uint32_t ch, uint32_t row, uint32_t col) const - { - return _tensor->info()->offset_element_in_bytes(::arm_compute::Coordinates{col, row, ch, nth}); - } - -private: - ::nnfw::util::kernel::Shape _shape; - ::arm_compute::ITensor *_tensor; -}; - -} // namespace kernel -} // namespace arm_compute -} // namespace internal - -#endif // __INTERNAL_ARM_COMPUTE_FEATURE_VIEW_H__ diff --git a/runtimes/neurun/src/backend/acl_cl/operand/CLSubTensor.cc b/runtimes/neurun/src/backend/acl_cl/operand/CLSubTensor.cc new file mode 100644 index 000000000..f64b521dd --- /dev/null +++ b/runtimes/neurun/src/backend/acl_cl/operand/CLSubTensor.cc @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2018 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 "CLSubTensor.h" + +namespace neurun +{ +namespace backend +{ +namespace acl_cl +{ +namespace operand +{ + +CLSubTensor::CLSubTensor(ICLTensor *parent, const arm_compute::TensorShape &tensor_shape, + const arm_compute::Coordinates &coords, bool extend_parent) + : _cl_sub_tensor(std::make_shared<arm_compute::CLSubTensor>(parent->handle(), tensor_shape, + coords, extend_parent)) +{ + // DO NOTHING +} + +arm_compute::CLSubTensor *CLSubTensor::handle() const { return _cl_sub_tensor.get(); } + +arm_compute::CLSubTensor *CLSubTensor::handle() { return _cl_sub_tensor.get(); } + +void CLSubTensor::map(bool blocking) { _cl_sub_tensor->map(blocking); } + +void CLSubTensor::unmap() { _cl_sub_tensor->unmap(); } + +uint8_t *CLSubTensor::doMap(cl::CommandQueue &q, bool blocking) +{ + assert(cl_buffer().get() == nullptr); + return static_cast<uint8_t *>(q.enqueueMapBuffer(cl_buffer(), blocking ? CL_TRUE : CL_FALSE, + CL_MAP_READ | CL_MAP_WRITE, 0, + info()->total_size())); +} + +void CLSubTensor::doUnmap(cl::CommandQueue &q) +{ + assert(cl_buffer().get() == nullptr); + q.enqueueUnmapMemObject(cl_buffer(), buffer()); +} + +} // namespace operand +} // namespace acl_cl +} // namespace backend +} // namespace neurun diff --git a/runtimes/neurun/src/backend/acl_cl/operand/CLSubTensor.h b/runtimes/neurun/src/backend/acl_cl/operand/CLSubTensor.h new file mode 100644 index 000000000..cef78c196 --- /dev/null +++ b/runtimes/neurun/src/backend/acl_cl/operand/CLSubTensor.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2018 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 __NEURUN_BACKEND_ACL_CL_OPERAND_CL_SUB_TENSOR_H__ +#define __NEURUN_BACKEND_ACL_CL_OPERAND_CL_SUB_TENSOR_H__ + +#include <arm_compute/runtime/CL/CLSubTensor.h> +#include "ICLTensor.h" +#include "compiler/SubTensorInfo.h" + +namespace neurun +{ +namespace backend +{ +namespace acl_cl +{ +namespace operand +{ + +class CLSubTensor : public ICLTensor +{ +public: + CLSubTensor() = delete; + +public: + CLSubTensor(ICLTensor *parent, const arm_compute::TensorShape &tensor_shape, + const arm_compute::Coordinates &coords, bool extend_parent = false); + +public: + arm_compute::CLSubTensor *handle() const override; + arm_compute::CLSubTensor *handle() override; + +public: + void map(bool blocking = true); + void unmap(); + +protected: + uint8_t *doMap(cl::CommandQueue &q, bool blocking) override; + virtual void doUnmap(cl::CommandQueue &q) override; + +private: + std::shared_ptr<arm_compute::CLSubTensor> _cl_sub_tensor; +}; + +} // namespace operand +} // namespace acl_cl +} // namespace backend +} // namespace neurun + +#endif // __NEURUN_BACKEND_ACL_CL_OPERAND_CL_SUB_TENSOR_H__ diff --git a/runtimes/neurun/src/backend/acl_cl/operand/CLTensor.cc b/runtimes/neurun/src/backend/acl_cl/operand/CLTensor.cc new file mode 100644 index 000000000..e7b718df3 --- /dev/null +++ b/runtimes/neurun/src/backend/acl_cl/operand/CLTensor.cc @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2018 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 <arm_compute/runtime/CL/CLScheduler.h> +#include <arm_compute/runtime/CL/CLMemory.h> +#include <arm_compute/runtime/CL/CLMemoryRegion.h> +#include "CLTensor.h" + +#include "backend/acl_cl/Convert.h" + +namespace neurun +{ +namespace backend +{ +namespace acl_cl +{ +namespace operand +{ + +CLTensor::CLTensor(const compiler::TensorInfo &info) + : _cl_tensor(std::make_shared<arm_compute::CLTensor>()) +{ + auto acl_cl_info = asTensorInfo(info.shape(), info.typeInfo()); + allocator()->init(acl_cl_info); +} + +arm_compute::CLTensor *CLTensor::handle() const { return _cl_tensor.get(); } + +arm_compute::CLTensor *CLTensor::handle() { return _cl_tensor.get(); } + +arm_compute::CLTensorAllocator *CLTensor::allocator() { return _cl_tensor->allocator(); } + +void CLTensor::map(bool blocking) { _cl_tensor->map(blocking); } + +void CLTensor::unmap() { _cl_tensor->unmap(); } + +uint8_t *CLTensor::doMap(cl::CommandQueue &q, bool blocking) +{ + return allocator()->map(q, blocking); +} + +void CLTensor::doUnmap(cl::CommandQueue &q) { allocator()->unmap(q, buffer()); } + +// handle() is Deprecated on acl v18.11 +// TODO Update this +#if 0 +void CLTensor::setBuffer(void *host_ptr) +{ + // create empty MemoryRegion: just context. Since flag isn't used here, no matter which flag to + // pass + auto memory = arm_compute::CLMemory(std::make_shared<arm_compute::CLBufferMemoryRegion>( + arm_compute::CLScheduler::get().context(), CL_MEM_USE_HOST_PTR | CL_MEM_READ_WRITE, 0)); + + // set buffer + auto mem = reinterpret_cast<cl::Buffer *>(memory.region()->handle()); + *mem = cl::Buffer(arm_compute::CLScheduler::get().context(), + CL_MEM_USE_HOST_PTR | CL_MEM_READ_WRITE, info()->total_size(), host_ptr); + // set correct buffer size + memory.region()->set_size(info()->total_size()); + // import memory + allocator()->import_memory(memory); +} +#endif + +} // namespace operand +} // namespace acl_cl +} // namespace backend +} // namespace neurun diff --git a/runtimes/neurun/src/backend/acl_cl/operand/CLTensor.h b/runtimes/neurun/src/backend/acl_cl/operand/CLTensor.h new file mode 100644 index 000000000..31c96e201 --- /dev/null +++ b/runtimes/neurun/src/backend/acl_cl/operand/CLTensor.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2018 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 __NEURUN_BACKEND_ACL_CL_OPERAND_CL_TENSOR_H__ +#define __NEURUN_BACKEND_ACL_CL_OPERAND_CL_TENSOR_H__ + +#include <arm_compute/core/TensorInfo.h> +#include <arm_compute/runtime/CL/CLTensor.h> +#include <arm_compute/runtime/CL/CLScheduler.h> +#include "arm_compute/runtime/CL/CLTensorAllocator.h" +#include "ICLTensor.h" +#include "compiler/TensorInfo.h" + +namespace neurun +{ +namespace backend +{ +namespace acl_cl +{ +namespace operand +{ + +class CLTensor : public ICLTensor +{ +public: + CLTensor() = delete; + +public: + CLTensor(const compiler::TensorInfo &info); + +public: + arm_compute::CLTensor *handle() const override; + arm_compute::CLTensor *handle() override; + +public: + arm_compute::CLTensorAllocator *allocator(); + void map(bool blocking = true); + void unmap(); + void setBuffer(void *host_ptr); + +protected: + uint8_t *doMap(cl::CommandQueue &q, bool blocking) override; + void doUnmap(cl::CommandQueue &q) override; + +private: + std::shared_ptr<arm_compute::CLTensor> _cl_tensor; +}; + +} // namespace operand +} // namespace acl_cl +} // namespace backend +} // namespace neurun + +#endif // __NEURUN_BACKEND_ACL_CL_OPERAND_CL_TENSOR_H__ diff --git a/runtimes/neurun/src/backend/acl_cl/operand/ICLTensor.cc b/runtimes/neurun/src/backend/acl_cl/operand/ICLTensor.cc new file mode 100644 index 000000000..23d723de4 --- /dev/null +++ b/runtimes/neurun/src/backend/acl_cl/operand/ICLTensor.cc @@ -0,0 +1,48 @@ +#include "ICLTensor.h" + +namespace neurun +{ +namespace backend +{ +namespace acl_cl +{ +namespace operand +{ + +size_t ICLTensor::total_size() const { return info()->total_size(); } + +size_t ICLTensor::dimension(size_t index) const { return info()->dimension(index); } + +size_t ICLTensor::num_dimensions() const { return info()->num_dimensions(); } + +size_t ICLTensor::calcOffset(const neurun::util::feature::Coordinate4D &coords) +{ + int32_t N = coords.n(); + int32_t C = coords.c(); + int32_t H = coords.h(); + int32_t W = coords.w(); + + ::arm_compute::Coordinates coordinates{W, H, C, N}; + return info()->offset_element_in_bytes(coordinates); +} + +arm_compute::DataType ICLTensor::data_type() const { return info()->data_type(); } + +uint8_t *ICLTensor::buffer() const { return handle()->buffer(); } + +const cl::Buffer &ICLTensor::cl_buffer() const { return handle()->cl_buffer(); } + +arm_compute::ITensorInfo *ICLTensor::info() const { return handle()->info(); } + +arm_compute::ITensorInfo *ICLTensor::info() { return handle()->info(); } + +void ICLTensor::map(cl::CommandQueue &q, bool blocking) { return handle()->map(q, blocking); } + +void ICLTensor::unmap(cl::CommandQueue &q) { return handle()->unmap(q); } + +void ICLTensor::clear(cl::CommandQueue &q) { return handle()->clear(q); } + +} // namespace operand +} // namespace acl_cl +} // namespace backend +} // namespace neurun diff --git a/runtimes/neurun/src/backend/acl_cl/operand/ICLTensor.h b/runtimes/neurun/src/backend/acl_cl/operand/ICLTensor.h new file mode 100644 index 000000000..226fbf814 --- /dev/null +++ b/runtimes/neurun/src/backend/acl_cl/operand/ICLTensor.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2018 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 __NEURUN_BACKEND_ACL_CL_OPERAND_I_CL_TENSOR_H__ +#define __NEURUN_BACKEND_ACL_CL_OPERAND_I_CL_TENSOR_H__ + +#include <arm_compute/core/ITensorInfo.h> +#include <arm_compute/core/CL/ICLTensor.h> +#include "backend/interface/operand/ITensor.h" + +namespace neurun +{ +namespace backend +{ +namespace acl_cl +{ +namespace operand +{ + +class ICLTensor : public ::neurun::backend::operand::ITensor +{ +public: + ICLTensor() = default; + ICLTensor(const ICLTensor &) = delete; + ICLTensor &operator=(const ICLTensor &) = delete; + ICLTensor(ICLTensor &&) = default; + ICLTensor &operator=(ICLTensor &&) = default; + virtual ~ICLTensor() = default; + +public: + virtual arm_compute::ICLTensor *handle() = 0; + virtual arm_compute::ICLTensor *handle() const = 0; + +public: + uint8_t *buffer() const override; + size_t total_size() const override; + size_t dimension(size_t index) const override; + size_t num_dimensions() const override; + size_t calcOffset(const neurun::util::feature::Coordinate4D &coords) override; + +public: + arm_compute::DataType data_type() const; + const cl::Buffer &cl_buffer() const; + arm_compute::ITensorInfo *info() const; + arm_compute::ITensorInfo *info(); + void map(cl::CommandQueue &q, bool blocking = true); + void unmap(cl::CommandQueue &q); + void clear(cl::CommandQueue &q); + +protected: + virtual uint8_t *doMap(cl::CommandQueue &q, bool blocking) = 0; + virtual void doUnmap(cl::CommandQueue &q) = 0; +}; + +} // namespace operand +} // namespace acl_cl +} // namespace backend +} // namespace neurun + +#endif // __NEURUN_BACKEND_ACL_CL_OPERAND_I_CL_TENSOR_H__ diff --git a/runtimes/neurun/src/backend/acl_cl/operand/Object.cc b/runtimes/neurun/src/backend/acl_cl/operand/Object.cc index 98b96a11a..a84fa2366 100644 --- a/runtimes/neurun/src/backend/acl_cl/operand/Object.cc +++ b/runtimes/neurun/src/backend/acl_cl/operand/Object.cc @@ -27,7 +27,8 @@ namespace acl_cl namespace operand { -void Object::access(const std::function<void(::arm_compute::ITensor &tensor)> &fn) const +void Object::access( + const std::function<void(::neurun::backend::operand::ITensor &tensor)> &fn) const { auto &queue = ::arm_compute::CLScheduler::get().queue(); diff --git a/runtimes/neurun/src/backend/acl_cl/operand/Object.h b/runtimes/neurun/src/backend/acl_cl/operand/Object.h index da33c0549..4ba22b269 100644 --- a/runtimes/neurun/src/backend/acl_cl/operand/Object.h +++ b/runtimes/neurun/src/backend/acl_cl/operand/Object.h @@ -18,9 +18,9 @@ #define __NEURUN_BACKEND_ACL_CL_OPERAND_OBJECT_H__ #include <memory> -#include <arm_compute/core/CL/ICLTensor.h> -#include "backend/IObject.h" +#include "backend/interface/operand/IObject.h" +#include "backend/acl_cl/operand/ICLTensor.h" namespace neurun { @@ -37,19 +37,21 @@ public: Object() = default; public: - Object(const std::shared_ptr<::arm_compute::ICLTensor> &tensor) : _tensor{tensor} + Object(const std::shared_ptr<::neurun::backend::acl_cl::operand::ICLTensor> &tensor) + : _tensor{tensor} { // DO NOTHING } public: - ::arm_compute::ICLTensor *ptr(void) const override { return _tensor.get(); } + ::neurun::backend::acl_cl::operand::ICLTensor *ptr(void) const override { return _tensor.get(); } private: - std::shared_ptr<::arm_compute::ICLTensor> _tensor; + std::shared_ptr<::neurun::backend::acl_cl::operand::ICLTensor> _tensor; public: - void access(const std::function<void(::arm_compute::ITensor &tensor)> &fn) const override; + void + access(const std::function<void(::neurun::backend::operand::ITensor &tensor)> &fn) const override; }; } // namespace operand diff --git a/runtimes/neurun/src/backend/cpu/CMakeLists.txt b/runtimes/neurun/src/backend/cpu/CMakeLists.txt index 95e9af687..dc4406a65 100644 --- a/runtimes/neurun/src/backend/cpu/CMakeLists.txt +++ b/runtimes/neurun/src/backend/cpu/CMakeLists.txt @@ -1,19 +1,18 @@ file(GLOB_RECURSE SOURCES "*.cc") -add_library(${LIB_NEURUN_BACKEND_CPU} STATIC ${SOURCES}) +add_library(${LIB_NEURUN_BACKEND_CPU} SHARED ${SOURCES}) target_include_directories(${LIB_NEURUN_BACKEND_CPU} PUBLIC ${NNFW_INCLUDE_DIR}) target_include_directories(${LIB_NEURUN_BACKEND_CPU} PUBLIC ${NEURUN_INCLUDE_DIR}) target_include_directories(${LIB_NEURUN_BACKEND_CPU} PUBLIC ${CMAKE_SOURCE_DIR}/externals/tensorflow) -target_link_libraries(${LIB_NEURUN_BACKEND_CPU} arm_compute) # TODO We should not need this target_link_libraries(${LIB_NEURUN_BACKEND_CPU} tensorflow-lite) -target_link_libraries(${LIB_NEURUN_BACKEND_CPU} nnfw_util) -target_link_libraries(${LIB_NEURUN_BACKEND_CPU} nnfw_support_nnapi) +target_link_libraries(${LIB_NEURUN_BACKEND_CPU} nnfw_lib_misc) +target_link_libraries(${LIB_NEURUN_BACKEND_CPU} nnfw_lib_cpp14) target_link_libraries(${LIB_NEURUN_BACKEND_CPU} ${LIB_NEURUN_KERNEL_CPU}) +target_link_libraries(${LIB_NEURUN_BACKEND_CPU} ${LIB_NEURUN}) target_compile_options(${LIB_NEURUN_BACKEND_CPU} PRIVATE -Wall -Wextra -Werror) -set_target_properties(${LIB_NEURUN_BACKEND_CPU} PROPERTIES POSITION_INDEPENDENT_CODE ON) set_target_properties(${LIB_NEURUN_BACKEND_CPU} PROPERTIES OUTPUT_NAME backend_cpu) install(TARGETS ${LIB_NEURUN_BACKEND_CPU} DESTINATION lib/neurun) diff --git a/runtimes/neurun/src/backend/cpu/BackendConfig.cc b/runtimes/neurun/src/backend/cpu/Config.cc index 34fc3491a..001ba9d02 100644 --- a/runtimes/neurun/src/backend/cpu/BackendConfig.cc +++ b/runtimes/neurun/src/backend/cpu/Config.cc @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "backend/cpu/BackendConfig.h" +#include "backend/cpu/Config.h" namespace neurun { @@ -23,7 +23,7 @@ namespace backend namespace cpu { -void BackendConfig::initialize() +void Config::initialize() { // DO NOTHING } diff --git a/runtimes/neurun/src/backend/cpu/BackendConfig.h b/runtimes/neurun/src/backend/cpu/Config.h index 109235bb1..ad9ca0ee8 100644 --- a/runtimes/neurun/src/backend/cpu/BackendConfig.h +++ b/runtimes/neurun/src/backend/cpu/Config.h @@ -14,10 +14,10 @@ * limitations under the License. */ -#ifndef __NEURUN_BACKEND_CPU_BACKEND_CONFIG_H__ -#define __NEURUN_BACKEND_CPU_BACKEND_CONFIG_H__ +#ifndef __NEURUN_BACKEND_CPU_CONFIG_H__ +#define __NEURUN_BACKEND_CPU_CONFIG_H__ -#include "backend/IBackendConfig.h" +#include "backend/interface/IConfig.h" namespace neurun { @@ -26,20 +26,26 @@ namespace backend namespace cpu { -class BackendConfig : public IBackendConfig +class Config : public IConfig { public: - BackendConfig() + Config() { // DO NOTHING } + virtual std::string id() override { return "cpu"; } virtual void initialize() override; virtual graph::operand::Layout getOperandLayout() { return graph::operand::Layout::NHWC; } + virtual bool SupportSubTensorAlloc() override + { + // NOTE CPU allocator cannot support subtensor allocation yet + return false; + } }; } // namespace cpu } // namespace backend } // namespace neurun -#endif // __NEURUN_BACKEND_CPU_BACKEND_CONFIG_H__ +#endif // __NEURUN_BACKEND_CPU_CONFIG_H__ diff --git a/runtimes/neurun/src/backend/cpu/InitializerGenerator.cc b/runtimes/neurun/src/backend/cpu/InitializerGenerator.cc deleted file mode 100644 index 7b08c7131..000000000 --- a/runtimes/neurun/src/backend/cpu/InitializerGenerator.cc +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright (c) 2018 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 "InitializerGenerator.h" - -#include "internal/nnapi/kernel/Reader.h" -#include "internal/nnapi/kernel/View.h" -#include "util/kernel/IndexIterator.h" - -#include "NeuralNetworks.h" - -namespace neurun -{ -namespace backend -{ -namespace cpu -{ - -InitializerGenerator::InitializerGenerator(const neurun::graph::operand::Set &ctx) : _ctx(ctx) -{ - // DO NOTHING -} - -Initializer -InitializerGenerator::generateWeight(const graph::operation::Conv2D::Implicit::Node &node) -{ - const ::neurun::graph::operand::Index ker_index{node.getInputs().at(1)}; - - const auto ker_shape = _ctx.at(ker_index).shape().asKernel(); - auto ker_base = _ctx.at(ker_index).data().base(); - auto ker_size = _ctx.at(ker_index).data().size(); - - return [ker_shape, ker_base, ker_size](::arm_compute::ITensor &tensor) { - const ::internal::nnapi::kernel::Reader<float> from{ker_shape, ker_base, ker_size}; - ::internal::nnapi::kernel::View<float> into{&tensor}; - - ::nnfw::util::kernel::iterate(ker_shape) - << [&](uint32_t nth, uint32_t ch, uint32_t row, uint32_t col) { - const auto value = from.at(nth, ch, row, col); - into.at(nth, row, col, ch) = value; - }; - }; -} - -Initializer InitializerGenerator::generateWeight(const graph::operation::FullyConnected::Node &node) -{ - const ::neurun::graph::operand::Index weight_index{node.getInputs().at(1)}; - const ::neurun::graph::operand::Index input_index{node.getInputs().at(0)}; - - const auto num_output = _ctx.at(weight_index).shape().dim(0); - auto weight_base = _ctx.at(weight_index).data().base(); - auto weight_size = _ctx.at(weight_index).data().size(); - auto weight_type = _ctx.at(weight_index).typeInfo().type(); - - // NOTE We assume that input is a feature map - // TODO Remove this restriction! - const auto ifm_shape = _ctx.at(input_index).shape().asFeature(); - - switch (weight_type) - { - case ::neurun::graph::operand::DataType::TENSOR_FLOAT32: - { - return [num_output, ifm_shape, weight_base, weight_size](::arm_compute::ITensor &tensor) { - const ::nnfw::util::kernel::Shape ker_shape{num_output, ifm_shape.C, ifm_shape.H, - ifm_shape.W}; - const ::internal::nnapi::kernel::Reader<float> from{ker_shape, weight_base, weight_size}; - - ::nnfw::util::kernel::iterate(ker_shape) - << [&](uint32_t nth, uint32_t ch, uint32_t row, uint32_t col) { - const auto value = from.at(nth, ch, row, col); - - uint32_t offset = 0; - - // NNAPI uses NHWC ordering - offset += nth * ifm_shape.H * ifm_shape.W * ifm_shape.C; - offset += row * ifm_shape.W * ifm_shape.C; - offset += col * ifm_shape.C; - offset += ch; - - const ::arm_compute::Coordinates coordinate{offset}; - - auto into = reinterpret_cast<float *>(tensor.ptr_to_element(coordinate)); - - *into = value; - }; - }; - } - case ::neurun::graph::operand::DataType::TENSOR_QUANT8_ASYMM: - { - return [num_output, ifm_shape, weight_base, weight_size](::arm_compute::ITensor &tensor) { - const ::nnfw::util::kernel::Shape ker_shape{num_output, ifm_shape.C, ifm_shape.H, - ifm_shape.W}; - const ::internal::nnapi::kernel::Reader<uint8_t> from{ker_shape, weight_base, weight_size}; - ::nnfw::util::kernel::iterate(ker_shape) - << [&](uint32_t nth, uint32_t ch, uint32_t row, uint32_t col) { - const auto value = from.at(nth, ch, row, col); - uint32_t offset = 0; - - // NNAPI uses NHWC ordering - offset += nth * ifm_shape.H * ifm_shape.W * ifm_shape.C; - offset += row * ifm_shape.W * ifm_shape.C; - offset += col * ifm_shape.C; - offset += ch; - - const ::arm_compute::Coordinates coordinate{offset}; - - auto into = reinterpret_cast<uint8_t *>(tensor.ptr_to_element(coordinate)); - - *into = value; - }; - }; - } - default: - { - throw std::runtime_error("Not supported weight type"); - } - } -} - -Initializer InitializerGenerator::generateBias(const graph::operation::Conv2D::Implicit::Node &node) -{ - // TODO Refactor so we can reuse the common code - - const ::neurun::graph::operand::Index bias_index{node.getInputs().at(2)}; - - auto bias_base = _ctx.at(bias_index).data().base(); - const auto bias_size = _ctx.at(bias_index).shape().asVector(); - - return [bias_base, bias_size](::arm_compute::ITensor &tensor) { - for (int32_t n = 0; n < bias_size; ++n) - { - const ::arm_compute::Coordinates coordinate{n}; - - float *into = reinterpret_cast<float *>(tensor.ptr_to_element(coordinate)); - - const float *from = reinterpret_cast<const float *>(bias_base) + n; - const auto value = *from; - - *into = value; - } - }; -} - -Initializer InitializerGenerator::generateBias(const graph::operation::FullyConnected::Node &node) -{ - const ::neurun::graph::operand::Index bias_index{node.getInputs().at(2)}; - - auto bias_base = _ctx.at(bias_index).data().base(); - auto bias_type = _ctx.at(bias_index).typeInfo().type(); - const auto bias_size = _ctx.at(bias_index).shape().asVector(); - - switch (bias_type) - { - case ::neurun::graph::operand::DataType::TENSOR_FLOAT32: - { - return [bias_base, bias_size](::arm_compute::ITensor &tensor) { - for (int32_t n = 0; n < bias_size; ++n) - { - const ::arm_compute::Coordinates coordinate{n}; - - float *into = reinterpret_cast<float *>(tensor.ptr_to_element(coordinate)); - - const float *from = reinterpret_cast<const float *>(bias_base) + n; - const auto value = *from; - - *into = value; - } - }; - } - case ::neurun::graph::operand::DataType::TENSOR_QUANT8_ASYMM: - { - return [bias_base, bias_size](::arm_compute::ITensor &tensor) { - for (int32_t n = 0; n < bias_size; ++n) - { - const ::arm_compute::Coordinates coordinate{n}; - - uint8_t *into = reinterpret_cast<uint8_t *>(tensor.ptr_to_element(coordinate)); - - const uint8_t *from = reinterpret_cast<const uint8_t *>(bias_base) + n; - const auto value = *from; - - *into = value; - } - }; - } - default: - { - throw std::runtime_error("Not supported bias type"); - } - } -} - -} // namespace cpu -} // namespace backend -} // namespace neurun diff --git a/runtimes/neurun/src/backend/cpu/InitializerGenerator.h b/runtimes/neurun/src/backend/cpu/InitializerGenerator.h deleted file mode 100644 index 42d37f48b..000000000 --- a/runtimes/neurun/src/backend/cpu/InitializerGenerator.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2018 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 __NEURUN_BACKEND_CPU_INITIALIZER_GENERATOR_H__ -#define __NEURUN_BACKEND_CPU_INITIALIZER_GENERATOR_H__ - -#include "backend/IInitializerGenerator.h" - -#include "graph/operand/Set.h" - -namespace neurun -{ -namespace backend -{ -namespace cpu -{ - -class InitializerGenerator : public IInitializerGenerator -{ -public: - InitializerGenerator(const neurun::graph::operand::Set &ctx); - - Initializer generateWeight(const graph::operation::Conv2D::Implicit::Node &node) override; - Initializer generateWeight(const graph::operation::FullyConnected::Node &node) override; - - Initializer generateBias(const graph::operation::Conv2D::Implicit::Node &node) override; - Initializer generateBias(const graph::operation::FullyConnected::Node &node) override; - -private: - const neurun::graph::operand::Set &_ctx; -}; - -} // namespace cpu -} // namespace backend -} // namespace neurun - -#endif // __NEURUN_BACKEND_CPU_INITIALIZER_GENERATOR_H__ diff --git a/runtimes/neurun/src/backend/cpu/MemoryAllocator.h b/runtimes/neurun/src/backend/cpu/MemoryAllocator.h deleted file mode 100644 index e3550ac07..000000000 --- a/runtimes/neurun/src/backend/cpu/MemoryAllocator.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2018 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 __INTERNAL_CPU_MEMORY_ALLOCATOR_H__ -#define __INTERNAL_CPU_MEMORY_ALLOCATOR_H__ - -#include "arm_compute/runtime/ITensorAllocator.h" -#include "arm_compute/runtime/Memory.h" - -#include <cstdint> -#include <memory> -#include <vector> - -namespace arm_compute -{ -class Coordinates; -class TensorInfo; -class Tensor; -}; - -/** Basic implementation of a CPU memory tensor allocator. */ -class TensorAllocator : public ITensorAllocator -{ -public: - /** Default constructor. */ - TensorAllocator(Tensor *owner = nullptr); - /** Default destructor */ - ~TensorAllocator(); - - /** Make ITensorAllocator's init methods available */ - using ITensorAllocator::init; - - /** Shares the same backing memory with another tensor allocator, while the tensor info might be - * different. - * In other words this can be used to create a sub-tensor from another tensor while sharing the - * same memory. - * - * @note TensorAllocator have to be of the same specialized type. - * - * @param[in] allocator The allocator that owns the backing memory to be shared. Ownership becomes - * shared afterwards. - * @param[in] coords The starting coordinates of the new tensor inside the parent tensor. - * @param[in] sub_info The new tensor information (e.g. shape etc) - */ - void init(const TensorAllocator &allocator, const Coordinates &coords, TensorInfo sub_info); - - /** Returns the pointer to the allocated data. */ - uint8_t *data() const; - - /** Allocate size specified by TensorInfo of CPU memory. - * - * @note The tensor must not already be allocated when calling this function. - * - */ - void allocate() override; - - /** Free allocated CPU memory. - * - * @note The tensor must have been allocated when calling this function. - * - */ - void free() override; - /** Import an existing memory as a tensor's backing memory - * - * @warning If the tensor is flagged to be managed by a memory manager, - * this call will lead to an error. - * @warning Ownership of memory depends on the way the @ref Memory object was constructed - * @note Calling free on a tensor with imported memory will just clear - * the internal pointer value. - * - * @param[in] memory Memory to import - * - * @return error status - */ - arm_compute::Status import_memory(Memory memory); - /** Associates the tensor with a memory group - * - * @param[in] associated_memory_group Memory group to associate the tensor with - */ - void set_associated_memory_group(MemoryGroup *associated_memory_group); - -protected: - /** No-op for CPU memory - * - * @return A pointer to the beginning of the tensor's allocation. - */ - uint8_t *lock() override; - - /** No-op for CPU memory. */ - void unlock() override; - -private: - MemoryGroup *_associated_memory_group; /**< Registered memory manager */ - Memory _memory; /**< CPU memory */ - Tensor *_owner; /**< Owner of the allocator */ -}; - -namespace internal -{ -namespace cpu -{ - -class MemoryAllocator : public -{ -}; - -} // namespace cpu -} // namespace internal - -#endif // __INTERNAL_CPU_MEMORY_ALLOCATOR_H__ diff --git a/runtimes/neurun/src/backend/cpu/MemoryPlanner.cc b/runtimes/neurun/src/backend/cpu/MemoryPlanner.cc new file mode 100644 index 000000000..2d0995b8a --- /dev/null +++ b/runtimes/neurun/src/backend/cpu/MemoryPlanner.cc @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2018 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 "MemoryPlanner.h" +#include "util/logging.h" +#include <cassert> + +namespace neurun +{ +namespace backend +{ +namespace cpu +{ + +Allocator::Allocator(uint32_t capacity) +{ + assert(!_base && capacity != 0); + + _base = new uint8_t[capacity]; + + VERBOSE(ALLOC) << "allocation capacity: " << capacity << std::endl; + VERBOSE(ALLOC) << "base pointer: " << static_cast<void *>(_base) << std::endl; +} + +Allocator::~Allocator() { delete[] _base; } + +void BumpPlanner::claim(const model::operand::Index &ind, size_t size) +{ + assert(size != 0); + + Block blk{_capacity, size}; + _mem_plans[ind] = blk; + _capacity += size; + + VERBOSE(BP_PLANNER) << "CLAIM(#" << ind.value() << "): " << blk.offset << ", " << blk.size + << std::endl; +} + +void BumpPlanner::release(const model::operand::Index &ind) +{ + VERBOSE(BP_PLANNER) << "RELEASE(#" << ind.value() << "): " + << "NOTHING does" << std::endl; +} + +// There are some assumptions for claiming memory(== making a reservation for memory). +// 1. About _claim_table(std::map). +// - The table's data structure is std::map so that it always sorts +// value(model::operand::Index) by key(base_offset). +// - This claim() inserts key/value into _claim_table and the release() removes the key/value from +// _claim_table. +// - _claim_table shows the memory status at a certain point in time. Therefore, +// - If _claim_table has an offset and a certain size at a certain point in time, +// it means the place at the offset has been already claimed(== can't claim now. need to find +// someplace new). +// - If _claim_table doesn't have any element for an offset and a certain size at a certain +// point in time, it means the place at the offset can be claimed. +// 2. In the loop for _claim_table, we can assume the current claim_base_offset value is bigger than +// the previous claim_base_offset. +void FirstFitPlanner::claim(const model::operand::Index &ind, size_t size) +{ + assert(size != 0); + + // Find the right position for claiming + uint32_t next_offset = 0; + for (auto &mem_claim : _claim_table) + { + auto claimed_base_offset = mem_claim.first; + auto claimed_size = _mem_plans[mem_claim.second].size; + if (next_offset + size <= claimed_base_offset) + { + break; + } + else + { + next_offset = claimed_base_offset + claimed_size; + } + } + + // Now next_offset is set to the proper offset + _claim_table[next_offset] = ind; + _mem_plans[ind] = {next_offset, size}; + + VERBOSE(FF_PLANNER) << "claim(#" << ind.value() << "): [+" << next_offset << ", " << size << "sz]" + << std::endl; + + if (_capacity < next_offset + size) + { + _capacity = next_offset + size; + } +} + +void FirstFitPlanner::release(const model::operand::Index &ind) +{ + for (auto it = _claim_table.cbegin(); it != _claim_table.cend(); ++it) + { + if (it->second == ind) + { + uint32_t offset = it->first; + uint32_t index = ind.value(); + uint32_t size = _mem_plans[ind].size; + + _claim_table.erase(it); + + VERBOSE(FF_PLANNER) << "release(#" << index << "): [+" << offset << ", " << size << "sz]" + << std::endl; + return; + } + } + assert(!"Cannot release for given index. It has been not claimed or released already."); +} + +} // namespace cpu +} // namespace backend +} // namespace neurun diff --git a/runtimes/neurun/src/backend/cpu/MemoryPlanner.h b/runtimes/neurun/src/backend/cpu/MemoryPlanner.h new file mode 100644 index 000000000..4b2661223 --- /dev/null +++ b/runtimes/neurun/src/backend/cpu/MemoryPlanner.h @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2018 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       MemoryPlanner.h + * @brief      This file contains Memory Planning related classes + */ + +#ifndef __NEURUN_BACKEND_CPU_MEMORY_PLANNER_H__ +#define __NEURUN_BACKEND_CPU_MEMORY_PLANNER_H__ + +#include <map> +#include <unordered_map> + +#include "model/operand/Index.h" + +namespace neurun +{ +namespace backend +{ +namespace cpu +{ + +/** + * @brief Structure to have memory offset and size + */ +struct Block +{ + uint32_t offset; + uint32_t size; +}; + +/** + * @brief Class to allocate memory + */ +class Allocator +{ +public: + Allocator(uint32_t capacity); + ~Allocator(); + /** + * @brief Get memory base pointer + * @return base pointer + */ + uint8_t *base() const { return _base; } + +private: + uint8_t *_base = nullptr; +}; + +/** + * @brief Interface to plan memory + */ +struct IMemoryPlanner +{ + using MemoryPlans = std::unordered_map<model::operand::Index, Block>; + + /** + * @brief Claim memory for operand + * @param[in] index The operand index + * @param[in] size The size of the memory + */ + virtual void claim(const model::operand::Index &, size_t) = 0; + /** + * @brief Release memory for operand + * @param[in] index The operand index + */ + virtual void release(const model::operand::Index &) = 0; + /** + * @brief Get capacity for memory planning + * @return The value of capacity + */ + virtual uint32_t capacity() = 0; + /** + * @brief Get MemoryPlans + * @return MemoryPlans + */ + virtual MemoryPlans &memory_plans() = 0; +}; + +/** + * @brief Class to plan memory by bump way + */ +class BumpPlanner : public IMemoryPlanner +{ +public: + /** + * @brief Claim memory for operand by bump way + * @param[in] index The operand index + * @param[in] size The size of the memory + */ + virtual void claim(const model::operand::Index &, size_t) override; + /** + * @brief Release memory for operand by bump way + * @param[in] index The operand index + */ + virtual void release(const model::operand::Index &) override; + /** + * @brief Get capacity for memory planning + * @return The value of capacity + */ + virtual uint32_t capacity() override { return _capacity; } + /** + * @brief Get MemoryPlans + * @return MemoryPlans + */ + virtual MemoryPlans &memory_plans() override { return _mem_plans; } + +private: + uint32_t _capacity = 0; + MemoryPlans _mem_plans; +}; + +/** + * @brief Class to plan memory by firstfit way + */ +class FirstFitPlanner : public IMemoryPlanner +{ +public: + /** + * @brief Claim memory for operand by firstfit way + * @param[in] index The operand index + * @param[in] size The size of the memory + */ + virtual void claim(const model::operand::Index &, size_t) override; + /** + * @brief Release memory for operand by firstfit way + * @param[in] index The operand index + */ + virtual void release(const model::operand::Index &) override; + /** + * @brief Get capacity for memory planning + * @return The value of capacity + */ + virtual uint32_t capacity() override { return _capacity; } + /** + * @brief Get MemoryPlans + * @return MemoryPlans + */ + virtual MemoryPlans &memory_plans() override { return _mem_plans; } + +private: + uint32_t _capacity = 0; + MemoryPlans _mem_plans; + // Use std::map because claim() assumes that _claim_table is sorted by uint32_t(base_offset) + std::map<uint32_t, model::operand::Index> _claim_table; +}; + +} // namespace cpu +} // namespace backend +} // namespace neurun + +#endif // __NEURUN_BACKEND_CPU_MEMORY_PLANNER_H__ diff --git a/runtimes/neurun/src/backend/cpu/PluginClassesAllocator.cc b/runtimes/neurun/src/backend/cpu/PluginClassesAllocator.cc new file mode 100644 index 000000000..26d4d8858 --- /dev/null +++ b/runtimes/neurun/src/backend/cpu/PluginClassesAllocator.cc @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2018 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 <memory> +#include "TensorBuilder.h" +#include "StageGenerator.h" +#include "Config.h" +#include "util/logging.h" + +extern "C" { +neurun::backend::cpu::TensorBuilder *allocate_TensorBuilder() +{ + VERBOSE(allocate_TensorBuilder) << "loaded from CPU\n"; + return new neurun::backend::cpu::TensorBuilder; +} + +neurun::backend::cpu::StageGenerator * +allocate_StageGenerator(const neurun::model::operand::Set &operand_ctx, + const std::shared_ptr<neurun::backend::cpu::TensorBuilder> &tensor_builder) +{ + VERBOSE(allocate_StageGenerator) << "loaded from CPU\n"; + return new neurun::backend::cpu::StageGenerator(operand_ctx, tensor_builder); +} + +neurun::backend::cpu::Config *allocate_Config() +{ + VERBOSE(allocate_Config) << "loaded from CPU\n"; + return new neurun::backend::cpu::Config; +} +} diff --git a/runtimes/neurun/src/backend/cpu/StageGenerator.cc b/runtimes/neurun/src/backend/cpu/StageGenerator.cc index b7a3fa24a..c53b320a4 100644 --- a/runtimes/neurun/src/backend/cpu/StageGenerator.cc +++ b/runtimes/neurun/src/backend/cpu/StageGenerator.cc @@ -18,7 +18,8 @@ #include <stdexcept> -#include "internal/Padding.h" +#include "cpp14/memory.h" +#include "util/Padding.h" #include "kernel/cpu/OperationUtils.h" #include "kernel/cpu/ConvolutionLayer.h" #include "kernel/cpu/AvgPoolLayer.h" @@ -27,12 +28,13 @@ #include "kernel/cpu/FullyConnectedLayer.h" #include "kernel/cpu/ReshapeLayer.h" #include "kernel/cpu/SoftMaxLayer.h" +#include "kernel/cpu/PermuteLayer.h" +#include "backend/BackendManager.h" +#include "backend/interface/IConfig.h" -#include "logging.h" +#include "util/logging.h" -#include "support/nnapi/Utils.h" - -#include "logging.h" +#include "util/Utils.h" namespace neurun { @@ -41,25 +43,27 @@ namespace backend namespace cpu { -StageGenerator::StageGenerator(const neurun::graph::operand::Set &operand_ctx, +StageGenerator::StageGenerator(const neurun::model::operand::Set &operand_ctx, const std::shared_ptr<TensorBuilder> &tensor_builder) : _ctx(operand_ctx), _tensor_builder(tensor_builder) { // DO NOTHING } -Stage StageGenerator::generate(const graph::operation::Conv2D::Implicit::Node &node) +void StageGenerator::visit(const model::operation::Conv2DNode &node) { - const ::neurun::graph::operand::Index ofm_index{node.getOutputs().at(0)}; - const ::neurun::graph::operand::Index ifm_index{node.getInputs().at(0)}; - const ::neurun::graph::operand::Index ker_index{node.getInputs().at(1)}; - const ::neurun::graph::operand::Index bias_index{node.getInputs().at(2)}; + using model::operation::Conv2DNode; + + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(Conv2DNode::Input::INPUT)}; + const auto ker_index{node.getInputs().at(Conv2DNode::Input::KERNEL)}; + const auto bias_index{node.getInputs().at(Conv2DNode::Input::BIAS)}; - const ::neurun::graph::operand::Index vstride_index{node.param().vstride_index}; - const ::neurun::graph::operand::Index hstride_index{node.param().hstride_index}; + const auto vstride_index{node.param().vstride_index}; + const auto hstride_index{node.param().hstride_index}; - const ::neurun::graph::operand::Index padding_index{node.param().padding_index}; - const ::neurun::graph::operand::Index activation_index{node.param().activation_index}; + const auto padding_index{node.param().padding_index}; + const auto activation_index{node.param().activation_index}; const PaddingCode padding_type = static_cast<PaddingCode>(_ctx.at(padding_index).asScalar<int32_t>()); @@ -67,7 +71,7 @@ Stage StageGenerator::generate(const graph::operation::Conv2D::Implicit::Node &n assert((ANEURALNETWORKS_PADDING_SAME == padding_type) || (ANEURALNETWORKS_PADDING_VALID == padding_type)); - ::internal::Stride stride; + util::Stride stride; stride.vertical = _ctx.at(vstride_index).asScalar<int32_t>(); stride.horizontal = _ctx.at(hstride_index).asScalar<int32_t>(); @@ -75,28 +79,28 @@ Stage StageGenerator::generate(const graph::operation::Conv2D::Implicit::Node &n // Construct operation parameters struct Param { - int ofm_index; - int ifm_index; - int ker_index; - int bias_index; + model::operand::Index ofm_index; + model::operand::Index ifm_index; + model::operand::Index ker_index; + model::operand::Index bias_index; ::neurun::kernel::cpu::Shape ofm_shape; ::neurun::kernel::cpu::Shape ifm_shape; ::neurun::kernel::cpu::Shape ker_shape; ::neurun::kernel::cpu::Shape bias_shape; - ::internal::Padding padding; - ::internal::Stride stride; + util::Padding padding; + util::Stride stride; FuseCode activation; }; Param param; - param.ofm_index = ofm_index.asInt(); - param.ifm_index = ifm_index.asInt(); - param.ker_index = ker_index.asInt(); - param.bias_index = bias_index.asInt(); + param.ofm_index = ofm_index; + param.ifm_index = ifm_index; + param.ker_index = ker_index; + param.bias_index = bias_index; param.ofm_shape = ::neurun::kernel::cpu::getShape(_ctx.at(ofm_index)); param.ifm_shape = ::neurun::kernel::cpu::getShape(_ctx.at(ifm_index)); @@ -105,21 +109,21 @@ Stage StageGenerator::generate(const graph::operation::Conv2D::Implicit::Node &n param.stride = stride; param.padding = (padding_type == ANEURALNETWORKS_PADDING_SAME) - ? ::internal::same_padding(_ctx.at(ifm_index).shape().asFeature(), - _ctx.at(ofm_index).shape().asFeature(), stride, - _ctx.at(ker_index).shape().asKernel().W, - _ctx.at(ker_index).shape().asKernel().H) - : ::internal::valid_padding(); + ? util::same_padding(_ctx.at(ifm_index).shape().asFeature(), + _ctx.at(ofm_index).shape().asFeature(), stride, + _ctx.at(ker_index).shape().asKernel().W, + _ctx.at(ker_index).shape().asKernel().H) + : util::valid_padding(); param.activation = static_cast<FuseCode>(_ctx.at(activation_index).asScalar<int32_t>()); auto tensors = _tensor_builder; - return [tensors, param](IExecutionBuilder &builder) { - auto ofm_alloc = tensors->at(::neurun::graph::operand::Index{param.ofm_index}); - auto ifm_alloc = tensors->at(::neurun::graph::operand::Index{param.ifm_index}); - auto ker_alloc = tensors->at(::neurun::graph::operand::Index{param.ker_index}); - auto bias_alloc = tensors->at(::neurun::graph::operand::Index{param.bias_index}); + returnStage([tensors, param](IExecutionBuilder &builder) { + auto ofm_alloc = tensors->at(param.ofm_index); + auto ifm_alloc = tensors->at(param.ifm_index); + auto ker_alloc = tensors->at(param.ker_index); + auto bias_alloc = tensors->at(param.bias_index); std::unique_ptr<::neurun::kernel::cpu::ConvolutionLayer> fn{ new ::neurun::kernel::cpu::ConvolutionLayer}; @@ -130,24 +134,22 @@ Stage StageGenerator::generate(const graph::operation::Conv2D::Implicit::Node &n param.stride.vertical, param.activation, ofm_alloc->buffer(), param.ofm_shape); builder.append(std::move(fn)); - }; + }); } -Stage StageGenerator::generate(const graph::operation::MaxPool2D::Implicit::Node &node) +void StageGenerator::visit(const model::operation::MaxPool2DNode &node) { - VERBOSE(MaxPool2D) << "generate CPU MaxPool2D" << std::endl; + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(model::operation::MaxPool2DNode::Input::INPUT)}; - const ::neurun::graph::operand::Index ofm_index{node.getOutputs().at(0)}; - const ::neurun::graph::operand::Index ifm_index{node.getInputs().at(0)}; + const auto kh_index{node.param().kh_index}; + const auto kw_index{node.param().kw_index}; - const ::neurun::graph::operand::Index kh_index{node.param().kh_index}; - const ::neurun::graph::operand::Index kw_index{node.param().kw_index}; + const auto vstride_index{node.param().vstride_index}; + const auto hstride_index{node.param().hstride_index}; - const ::neurun::graph::operand::Index vstride_index{node.param().vstride_index}; - const ::neurun::graph::operand::Index hstride_index{node.param().hstride_index}; - - const ::neurun::graph::operand::Index padding_index{node.param().padding_index}; - const ::neurun::graph::operand::Index activation_index{node.param().activation_index}; + const auto padding_index{node.param().padding_index}; + const auto activation_index{node.param().activation_index}; const int32_t kh = _ctx.at(kh_index).asScalar<int32_t>(); const int32_t kw = _ctx.at(kw_index).asScalar<int32_t>(); @@ -161,8 +163,8 @@ Stage StageGenerator::generate(const graph::operation::MaxPool2D::Implicit::Node // Construct operation parameters struct Param { - int ofm_index; - int ifm_index; + model::operand::Index ofm_index; + model::operand::Index ifm_index; uint32_t kw; uint32_t kh; @@ -170,16 +172,16 @@ Stage StageGenerator::generate(const graph::operation::MaxPool2D::Implicit::Node ::neurun::kernel::cpu::Shape ofm_shape; ::neurun::kernel::cpu::Shape ifm_shape; - ::internal::Padding padding; - ::internal::Stride stride; + util::Padding padding; + util::Stride stride; FuseCode activation; }; Param param; - param.ofm_index = ofm_index.asInt(); - param.ifm_index = ifm_index.asInt(); + param.ofm_index = ofm_index; + param.ifm_index = ifm_index; param.kh = kh; param.kw = kw; @@ -192,30 +194,17 @@ Stage StageGenerator::generate(const graph::operation::MaxPool2D::Implicit::Node param.padding = (padding_type == ANEURALNETWORKS_PADDING_SAME) - ? ::internal::same_padding(_ctx.at(ifm_index).shape().asFeature(), - _ctx.at(ofm_index).shape().asFeature(), param.stride, kw, kh) - : ::internal::valid_padding(); + ? util::same_padding(_ctx.at(ifm_index).shape().asFeature(), + _ctx.at(ofm_index).shape().asFeature(), param.stride, kw, kh) + : util::valid_padding(); param.activation = static_cast<FuseCode>(_ctx.at(activation_index).asScalar<int32_t>()); - VERBOSE(MaxPool2D) << "IFM_H: " << _ctx.at(ifm_index).shape().asFeature().H << std::endl; - VERBOSE(MaxPool2D) << "IFM_W: " << _ctx.at(ifm_index).shape().asFeature().W << std::endl; - VERBOSE(MaxPool2D) << "OFM_H: " << _ctx.at(ofm_index).shape().asFeature().H << std::endl; - VERBOSE(MaxPool2D) << "OFM_W: " << _ctx.at(ofm_index).shape().asFeature().W << std::endl; - VERBOSE(MaxPool2D) << "KER_H: " << kh << std::endl; - VERBOSE(MaxPool2D) << "KER_W: " << kw << std::endl; - VERBOSE(MaxPool2D) << "STRIDE_H: " << vstride << std::endl; - VERBOSE(MaxPool2D) << "STRIDE_W: " << hstride << std::endl; - VERBOSE(MaxPool2D) << "PAD(T): " << param.padding.top << std::endl; - VERBOSE(MaxPool2D) << "PAD(B): " << param.padding.bottom << std::endl; - VERBOSE(MaxPool2D) << "PAD(L): " << param.padding.left << std::endl; - VERBOSE(MaxPool2D) << "PAD(R): " << param.padding.right << std::endl; - auto tensors = _tensor_builder; - return [tensors, param](IExecutionBuilder &builder) { - auto ofm_alloc = tensors->at(::neurun::graph::operand::Index{param.ofm_index}).get(); - auto ifm_alloc = tensors->at(::neurun::graph::operand::Index{param.ifm_index}).get(); + returnStage([tensors, param](IExecutionBuilder &builder) { + auto ofm_alloc = tensors->at(param.ofm_index).get(); + auto ifm_alloc = tensors->at(param.ifm_index).get(); std::unique_ptr<::neurun::kernel::cpu::MaxPoolLayer> fn{ new ::neurun::kernel::cpu::MaxPoolLayer}; @@ -226,24 +215,22 @@ Stage StageGenerator::generate(const graph::operation::MaxPool2D::Implicit::Node param.ofm_shape); builder.append(std::move(fn)); - }; + }); } -Stage StageGenerator::generate(const graph::operation::AvgPool2D::Implicit::Node &node) +void StageGenerator::visit(const model::operation::AvgPool2DNode &node) { - VERBOSE(AvgPool2D) << "generate CPU AvgPool2D" << std::endl; - - const ::neurun::graph::operand::Index ofm_index{node.getOutputs().at(0)}; - const ::neurun::graph::operand::Index ifm_index{node.getInputs().at(0)}; + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(model::operation::AvgPool2DNode::Input::INPUT)}; - const ::neurun::graph::operand::Index kh_index{node.param().kh_index}; - const ::neurun::graph::operand::Index kw_index{node.param().kw_index}; + const auto kh_index{node.param().kh_index}; + const auto kw_index{node.param().kw_index}; - const ::neurun::graph::operand::Index vstride_index{node.param().vstride_index}; - const ::neurun::graph::operand::Index hstride_index{node.param().hstride_index}; + const auto vstride_index{node.param().vstride_index}; + const auto hstride_index{node.param().hstride_index}; - const ::neurun::graph::operand::Index padding_index{node.param().padding_index}; - const ::neurun::graph::operand::Index activation_index{node.param().activation_index}; + const auto padding_index{node.param().padding_index}; + const auto activation_index{node.param().activation_index}; const int32_t kh = _ctx.at(kh_index).asScalar<int32_t>(); const int32_t kw = _ctx.at(kw_index).asScalar<int32_t>(); @@ -260,8 +247,8 @@ Stage StageGenerator::generate(const graph::operation::AvgPool2D::Implicit::Node // Construct operation parameters struct Param { - int ofm_index; - int ifm_index; + model::operand::Index ofm_index; + model::operand::Index ifm_index; uint32_t kw; uint32_t kh; @@ -269,16 +256,16 @@ Stage StageGenerator::generate(const graph::operation::AvgPool2D::Implicit::Node ::neurun::kernel::cpu::Shape ofm_shape; ::neurun::kernel::cpu::Shape ifm_shape; - ::internal::Padding padding; - ::internal::Stride stride; + util::Padding padding; + util::Stride stride; FuseCode activation; }; Param param; - param.ofm_index = ofm_index.asInt(); - param.ifm_index = ifm_index.asInt(); + param.ofm_index = ofm_index; + param.ifm_index = ifm_index; param.kh = kh; param.kw = kw; @@ -291,31 +278,17 @@ Stage StageGenerator::generate(const graph::operation::AvgPool2D::Implicit::Node param.padding = (padding_type == ANEURALNETWORKS_PADDING_SAME) - ? ::internal::same_padding(_ctx.at(ifm_index).shape().asFeature(), - _ctx.at(ofm_index).shape().asFeature(), param.stride, kw, kh) - : ::internal::valid_padding(); + ? util::same_padding(_ctx.at(ifm_index).shape().asFeature(), + _ctx.at(ofm_index).shape().asFeature(), param.stride, kw, kh) + : util::valid_padding(); param.activation = static_cast<FuseCode>(_ctx.at(activation_index).asScalar<int32_t>()); - VERBOSE(AvgPool2D) << "IFM_H: " << _ctx.at(ifm_index).shape().asFeature().H << std::endl; - VERBOSE(AvgPool2D) << "IFM_W: " << _ctx.at(ifm_index).shape().asFeature().W << std::endl; - VERBOSE(AvgPool2D) << "OFM_H: " << _ctx.at(ofm_index).shape().asFeature().H << std::endl; - VERBOSE(AvgPool2D) << "OFM_W: " << _ctx.at(ofm_index).shape().asFeature().W << std::endl; - VERBOSE(AvgPool2D) << "KER_H: " << kh << std::endl; - VERBOSE(AvgPool2D) << "KER_W: " << kw << std::endl; - VERBOSE(AvgPool2D) << "STRIDE_H: " << vstride << std::endl; - VERBOSE(AvgPool2D) << "STRIDE_W: " << hstride << std::endl; - VERBOSE(AvgPool2D) << "PAD: " << ::nnfw::support::nnapi::to_string(padding_type) << std::endl; - VERBOSE(AvgPool2D) << "PAD(T): " << param.padding.top << std::endl; - VERBOSE(AvgPool2D) << "PAD(B): " << param.padding.bottom << std::endl; - VERBOSE(AvgPool2D) << "PAD(L): " << param.padding.left << std::endl; - VERBOSE(AvgPool2D) << "PAD(R): " << param.padding.right << std::endl; - auto tensors = _tensor_builder; - return [tensors, param](IExecutionBuilder &builder) { - auto ofm_alloc = tensors->at(::neurun::graph::operand::Index{param.ofm_index}).get(); - auto ifm_alloc = tensors->at(::neurun::graph::operand::Index{param.ifm_index}).get(); + returnStage([tensors, param](IExecutionBuilder &builder) { + auto ofm_alloc = tensors->at(param.ofm_index).get(); + auto ifm_alloc = tensors->at(param.ifm_index).get(); std::unique_ptr<::neurun::kernel::cpu::AvgPoolLayer> fn{ new ::neurun::kernel::cpu::AvgPoolLayer}; @@ -326,20 +299,18 @@ Stage StageGenerator::generate(const graph::operation::AvgPool2D::Implicit::Node param.ofm_shape); builder.append(std::move(fn)); - }; + }); } -Stage StageGenerator::generate(const graph::operation::Concat::Node &node) +void StageGenerator::visit(const model::operation::ConcatNode &node) { - VERBOSE(Concat) << "generate CPU Concat" << std::endl; - - const ::neurun::graph::operand::Index ofm_index{node.getOutputs().at(0)}; - const ::neurun::graph::operand::Index axis_index{node.param().axis_index}; + const auto ofm_index{node.getOutputs().at(0)}; + const auto axis_index{node.param().axis_index}; struct Param { - int32_t output_index; - std::vector<int32_t> input_indexes; + model::operand::Index output_index; + std::vector<model::operand::Index> input_indexes; int32_t axis; @@ -349,10 +320,10 @@ Stage StageGenerator::generate(const graph::operation::Concat::Node &node) Param param; - param.output_index = ofm_index.asInt(); + param.output_index = ofm_index; for (const auto &e : node.getInputs()) { - param.input_indexes.emplace_back(e.asInt()); + param.input_indexes.emplace_back(e); } param.axis = _ctx.at(axis_index).asScalar<int32_t>(); @@ -365,14 +336,13 @@ Stage StageGenerator::generate(const graph::operation::Concat::Node &node) auto tensors = _tensor_builder; - return [tensors, param](IExecutionBuilder &builder) { - auto output_alloc = tensors->at(::neurun::graph::operand::Index{param.output_index}).get(); + returnStage([tensors, param](IExecutionBuilder &builder) { + auto output_alloc = tensors->at(param.output_index).get(); std::vector<const uint8_t *> input_buffers; for (auto ifm_ind : param.input_indexes) { - input_buffers.emplace_back( - tensors->at(::neurun::graph::operand::Index{ifm_ind}).get()->buffer()); + input_buffers.emplace_back(tensors->at(ifm_ind).get()->buffer()); } std::unique_ptr<::neurun::kernel::cpu::ConcatLayer> fn{new ::neurun::kernel::cpu::ConcatLayer}; @@ -381,26 +351,26 @@ Stage StageGenerator::generate(const graph::operation::Concat::Node &node) param.ofm_shape); builder.append(std::move(fn)); - }; + }); } -Stage StageGenerator::generate(const graph::operation::FullyConnected::Node &node) +void StageGenerator::visit(const model::operation::FullyConnectedNode &node) { - VERBOSE(FullyConnected) << "generate CPU FullyConnected" << std::endl; + using model::operation::FullyConnectedNode; - const ::neurun::graph::operand::Index output_index{node.getOutputs().at(0)}; - const ::neurun::graph::operand::Index input_index{node.getInputs().at(0)}; - const ::neurun::graph::operand::Index weight_index{node.getInputs().at(1)}; - const ::neurun::graph::operand::Index bias_index{node.getInputs().at(2)}; - const ::neurun::graph::operand::Index activation_index{node.param().activation_index}; + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(FullyConnectedNode::Input::INPUT)}; + const auto weight_index{node.getInputs().at(FullyConnectedNode::Input::WEIGHT)}; + const auto bias_index{node.getInputs().at(FullyConnectedNode::Input::BIAS)}; + const auto activation_index{node.param().activation_index}; // Construct operation parameters struct Param { - int output_index; - int input_index; - int weight_index; - int bias_index; + model::operand::Index output_index; + model::operand::Index input_index; + model::operand::Index weight_index; + model::operand::Index bias_index; ::neurun::kernel::cpu::Shape ofm_shape; ::neurun::kernel::cpu::Shape ifm_shape; @@ -412,10 +382,10 @@ Stage StageGenerator::generate(const graph::operation::FullyConnected::Node &nod Param param; - param.output_index = output_index.asInt(); - param.input_index = input_index.asInt(); - param.weight_index = weight_index.asInt(); - param.bias_index = bias_index.asInt(); + param.output_index = output_index; + param.input_index = input_index; + param.weight_index = weight_index; + param.bias_index = bias_index; param.ofm_shape = ::neurun::kernel::cpu::getShape(_ctx.at(output_index)); param.ifm_shape = ::neurun::kernel::cpu::getShape(_ctx.at(input_index)); @@ -426,11 +396,11 @@ Stage StageGenerator::generate(const graph::operation::FullyConnected::Node &nod auto tensors = _tensor_builder; - return [tensors, param](IExecutionBuilder &builder) { - auto output_alloc = tensors->at(::neurun::graph::operand::Index{param.output_index}).get(); - auto input_alloc = tensors->at(::neurun::graph::operand::Index{param.input_index}).get(); - auto weight_alloc = tensors->at(::neurun::graph::operand::Index{param.weight_index}).get(); - auto bias_alloc = tensors->at(::neurun::graph::operand::Index{param.bias_index}).get(); + returnStage([tensors, param](IExecutionBuilder &builder) { + auto output_alloc = tensors->at(param.output_index).get(); + auto input_alloc = tensors->at(param.input_index).get(); + auto weight_alloc = tensors->at(param.weight_index).get(); + auto bias_alloc = tensors->at(param.bias_index).get(); std::unique_ptr<::neurun::kernel::cpu::FullyConnectedLayer> fn{ new ::neurun::kernel::cpu::FullyConnectedLayer}; @@ -440,18 +410,18 @@ Stage StageGenerator::generate(const graph::operation::FullyConnected::Node &nod output_alloc->buffer(), param.ofm_shape); builder.append(std::move(fn)); - }; + }); } -Stage StageGenerator::generate(const graph::operation::Reshape::Node &node) +void StageGenerator::visit(const model::operation::ReshapeNode &node) { - const ::neurun::graph::operand::Index output_index{node.getOutputs().at(0)}; - const ::neurun::graph::operand::Index input_index{node.getInputs().at(0)}; + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(model::operation::ReshapeNode::Input::INPUT)}; struct Param { - int output_index; - int input_index; + model::operand::Index output_index; + model::operand::Index input_index; ::neurun::kernel::cpu::Shape ofm_shape; ::neurun::kernel::cpu::Shape ifm_shape; @@ -459,17 +429,17 @@ Stage StageGenerator::generate(const graph::operation::Reshape::Node &node) Param param; - param.output_index = output_index.asInt(); - param.input_index = input_index.asInt(); + param.output_index = output_index; + param.input_index = input_index; param.ofm_shape = ::neurun::kernel::cpu::getShape(_ctx.at(output_index)); param.ifm_shape = ::neurun::kernel::cpu::getShape(_ctx.at(input_index)); auto tensors = _tensor_builder; - return [tensors, param](IExecutionBuilder &builder) { - auto output_alloc = tensors->at(::neurun::graph::operand::Index{param.output_index}).get(); - auto input_alloc = tensors->at(::neurun::graph::operand::Index{param.input_index}).get(); + returnStage([tensors, param](IExecutionBuilder &builder) { + auto output_alloc = tensors->at(param.output_index).get(); + auto input_alloc = tensors->at(param.input_index).get(); std::unique_ptr<::neurun::kernel::cpu::ReshapeLayer> fn{ new ::neurun::kernel::cpu::ReshapeLayer}; @@ -477,21 +447,19 @@ Stage StageGenerator::generate(const graph::operation::Reshape::Node &node) fn->configure(input_alloc->buffer(), param.ifm_shape, output_alloc->buffer(), param.ofm_shape); builder.append(std::move(fn)); - }; + }); } -Stage StageGenerator::generate(const graph::operation::Softmax::Node &node) +void StageGenerator::visit(const model::operation::SoftmaxNode &node) { - VERBOSE(Softmax) << "generate CPU Softmax" << std::endl; - - const ::neurun::graph::operand::Index output_index{node.getOutputs().at(0)}; - const ::neurun::graph::operand::Index input_index{node.getInputs().at(0)}; - const ::neurun::graph::operand::Index scale_index{node.param().scale_index}; + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(model::operation::SoftmaxNode::Input::INPUT)}; + const auto scale_index{node.param().scale_index}; struct Param { - int output_index; - int input_index; + model::operand::Index output_index; + model::operand::Index input_index; ::neurun::kernel::cpu::Shape ofm_shape; ::neurun::kernel::cpu::Shape ifm_shape; @@ -501,8 +469,8 @@ Stage StageGenerator::generate(const graph::operation::Softmax::Node &node) Param param; - param.output_index = output_index.asInt(); - param.input_index = input_index.asInt(); + param.output_index = output_index; + param.input_index = input_index; param.ofm_shape = ::neurun::kernel::cpu::getShape(_ctx.at(output_index)); param.ifm_shape = ::neurun::kernel::cpu::getShape(_ctx.at(input_index)); @@ -511,9 +479,9 @@ Stage StageGenerator::generate(const graph::operation::Softmax::Node &node) auto tensors = _tensor_builder; - return [tensors, param](IExecutionBuilder &builder) { - auto output_alloc = tensors->at(::neurun::graph::operand::Index{param.output_index}).get(); - auto input_alloc = tensors->at(::neurun::graph::operand::Index{param.input_index}).get(); + returnStage([tensors, param](IExecutionBuilder &builder) { + auto output_alloc = tensors->at(param.output_index).get(); + auto input_alloc = tensors->at(param.input_index).get(); std::unique_ptr<::neurun::kernel::cpu::SoftMaxLayer> fn{ new ::neurun::kernel::cpu::SoftMaxLayer}; @@ -522,15 +490,58 @@ Stage StageGenerator::generate(const graph::operation::Softmax::Node &node) param.ofm_shape); builder.append(std::move(fn)); - }; + }); } -Stage StageGenerator::generate(const graph::operation::NOP::Node & /* node */) +void StageGenerator::visit(const model::operation::PermuteNode &node) { - // DO NOTHING - return nullptr; + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(0)}; + + using PermuteType = model::operation::PermuteNode::Type; + + struct Param + { + model::operand::Index output_index; + model::operand::Index input_index; + + model::operand::Shape shape; + + PermuteType type{PermuteType::COPY}; + }; + + Param param; + + param.output_index = output_index; + param.input_index = input_index; + + param.shape = _ctx.at(output_index).shape(); + param.type = node.param().type; + + // assert(param.shape == _ctx.at(input_index)); + + const auto &input_li = _ctx.at(input_index).lower_info(); + const auto &output_li = _ctx.at(output_index).lower_info(); + const auto input_backend = input_li->def_backends().getOnlyElement(); + const auto output_backend = output_li->def_backends().getOnlyElement(); + + const auto input_tensors = input_backend->tensor_builder(); + const auto output_tensors = output_backend->tensor_builder(); + + returnStage([input_tensors, output_tensors, param](IExecutionBuilder &builder) { + auto output_object = output_tensors->wrapTensor(param.output_index); + auto input_object = input_tensors->wrapTensor(param.input_index); + + auto fn = nnfw::cpp14::make_unique<::neurun::kernel::cpu::PermuteLayer>(); + + fn->configure(input_object, output_object, param.shape, param.type); + + builder.append(std::move(fn)); + }); } +void StageGenerator::visit(const model::operation::AddNode &) { throw std::runtime_error("NYI"); } + } // namespace neurun } // namespace backend } // namespace cpu diff --git a/runtimes/neurun/src/backend/cpu/StageGenerator.h b/runtimes/neurun/src/backend/cpu/StageGenerator.h index acdd2c8b2..6a0e387da 100644 --- a/runtimes/neurun/src/backend/cpu/StageGenerator.h +++ b/runtimes/neurun/src/backend/cpu/StageGenerator.h @@ -17,9 +17,9 @@ #ifndef __NEURUN_BACKEND_CPU_STAGE_GENERATOR_H__ #define __NEURUN_BACKEND_CPU_STAGE_GENERATOR_H__ -#include "backend/IStageGenerator.h" +#include "backend/interface/IStageGenerator.h" -#include "graph/operand/Set.h" +#include "model/operand/Set.h" #include "backend/cpu/operand/Tensor.h" #include "TensorBuilder.h" @@ -33,22 +33,18 @@ namespace cpu class StageGenerator : public IStageGenerator { public: - StageGenerator(const neurun::graph::operand::Set &ctx, + StageGenerator(const neurun::model::operand::Set &ctx, const std::shared_ptr<TensorBuilder> &tensor_builder); virtual std::shared_ptr<ITensorBuilder> tensor_builder() override { return _tensor_builder; } - virtual Stage generate(const graph::operation::Conv2D::Implicit::Node &node) override; - virtual Stage generate(const graph::operation::MaxPool2D::Implicit::Node &node) override; - virtual Stage generate(const graph::operation::AvgPool2D::Implicit::Node &node) override; - virtual Stage generate(const graph::operation::Concat::Node &node) override; - virtual Stage generate(const graph::operation::FullyConnected::Node &node) override; - virtual Stage generate(const graph::operation::Reshape::Node &node) override; - virtual Stage generate(const graph::operation::Softmax::Node &node) override; - virtual Stage generate(const graph::operation::NOP::Node &node) override; +#define OP(InternalName, IsNnApi, NnApiName) \ + virtual void visit(const model::operation::InternalName &) override; +#include "model/operation/Op.lst" +#undef OP private: - const neurun::graph::operand::Set &_ctx; + const neurun::model::operand::Set &_ctx; std::shared_ptr<TensorBuilder> _tensor_builder; }; diff --git a/runtimes/neurun/src/backend/cpu/TensorBuilder.cc b/runtimes/neurun/src/backend/cpu/TensorBuilder.cc index 1b972a830..9c39b9c00 100644 --- a/runtimes/neurun/src/backend/cpu/TensorBuilder.cc +++ b/runtimes/neurun/src/backend/cpu/TensorBuilder.cc @@ -19,6 +19,7 @@ #include <cassert> #include "operand/Object.h" +#include "util/logging.h" namespace neurun { @@ -27,43 +28,93 @@ namespace backend namespace cpu { -TensorBuilder::TensorBuilder() +TensorBuilder::TensorBuilder() : _mem_planner(std::make_shared<FirstFitPlanner>()) { // DO NOTHING } -void TensorBuilder::mark(const ::neurun::graph::operand::Index &ind) +void TensorBuilder::registerTensorInfo(const model::operand::Index &ind, + const compiler::TensorInfo &info) { - assert(_tensors.size() == 0); + _tensor_info_map.insert({ind, info}); +} + +void TensorBuilder::registerSubTensorInfo(const model::operand::Index &, + const compiler::SubTensorInfo &) +{ + // Not supported yet + assert(false); +} + +void TensorBuilder::notifyFirstUse(const model::operand::Index &ind) +{ + assert(_tensor_info_map.find(ind) != _tensor_info_map.end()); + const auto &info = _tensor_info_map.at(ind); - _inds.insert(ind); + const auto size = info.total_size(); + _mem_planner->claim(ind, size); } -void TensorBuilder::prepare(codegen::Plan &plan, - const std::map<int, ::arm_compute::TensorInfo> &tensor_info_ctx) +void TensorBuilder::notifyLastUse(const model::operand::Index &ind) { _mem_planner->release(ind); } + +void TensorBuilder::prepare(void) { assert(_tensors.size() == 0); - for (auto ind_int : _inds) + _mem_alloc = std::make_shared<Allocator>(_mem_planner->capacity()); + assert(_mem_alloc->base()); + + for (auto &mem_plan : _mem_planner->memory_plans()) { - ::neurun::graph::operand::Index ind{ind_int}; - auto tensor = std::make_shared<operand::Tensor>(tensor_info_ctx.at(ind.asInt())); - // TODO Fix allocation here. When Tensor object is created the memory for tensor is also - // allocated, and this must be fixed. - plan.operands().set(ind, std::make_shared<operand::Object>(tensor)); + auto ind = mem_plan.first; + auto mem_blk = mem_plan.second; + const auto &info = _tensor_info_map[ind]; + + uint8_t *buffer = _mem_alloc->base() + mem_blk.offset; + auto tensor = std::make_shared<operand::Tensor>(info); + tensor->setBuffer(buffer); _tensors[ind] = tensor; + + VERBOSE(CPU_TENSORBUILDER) << "TENSOR(#" << ind.value() << "): " << static_cast<void *>(buffer) + << std::endl; + + // If we do not make tensor here currently, stages would cause segment fault } } void TensorBuilder::allocate(void) { - assert(_inds.size() == _tensors.size()); - // NOTE For now nothing to do. Allocation is done in prepare stage, which is wrong - // See also: comment in `prepare()` } -std::shared_ptr<operand::Tensor> TensorBuilder::at(const ::neurun::graph::operand::Index &ind) +std::shared_ptr<::neurun::backend::operand::ITensor> +TensorBuilder::tensorAt(const model::operand::Index &ind) +{ + return _tensors.at(ind); +} + +std::shared_ptr<backend::operand::IObject> +TensorBuilder::wrapTensor(const model::operand::Index &ind) +{ + if (_objects.find(ind) != _objects.end()) + { + return _objects.at(ind); + } + else + { + return _objects[ind] = std::make_shared<operand::Object>(_tensors.at(ind)); + } +} + +void TensorBuilder::iterate(const IterateFunction &fn) +{ + for (auto it : _tensors) + { + fn(it.first); + } +} + +std::shared_ptr<operand::Tensor> TensorBuilder::at(const ::neurun::model::operand::Index &ind) { return _tensors.at(ind); } diff --git a/runtimes/neurun/src/backend/cpu/TensorBuilder.h b/runtimes/neurun/src/backend/cpu/TensorBuilder.h index f61a930fe..2715d57f0 100644 --- a/runtimes/neurun/src/backend/cpu/TensorBuilder.h +++ b/runtimes/neurun/src/backend/cpu/TensorBuilder.h @@ -18,11 +18,12 @@ #define __NEURUN_BACKEND_CPU_TENSOR_BUILDER_H__ #include <unordered_map> -#include <unordered_set> -#include "backend/ITensorBuilder.h" +#include "backend/interface/ITensorBuilder.h" #include "backend/cpu/operand/Tensor.h" -#include "graph/operand/Index.h" +#include "backend/cpu/operand/Object.h" +#include "model/operand/Index.h" +#include "MemoryPlanner.h" namespace neurun { @@ -31,23 +32,47 @@ namespace backend namespace cpu { -class Plan; - class TensorBuilder : public ITensorBuilder { public: TensorBuilder(); - virtual void mark(const ::neurun::graph::operand::Index &ind) override; - virtual void prepare(codegen::Plan &plan, - const std::map<int, ::arm_compute::TensorInfo> &tensor_info_ctx) override; + /** + * @brief Register tensor information to allocate on CPU backend + * @param[in] ind Operand index + * @param[in] info Tensor information + */ + virtual void registerTensorInfo(const model::operand::Index &ind, + const compiler::TensorInfo &info) override; + /** + * @brief Register subtensor information to allocate on CPU backend + * @param[in] ind Operand index + * @param[in] info Tensor information + */ + virtual void registerSubTensorInfo(const model::operand::Index &ind, + const compiler::SubTensorInfo &info) override; + + virtual void notifyFirstUse(const model::operand::Index &) override; + virtual void notifyLastUse(const model::operand::Index &) override; + + virtual void prepare(void) override; virtual void allocate(void) override; - std::shared_ptr<operand::Tensor> at(const ::neurun::graph::operand::Index &ind); + virtual std::shared_ptr<::neurun::backend::operand::ITensor> + tensorAt(const model::operand::Index &ind) override; + virtual std::shared_ptr<backend::operand::IObject> + wrapTensor(const model::operand::Index &ind) override; + virtual void iterate(const IterateFunction &fn) override; + + std::shared_ptr<operand::Tensor> at(const ::neurun::model::operand::Index &ind); private: - std::unordered_set<graph::operand::Index> _inds; - std::unordered_map<graph::operand::Index, std::shared_ptr<operand::Tensor>> _tensors; + std::unordered_map<model::operand::Index, compiler::TensorInfo> _tensor_info_map; + std::unordered_map<model::operand::Index, std::shared_ptr<operand::Tensor>> _tensors; + std::unordered_map<model::operand::Index, std::shared_ptr<operand::Object>> _objects; + std::unordered_map<model::operand::Index, Block> _tensor_mem_map; + std::shared_ptr<IMemoryPlanner> _mem_planner; + std::shared_ptr<Allocator> _mem_alloc; }; } // namespace cpu diff --git a/runtimes/neurun/src/backend/cpu/operand/Object.cc b/runtimes/neurun/src/backend/cpu/operand/Object.cc index 52b63fba7..011747a8c 100644 --- a/runtimes/neurun/src/backend/cpu/operand/Object.cc +++ b/runtimes/neurun/src/backend/cpu/operand/Object.cc @@ -25,7 +25,8 @@ namespace cpu namespace operand { -void Object::access(const std::function<void(::arm_compute::ITensor &tensor)> &fn) const +void Object::access( + const std::function<void(::neurun::backend::operand::ITensor &tensor)> &fn) const { fn(*_tensor); } diff --git a/runtimes/neurun/src/backend/cpu/operand/Object.h b/runtimes/neurun/src/backend/cpu/operand/Object.h index 08f63f3dc..5ef7c4fbf 100644 --- a/runtimes/neurun/src/backend/cpu/operand/Object.h +++ b/runtimes/neurun/src/backend/cpu/operand/Object.h @@ -18,9 +18,9 @@ #define __NEURUN_BACKEND_CPU_OPERAND_OBJECT_H__ #include <memory> -#include <arm_compute/core/ITensor.h> +#include "backend/interface/operand/ITensor.h" -#include "backend/IObject.h" +#include "backend/interface/operand/IObject.h" namespace neurun { @@ -37,19 +37,20 @@ public: Object() = default; public: - Object(const std::shared_ptr<::arm_compute::ITensor> &tensor) : _tensor{tensor} + Object(const std::shared_ptr<::neurun::backend::operand::ITensor> &tensor) : _tensor{tensor} { // DO NOTHING } public: - ::arm_compute::ITensor *ptr(void) const override { return _tensor.get(); } + ::neurun::backend::operand::ITensor *ptr(void) const override { return _tensor.get(); } private: - std::shared_ptr<::arm_compute::ITensor> _tensor; + std::shared_ptr<::neurun::backend::operand::ITensor> _tensor; public: - void access(const std::function<void(::arm_compute::ITensor &tensor)> &fn) const override; + void + access(const std::function<void(::neurun::backend::operand::ITensor &tensor)> &fn) const override; }; } // namespace operand diff --git a/runtimes/neurun/src/backend/cpu/operand/Tensor.cc b/runtimes/neurun/src/backend/cpu/operand/Tensor.cc index 0e4f34aac..a5251292e 100644 --- a/runtimes/neurun/src/backend/cpu/operand/Tensor.cc +++ b/runtimes/neurun/src/backend/cpu/operand/Tensor.cc @@ -16,6 +16,8 @@ #include "Tensor.h" +#define NO_USE(a) (void)(a) + namespace neurun { namespace backend @@ -25,7 +27,11 @@ namespace cpu namespace operand { -// NO IMPLEMENTATION YET +size_t Tensor::calcOffset(const neurun::util::feature::Coordinate4D &coords) +{ + NO_USE(coords); + throw std::runtime_error("offset_element_in_bytes is not supported for cpu::Tensor now."); +} } // namespace operand } // namespace cpu diff --git a/runtimes/neurun/src/backend/cpu/operand/Tensor.h b/runtimes/neurun/src/backend/cpu/operand/Tensor.h index 83a99acf2..7500f890f 100644 --- a/runtimes/neurun/src/backend/cpu/operand/Tensor.h +++ b/runtimes/neurun/src/backend/cpu/operand/Tensor.h @@ -17,8 +17,8 @@ #ifndef __NEURUN_BACKEND_CPU_OPERAND_TENSOR_H__ #define __NEURUN_BACKEND_CPU_OPERAND_TENSOR_H__ -#include <arm_compute/core/ITensor.h> -#include <arm_compute/core/TensorInfo.h> +#include "backend/interface/operand/ITensor.h" +#include "compiler/TensorInfo.h" namespace neurun { @@ -29,38 +29,40 @@ namespace cpu namespace operand { -class Tensor : public ::arm_compute::ITensor +class Tensor : public ::neurun::backend::operand::ITensor { public: - Tensor() = default; + Tensor() = delete; - Tensor(::arm_compute::TensorInfo info) : _info(info) - { - // TODO Do not allocate buffer here. This tensor is just an abstract Tensor object for cpu. - uint32_t size = _info.total_size(); // NOTE This size may not be accurate - _buffer = new uint8_t[size]; // NOTE The allocated buffer is never deallocated. - } - - Tensor(uint8_t *buffer) : _buffer(buffer) +public: + Tensor(const compiler::TensorInfo &info) : _info(info) { // DO NOTHING } public: void setBuffer(uint8_t *buffer) { _buffer = buffer; } + ::neurun::model::operand::DataType data_type() const { return _info.typeInfo().type(); } public: - ::arm_compute::TensorInfo *info() const override - { - return const_cast<::arm_compute::TensorInfo *>(&_info); - } - - ::arm_compute::TensorInfo *info() override { return &_info; } - uint8_t *buffer() const override { return _buffer; } + /** + * @brief Get dimension by index + * + * @param index Index to get diemension + * @return size_t Dimension at index + * @note N : dimension(0) + * H : dimension(1) + * W : dimension(2) + * C : dimension(3) + */ + size_t dimension(size_t index) const override { return _info.shape().dim(index); } + size_t num_dimensions() const override { return _info.shape().dims().size(); } + size_t total_size() const override { return _info.total_size(); } + size_t calcOffset(const neurun::util::feature::Coordinate4D &coords) override; private: - ::arm_compute::TensorInfo _info; + compiler::TensorInfo _info; uint8_t *_buffer = nullptr; }; diff --git a/runtimes/neurun/src/backend/IBackendConfig.h b/runtimes/neurun/src/backend/interface/IConfig.h index a6c7ce517..82789d0ff 100644 --- a/runtimes/neurun/src/backend/IBackendConfig.h +++ b/runtimes/neurun/src/backend/interface/IConfig.h @@ -14,8 +14,10 @@ * limitations under the License. */ -#ifndef __INTERNAL_IBACKEND_CONFIG_H__ -#define __INTERNAL_IBACKEND_CONFIG_H__ +#ifndef __NEURUN_BACKEND_ICONFIG_H__ +#define __NEURUN_BACKEND_ICONFIG_H__ + +#include <string> #include "graph/operand/Layout.h" @@ -24,16 +26,19 @@ namespace neurun namespace backend { -struct IBackendConfig +struct IConfig { - virtual ~IBackendConfig() = default; + virtual ~IConfig() = default; + virtual std::string id() = 0; virtual void initialize() = 0; // NOTE Assume backend has only one type of operand layout virtual graph::operand::Layout getOperandLayout() = 0; + // Support subtensor allocation + virtual bool SupportSubTensorAlloc() = 0; }; } // namespace backend } // namespace neurun -#endif // __INTERNAL_IBACKEND_CONFIG_H__ +#endif // __NEURUN_BACKEND_ICONFIG_H__ diff --git a/runtimes/neurun/src/backend/interface/IStageGenerator.h b/runtimes/neurun/src/backend/interface/IStageGenerator.h new file mode 100644 index 000000000..878a50e3f --- /dev/null +++ b/runtimes/neurun/src/backend/interface/IStageGenerator.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2018 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 __NEURUN_BACKEND_ISTAGE_GENERATOR_H__ +#define __NEURUN_BACKEND_ISTAGE_GENERATOR_H__ + +#include <memory> +#include <functional> + +#include "exec/interface/IFunction.h" + +#include "backend/interface/ITensorBuilder.h" +#include "model/operation/NodeVisitor.h" + +struct IExecutionBuilder +{ + virtual ~IExecutionBuilder() = default; + + virtual void append(std::unique_ptr<::neurun::exec::IFunction> &&f) = 0; +}; + +using Stage = std::function<void(IExecutionBuilder &)>; + +namespace neurun +{ +namespace backend +{ + +class IStageGenerator : model::operation::NodeVisitor +{ +public: + virtual ~IStageGenerator() = default; + + virtual std::shared_ptr<ITensorBuilder> tensor_builder() = 0; + +protected: +#define OP(InternalName, IsNnApi, NnApiName) \ + virtual void visit(const model::operation::InternalName &) override {} +#include "model/operation/Op.lst" +#undef OP + +protected: + void returnStage(const Stage &stage) { _return = stage; } + +public: + Stage generate(const model::operation::Node &node) + { + node.accept(std::move(*this)); + return _return; + } + +private: + Stage _return = nullptr; +}; + +} // namespace backend +} // namespace neurun + +#endif // __NEURUN_BACKEND_ISTAGE_GENERATOR_H__ diff --git a/runtimes/neurun/src/backend/interface/ITensorBuilder.h b/runtimes/neurun/src/backend/interface/ITensorBuilder.h new file mode 100644 index 000000000..354a270e6 --- /dev/null +++ b/runtimes/neurun/src/backend/interface/ITensorBuilder.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2018 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 __NEURUN_BACKEND_ITENSOR_BUILDER_H__ +#define __NEURUN_BACKEND_ITENSOR_BUILDER_H__ + +#include <map> + +#include "model/operand/Index.h" +#include "operand/IObject.h" +#include "compiler/SubTensorInfo.h" +#include "compiler/TensorInfo.h" +#include "backend/interface/operand/ITensor.h" + +namespace neurun +{ +namespace backend +{ + +struct ITensorBuilder +{ + using IterateFunction = std::function<void(const model::operand::Index &)>; + + virtual ~ITensorBuilder(void) = default; + + // TODO Merge registerTensorInfo and registerSubTensorInfo using abstraction by internal class + /** + * @brief Register tensor information to allocate on backend + */ + virtual void registerTensorInfo(const model::operand::Index &, const compiler::TensorInfo &) = 0; + /** + * @brief Register subtensor information to allocate on backend + */ + virtual void registerSubTensorInfo(const model::operand::Index &, + const compiler::SubTensorInfo &) = 0; + + virtual void notifyFirstUse(const model::operand::Index &) = 0; + virtual void notifyLastUse(const model::operand::Index &) = 0; + + virtual void prepare(void) = 0; + virtual void allocate(void) = 0; + + virtual std::shared_ptr<::neurun::backend::operand::ITensor> + tensorAt(const model::operand::Index &ind) = 0; + virtual std::shared_ptr<backend::operand::IObject> + wrapTensor(const model::operand::Index &ind) = 0; + virtual void iterate(const IterateFunction &fn) = 0; +}; + +} // namespace backend +} // namespace neurun + +#include <set> +#include <memory> + +namespace neurun +{ +namespace backend +{ + +using TensorBuilderSet = std::set<std::shared_ptr<backend::ITensorBuilder>>; + +} // namespace backend +} // namespace neurun + +#endif // __NEURUN_BACKEND_ITENSOR_BUILDER_H__ diff --git a/runtimes/neurun/src/backend/IObject.h b/runtimes/neurun/src/backend/interface/operand/IObject.h index f7d511095..44b33b080 100644 --- a/runtimes/neurun/src/backend/IObject.h +++ b/runtimes/neurun/src/backend/interface/operand/IObject.h @@ -19,7 +19,7 @@ #include <functional> -#include <arm_compute/core/ITensor.h> +#include "ITensor.h" namespace neurun { @@ -31,8 +31,9 @@ namespace operand struct IObject { virtual ~IObject() = default; - virtual ::arm_compute::ITensor *ptr(void) const = 0; - virtual void access(const std::function<void(::arm_compute::ITensor &tensor)> &fn) const = 0; + virtual ::neurun::backend::operand::ITensor *ptr(void) const = 0; + virtual void + access(const std::function<void(::neurun::backend::operand::ITensor &tensor)> &fn) const = 0; }; } // namespace operand diff --git a/runtimes/neurun/src/backend/interface/operand/ITensor.h b/runtimes/neurun/src/backend/interface/operand/ITensor.h new file mode 100644 index 000000000..8bc3ff465 --- /dev/null +++ b/runtimes/neurun/src/backend/interface/operand/ITensor.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2018 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 __NEURUN_BACKEND_OPERAND_I_TENSOR_H__ +#define __NEURUN_BACKEND_OPERAND_I_TENSOR_H__ + +#include <cstring> +#include <cstdint> + +#include "util/feature/Coordinate4D.h" + +namespace neurun +{ +namespace backend +{ +namespace operand +{ + +class ITensor +{ +public: + virtual ~ITensor() = default; + +public: + virtual uint8_t *buffer() const = 0; + virtual size_t total_size() const = 0; + virtual size_t dimension(size_t index) const = 0; + virtual size_t num_dimensions() const = 0; + virtual size_t calcOffset(const neurun::util::feature::Coordinate4D &coords) = 0; +}; + +} // namespace operand +} // namespace backend +} // namespace neurun + +#endif // __NEURUN_BACKEND_OPERAND_I_TENSOR_H__ diff --git a/runtimes/neurun/src/codegen/IPlanBuilder.h b/runtimes/neurun/src/codegen/IPlanBuilder.h deleted file mode 100644 index 197681432..000000000 --- a/runtimes/neurun/src/codegen/IPlanBuilder.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2018 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 __NEURUN_CODEGEN_I_PLAN_BUILDER_H__ -#define __NEURUN_CODEGEN_I_PLAN_BUILDER_H__ - -#include "arm_compute/core/TensorInfo.h" -#include "backend/IStageGenerator.h" -#include "backend/IInitializerGenerator.h" - -namespace neurun -{ -namespace codegen -{ - -struct IPlanBuilder -{ - virtual ~IPlanBuilder() = default; - - virtual void addShapeConstr(const ::neurun::graph::operand::Index &ind, - const ::arm_compute::TensorInfo &info) = 0; - virtual void addInitializer(const ::neurun::graph::operand::Index &ind, - const Initializer &initializer) = 0; - virtual void addStage(const Stage &) = 0; -}; - -} // namespace codegen -} // namespace neurun - -#endif // __NEURUN_CODEGEN_I_PLAN_BUILDER_H__ diff --git a/runtimes/neurun/src/codegen/PlanBuilder.h b/runtimes/neurun/src/codegen/PlanBuilder.h deleted file mode 100644 index 4323143b3..000000000 --- a/runtimes/neurun/src/codegen/PlanBuilder.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2018 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 __NEURUN_CODEGEN_PLAN_BUILDER_H__ -#define __NEURUN_CODEGEN_PLAN_BUILDER_H__ - -#include "IPlanBuilder.h" -#include "codegen/Plan.h" -#include "backend/IStageGenerator.h" -#include "backend/ITensorBuilder.h" - -namespace neurun -{ -namespace codegen -{ - -class ExecutionBuilder final : public IExecutionBuilder -{ -public: - ExecutionBuilder(codegen::Plan &plan) : _plan{plan} - { - // DO NOTHING - } - -public: - void append(std::unique_ptr<::arm_compute::IFunction> &&f) override - { - _plan.operations().append(std::move(f)); - } - -private: - codegen::Plan &_plan; -}; - -class PlanBuilder final : public IPlanBuilder -{ -public: - PlanBuilder(codegen::Plan &plan) : _plan{plan} - { - // DO NOTHING - } - -public: - void addShapeConstr(const ::neurun::graph::operand::Index &ind, - const ::arm_compute::TensorInfo &info) override; - -public: - void addInitializer(const ::neurun::graph::operand::Index &ind, - const Initializer &initializer) override; - -public: - void addStage(const Stage &stage) override; - -public: - // TODO Remove the argument `tensor_builders` - void finalize(const backend::TensorBuilderSet &tensor_builders); - -public: - const std::map<int, ::arm_compute::TensorInfo> &tensor_info_ctx() { return _tensor_info_ctx; } - -private: - codegen::Plan &_plan; - -private: - std::map<int, ::arm_compute::TensorInfo> _tensor_info_ctx; - std::map<int, Initializer> _initializer_ctx; - std::vector<Stage> _stages; -}; - -} // namepsace codegen -} // namespace neurun - -#endif // __NEURUN_CODEGEN_PLAN_BUILDER_H__ diff --git a/runtimes/neurun/src/codegen/Planner.cc b/runtimes/neurun/src/codegen/Planner.cc deleted file mode 100644 index 1add3acf5..000000000 --- a/runtimes/neurun/src/codegen/Planner.cc +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Copyright (c) 2018 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 "Planner.h" - -#include <typeinfo> - -#include "internal/Convert.h" -#include "graph/operand/Set.h" -#include "codegen/IPlanBuilder.h" -#include "graph/operation/LowerInfo.h" - -#include "logging.h" - -namespace neurun -{ -namespace codegen -{ - -void Planner::visit(const graph::operation::Conv2D::Implicit::Node &node) -{ - const auto ofm_index = node.getOutputs().at(0); - - const auto ifm_index = node.getInputs().at(0); - const auto ker_index = node.getInputs().at(1); - const auto bias_index = node.getInputs().at(2); - - const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(); - const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(); - const auto ker_shape = _ctx.at(ker_index).shape().asKernel(); - const auto bias_size = _ctx.at(bias_index).shape().asVector(); - - // Set Shape Constraints - _builder.addShapeConstr(ofm_index, ::internal::asTensorInfo(ofm_shape)); - _builder.addShapeConstr(ifm_index, ::internal::asTensorInfo(ifm_shape)); - _builder.addShapeConstr(ker_index, ::internal::asTensorInfo(ker_shape)); - _builder.addShapeConstr(bias_index, ::internal::asTensorInfo(bias_size)); - - // backend - auto backend = node.lower_info()->backend(); - - // Generate Initializers - auto init_gen = backend.initializer_gen(); - _builder.addInitializer(ker_index, init_gen->generateWeight(node)); - _builder.addInitializer(bias_index, init_gen->generateBias(node)); - - // Generate Stage - auto stage_gen = backend.stage_gen(); - _builder.addStage(stage_gen->generate(node)); -} - -void Planner::visit(const graph::operation::MaxPool2D::Implicit::Node &node) -{ - const ::neurun::graph::operand::Index ofm_index{node.getOutputs().at(0)}; - const ::neurun::graph::operand::Index ifm_index{node.getInputs().at(0)}; - - const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(); - const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(); - - // Set Shape Constraints - _builder.addShapeConstr(ofm_index, ::internal::asTensorInfo(ofm_shape)); - _builder.addShapeConstr(ifm_index, ::internal::asTensorInfo(ifm_shape)); - - // backend - auto backend = node.lower_info()->backend(); - - // Generate Stage - auto stage_gen = backend.stage_gen(); - _builder.addStage(stage_gen->generate(node)); -} - -void Planner::visit(const graph::operation::AvgPool2D::Implicit::Node &node) -{ - const ::neurun::graph::operand::Index ofm_index{node.getOutputs().at(0)}; - const ::neurun::graph::operand::Index ifm_index{node.getInputs().at(0)}; - - const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(); - const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(); - - // Set Shape Constraints - _builder.addShapeConstr(ofm_index, ::internal::asTensorInfo(ofm_shape)); - _builder.addShapeConstr(ifm_index, ::internal::asTensorInfo(ifm_shape)); - - // backend - auto backend = node.lower_info()->backend(); - - // Generate Stage - auto stage_gen = backend.stage_gen(); - _builder.addStage(stage_gen->generate(node)); -} - -void Planner::visit(const graph::operation::Concat::Node &node) -{ - const ::neurun::graph::operand::Index ofm_index{node.getOutputs().at(0)}; - - // NOTE This implementation assumes that input and output are a feature - // TODO Remove this assumption - const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(); - - // NOTE This implementation assumes concat over feature depth - // TODO Remove this assumption - assert(_ctx.at(::neurun::graph::operand::Index{node.param().axis_index}).asScalar<int32_t>() == - 3); - - // Set Shape Constraints (for output) - _builder.addShapeConstr(ofm_index, ::internal::asTensorInfo(ofm_shape)); - - // Set Shape Constraints (for input) - for (const auto &index : node.getInputs()) - { - const ::neurun::graph::operand::Index ifm_index{index}; - const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(); - _builder.addShapeConstr(ifm_index, ::internal::asTensorInfo(ifm_shape)); - } - - // backend - auto backend = node.lower_info()->backend(); - - // Generate Stage - auto stage_gen = backend.stage_gen(); - _builder.addStage(stage_gen->generate(node)); -} - -void Planner::visit(const graph::operation::FullyConnected::Node &node) -{ - VERBOSE(FullyConnected) << "Configure FULLY_CONNECTED operation" << std::endl; - - const ::neurun::graph::operand::Index output_index{node.getOutputs().at(0)}; - - const ::neurun::graph::operand::Index input_index{node.getInputs().at(0)}; - const ::neurun::graph::operand::Index weight_index{node.getInputs().at(1)}; - const ::neurun::graph::operand::Index bias_index{node.getInputs().at(2)}; - - const ::neurun::graph::operand::Index activation_index{node.param().activation_index}; - - assert(_ctx.at(output_index).shape().rank() == 2); - const auto output_size = _ctx.at(output_index).shape().dim(1); - - // NOTE We assume that input is a feature map - // TODO Remove this restriction! - const auto ifm_shape = _ctx.at(input_index).shape().asFeature(); - - assert(_ctx.at(weight_index).shape().rank() == 2); - const auto num_output = _ctx.at(weight_index).shape().dim(0); - const auto input_size = _ctx.at(weight_index).shape().dim(1); - assert(ifm_shape.C * ifm_shape.H * ifm_shape.W == input_size); - - const auto bias_size = _ctx.at(bias_index).shape().asVector(); - - // Set Shape Constraints - _builder.addShapeConstr(output_index, ::internal::asTensorInfo(output_size)); - _builder.addShapeConstr(input_index, ::internal::asTensorInfo(ifm_shape)); - _builder.addShapeConstr(weight_index, - ::internal::asTensorInfo(num_output /*H*/, input_size /*W*/)); - _builder.addShapeConstr(bias_index, ::internal::asTensorInfo(bias_size)); - - // backend - auto backend = node.lower_info()->backend(); - - // Generate Initializers - auto init_gen = backend.initializer_gen(); - _builder.addInitializer(weight_index, init_gen->generateWeight(node)); - _builder.addInitializer(bias_index, init_gen->generateBias(node)); - - // Generate Stage - auto stage_gen = backend.stage_gen(); - _builder.addStage(stage_gen->generate(node)); -} - -void Planner::visit(const graph::operation::Reshape::Node &node) -{ - const ::neurun::graph::operand::Index output_index{node.getOutputs().at(0)}; - const ::neurun::graph::operand::Index input_index{node.getInputs().at(0)}; - - // NOTE The content of a tensor specified by shape_index should be aligned with - // output tensor shape - // TODO Check consistency of ouput shape - - // 'Feature Map' to 'Vector' reshape - assert(_ctx.at(input_index).shape().rank() == 4); - assert(_ctx.at(output_index).shape().rank() == 2); - assert(_ctx.at(output_index).shape().dim(0) == 1); - - const auto ifm_shape = _ctx.at(input_index).shape().asFeature(); - const auto out_size = _ctx.at(output_index).shape().dim(1); - - // NOTE Vector element ordering issue arises when H or W is not 1 - assert(ifm_shape.H == 1); - assert(ifm_shape.W == 1); - assert((ifm_shape.C * ifm_shape.H * ifm_shape.W) == out_size); - - _builder.addShapeConstr(output_index, ::internal::asTensorInfo(out_size)); - _builder.addShapeConstr(input_index, ::internal::asTensorInfo(ifm_shape)); - - // backend - auto backend = node.lower_info()->backend(); - - // Generate Stage - auto stage_gen = backend.stage_gen(); - _builder.addStage(stage_gen->generate(node)); -} - -void Planner::visit(const graph::operation::Softmax::Node &node) -{ - VERBOSE(Softmax) << "Configure SOFTMAX operation" << std::endl; - - const ::neurun::graph::operand::Index output_index{node.getOutputs().at(0)}; - const ::neurun::graph::operand::Index input_index{node.getInputs().at(0)}; - - assert(_ctx.at(output_index).shape().rank() == _ctx.at(input_index).shape().rank()); - - // TODO Support 'feature map' input - assert(_ctx.at(input_index).shape().rank() == 2); - assert(_ctx.at(input_index).shape().dim(0) == 1); - assert(_ctx.at(input_index).shape().dim(0) == _ctx.at(output_index).shape().dim(0)); - assert(_ctx.at(input_index).shape().dim(1) == _ctx.at(output_index).shape().dim(1)); - - const uint32_t len = _ctx.at(output_index).shape().dim(1); - - _builder.addShapeConstr(output_index, ::internal::asTensorInfo(len)); - _builder.addShapeConstr(input_index, ::internal::asTensorInfo(len)); - - // backend - auto backend = node.lower_info()->backend(); - - // Generate Stage - auto stage_gen = backend.stage_gen(); - _builder.addStage(stage_gen->generate(node)); -} - -void Planner::visit(const graph::operation::NOP::Node & /* node */) -{ - // DO NOTHING - // TODO : It's just for graph manipulation test now, it should be added tensor copy stage later. -} - -void Planner::visit(const graph::operation::Permute::Node & /* node */) { throw "NYI"; } - -} // namespace codegen -} // namespace neurun diff --git a/runtimes/neurun/src/codegen/Planner.h b/runtimes/neurun/src/codegen/Planner.h deleted file mode 100644 index d725567b5..000000000 --- a/runtimes/neurun/src/codegen/Planner.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2018 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 __NEURUN_CODEGEN_PLANNER_H__ -#define __NEURUN_CODEGEN_PLANNER_H__ - -#include "graph/operation/NodeVisitor.h" - -namespace neurun -{ -namespace graph -{ -namespace operand -{ -class Set; -} // namespace operand -} // namespace graph -} // namespace neurun - -namespace neurun -{ -namespace codegen -{ - -class IPlanBuilder; - -class Planner : public graph::operation::NodeVisitor -{ -public: - Planner(const neurun::graph::operand::Set &ctx, neurun::codegen::IPlanBuilder &builder) - : _ctx{ctx}, _builder{builder} - { - } - -public: - virtual void visit(const graph::operation::Conv2D::Implicit::Node &) override; - virtual void visit(const graph::operation::MaxPool2D::Implicit::Node &) override; - virtual void visit(const graph::operation::AvgPool2D::Implicit::Node &) override; - virtual void visit(const graph::operation::Concat::Node &) override; - virtual void visit(const graph::operation::Reshape::Node &) override; - virtual void visit(const graph::operation::FullyConnected::Node &) override; - virtual void visit(const graph::operation::Softmax::Node &) override; - virtual void visit(const graph::operation::NOP::Node &) override; - virtual void visit(const graph::operation::Permute::Node &) override; - -private: - const neurun::graph::operand::Set &_ctx; - neurun::codegen::IPlanBuilder &_builder; -}; - -} // namespace codegen -} // namespace neurun - -#endif // __NEURUN_CODEGEN_PLANNER_H__ diff --git a/runtimes/neurun/src/codegen/BackendResolver.cc b/runtimes/neurun/src/compiler/BackendResolver.cc index 4037a2813..6c1f32603 100644 --- a/runtimes/neurun/src/codegen/BackendResolver.cc +++ b/runtimes/neurun/src/compiler/BackendResolver.cc @@ -18,10 +18,10 @@ namespace neurun { -namespace codegen +namespace compiler { // NOT IMPLEMENTED -} // namespace codegen +} // namespace compiler } // namespace neurun diff --git a/runtimes/neurun/src/codegen/BackendResolver.h b/runtimes/neurun/src/compiler/BackendResolver.h index 02f22b278..4742b2d94 100644 --- a/runtimes/neurun/src/codegen/BackendResolver.h +++ b/runtimes/neurun/src/compiler/BackendResolver.h @@ -14,69 +14,75 @@ * limitations under the License. */ -#ifndef __NEURUN_CODEGEN_BACKEND_RESOLVER_H__ -#define __NEURUN_CODEGEN_BACKEND_RESOLVER_H__ +#ifndef __NEURUN_COMPILER_BACKEND_RESOLVER_H__ +#define __NEURUN_COMPILER_BACKEND_RESOLVER_H__ #include <set> #include <unordered_map> #include <typeindex> -#include "logging.h" -#include "util/EnvVar.h" +#include "util/logging.h" +#include "util/config/ConfigManager.h" #include "backend/BackendManager.h" -#include "backend/IInitializerGenerator.h" -#include "backend/IStageGenerator.h" +#include "backend/interface/IStageGenerator.h" namespace neurun { -namespace codegen +namespace compiler { class BackendResolver { public: - BackendResolver(const neurun::graph::operand::Set &operands) + BackendResolver(const neurun::model::operand::Set &operands) { _backend_manager = std::make_shared<backend::BackendManager>(operands); - const auto &backend_all_str = - ::nnfw::util::EnvVar{std::string("OP_BACKEND_ALLOPS")}.asString("none"); + const auto backend_all_str = + config::ConfigManager::instance().get<std::string>("OP_BACKEND_ALLOPS"); if (backend_all_str.compare("none") != 0) { VERBOSE(BackendResolver) << "Use backend for all ops: " << backend_all_str << std::endl; -#define OP(InternalName, NnApiName) \ - { \ - auto backend = _backend_manager->get(backend_all_str); \ - _gen_map[typeid(graph::operation::InternalName::Node)] = backend; \ +#define OP(InternalName, IsNnApi, NnApiName) \ + if (IsNnApi) \ + { \ + auto backend = _backend_manager->get(backend_all_str); \ + _gen_map[typeid(model::operation::InternalName)] = backend; \ } -#include "graph/operation/Op.lst" +#include "model/operation/Op.lst" #undef OP } else { -#define OP(InternalName, NnApiName) \ +#define OP(InternalName, IsNnApi, NnApiName) \ + if (IsNnApi) \ { \ const auto &backend_str = \ - ::nnfw::util::EnvVar{std::string("OP_BACKEND_") + #NnApiName}.asString("acl_cl"); \ + config::ConfigManager::instance().get<std::string>("OP_BACKEND_" #NnApiName); \ auto backend = _backend_manager->get(backend_str); \ VERBOSE(BackendResolver) << "backend for " << #NnApiName << ": " << backend_str << std::endl; \ - _gen_map[typeid(graph::operation::InternalName::Node)] = backend; \ + _gen_map[typeid(model::operation::InternalName)] = backend; \ } -#include "graph/operation/Op.lst" +#include "model/operation/Op.lst" #undef OP } } public: - const backend::Backend &getBackend(const std::type_index &type) { return _gen_map[type]; } + const backend::Backend *getBackend(const std::type_index &type) { return _gen_map[type]; } + const backend::Backend *getDefaultBackend() const + { + backend::Backend *default_backend = _backend_manager->get("cpu"); + return default_backend; + } private: - std::unordered_map<std::type_index, backend::Backend> _gen_map; + std::unordered_map<std::type_index, backend::Backend *> _gen_map; std::shared_ptr<backend::BackendManager> _backend_manager; }; -} // namespace codegen +} // namespace compiler } // namespace neurun -#endif // __NEURUN_CODEGEN_BACKEND_RESOLVER_H__ +#endif // __NEURUN_COMPILER_BACKEND_RESOLVER_H__ diff --git a/runtimes/neurun/src/compiler/Compiler.cc b/runtimes/neurun/src/compiler/Compiler.cc new file mode 100644 index 000000000..92ec69afb --- /dev/null +++ b/runtimes/neurun/src/compiler/Compiler.cc @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2018 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.h" + +#include "OperationValidator.h" +#include "SubTensorAnalyzer.h" +#include "PlanBuilder.h" +#include "ConstantInitializer.h" + +#include "graph/dumper/Dumper.h" +#include "graph/operation/LowerInfo.h" +#include "dumper/dot/DotDumper.h" +#include "linear/Linear.h" + +namespace neurun +{ + +namespace compiler +{ + +void Compiler::compile(void) +{ + auto &plan = this->plan(); + auto &graph = plan.model(); + const auto &operands = graph.operands(); + + // Disable compile phase + // When ready to use interpreter backend, remove this config and use backend setting + const auto env_disable_compile = config::ConfigManager::instance().get<bool>("DISABLE_COMPILE"); + if (env_disable_compile) + { + plan.state(State::NOT_COMPILED); + return; + } + + /*************************************************** + * Backend independent analysis & optimization phase + ***************************************************/ + + /************************************************************* + * Backend independent analysis & optimization phase finished + *************************************************************/ + + // dump graph to .dot + neurun::dumper::dot::DotDumper dot_dumper(graph); + dot_dumper.dumpIfNeeded("before_lower"); + + // Lower: decide backend + graph.lower(); + plan.state(State::LOWERED); + + dot_dumper.dumpIfNeeded("after_lower"); + + auto linear = graph.linearize(); + plan.state(State::LINEARIZED); + + // Dump ops + linear->accept(neurun::graph::dumper::Dumper{}); + + linear->accept(OperationValidator{operands}); + + /************************************************* + * Backend dependent analysis & optimization phase + *************************************************/ + + // SubTensorInfo should be generated after lower, before stage generation and finalize + // because SubTensorAnalyzer assume that insert permutation is already finished + // lower: decide backend and insert permutation + // stage generation: prepare codegen to optimization + // finalize: generate tensor using subtensor info, then execute stage + // Generated SubTensorInfo is in operand(Object) + // for easy pass SubTensorInfo to plan builder and tensor builder + linear->accept(SubTensorAnalyzer{graph.operands()}); + + /********************************************************** + * Backend dependent analysis & optimization phase finished + **********************************************************/ + + /*********************** + * Code generation phase + ***********************/ + + PlanBuilder plan_builder{plan}; + + // Plan building + linear->iterate([&](const linear::Element &element) { + auto backend = element.lower_info->backend(); + + // Generate Stage + auto stage_gen = backend->stage_gen(); + plan_builder.addStage(stage_gen->generate(*element.node)); + }); + + auto tensor_builders = linear->planTensors(); + + // TODO Add optimization passes + plan_builder.finalize(tensor_builders); + + ConstantInitializer{graph, plan}(); + + /******************************** + * Code generation phase finished + ********************************/ + + plan.state(State::COMPILED); +} + +} // namespace compiler + +} // namespace neurun diff --git a/runtimes/neurun/src/compiler/Compiler.h b/runtimes/neurun/src/compiler/Compiler.h new file mode 100644 index 000000000..d8f620a10 --- /dev/null +++ b/runtimes/neurun/src/compiler/Compiler.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2018 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 Compiler.h + * @brief This file contains Compiler class to define and run compilation phase + */ + +#ifndef __NEURUN_COMPILER_COMPILE_H_ +#define __NEURUN_COMPILER_COMPILE_H_ + +#include "graph/Graph.h" +#include "Plan.h" + +namespace neurun +{ + +namespace compiler +{ + +/** + * @brief Class to compile graph model + */ +class Compiler +{ +public: + /** + * @brief Construct a new Compiler object + * @param[in] model Graph model + */ + Compiler(const std::shared_ptr<graph::Graph> &model) : _plan{new Plan{model}} + { + // DO NOTHING + } + +public: + /** + * @brief Return plan + * @return Plan + */ + Plan &plan(void) { return *_plan; } + /** + * @brief Run compilation + */ + void compile(void); + /** + * @brief Pass plan reference + * @param[out] plan Plan reference to return + */ + void release(std::shared_ptr<const Plan> &plan) { plan = _plan; } + +private: + std::shared_ptr<Plan> _plan; +}; + +} // namespace compiler + +} // namespace neurun + +#endif // __NEURUN_COMPILER_COMPILE_H_ diff --git a/runtimes/neurun/src/compiler/ConstantInitializer.cc b/runtimes/neurun/src/compiler/ConstantInitializer.cc new file mode 100644 index 000000000..d6d58e273 --- /dev/null +++ b/runtimes/neurun/src/compiler/ConstantInitializer.cc @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2018 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 "ConstantInitializer.h" + +#include "backend/interface/operand/IObject.h" +#include "backend/interface/IConfig.h" +#include "backend/BackendManager.h" +#include "model/operation/FullyConnectedNode.h" +#include "util/feature/nhwc/Reader.h" +#include "util/feature/nhwc/View.h" +#include "util/feature/nchw/View.h" +#include "misc/feature/IndexIterator.h" +#include "util/logging.h" + +namespace neurun +{ +namespace compiler +{ + +ConstantInitializer::ConstantInitializer(const graph::Graph &graph, Plan &plan) + : _graph{graph}, _plan{plan} +{ +} + +void ConstantInitializer::operator()() +{ + // Fill operand data + _plan.operands().iterate([&](int ind, neurun::backend::operand::IObject &obj) { + neurun::model::operand::Index index(ind); + const auto &model_obj = _graph.operands().at(index); + + // For only CONSTANTS + if (model_obj.getUsage() != neurun::model::operand::OperandUsage::CONSTANT) + return; + + // Only float32 is supported + auto type = model_obj.typeInfo().type(); + if (type != ::neurun::model::operand::DataType::TENSOR_FLOAT32) + throw std::runtime_error{"Unsupported data type. Only TENSOR_FLOAT32 is supported."}; + + VERBOSE(FillOperandData) << "Fill data for operand " << ind << std::endl; + + auto layout = + model_obj.lower_info()->def_backends().getOnlyElement()->config()->getOperandLayout(); + const auto shape = model_obj.shape(); + auto base = reinterpret_cast<const float *>(model_obj.data().base()); + auto size = model_obj.data().size(); + + obj.access([&](::neurun::backend::operand::ITensor &tensor) { + switch (shape.rank()) + { + case 1: + { + auto vec_size = shape.asVector(); + for (int32_t n = 0; n < vec_size; ++n) + { + const float *from = reinterpret_cast<const float *>(base) + n; + const auto value = *from; + + float *into = reinterpret_cast<float *>(tensor.buffer()) + n; + + *into = value; + } + break; + } + case 2: + { + // NOTE This is a WORKAROUND which supports FullyConnected weight only + // For FullyConnected, we must know the IFM shape to deduce 2D weight shape from 4D + // IFM. + // This is because of NHWC/NCHW layout, the order of mapping will be different. + // TODO Support general case - explicitly insert Reshape op for IFM as 2D + + // Find corresponding FullyConnected IFM + auto operation_index = _graph.operands().at(index).getUses().list().front(); + auto operation = &_graph.operations().at(operation_index); + auto fc_operation = + dynamic_cast<const neurun::model::operation::FullyConnectedNode *>(operation); + + if (fc_operation == nullptr) + break; + + auto ifm_index = fc_operation->getInputs().at( + neurun::model::operation::FullyConnectedNode::Input::INPUT); + const auto &ifm = _graph.operands().at(ifm_index); + const auto ifm_shape = ifm.shape().asFeature(); + const auto num_output = shape.dim(0); + + const ::nnfw::misc::feature::Shape ker_shape{num_output, ifm_shape.C, ifm_shape.H, + ifm_shape.W}; + const util::feature::nhwc::Reader<float> from{ker_shape, base, size}; + + if (layout == neurun::graph::operand::Layout::NHWC) + { + ::nnfw::misc::feature::iterate(ker_shape) + << [&](uint32_t nth, uint32_t ch, uint32_t row, uint32_t col) { + const auto value = from.at(nth, ch, row, col); + + uint32_t offset = 0; + + // NNAPI uses NHWC ordering + offset += nth * ifm_shape.H * ifm_shape.W * ifm_shape.C; + offset += row * ifm_shape.W * ifm_shape.C; + offset += col * ifm_shape.C; + offset += ch; + + float *into = reinterpret_cast<float *>(tensor.buffer()) + offset; + + *into = value; + }; + } + else + { + assert(layout == neurun::graph::operand::Layout::NCHW); + + ::nnfw::misc::feature::iterate(ker_shape) + << [&](uint32_t nth, uint32_t ch, uint32_t row, uint32_t col) { + const auto value = from.at(nth, ch, row, col); + + uint32_t offset = 0; + + // 'NCHW' ordering + offset += nth * ifm_shape.C * ifm_shape.H * ifm_shape.W; + offset += ch * ifm_shape.H * ifm_shape.W; + offset += row * ifm_shape.W; + offset += col; + + float *into = reinterpret_cast<float *>(tensor.buffer()) + offset; + + *into = value; + }; + } + + break; + } + case 4: + { + auto ker_shape = shape.asFeature(); + auto from = util::feature::nhwc::Reader<float>{ker_shape, base, size}; + + if (layout == neurun::graph::operand::Layout::NHWC) + { + auto into = util::feature::nhwc::View<float>{ + ker_shape, reinterpret_cast<float *>(tensor.buffer()), size}; + + ::nnfw::misc::feature::iterate(ker_shape) + << [&](uint32_t nth, uint32_t ch, uint32_t row, uint32_t col) { + const auto value = from.at(nth, ch, row, col); + into.at(nth, ch, row, col) = value; + }; + } + else + { + assert(layout == neurun::graph::operand::Layout::NCHW); + + auto into = util::feature::nchw::View<float>{&tensor}; + + ::nnfw::misc::feature::iterate(ker_shape) + << [&](uint32_t nth, uint32_t ch, uint32_t row, uint32_t col) { + const auto value = from.at(nth, ch, row, col); + into.at(nth, ch, row, col) = value; + }; + } + break; + } + default: + throw std::runtime_error{"Not yet supported"}; + } + }); + }); +} + +} // namespace codegen +} // namespace neurun diff --git a/runtimes/neurun/src/compiler/ConstantInitializer.h b/runtimes/neurun/src/compiler/ConstantInitializer.h new file mode 100644 index 000000000..7d9231908 --- /dev/null +++ b/runtimes/neurun/src/compiler/ConstantInitializer.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2018 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 __NEURUN_COMPILER_CONSTANT_INITIALIZER_H__ +#define __NEURUN_COMPILER_CONSTANT_INITIALIZER_H__ + +#include "graph/Graph.h" +#include "Plan.h" + +namespace neurun +{ +namespace compiler +{ + +class ConstantInitializer +{ +public: + ConstantInitializer(const graph::Graph &graph, Plan &plan); + + void operator()(); + +private: + const graph::Graph &_graph; + Plan &_plan; +}; + +} // namespace compiler +} // namespace neurun + +#endif // __NEURUN_COMPILER_CONSTANT_INITIALIZER_H__ diff --git a/runtimes/neurun/src/compiler/OperationValidator.cc b/runtimes/neurun/src/compiler/OperationValidator.cc new file mode 100644 index 000000000..0110eccb8 --- /dev/null +++ b/runtimes/neurun/src/compiler/OperationValidator.cc @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2018 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 "OperationValidator.h" + +#include <typeinfo> + +#include "model/operand/Set.h" +#include "graph/operation/LowerInfo.h" + +#include "util/logging.h" + +namespace neurun +{ +namespace compiler +{ + +void OperationValidator::visit(const model::operation::Conv2DNode &) +{ + // DO NOTHING +} + +void OperationValidator::visit(const model::operation::MaxPool2DNode &) +{ + // DO NOTHING +} + +void OperationValidator::visit(const model::operation::AvgPool2DNode &) +{ + // DO NOTHING +} + +void OperationValidator::visit(const model::operation::ConcatNode &node) +{ + (void)node; // NOTE To prevent from unused variable warning + + // NOTE This implementation assumes concat over feature depth + // TODO Remove this assumption + assert(_ctx.at(::neurun::model::operand::Index{node.param().axis_index}).asScalar<int32_t>() == + 3); +} + +void OperationValidator::visit(const model::operation::FullyConnectedNode &) +{ + // DO NOTHING +} + +void OperationValidator::visit(const model::operation::ReshapeNode &node) +{ + (void)node; // NOTE To prevent from unused variable warning + + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(0)}; + + // NOTE The content of a tensor specified by shape_index should be aligned with + // output tensor shape + // TODO Check consistency of ouput shape + + // 'Feature Map' to 'Vector' reshape + assert(_ctx.at(input_index).shape().rank() == 4); + assert(_ctx.at(output_index).shape().rank() == 2); + assert(_ctx.at(output_index).shape().dim(0) == 1); + + // NOTE Vector element ordering issue arises when H or W is not 1 + assert(_ctx.at(input_index).shape().dim(1) == 1); // H + assert(_ctx.at(input_index).shape().dim(2) == 1); // W + // input(4D)'s C * H * W == output(2D)'s W + assert((_ctx.at(input_index).shape().dim(3) * _ctx.at(input_index).shape().dim(1) * + _ctx.at(input_index).shape().dim(2)) == _ctx.at(output_index).shape().dim(1)); +} + +void OperationValidator::visit(const model::operation::SoftmaxNode &node) +{ + (void)node; // NOTE To prevent from unused variable warning + + VERBOSE(Softmax) << "Configure SOFTMAX operation" << std::endl; + + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(0)}; + + assert(_ctx.at(output_index).shape().rank() == _ctx.at(input_index).shape().rank()); + + // TODO Support 'feature map' input + assert(_ctx.at(input_index).shape().rank() == 2); + assert(_ctx.at(input_index).shape().dim(0) == 1); + assert(_ctx.at(input_index).shape().dim(0) == _ctx.at(output_index).shape().dim(0)); + assert(_ctx.at(input_index).shape().dim(1) == _ctx.at(output_index).shape().dim(1)); +} + +void OperationValidator::visit(const model::operation::PermuteNode &node) +{ + (void)node; // NOTE To prevent from unused variable warning + + VERBOSE(Permute) << "Configure Permute operation" << std::endl; + + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(0)}; + + assert(_ctx.at(output_index).shape().rank() == _ctx.at(input_index).shape().rank()); +} + +void OperationValidator::visit(const model::operation::AddNode &) +{ + // DO NOTHING +} + +} // namespace compiler +} // namespace neurun diff --git a/runtimes/neurun/src/compiler/OperationValidator.h b/runtimes/neurun/src/compiler/OperationValidator.h new file mode 100644 index 000000000..f4ed533ed --- /dev/null +++ b/runtimes/neurun/src/compiler/OperationValidator.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2018 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 __NEURUN_COMPILER_OPERATION_VALIDATOR_H__ +#define __NEURUN_COMPILER_OPERATION_VALIDATOR_H__ + +#include "model/operation/NodeVisitor.h" + +namespace neurun +{ +namespace model +{ +namespace operand +{ +class Set; +} // namespace operand +} // namespace graph +} // namespace neurun + +namespace neurun +{ +namespace compiler +{ + +class OperationValidator : public model::operation::NodeVisitor +{ +public: + OperationValidator(const neurun::model::operand::Set &ctx) : _ctx{ctx} {} + +public: +#define OP(InternalName, IsNnApi, NnApiName) \ + virtual void visit(const model::operation::InternalName &) override; +#include "model/operation/Op.lst" +#undef OP + +private: + const neurun::model::operand::Set &_ctx; +}; + +} // namespace compiler +} // namespace neurun + +#endif // __NEURUN_COMPILER_OPERATION_VALIDATOR_H__ diff --git a/runtimes/neurun/src/codegen/Plan.cc b/runtimes/neurun/src/compiler/Plan.cc index b7637b189..b7637b189 100644 --- a/runtimes/neurun/src/codegen/Plan.cc +++ b/runtimes/neurun/src/compiler/Plan.cc diff --git a/runtimes/neurun/src/codegen/Plan.h b/runtimes/neurun/src/compiler/Plan.h index 47624ed35..f2a526e0e 100644 --- a/runtimes/neurun/src/codegen/Plan.h +++ b/runtimes/neurun/src/compiler/Plan.h @@ -18,18 +18,27 @@ #define __NEURUN_CODEGEN_PLAN_H__ #include "graph/Graph.h" -#include "codegen/operand/Context.h" -#include "codegen/operation/Sequence.h" +#include "compiler/operand/Context.h" +#include "compiler/operation/Sequence.h" namespace neurun { -namespace codegen +namespace compiler { +enum class State +{ + NONE, // Initial state + LOWERED, // Backend is decided + LINEARIZED, // Everything is moved to Linear object so this Graph object is no longer effective + COMPILED, // Success compilation + NOT_COMPILED // Not compiled by environment or graph status +}; + class Plan { public: - Plan(const std::shared_ptr<neurun::graph::Graph> &model) : _model(model) + Plan(const std::shared_ptr<neurun::graph::Graph> &model) : _model(model), _state(State::NONE) { // DO NOTHING } @@ -38,6 +47,9 @@ public: neurun::graph::Graph &model(void) { return *_model; } const neurun::graph::Graph &model(void) const { return *_model; } + void state(State state) { _state = state; } + State state(void) const { return _state; } + public: operand::Context &operands(void) { return _operands; } const operand::Context &operands(void) const { return _operands; } @@ -50,9 +62,10 @@ private: std::shared_ptr<neurun::graph::Graph> _model; operand::Context _operands; operation::Sequence _ops; + State _state; }; -} // namespace codegen +} // namespace compiler } // namespace neurun #endif // __NEURUN_CODEGEN_PLAN_H__ diff --git a/runtimes/neurun/src/codegen/PlanBuilder.cc b/runtimes/neurun/src/compiler/PlanBuilder.cc index 5d4d6f9c9..8ef3fedbf 100644 --- a/runtimes/neurun/src/codegen/PlanBuilder.cc +++ b/runtimes/neurun/src/compiler/PlanBuilder.cc @@ -16,31 +16,29 @@ #include "PlanBuilder.h" +#include "backend/interface/operand/IObject.h" + namespace neurun { -namespace codegen -{ - -void PlanBuilder::addShapeConstr(const ::neurun::graph::operand::Index &ind, - const ::arm_compute::TensorInfo &info) +namespace compiler { - _tensor_info_ctx[ind.asInt()] = info; -} - -void PlanBuilder::addInitializer(const ::neurun::graph::operand::Index &ind, - const Initializer &initializer) -{ - _initializer_ctx[ind.asInt()] = initializer; -} void PlanBuilder::addStage(const Stage &stage) { _stages.emplace_back(stage); } void PlanBuilder::finalize(const backend::TensorBuilderSet &tensor_builders) { + auto &operands = _plan.operands(); + // Prepare tensors for (auto &tensor_builder : tensor_builders) { - tensor_builder->prepare(_plan, _tensor_info_ctx); + tensor_builder->prepare(); + + // Wrap tensors as Object and store them to plan + tensor_builder->iterate([&](const model::operand::Index &index) { + auto object = tensor_builder->wrapTensor(index); + operands.set(index, object); + }); } // Process Stage @@ -51,25 +49,12 @@ void PlanBuilder::finalize(const backend::TensorBuilderSet &tensor_builders) stage(execution_builder); } - // TODO Add code for CPU/ACL tensor allocation // Allocate Tensor Memory for cl_tensors for (auto &tensor_builder : tensor_builders) { tensor_builder->allocate(); } - - // Fill weight/bias - for (auto it = _initializer_ctx.begin(); it != _initializer_ctx.end(); ++it) - { - const ::neurun::graph::operand::Index operand_index{it->first}; - auto objects = _plan.operands().at(operand_index); - - for (auto object : objects) - { - object->access(it->second); - } - } } -} // namepsace codegen +} // namepsace compiler } // namespace neurun diff --git a/runtimes/neurun/src/compiler/PlanBuilder.h b/runtimes/neurun/src/compiler/PlanBuilder.h new file mode 100644 index 000000000..3231906d2 --- /dev/null +++ b/runtimes/neurun/src/compiler/PlanBuilder.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2018 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 __NEURUN_COMPILER_PLAN_BUILDER_H__ +#define __NEURUN_COMPILER_PLAN_BUILDER_H__ + +#include "Plan.h" +#include "backend/interface/IStageGenerator.h" +#include "backend/interface/ITensorBuilder.h" + +namespace neurun +{ +namespace compiler +{ + +class ExecutionBuilder final : public IExecutionBuilder +{ +public: + ExecutionBuilder(Plan &plan) : _plan{plan} + { + // DO NOTHING + } + +public: + void append(std::unique_ptr<::neurun::exec::IFunction> &&f) override + { + _plan.operations().append(std::move(f)); + } + +private: + Plan &_plan; +}; + +class PlanBuilder +{ +public: + PlanBuilder(Plan &plan) : _plan{plan} + { + // DO NOTHING + } + +public: + void addStage(const Stage &stage); + +public: + // TODO Remove the argument `tensor_builders` + void finalize(const backend::TensorBuilderSet &tensor_builders); + +private: + Plan &_plan; + +private: + std::vector<Stage> _stages; +}; + +} // namepsace compiler +} // namespace neurun + +#endif // __NEURUN_COMPILER_PLAN_BUILDER_H__ diff --git a/runtimes/neurun/src/compiler/SubTensorAnalyzer.cc b/runtimes/neurun/src/compiler/SubTensorAnalyzer.cc new file mode 100644 index 000000000..0851b7991 --- /dev/null +++ b/runtimes/neurun/src/compiler/SubTensorAnalyzer.cc @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2018 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 "SubTensorAnalyzer.h" + +#include <typeinfo> + +#include "cpp14/memory.h" +#include "model/operand/Set.h" +#include "graph/operation/LowerInfo.h" +#include "util/logging.h" + +namespace neurun +{ +namespace compiler +{ + +void SubTensorAnalyzer::visit(const model::operation::ConcatNode &node) +{ + // If operator is concat (or other operators related with subsumption), fill subsumption info + // TODO: if one tensor is subset of many parents or model input + // Solution 1. Handle 1st parent only, ignore others (need to invert for other childrun) + // Solution 2. Insert copy operation for other parents + auto axis_index = node.param().axis_index; + + // To prepare concat elimination, axis should be constant + if (_ctx.at(axis_index).getUsage() != model::operand::OperandUsage::CONSTANT) + { + VERBOSE(SUBTENSOR) << "Cannot handle non-constant axis" << std::endl; + return; + } + + // NOTE This implementation assumes concat over feature depth + // TODO Remove this assumption + int32_t axis = _ctx.at(axis_index).asScalar<int32_t>(); + if (axis != 3) + { + VERBOSE(SUBTENSOR) << "Cannot handle axis is not channel" << std::endl; + return; + } + + auto &output_index = node.getOutputs().at(0); + auto &inputs = node.getInputs(); + + int32_t axis_point = 0; + for (auto &input_index : inputs) + { + auto input_shape_4D = _ctx.at(input_index).lower_info()->shape(); + std::vector<int32_t> offset = {0, 0, 0, 0}; + offset[axis] = axis_point; + neurun::util::feature::Coordinate4D coordinate_info(offset[0], offset[1], offset[2], offset[3]); + std::unique_ptr<graph::operand::ParentInfo> parentInfo = + nnfw::cpp14::make_unique<graph::operand::ParentInfo>(output_index, coordinate_info); + + // NOTD Not support multiple parent tensor yet + assert(_ctx.at(input_index).parent_info() == nullptr); + _ctx.at(input_index).parent_info(std::move(parentInfo)); + + // NOTE Only support when axis is 3(channel) + axis_point += input_shape_4D.c(); + } +} + +} // namespace compiler +} // namespace neurun diff --git a/runtimes/neurun/src/compiler/SubTensorAnalyzer.h b/runtimes/neurun/src/compiler/SubTensorAnalyzer.h new file mode 100644 index 000000000..ddfd10263 --- /dev/null +++ b/runtimes/neurun/src/compiler/SubTensorAnalyzer.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2018 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 SubTensorAnalyzer.h + * @brief This file contains SubTensorAnalyzer to analyze tensor subsumption + * using operation visitor + */ + +#ifndef __NEURUN_COMPILER_SUBTENSOR_ANALYZER_H__ +#define __NEURUN_COMPILER_SUBTENSOR_ANALYZER_H__ + +#include "model/operation/NodeVisitor.h" + +namespace neurun +{ +namespace model +{ +namespace operand +{ +class Set; +} // namespace operation +} // namespace graph +} // namespace neurun + +namespace neurun +{ +namespace compiler +{ + +/** + * @brief Class to analyze tensor subsumption + */ +class SubTensorAnalyzer : public model::operation::NodeVisitor +{ +public: + /** + * @brief Construct a new SubTensorAnalyzer object + * @param[in] ctx Graph operand set + */ + SubTensorAnalyzer(neurun::model::operand::Set &ctx) : _ctx{ctx} {} + +public: + virtual void visit(const model::operation::ConcatNode &) override; + +private: + neurun::model::operand::Set &_ctx; +}; + +} // namespace compiler +} // namespace neurun + +#endif // __NEURUN_COMPILER_SUBTENSOR_ANALYZER_H__ diff --git a/runtimes/neurun/src/compiler/SubTensorInfo.h b/runtimes/neurun/src/compiler/SubTensorInfo.h new file mode 100644 index 000000000..c0fb857d0 --- /dev/null +++ b/runtimes/neurun/src/compiler/SubTensorInfo.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2018 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 SubTensorInfo.h + * @brief This file contains SubTensorInfo to represent subsumption between tensors + * for backend tensor allocation + */ +#ifndef __NEURUN_COMPILER_SUBTENSOR_INFO_H__ +#define __NEURUN_COMPILER_SUBTENSOR_INFO_H__ + +#include "model/operand/Object.h" +#include "util/feature/Coordinate4D.h" + +namespace neurun +{ +namespace compiler +{ + +/** + * @brief Class to represent information of subtensor + */ +class SubTensorInfo +{ +public: + SubTensorInfo() = delete; + + /** + * @brief Construct a new SubTensorInfo object + * @param[in] obj SubTensor object + */ + SubTensorInfo(const model::operand::Object &obj) + : _parent{obj.parent_info()->parent()}, _shape{obj.shape()}, _type{obj.typeInfo()}, + _offset{obj.parent_info()->offset()} + { + // DO NOTHING + } + +public: + /** + * @brief Return parent tensor index + * @return Parent tensor index + */ + const model::operand::Index parent(void) const { return _parent; } + /** + * @brief Return tensor shape + * @return Tensor shape + */ + const model::operand::Shape shape(void) const { return _shape; } + /** + * @brief Return tensor type + * @return Tensor type + */ + const model::operand::TypeInfo type(void) const { return _type; } + /** + * @brief Return tensor's offset in parent tensor + * @return Tensor offset + */ + const neurun::util::feature::Coordinate4D offset(void) const { return _offset; } + +private: + const model::operand::Index _parent; + const model::operand::Shape _shape; + const model::operand::TypeInfo _type; + const neurun::util::feature::Coordinate4D _offset; +}; + +} // compiler +} // neurun + +#endif // __NEURUN_COMPILER_SUBTENSOR_INFO_H__ diff --git a/runtimes/neurun/src/compiler/TensorInfo.h b/runtimes/neurun/src/compiler/TensorInfo.h new file mode 100644 index 000000000..787c433e5 --- /dev/null +++ b/runtimes/neurun/src/compiler/TensorInfo.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2018 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 __NEURUN_COMPILER_TENSOR_INFO_H__ +#define __NEURUN_COMPILER_TENSOR_INFO_H__ + +#include "model/operand/Shape.h" +#include "model/operand/TypeInfo.h" + +#include <numeric> + +namespace neurun +{ +namespace compiler +{ + +class TensorInfo +{ +public: + TensorInfo() = default; + +public: + TensorInfo(const ::neurun::model::operand::Shape &shape, + const ::neurun::model::operand::TypeInfo &typeInfo) + : _shape(shape), _typeInfo(typeInfo) + { + // DO NOTHING + } + +public: + const ::neurun::model::operand::Shape &shape() const { return _shape; } + const ::neurun::model::operand::TypeInfo &typeInfo() const { return _typeInfo; } + size_t total_size() const + { + const auto &dims = _shape.dims(); + return std::accumulate(dims.begin(), dims.end(), 4, std::multiplies<size_t>()); + } + +private: + ::neurun::model::operand::Shape _shape; + ::neurun::model::operand::TypeInfo _typeInfo; +}; + +} // namespace compiler +} // namespace neurun + +#endif // __NEURUN_COMPILER_TENSOR_INFO_H__ diff --git a/runtimes/neurun/src/codegen/operand/Context.cc b/runtimes/neurun/src/compiler/operand/Context.cc index 7e5cdeccf..3fa529995 100644 --- a/runtimes/neurun/src/codegen/operand/Context.cc +++ b/runtimes/neurun/src/compiler/operand/Context.cc @@ -16,20 +16,32 @@ #include "Context.h" +#include <cassert> + namespace neurun { -namespace codegen +namespace compiler { namespace operand { -Context &Context::set(const graph::operand::Index &id, +Context &Context::set(const model::operand::Index &id, const std::shared_ptr<backend::operand::IObject> &object) { - _objects[id.value()].emplace_back(object); + // Only one object for an id + assert(_objects.find(id.value()) == _objects.end()); + _objects[id.value()] = object; return (*this); } +void Context::iterate(const std::function<void(int, backend::operand::IObject &)> &fn) +{ + for (auto &e : _objects) + { + fn(e.first, *e.second); + } +} + } // namespace operand -} // namespace codegen +} // namespace compiler } // namespace neurun diff --git a/runtimes/neurun/src/codegen/operand/Context.h b/runtimes/neurun/src/compiler/operand/Context.h index 386c253c6..bc558404e 100644 --- a/runtimes/neurun/src/codegen/operand/Context.h +++ b/runtimes/neurun/src/compiler/operand/Context.h @@ -14,17 +14,18 @@ * limitations under the License. */ -#ifndef __NEURUN_CODEGEN_OPERAND_CONTEXT_H__ -#define __NEURUN_CODEGEN_OPERAND_CONTEXT_H__ +#ifndef __NEURUN_COMPILER_OPERAND_CONTEXT_H__ +#define __NEURUN_COMPILER_OPERAND_CONTEXT_H__ -#include "backend/IObject.h" -#include "graph/operand/Index.h" +#include "backend/interface/operand/IObject.h" +#include "model/operand/Index.h" #include <map> +#include <memory> namespace neurun { -namespace codegen +namespace compiler { namespace operand { @@ -32,33 +33,34 @@ namespace operand class Context { public: - Context &set(const graph::operand::Index &ind, + Context &set(const model::operand::Index &ind, const std::shared_ptr<backend::operand::IObject> &object); public: - bool exist(const ::neurun::graph::operand::Index &ind) const + bool exist(const ::neurun::model::operand::Index &ind) const { return _objects.find(ind.asInt()) != _objects.end(); } public: - const std::vector<std::shared_ptr<backend::operand::IObject>> & - at(const graph::operand::Index &ind) const + std::shared_ptr<backend::operand::IObject> at(const model::operand::Index &ind) const { return _objects.at(ind.asInt()); } - std::vector<std::shared_ptr<backend::operand::IObject>> &at(const graph::operand::Index &ind) + std::shared_ptr<backend::operand::IObject> &at(const model::operand::Index &ind) { return _objects.at(ind.asInt()); } + void iterate(const std::function<void(int, backend::operand::IObject &)> &fn); + private: - std::map<int, std::vector<std::shared_ptr<backend::operand::IObject>>> _objects; + std::map<int, std::shared_ptr<backend::operand::IObject>> _objects; }; } // namespace operand -} // namespace codegen +} // namespace compiler } // namespace neurun -#endif // __NEURUN_CODEGEN_OPERAND_CONTEXT_H__ +#endif // __NEURUN_COMPILER_OPERAND_CONTEXT_H__ diff --git a/runtimes/neurun/src/codegen/operation/Sequence.cc b/runtimes/neurun/src/compiler/operation/Sequence.cc index 908e84a5c..3160e04b6 100644 --- a/runtimes/neurun/src/codegen/operation/Sequence.cc +++ b/runtimes/neurun/src/compiler/operation/Sequence.cc @@ -18,7 +18,7 @@ namespace neurun { -namespace codegen +namespace compiler { namespace operation { @@ -26,5 +26,5 @@ namespace operation // NO IMPLEMENTATION YET } // namespace operation -} // namespace codegen +} // namespace compiler } // namespace neurun diff --git a/runtimes/neurun/src/codegen/operation/Sequence.h b/runtimes/neurun/src/compiler/operation/Sequence.h index 83403feae..d69cfcfe3 100644 --- a/runtimes/neurun/src/codegen/operation/Sequence.h +++ b/runtimes/neurun/src/compiler/operation/Sequence.h @@ -14,17 +14,16 @@ * limitations under the License. */ -#ifndef __NEURUN_CODEGEN_OPERATION_SEQUENCE_H__ -#define __NEURUN_CODEGEN_OPERATION_SEQUENCE_H__ - +#ifndef __NEURUN_COMPILER_OPERATION_SEQUENCE_H__ +#define __NEURUN_COMPILER_OPERATION_SEQUENCE_H__ #include <stdint.h> -#include <arm_compute/runtime/IFunction.h> +#include "exec/interface/IFunction.h" #include <memory> #include <vector> namespace neurun { -namespace codegen +namespace compiler { namespace operation { @@ -35,21 +34,21 @@ public: uint32_t size(void) const { return _functions.size(); } public: - Sequence &append(std::unique_ptr<::arm_compute::IFunction> &&func) + Sequence &append(std::unique_ptr<::neurun::exec::IFunction> &&func) { _functions.emplace_back(std::move(func)); return (*this); } public: - ::arm_compute::IFunction &at(uint32_t n) const { return *(_functions.at(n)); } + ::neurun::exec::IFunction &at(uint32_t n) const { return *(_functions.at(n)); } private: - std::vector<std::unique_ptr<::arm_compute::IFunction>> _functions; + std::vector<std::unique_ptr<::neurun::exec::IFunction>> _functions; }; } // namespace operation -} // namespace codegen +} // namespace compiler } // namespace neurun -#endif // __NEURUN_CODEGEN_OPERATION_SEQUENCE_H__ +#endif // __NEURUN_COMPILER_OPERATION_SEQUENCE_H__ diff --git a/runtimes/neurun/src/dumper/dot/DotBuilder.cc b/runtimes/neurun/src/dumper/dot/DotBuilder.cc new file mode 100644 index 000000000..d694323b4 --- /dev/null +++ b/runtimes/neurun/src/dumper/dot/DotBuilder.cc @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2018 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 "DotBuilder.h" + +namespace neurun +{ +namespace dumper +{ +namespace dot +{ + +// NodeAttr +NodeAttr &NodeAttr::addAttr(const std::string &name, const std::string &attr) +{ + _attrs.emplace_back(name, attr); + + return *this; +} + +void NodeAttr::finish() +{ + _attr_stream << "["; + for (auto attr : _attrs) + { + _attr_stream << attr.first << "=" + << "\"" << attr.second << "\" "; + } + _attr_stream << "];\n"; +} + +// DotDumper +DotBuilder::DotBuilder() {} + +void DotBuilder::update(const IDotInfo &node_info) +{ + addNode(node_info); + for (auto child : node_info.children()) + { + addEdge(node_info, *child); + } +} + +void DotBuilder::writeDot(std::ostream &os) +{ + os << "digraph D {\n" + << _dot.str() << "\n" + << "}\n"; +} + +void DotBuilder::addNode(const IDotInfo &dotinfo) +{ + NodeAttr attr; + attr.addAttr("shape", dotinfo.dot_shape()) + .addAttr("label", dotinfo.label()) + .addAttr("style", "filled") + .addAttr("colorscheme", dotinfo.bg_color_scheme()) + .addAttr("fillcolor", dotinfo.bg_color()); + + attr.finish(); + + _dot << dotinfo.index_str() << attr.attr_stream(); +} + +void DotBuilder::addEdge(const IDotInfo &dotinfo1, const IDotInfo &dotinfo2) +{ + _dot << dotinfo1.index_str() << " -> " << dotinfo2.index_str() << ";\n"; +} + +} // namespace dot +} // namespace dumper +} // namespace neurun diff --git a/runtimes/neurun/src/dumper/dot/DotBuilder.h b/runtimes/neurun/src/dumper/dot/DotBuilder.h new file mode 100644 index 000000000..783e92b80 --- /dev/null +++ b/runtimes/neurun/src/dumper/dot/DotBuilder.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2018 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 __NEURUN_DUMPER_DOT_DOT_BUILDER_H__ +#define __NEURUN_DUMPER_DOT_DOT_BUILDER_H__ + +#include <sstream> + +#include "model/operation/Index.h" +#include "model/operand/Index.h" + +#include "model/operation/Node.h" +#include "model/operand/Object.h" + +#include "DotNodeInfo.h" +#include "DotOperandInfo.h" + +using Node = neurun::model::operation::Node; +using Object = neurun::model::operand::Object; + +namespace neurun +{ +namespace dumper +{ +namespace dot +{ + +class NodeAttr +{ +public: + NodeAttr() = default; + +public: + void finish(); + NodeAttr &addAttr(const std::string &name, const std::string &attr); + +public: + std::stringbuf *attr_stream() { return _attr_stream.rdbuf(); } + +private: + std::vector<std::pair<std::string, std::string>> _attrs; + std::stringstream _attr_stream; +}; + +class DotBuilder +{ +public: + DotBuilder(); + +public: + void update(const IDotInfo &dotinfo); + + void writeDot(std::ostream &os); + +private: + void addNode(const IDotInfo &dotinfo); + void addEdge(const IDotInfo &dotinfo1, const IDotInfo &dotinfo2); + + std::stringstream _dot; +}; + +} // namespace dot +} // namespace dumper +} // namespace neurun + +#endif // __NEURUN_DUMPER_DOT_DOT_BUILDER_H__ diff --git a/runtimes/neurun/src/dumper/dot/DotDumper.cc b/runtimes/neurun/src/dumper/dot/DotDumper.cc new file mode 100644 index 000000000..1e53ece19 --- /dev/null +++ b/runtimes/neurun/src/dumper/dot/DotDumper.cc @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2018 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 <fstream> + +#include "DotDumper.h" +#include "DotBuilder.h" + +namespace neurun +{ +namespace dumper +{ +namespace dot +{ + +using namespace neurun::graph; + +void DotDumper::dumpIfNeeded(const std::string &tag) +{ + if (_option == OPTIONS::DUMP_OFF) + { + return; + } + neurun::dumper::dot::DotBuilder dot_builder; + + auto &operations = _graph.operations(); + auto &operands = _graph.operands(); + + operations.iterate([&](const model::operation::Index &index, const model::operation::Node &node) { + neurun::dumper::dot::DotNodeInfo node_info(_graph, index, node); + + for (auto output : node.getOutputs()) + { + using neurun::dumper::dot::DotOperandInfo; + auto child = std::make_shared<DotOperandInfo>(output, operands.at(output), + DotOperandInfo::Type::MODEL_OUTPUT); + node_info.appendChild(child); + } + + dot_builder.update(node_info); + }); + + operands.iterate([&](const model::operand::Index &index, const model::operand::Object &object) { + bool showing_cond = false; + auto usage = object.getUsage(); + if (_option == OPTIONS::SHOW_CONSTANTS) + { + showing_cond = object.usageIsDefined(); + } + else + { + showing_cond = (usage == model::operand::OperandUsage::MODEL_INPUT) || + (usage == model::operand::OperandUsage::OPERATION_OUTPUT); + } + if (usage != model::operand::OperandUsage::OPERATION_OUTPUT) + { + showing_cond = showing_cond && (object.getUses().size() > 0); + } + if (showing_cond) + { + auto type = [&]() { + using neurun::dumper::dot::DotOperandInfo; + if (_graph.getInputs().contains(index)) + return DotOperandInfo::Type::MODEL_INPUT; + if (_graph.getOutputs().contains(index)) + return DotOperandInfo::Type::MODEL_OUTPUT; + return DotOperandInfo::Type::INTERNAL; + }(); + + neurun::dumper::dot::DotOperandInfo operand_info(index, object, type); + + for (auto operation_index : object.getUses().list()) + { + auto &node = operations.at(operation_index); + auto child = + std::make_shared<neurun::dumper::dot::DotNodeInfo>(_graph, operation_index, node); + operand_info.appendChild(child); + } + + dot_builder.update(operand_info); + } + }); + + // Dump to file + { + std::string file_name; + file_name += tag; + file_name += ".dot"; + std::filebuf fb; + + fb.open(file_name, std::ios::out); + std::ostream os(&fb); + + dot_builder.writeDot(os); + + fb.close(); + } +} + +} // namespace dot +} // namespace dumper +} // namespace neurun diff --git a/runtimes/neurun/src/dumper/dot/DotDumper.h b/runtimes/neurun/src/dumper/dot/DotDumper.h new file mode 100644 index 000000000..0c0a9b8df --- /dev/null +++ b/runtimes/neurun/src/dumper/dot/DotDumper.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2018 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 "graph/Graph.h" +#include "util/config/ConfigManager.h" + +#ifndef __NEURUN_DUMPER_DOT_DOT_DUMPER_H__ +#define __NEURUN_DUMPER_DOT_DOT_DUMPER_H__ + +namespace neurun +{ +namespace dumper +{ +namespace dot +{ + +enum OPTIONS +{ + DUMP_OFF = 0, // Don't dump + DEFAULT = 1, // Show default dot graph + SHOW_CONSTANTS // Show dot graph with input constants +}; + +class DotDumper +{ +public: + DotDumper(const neurun::graph::Graph &graph) : _graph(graph) + { + _option = config::ConfigManager::instance().get<int>("GRAPH_DOT_DUMP"); + } + +public: + /** + * @brief Dump to dot file as tag name if "GRAPH_DOT_DUMP" is set + * + * @param[in] tag The name of dot file that would be created + * @return N/A + */ + void dumpIfNeeded(const std::string &tag); + +private: + const neurun::graph::Graph &_graph; + uint32_t _option; +}; + +} // namespace dot +} // namespace dumper +} // namespace neurun + +#endif // __NEURUN_DUMPER_DOT_DOT_DUMPER_H__ diff --git a/runtimes/neurun/src/dumper/dot/DotNodeInfo.cc b/runtimes/neurun/src/dumper/dot/DotNodeInfo.cc new file mode 100644 index 000000000..aefe12e2a --- /dev/null +++ b/runtimes/neurun/src/dumper/dot/DotNodeInfo.cc @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2018 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 <sstream> + +#include "DotNodeInfo.h" +#include "graph/Graph.h" +#include "graph/operation/LowerInfo.h" +#include "backend/interface/IConfig.h" + +namespace neurun +{ +namespace dumper +{ +namespace dot +{ + +const std::string DotNodeInfo::NODE_SHAPE = "rect"; +const std::string DotNodeInfo::BG_COLOR_SCHEME = "pastel18"; +// RED BLUE ORANGE YELLOW GREEN PUPLE CYAN PINK +const std::string DotNodeInfo::BG_COLORS[8] = {"1", "2", "5", "6", "3", "4", "7", "8"}; + +DotNodeInfo::DotNodeInfo(const neurun::graph::Graph &graph, + const neurun::model::operation::Index &index, + const neurun::model::operation::Node &node) + : _index(index), _node(node), _lower_info(graph.getLowerInfo(index)) +{ + addBackendLabel(); +} + +std::string DotNodeInfo::index_str() const +{ + std::stringstream ss; + ss << "node" << _index.value(); + + return ss.str(); +} + +std::string DotNodeInfo::label() const +{ + std::stringstream ss; + ss << _index.value() << " : " << _node.getName() << std::endl; + for (auto label : _labels) + { + ss << label << std::endl; + } + + return ss.str(); +} + +std::string DotNodeInfo::dot_shape() const { return NODE_SHAPE; } + +std::string DotNodeInfo::bg_color_scheme() const { return BG_COLOR_SCHEME; } + +std::string DotNodeInfo::bg_color() const +{ + if (!_lower_info) + return DEFAULT_BG_COLOR; + assert(_lower_info != nullptr); + const auto &backend = _lower_info->backend(); + assert(backend != nullptr); + + std::string backend_id = backend->config()->id(); + // TODO : This is just workaround it can be made more efficient. + if (backend_id == "acl_cl") + { + return BG_COLORS[RED]; + } + else if (backend_id == "cpu") + { + return BG_COLORS[BLUE]; + } + else + { + return DEFAULT_BG_COLOR; + } +} + +void DotNodeInfo::addBackendLabel() +{ + if (!_lower_info) + return; + + std::string label; + const auto &backend = _lower_info->backend(); + assert(backend != nullptr); + + label += "[Backend] : "; + label += backend->config()->id(); + _labels.emplace_back(label); +} + +} // namespace dot +} // namespace dumper +} // namespace neurun diff --git a/runtimes/neurun/src/dumper/dot/DotNodeInfo.h b/runtimes/neurun/src/dumper/dot/DotNodeInfo.h new file mode 100644 index 000000000..656a05af6 --- /dev/null +++ b/runtimes/neurun/src/dumper/dot/DotNodeInfo.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2018 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 __NEURUN_DUMPER_DOT_DOT_NODE_INFO_H__ +#define __NEURUN_DUMPER_DOT_DOT_NODE_INFO_H__ + +#include "IDotInfo.h" +#include "model/operation/Node.h" +#include "model/operation/Index.h" + +namespace neurun +{ +namespace graph +{ +class Graph; +} // namespace graph +} // namespace neurun + +namespace neurun +{ +namespace dumper +{ +namespace dot +{ + +class DotNodeInfo : public IDotInfo +{ +public: + static const std::string NODE_SHAPE; + static const std::string BG_COLOR_SCHEME; + static const std::string BG_COLORS[8]; + +public: + DotNodeInfo(const neurun::graph::Graph &graph, const neurun::model::operation::Index &index, + const neurun::model::operation::Node &node); + +public: + virtual std::string index_str() const override; + virtual std::string label() const override; + virtual std::string dot_shape() const override; + virtual std::string bg_color_scheme() const override; + virtual std::string bg_color() const override; + +private: + void addBackendLabel(); + +private: + neurun::model::operation::Index _index; + const neurun::model::operation::Node &_node; + const neurun::graph::operation::LowerInfo *_lower_info; + std::vector<std::string> _labels; +}; + +} // namespace dot +} // namespace dumper +} // namespace neurun + +#endif // __NEURUN_DUMPER_DOT_DOT_NODE_INFO_H__ diff --git a/runtimes/neurun/src/dumper/dot/DotOperandInfo.cc b/runtimes/neurun/src/dumper/dot/DotOperandInfo.cc new file mode 100644 index 000000000..8f5905020 --- /dev/null +++ b/runtimes/neurun/src/dumper/dot/DotOperandInfo.cc @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2018 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 <sstream> + +#include "DotOperandInfo.h" +#include "graph/operand/LowerInfo.h" +#include "backend/interface/IConfig.h" +#include "backend/BackendManager.h" + +namespace neurun +{ +namespace dumper +{ +namespace dot +{ + +const std::string DotOperandInfo::INPUT_SHAPE = "doublecircle"; +const std::string DotOperandInfo::OUTPUT_SHAPE = "doublecircle"; +const std::string DotOperandInfo::OPERAND_SHAPE = "ellipse"; +const std::string DotOperandInfo::BG_COLOR_SCHEME = "set38"; +// RED BLUE ORANGE YELLOW GREEN PUPLE CYAN PINK +const std::string DotOperandInfo::BG_COLORS[8] = {"4", "5", "6", "2", "7", "3", "1", "8"}; + +DotOperandInfo::DotOperandInfo(const neurun::model::operand::Index &index, + const neurun::model::operand::Object &object, Type type) + : _index(index), _object(object), _type(type) +{ + const auto &lower_info = object.lower_info(); + if (lower_info) + { + addBackendLabel(); + } +} + +std::string DotOperandInfo::index_str() const +{ + std::stringstream ss; + ss << "obj" << _index.value(); + + return ss.str(); +} + +std::string DotOperandInfo::label() const +{ + std::stringstream ss; + ss << _index.value() << std::endl; + for (auto label : _labels) + { + ss << label << std::endl; + } + + return ss.str(); +} + +std::string DotOperandInfo::dot_shape() const +{ + switch (_type) + { + case Type::MODEL_INPUT: + return INPUT_SHAPE; + + case Type::MODEL_OUTPUT: + return OUTPUT_SHAPE; + + case Type::UNDEFINED: + case Type::INTERNAL: + default: + return OPERAND_SHAPE; + } +} + +std::string DotOperandInfo::bg_color_scheme() const { return BG_COLOR_SCHEME; } + +std::string DotOperandInfo::bg_color() const +{ + const auto &lower_info = _object.lower_info(); + if (!lower_info) + return DEFAULT_BG_COLOR; + assert(lower_info != nullptr); + const auto &def_backends = lower_info->def_backends(); + assert(def_backends.size() == 1); + + std::string backend_id = def_backends.getOnlyElement()->config()->id(); + // TODO : This is just workaround it can be made more efficient. + if (backend_id == "acl_cl") + { + return BG_COLORS[RED]; + } + else if (backend_id == "cpu") + { + return BG_COLORS[BLUE]; + } + else + { + return DEFAULT_BG_COLOR; + } +} + +void DotOperandInfo::addBackendLabel() +{ + std::string label; + const auto &lower_info = _object.lower_info(); + assert(lower_info != nullptr); + const auto &def_backends = lower_info->def_backends(); + assert(def_backends.size() == 1); + + label += "["; + label += def_backends.getOnlyElement()->config()->id(); + label += "]"; + _labels.emplace_back(label); +} + +} // namespace dot +} // namespace dumper +} // namespace neurun diff --git a/runtimes/neurun/src/dumper/dot/DotOperandInfo.h b/runtimes/neurun/src/dumper/dot/DotOperandInfo.h new file mode 100644 index 000000000..c54da444d --- /dev/null +++ b/runtimes/neurun/src/dumper/dot/DotOperandInfo.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2018 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 __NEURUN_DUMPER_DOT_DOT_OPERAND_INFO_H__ +#define __NEURUN_DUMPER_DOT_DOT_OPERAND_INFO_H__ + +#include <vector> + +#include "IDotInfo.h" +#include "model/operand/Object.h" +#include "model/operand/Index.h" + +namespace neurun +{ +namespace dumper +{ +namespace dot +{ + +class DotOperandInfo : public IDotInfo +{ +public: + enum class Type + { + UNDEFINED, + MODEL_INPUT, + MODEL_OUTPUT, + INTERNAL + }; + +public: + static const std::string INPUT_SHAPE; + static const std::string OUTPUT_SHAPE; + static const std::string OPERAND_SHAPE; + static const std::string BG_COLOR_SCHEME; + static const std::string BG_COLORS[8]; + +public: + DotOperandInfo(const neurun::model::operand::Index &index, + const neurun::model::operand::Object &object, Type type); + +public: + virtual std::string index_str() const override; + virtual std::string label() const override; + virtual std::string dot_shape() const override; + virtual std::string bg_color_scheme() const override; + virtual std::string bg_color() const override; + +private: + void addBackendLabel(); + +private: + const neurun::model::operand::Index &_index; + const neurun::model::operand::Object &_object; + Type _type; + + std::vector<std::string> _labels; +}; + +} // namespace dot +} // namespace dumper +} // namespace neurun + +#endif // __NEURUN_DUMPER_DOT_DOT_OPERAND_INFO_H__ diff --git a/runtimes/neurun/src/dumper/dot/IDotInfo.h b/runtimes/neurun/src/dumper/dot/IDotInfo.h new file mode 100644 index 000000000..d507e724a --- /dev/null +++ b/runtimes/neurun/src/dumper/dot/IDotInfo.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2018 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 __NEURUN_DUMPER_DOT_IDOTINFO_H__ +#define __NEURUN_DUMPER_DOT_IDOTINFO_H__ + +#include <string> +#include <memory> +#include <vector> + +namespace neurun +{ +namespace dumper +{ +namespace dot +{ + +#define DEFAULT_BG_COLOR_SCHEME "x11" +#define DEFAULT_BG_COLOR "white" + +enum BGCOLORS : int +{ + RED, + BLUE, + ORANGE, + YELLOW, + GREEN, + PUPLE, + CYAN, + PINK +}; + +struct IDotInfo +{ + virtual ~IDotInfo() = default; + + virtual std::string index_str() const = 0; + virtual std::string label() const = 0; + virtual std::string dot_shape() const = 0; + virtual std::string bg_color_scheme() const { return DEFAULT_BG_COLOR_SCHEME; } + virtual std::string bg_color() const { return DEFAULT_BG_COLOR; } + + void appendChild(std::shared_ptr<IDotInfo> dotinfo) { _children.emplace_back(dotinfo); } + const std::vector<std::shared_ptr<IDotInfo>> &children() const { return _children; } + +private: + std::vector<std::shared_ptr<IDotInfo>> _children; +}; + +} // namespace dot +} // namespace dumper +} // namespace neurun + +#endif // __NEURUN_DUMPER_DOT_IDOTINFO_H__ diff --git a/runtimes/neurun/src/exec/Sink.h b/runtimes/neurun/src/exec/Sink.h index a96f08320..fe23e8ac3 100644 --- a/runtimes/neurun/src/exec/Sink.h +++ b/runtimes/neurun/src/exec/Sink.h @@ -19,105 +19,119 @@ #include <cassert> -#include <arm_compute/core/ITensor.h> - -#include <util/feature/Shape.h> -#include <util/feature/IndexIterator.h> - -#include "backend/cpu/operand/Tensor.h" // TODO Remove this dependency to backend -#include "internal/nnapi/feature/View.h" -#include "internal/nnapi/feature/Reader.h" +#include "cpp14/memory.h" +#include "util/feature/nhwc/View.h" +#include "util/feature/nchw/View.h" +#include <misc/feature/IndexIterator.h> namespace neurun { namespace exec { -struct Sink +struct ISink { - virtual ~Sink() = default; + virtual ~ISink() = default; - virtual void pull(::arm_compute::ITensor &tensor) const = 0; + virtual void pull(::neurun::backend::operand::ITensor &tensor) const = 0; }; -// -// VectorSink -// -class VectorSink final : public Sink +template <typename T> class Sink final : public ISink { public: - VectorSink(const int32_t vlen, uint8_t *base, const size_t size) : _vlen{vlen}, _base{base} - { - (void)size; // Workaround for unused variable in release mode - assert(size >= _vlen * sizeof(float)); - } + Sink(T *base, const size_t size) : _base{base}, _size{size} {} public: - void pull(::arm_compute::ITensor &tensor) const override + void pull(::neurun::backend::operand::ITensor &tensor) const override { - float *base = reinterpret_cast<float *>(_base); - - for (int32_t n = 0; n < _vlen; ++n) - { - auto from = reinterpret_cast<float *>(tensor.ptr_to_element(::arm_compute::Coordinates{n})); - auto into = base + n; - - *into = *from; - } + memcpy(_base, tensor.buffer(), _size); } private: - const int32_t _vlen; - uint8_t *const _base; + T *const _base; + const size_t _size; }; -// -// FeatureSink -// -class FeatureSink final : public Sink +class PermutateSink final : public ISink { public: - FeatureSink(const nnfw::util::feature::Shape &shape, uint8_t *base, const size_t size) - : _shape{shape}, _base{base}, _size{size} + PermutateSink(void *output_buffer, const size_t &output_size, const model::operand::Shape &shape) + : _output_buffer{(uint8_t *)output_buffer}, _output_size{output_size}, _shape{shape} { - // DO NOTHING } public: - void pull(::arm_compute::ITensor &tensor) const override + void pull(neurun::backend::operand::ITensor &tensor) const override { - // TODO: This is just workaround codes, It needs to refactor. - if (typeid(tensor) == typeid(neurun::backend::cpu::operand::Tensor)) - { - const ::internal::nnapi::feature::Reader<float> from{_shape, tensor.buffer(), _size}; - ::internal::nnapi::feature::View<float> into{_shape, _base, _size}; - - ::nnfw::util::feature::iterate(_shape) - << [&](uint32_t bat, uint32_t ch, uint32_t row, uint32_t col) { - const auto value = from.at(bat, ch, row, col); - into.at(bat, ch, row, col) = value; - }; - } - else if (typeid(tensor) == typeid(::arm_compute::CLTensor)) + // do NCHW_TO_NHWC permutation + auto input_buffer = tensor.buffer(); + auto rank = _shape.rank(); + + switch (rank) { - const ::internal::arm_compute::feature::View<float> from{&tensor}; - ::internal::nnapi::feature::View<float> into{_shape, _base, _size}; - - ::nnfw::util::feature::iterate(_shape) - << [&](uint32_t bat, uint32_t ch, uint32_t row, uint32_t col) { - const auto value = from.at(bat, ch, row, col); - into.at(bat, ch, row, col) = value; - }; + case 0: + case 1: + { + memcpy(_output_buffer, input_buffer, _output_size); + break; + } + case 2: + { + auto matrix_shape = _shape.asMatrix(); + + for (auto h = 0; h < matrix_shape.H; ++h) + { + neurun::util::feature::Coordinate4D coord{0, h, 0, 0}; + memcpy(_output_buffer + h * matrix_shape.W, input_buffer + tensor.calcOffset(coord), + matrix_shape.W * sizeof(float)); + } + break; + } + case 3: + { + const int32_t depth = _shape.dim(0); + const int32_t height = _shape.dim(1); + const int32_t width = _shape.dim(2); + + for (auto c = 0; c < depth; ++c) + { + for (auto h = 0; h < height; ++h) + { + neurun::util::feature::Coordinate4D coord{0, h, 0, c}; + memcpy(_output_buffer + c * height * width + h * width, + input_buffer + tensor.calcOffset(coord), width * sizeof(float)); + } + } + break; + } + case 4: + { + auto feature = _shape.asFeature(); + + const util::feature::nchw::View<float> from{&tensor}; + util::feature::nhwc::View<float> into{feature, reinterpret_cast<float *>(_output_buffer), + _output_size}; + + ::nnfw::misc::feature::iterate(feature) + << [&](uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) { + const auto value = from.at(batch, ch, row, col); + into.at(batch, ch, row, col) = value; + }; + break; + } + default: + throw "NYI"; + break; } } private: - const nnfw::util::feature::Shape _shape; - uint8_t *const _base; - const size_t _size; + uint8_t *_output_buffer; + const size_t _output_size; + const model::operand::Shape _shape; }; } // namespace exec } // namespace neurun -#endif // __INTERNAL_SINK_H__ +#endif // __NEURUN_EXEC_SINK_H__ diff --git a/runtimes/neurun/src/exec/Source.h b/runtimes/neurun/src/exec/Source.h index e7c2e80c4..169f8b386 100644 --- a/runtimes/neurun/src/exec/Source.h +++ b/runtimes/neurun/src/exec/Source.h @@ -19,105 +19,118 @@ #include <cassert> -#include <arm_compute/runtime/CL/CLTensor.h> - -#include <util/feature/Shape.h> -#include <util/feature/IndexIterator.h> - -#include "backend/cpu/operand/Tensor.h" // TODO Remove this dependency to backend -#include "internal/nnapi/feature/Reader.h" -#include "internal/nnapi/feature/View.h" - -#include "backend/acl_cl/feature/View.h" +#include "cpp14/memory.h" +#include "util/feature/nchw/View.h" +#include "util/feature/nhwc/Reader.h" +#include "util/feature/Coordinate4D.h" +#include <misc/feature/IndexIterator.h> namespace neurun { namespace exec { -struct Source +struct ISource { - virtual ~Source() = default; + virtual ~ISource() = default; - virtual void push(::arm_compute::ITensor &tensor) const = 0; + virtual void push(::neurun::backend::operand::ITensor &tensor) const = 0; }; -// -// VectorSource -// -class VectorSource final : public Source +template <typename T> class Source final : public ISource { public: - VectorSource(const int32_t vlen, const uint8_t *base, const size_t size) - : _vlen{vlen}, _base{base} - { - (void)size; // Workaround for unused variable in release mode - assert(size >= _vlen * sizeof(float)); - } + Source(const T *base, const size_t size) : _base{base}, _size{size} {} public: - void push(::arm_compute::ITensor &tensor) const override + void push(::neurun::backend::operand::ITensor &tensor) const override { - auto base = reinterpret_cast<const float *>(_base); - - for (int32_t n = 0; n < _vlen; ++n) - { - auto from = base + n; - auto into = reinterpret_cast<float *>(tensor.ptr_to_element(::arm_compute::Coordinates{n})); - - *into = *from; - } + memcpy(tensor.buffer(), _base, _size); } private: - const int32_t _vlen; - const uint8_t *const _base; + const T *const _base; + const size_t _size; }; -// -// FeatureSource -// -class FeatureSource final : public Source +class PermutateSource final : public ISource { public: - FeatureSource(const nnfw::util::feature::Shape &shape, const uint8_t *base, const size_t size) - : _shape{shape}, _base{base}, _size{size} + PermutateSource(const void *input_buffer, const size_t &input_size, + const model::operand::Shape &shape) + : _input_buffer{(uint8_t *)input_buffer}, _input_size{input_size}, _shape{shape} { - // DO NOTHING } public: - void push(::arm_compute::ITensor &tensor) const override + void push(neurun::backend::operand::ITensor &tensor) const override { - // TODO: This is just workaround codes, It needs to refactor. - if (typeid(tensor) == typeid(neurun::backend::cpu::operand::Tensor)) - { - const ::internal::nnapi::feature::Reader<float> from{_shape, _base, _size}; - ::internal::nnapi::feature::View<float> into{_shape, tensor.buffer(), _size}; - - ::nnfw::util::feature::iterate(_shape) - << [&](uint32_t bat, uint32_t ch, uint32_t row, uint32_t col) { - const auto value = from.at(bat, ch, row, col); - into.at(bat, ch, row, col) = value; - }; - } - else if (typeid(tensor) == typeid(::arm_compute::CLTensor)) + // do NHWC_TO_NCHW permutation + auto output_buffer = tensor.buffer(); + auto rank = _shape.rank(); + + switch (rank) { - const ::internal::nnapi::feature::Reader<float> from{_shape, _base, _size}; - ::internal::arm_compute::feature::View<float> into{&tensor}; - - ::nnfw::util::feature::iterate(_shape) - << [&](uint32_t bat, uint32_t ch, uint32_t row, uint32_t col) { - const auto value = from.at(bat, ch, row, col); - into.at(bat, ch, row, col) = value; - }; + case 0: + case 1: + { + memcpy(output_buffer, _input_buffer, _input_size); + break; + } + case 2: + { + auto matrix_shape = _shape.asMatrix(); + + for (auto h = 0; h < matrix_shape.H; ++h) + { + neurun::util::feature::Coordinate4D coord{0, h, 0, 0}; + memcpy(output_buffer + tensor.calcOffset(coord), _input_buffer + h * matrix_shape.W, + matrix_shape.W * sizeof(float)); + } + break; + } + case 3: + { + const int32_t depth = _shape.dim(0); + const int32_t height = _shape.dim(1); + const int32_t width = _shape.dim(2); + + for (auto c = 0; c < depth; ++c) + { + for (auto h = 0; h < height; ++h) + { + neurun::util::feature::Coordinate4D coord{0, h, 0, c}; + memcpy(output_buffer + tensor.calcOffset(coord), + _input_buffer + c * height * width + h * width, width * sizeof(float)); + } + } + break; + } + case 4: + { + auto feature = _shape.asFeature(); + + const util::feature::nhwc::Reader<float> from{ + feature, reinterpret_cast<const float *>(_input_buffer), _input_size}; + util::feature::nchw::View<float> into{&tensor}; + + ::nnfw::misc::feature::iterate(feature) + << [&](uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) { + const auto value = from.at(batch, ch, row, col); + into.at(batch, ch, row, col) = value; + }; + break; + } + default: + throw "NYI"; + break; } } private: - const nnfw::util::feature::Shape _shape; - const uint8_t *const _base; - const size_t _size; + const uint8_t *_input_buffer; + const size_t _input_size; + const model::operand::Shape _shape; }; } // namespace exec diff --git a/runtimes/neurun/src/exec/interface/IFunction.h b/runtimes/neurun/src/exec/interface/IFunction.h new file mode 100644 index 000000000..b7a721d1d --- /dev/null +++ b/runtimes/neurun/src/exec/interface/IFunction.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2018 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 __NEURUN_EXEC_I_FUNCTION_H__ +#define __NEURUN_EXEC_I_FUNCTION_H__ + +namespace neurun +{ +namespace exec +{ + +class IFunction +{ +public: + virtual ~IFunction() = default; + virtual void run() = 0; + virtual void prepare() {} +}; + +} // namespace exec +} // namespace neurun + +#endif // __NEURUN_EXEC_I_FUNCTION_H__ diff --git a/runtimes/neurun/src/frontend/compilation.cc b/runtimes/neurun/src/frontend/compilation.cc index a135edac5..9b0719f46 100644 --- a/runtimes/neurun/src/frontend/compilation.cc +++ b/runtimes/neurun/src/frontend/compilation.cc @@ -32,6 +32,11 @@ int ANeuralNetworksCompilation_create(ANeuralNetworksModel *model, return ANEURALNETWORKS_UNEXPECTED_NULL; } + if (!model->isFinished()) + { + return ANEURALNETWORKS_BAD_STATE; + } + std::shared_ptr<neurun::graph::Graph> internal; model->release(internal); diff --git a/runtimes/neurun/src/frontend/execution.cc b/runtimes/neurun/src/frontend/execution.cc index ff34921b7..5f1729b30 100644 --- a/runtimes/neurun/src/frontend/execution.cc +++ b/runtimes/neurun/src/frontend/execution.cc @@ -22,7 +22,122 @@ #include "frontend/wrapper/execution.h" #include "frontend/wrapper/event.h" -#include "graph/operand/Index.h" +#include "model/operand/DataType.h" +#include "model/operand/Index.h" +#include "graph/operand/Layout.h" +#include "backend/BackendManager.h" +#include "backend/interface/IConfig.h" +#include "compiler/BackendResolver.h" +#include "compiler/TensorInfo.h" +#include "backend/interface/operand/ITensor.h" + +inline void source(ANeuralNetworksExecution *execution, + const ::neurun::model::operand::DataType &type, int32_t index, + const void *buffer, size_t length) +{ + const auto &operands = execution->plan().model().operands(); + neurun::model::operand::IO::Index input_index{index}; + + const auto operand_index = execution->plan().model().getInputs().at(input_index); + auto operand = &operands.at(operand_index); + auto operand_li = operand->lower_info(); + const auto output_backend = operand_li->def_backends().getOnlyElement(); + const auto output_layout = output_backend->config()->getOperandLayout(); + auto input_layout = execution->plan() + .model() + .backend_resolver() + ->getDefaultBackend() + ->config() + ->getOperandLayout(); + if (input_layout == neurun::graph::operand::Layout::NHWC && + output_layout == neurun::graph::operand::Layout::NCHW) + { + const auto tensor_info = neurun::compiler::TensorInfo(operand->shape(), operand->typeInfo()); + + execution->source<::neurun::exec::PermutateSource>(index, buffer, tensor_info.total_size(), + operand->shape()); + return; + } + using ::neurun::model::operand::DataType; + switch (type) + { + case DataType::SCALAR_FLOAT32: + case DataType::TENSOR_FLOAT32: + execution->source<::neurun::exec::Source<float>>( + index, reinterpret_cast<const float *>(buffer), length); + break; + case DataType::SCALAR_INT32: + case DataType::TENSOR_INT32: + execution->source<::neurun::exec::Source<int32_t>>( + index, reinterpret_cast<const int32_t *>(buffer), length); + break; + case DataType::SCALAR_UINT32: + execution->source<::neurun::exec::Source<uint32_t>>( + index, reinterpret_cast<const uint32_t *>(buffer), length); + break; + case DataType::TENSOR_QUANT8_ASYMM: + execution->source<::neurun::exec::Source<uint8_t>>( + index, reinterpret_cast<const uint8_t *>(buffer), length); + break; + default: + throw std::runtime_error("Not supported, yet"); + break; + } +} + +inline void sink(ANeuralNetworksExecution *execution, + const ::neurun::model::operand::DataType &type, int32_t index, void *buffer, + size_t length) +{ + const auto &operands = execution->plan().model().operands(); + neurun::model::operand::IO::Index input_index{index}; + + const auto operand_index = execution->plan().model().getOutputs().at(input_index); + auto operand = &operands.at(operand_index); + auto operand_li = operand->lower_info(); + const auto input_backend = operand_li->def_backends().getOnlyElement(); + const auto input_layout = input_backend->config()->getOperandLayout(); + auto output_layout = execution->plan() + .model() + .backend_resolver() + ->getDefaultBackend() + ->config() + ->getOperandLayout(); + if (input_layout == neurun::graph::operand::Layout::NCHW && + output_layout == neurun::graph::operand::Layout::NHWC) + { + const auto tensor_info = neurun::compiler::TensorInfo(operand->shape(), operand->typeInfo()); + + execution->sink<::neurun::exec::PermutateSink>(index, buffer, tensor_info.total_size(), + operand->shape()); + return; + } + using ::neurun::model::operand::DataType; + switch (type) + { + case DataType::SCALAR_FLOAT32: + case DataType::TENSOR_FLOAT32: + execution->sink<::neurun::exec::Sink<float>>(index, reinterpret_cast<float *>(buffer), + length); + break; + case DataType::SCALAR_INT32: + case DataType::TENSOR_INT32: + execution->sink<::neurun::exec::Sink<int32_t>>(index, reinterpret_cast<int32_t *>(buffer), + length); + break; + case DataType::SCALAR_UINT32: + execution->sink<::neurun::exec::Sink<uint32_t>>(index, reinterpret_cast<uint32_t *>(buffer), + length); + break; + case DataType::TENSOR_QUANT8_ASYMM: + execution->sink<::neurun::exec::Sink<uint8_t>>(index, reinterpret_cast<uint8_t *>(buffer), + length); + break; + default: + throw std::runtime_error("Not supported, yet"); + break; + } +} // // NNAPI Implementation @@ -35,7 +150,13 @@ int ANeuralNetworksExecution_create(ANeuralNetworksCompilation *compilation, return ANEURALNETWORKS_UNEXPECTED_NULL; } - std::shared_ptr<const neurun::codegen::Plan> plan; + // Can handle compiled state only + if (compilation->plan().state() != neurun::compiler::State::COMPILED) + { + return ANEURALNETWORKS_BAD_STATE; + } + + std::shared_ptr<const neurun::compiler::Plan> plan; compilation->publish(plan); @@ -61,36 +182,23 @@ int ANeuralNetworksExecution_setInput(ANeuralNetworksExecution *execution, int32 return ANEURALNETWORKS_UNEXPECTED_NULL; } + // TODO Handle optional input + if (buffer == nullptr) + { + throw std::runtime_error("Not supported optional input, yet"); + } + const auto &operands = execution->plan().model().operands(); // TODO Check type conflicts - // NOTE The current implemenation assumes that every input is a feature map. - // TODO Remove this assumption - neurun::graph::operand::IO::Index input_index{index}; + neurun::model::operand::IO::Index input_index{index}; const auto operand_index = execution->plan().model().getInputs().at(input_index); + const auto data_type = operands.at(operand_index).typeInfo().type(); + const auto operand_shape = operands.at(operand_index).shape(); - if (operands.at(operand_index).shape().rank() == 2) - { - assert(operands.at(operand_index).shape().dim(0) == 1); - - const auto len = operands.at(operand_index).shape().dim(1); - - execution->source<neurun::exec::VectorSource>( - index, len, reinterpret_cast<const uint8_t *>(buffer), length); - } - else if (operands.at(operand_index).shape().rank() == 4) - { - const auto &operand_shape = operands.at(operand_index).shape().asFeature(); - - execution->source<neurun::exec::FeatureSource>( - index, operand_shape, reinterpret_cast<const uint8_t *>(buffer), length); - } - else - { - throw std::runtime_error{"Not supported, yet"}; - } + source(execution, data_type, index, buffer, length); return ANEURALNETWORKS_NO_ERROR; } @@ -108,36 +216,23 @@ int ANeuralNetworksExecution_setOutput(ANeuralNetworksExecution *execution, int3 return ANEURALNETWORKS_UNEXPECTED_NULL; } + // Handle optional output + if (buffer == nullptr) + { + return ANEURALNETWORKS_NO_ERROR; + } + const auto &operands = execution->plan().model().operands(); // TODO Check type conflicts - // NOTE The current implemenation assumes that every output is a feature map. - // TODO Remove this assumption - neurun::graph::operand::IO::Index output_index{index}; + neurun::model::operand::IO::Index output_index{index}; const auto operand_index = execution->plan().model().getOutputs().at(output_index); + const auto data_type = operands.at(operand_index).typeInfo().type(); + const auto operand_shape = operands.at(operand_index).shape(); - if (operands.at(operand_index).shape().rank() == 2) - { - assert(operands.at(operand_index).shape().dim(0) == 1); - - const auto len = operands.at(operand_index).shape().dim(1); - - execution->sink<neurun::exec::VectorSink>(index, len, reinterpret_cast<uint8_t *>(buffer), - length); - } - else if (operands.at(operand_index).shape().rank() == 4) - { - const auto &operand_shape = operands.at(operand_index).shape().asFeature(); - - execution->sink<neurun::exec::FeatureSink>(index, operand_shape, - reinterpret_cast<uint8_t *>(buffer), length); - } - else - { - throw std::runtime_error{"Not supported, yet"}; - } + sink(execution, data_type, index, buffer, length); return ANEURALNETWORKS_NO_ERROR; } @@ -163,17 +258,16 @@ int ANeuralNetworksExecution_startCompute(ANeuralNetworksExecution *execution, // Set input(s) for (uint32_t n = 0; n < model.getInputs().size(); ++n) { - auto setter = [&](::arm_compute::ITensor &tensor) { execution->source(n).push(tensor); }; + auto setter = [&](::neurun::backend::operand::ITensor &tensor) { + execution->source(n).push(tensor); + }; - neurun::graph::operand::IO::Index input_index{n}; + neurun::model::operand::IO::Index input_index{n}; - ::neurun::graph::operand::Index index{model.getInputs().at(input_index)}; - auto objects = plan.operands().at(index); + ::neurun::model::operand::Index index{model.getInputs().at(input_index)}; + auto object = plan.operands().at(index); - for (auto object : objects) - { - object->access(setter); - } + object->access(setter); } const auto &operations = execution->plan().operations(); @@ -186,17 +280,16 @@ int ANeuralNetworksExecution_startCompute(ANeuralNetworksExecution *execution, // Get output(s) for (uint32_t n = 0; n < model.getOutputs().size(); ++n) { - auto getter = [&](::arm_compute::ITensor &tensor) { execution->sink(n).pull(tensor); }; + auto getter = [&](::neurun::backend::operand::ITensor &tensor) { + execution->sink(n).pull(tensor); + }; - neurun::graph::operand::IO::Index output_index{n}; + neurun::model::operand::IO::Index output_index{n}; - ::neurun::graph::operand::Index index{model.getOutputs().at(output_index)}; - auto objects = plan.operands().at(index); + ::neurun::model::operand::Index index{model.getOutputs().at(output_index)}; + auto object = plan.operands().at(index); - for (auto object : objects) - { - object->access(getter); - } + object->access(getter); } return ANEURALNETWORKS_NO_ERROR; diff --git a/runtimes/neurun/src/frontend/memory.cc b/runtimes/neurun/src/frontend/memory.cc index cc891feef..b2f6ab2d0 100644 --- a/runtimes/neurun/src/frontend/memory.cc +++ b/runtimes/neurun/src/frontend/memory.cc @@ -19,7 +19,7 @@ #include <new> #include <memory> -#include "nnfw/std/memory.h" +#include "cpp14/memory.h" #include "frontend/wrapper/memory.h" int ANeuralNetworksMemory_createFromFd(size_t size, int protect, int fd, size_t offset, @@ -32,7 +32,7 @@ int ANeuralNetworksMemory_createFromFd(size_t size, int protect, int fd, size_t // Use unique pointer to avoid memory leak std::unique_ptr<ANeuralNetworksMemory> memory_ptr = - nnfw::make_unique<ANeuralNetworksMemory>(size, protect, fd, offset); + nnfw::cpp14::make_unique<ANeuralNetworksMemory>(size, protect, fd, offset); if (memory_ptr == nullptr) { return ANEURALNETWORKS_OUT_OF_MEMORY; diff --git a/runtimes/neurun/src/frontend/model.cc b/runtimes/neurun/src/frontend/model.cc index 28a9b2515..3aa2aa2ff 100644 --- a/runtimes/neurun/src/frontend/model.cc +++ b/runtimes/neurun/src/frontend/model.cc @@ -21,18 +21,12 @@ #include <stdexcept> #include <new> -#include "nnfw/std/memory.h" +#include "cpp14/memory.h" #include "graph/Graph.h" #include "frontend/wrapper/model.h" #include "frontend/wrapper/memory.h" -#include "graph/operation/AvgPool2D.h" -#include "graph/operation/Concat.h" -#include "graph/operation/Conv2D.h" -#include "graph/operation/FullyConnected.h" -#include "graph/operation/MaxPool2D.h" -#include "graph/operation/Reshape.h" -#include "graph/operation/Softmax.h" +#include "model/operation/Node.Include.h" int ANeuralNetworksModel_create(ANeuralNetworksModel **model) { @@ -94,8 +88,8 @@ int ANeuralNetworksModel_addOperand(ANeuralNetworksModel *model, return ANEURALNETWORKS_BAD_DATA; } - ::neurun::graph::operand::Shape shape(type->dimensionCount); - ::neurun::graph::operand::TypeInfo typeInfo((OperandCode)(type->type), type->scale, + ::neurun::model::operand::Shape shape(type->dimensionCount); + ::neurun::model::operand::TypeInfo typeInfo((OperandCode)(type->type), type->scale, type->zeroPoint); for (uint32_t axis = 0; axis < type->dimensionCount; ++axis) @@ -115,6 +109,8 @@ int ANeuralNetworksModel_addOperand(ANeuralNetworksModel *model, int ANeuralNetworksModel_setOperandValue(ANeuralNetworksModel *model, int32_t index, const void *buffer, size_t length) { + const bool isOptional = ((buffer == nullptr) && (length == 0)); + if ((model == nullptr) || ((buffer == nullptr) && (length != 0))) { return ANEURALNETWORKS_UNEXPECTED_NULL; @@ -130,7 +126,7 @@ int ANeuralNetworksModel_setOperandValue(ANeuralNetworksModel *model, int32_t in { return ANEURALNETWORKS_BAD_DATA; } - const neurun::graph::operand::Index ind{static_cast<uint32_t>(index)}; + const neurun::model::operand::Index ind{static_cast<uint32_t>(index)}; if (!model->deref().operands().exist(ind)) { @@ -138,7 +134,7 @@ int ANeuralNetworksModel_setOperandValue(ANeuralNetworksModel *model, int32_t in } auto &obj = model->deref().operands().at(ind); - if (obj.operandSize() != length) + if ((obj.operandSize() != length) && !isOptional) { return ANEURALNETWORKS_BAD_DATA; } @@ -147,10 +143,30 @@ int ANeuralNetworksModel_setOperandValue(ANeuralNetworksModel *model, int32_t in return ANEURALNETWORKS_BAD_DATA; } - using ::neurun::graph::operand::CachedData; + using ::neurun::model::operand::CachedData; + using ::neurun::model::operand::ExternalData; - model->deref().setOperandValue( - ind, nnfw::make_unique<CachedData>(reinterpret_cast<const uint8_t *>(buffer), length)); + // Remain operands.at(ind).data()->base() as nullptr for optional operand + // This will be filled when model finished + if (isOptional) + { + model->setOptionalOperand(ind); + } + + // NNAPI spec in NeuralNetworks.h + // For values of length greater than ANEURALNETWORKS_MAX_SIZE_OF_IMMEDIATELY_COPIED_VALUES, + // the application is responsible for not changing the content of this region + // until all executions using this model have completed + if (length <= ANEURALNETWORKS_MAX_SIZE_OF_IMMEDIATELY_COPIED_VALUES) + { + model->deref().setOperandValue(ind, nnfw::cpp14::make_unique<CachedData>( + reinterpret_cast<const uint8_t *>(buffer), length)); + } + else + { + model->deref().setOperandValue(ind, nnfw::cpp14::make_unique<ExternalData>( + reinterpret_cast<const uint8_t *>(buffer), length)); + } return ANEURALNETWORKS_NO_ERROR; } @@ -174,7 +190,7 @@ int ANeuralNetworksModel_setOperandValueFromMemory(ANeuralNetworksModel *model, { return ANEURALNETWORKS_BAD_DATA; } - const neurun::graph::operand::Index ind{static_cast<uint32_t>(index)}; + const neurun::model::operand::Index ind{static_cast<uint32_t>(index)}; if (!model->deref().operands().exist(ind)) { @@ -191,10 +207,10 @@ int ANeuralNetworksModel_setOperandValueFromMemory(ANeuralNetworksModel *model, return ANEURALNETWORKS_BAD_DATA; } - using ::neurun::graph::operand::ExternalData; + using ::neurun::model::operand::ExternalData; model->deref().setOperandValue( - ind, nnfw::make_unique<ExternalData>( + ind, nnfw::cpp14::make_unique<ExternalData>( reinterpret_cast<const uint8_t *>(memory->base() + offset), length)); return ANEURALNETWORKS_NO_ERROR; @@ -210,6 +226,13 @@ int ANeuralNetworksModel_addOperation(ANeuralNetworksModel *model, return ANEURALNETWORKS_UNEXPECTED_NULL; } + const ANeuralNetworksOperationType FIRST_OPERATION = ANEURALNETWORKS_ADD; + const ANeuralNetworksOperationType LAST_OPERATION = ANEURALNETWORKS_TRANSPOSE; + if ((type < FIRST_OPERATION) || (type > LAST_OPERATION)) + { + return ANEURALNETWORKS_BAD_DATA; + } + if (model->isFinished()) { return ANEURALNETWORKS_BAD_STATE; @@ -217,7 +240,7 @@ int ANeuralNetworksModel_addOperation(ANeuralNetworksModel *model, for (uint32_t i = 0; i < outputCount; i++) { - const ::neurun::graph::operand::Index ind{outputs[i]}; + const ::neurun::model::operand::Index ind{outputs[i]}; auto &obj = model->deref().operands().at(ind); if (!obj.setAsOperationOutput()) @@ -229,108 +252,115 @@ int ANeuralNetworksModel_addOperation(ANeuralNetworksModel *model, auto &graph = model->deref(); auto node_param = - neurun::graph::operation::Node::InitParam{inputCount, inputs, outputCount, outputs}; + neurun::model::operation::Node::InitParam{inputCount, inputs, outputCount, outputs}; - switch (type) + try { - case ANEURALNETWORKS_CONV_2D: + switch (type) { - // inputCount is either 7 or 10 acccording to NN API specification. - // - Padding is implicit when inputCount is 7 - // - Padding is explicit when inputCount is 10 - assert(inputCount == 7 || inputCount == 10); - assert(outputCount == 1); - - if (inputCount == 7) + case ANEURALNETWORKS_CONV_2D: { - using GraphNode = neurun::graph::operation::Conv2D::Implicit::Node; - - graph.addOperation(nnfw::make_unique<GraphNode>(node_param)); + // inputCount is either 7 or 10 acccording to NN API specification. + // - Padding is implicit when inputCount is 7 + // - Padding is explicit when inputCount is 10 + assert(inputCount == 7 || inputCount == 10); + assert(outputCount == 1); + + if (inputCount == 7) + { + using GraphNode = neurun::model::operation::Conv2DNode; + + graph.addOperation(nnfw::cpp14::make_unique<GraphNode>(node_param)); + } + else + { + throw std::runtime_error{"Explicit padding in Conv2D is not supported, yet"}; + } + + break; } - else + case ANEURALNETWORKS_MAX_POOL_2D: { - throw std::runtime_error{"Explicit padding in Conv2D is not supported, yet"}; + // inputCount is either 7 or 10 acccording to NN API specification. + // - Padding is implicit when inputCount is 7 + // - Padding is explicit when inputCount is 10 + assert(inputCount == 7 || inputCount == 10); + assert(outputCount == 1); + + if (inputCount == 7) + { + using GraphNode = neurun::model::operation::MaxPool2DNode; + + graph.addOperation(nnfw::cpp14::make_unique<GraphNode>(node_param)); + } + else + { + throw std::runtime_error{"Explicit padding in MaxPool2D is not supported, yet"}; + } + + break; } - - break; - } - case ANEURALNETWORKS_MAX_POOL_2D: - { - // inputCount is either 7 or 10 acccording to NN API specification. - // - Padding is implicit when inputCount is 7 - // - Padding is explicit when inputCount is 10 - assert(inputCount == 7 || inputCount == 10); - assert(outputCount == 1); - - if (inputCount == 7) + case ANEURALNETWORKS_AVERAGE_POOL_2D: { - using GraphNode = neurun::graph::operation::MaxPool2D::Implicit::Node; - - graph.addOperation(nnfw::make_unique<GraphNode>(node_param)); + // inputCount is either 7 or 10 acccording to NN API specification. + // - Padding is implicit when inputCount is 7 + // - Padding is explicit when inputCount is 10 + assert(inputCount == 7 || inputCount == 10); + assert(outputCount == 1); + + if (inputCount == 7) + { + using GraphNode = neurun::model::operation::AvgPool2DNode; + + graph.addOperation(nnfw::cpp14::make_unique<GraphNode>(node_param)); + } + else + { + throw std::runtime_error{"Explicit padding in AvgPool2D is not supported, yet"}; + } + + break; } - else + case ANEURALNETWORKS_CONCATENATION: { - throw std::runtime_error{"Explicit padding in MaxPool2D is not supported, yet"}; - } - - break; - } - case ANEURALNETWORKS_AVERAGE_POOL_2D: - { - // inputCount is either 7 or 10 acccording to NN API specification. - // - Padding is implicit when inputCount is 7 - // - Padding is explicit when inputCount is 10 - assert(inputCount == 7 || inputCount == 10); - assert(outputCount == 1); + using GraphNode = neurun::model::operation::ConcatNode; - if (inputCount == 7) - { - using GraphNode = neurun::graph::operation::AvgPool2D::Implicit::Node; + graph.addOperation(nnfw::cpp14::make_unique<GraphNode>(node_param)); - graph.addOperation(nnfw::make_unique<GraphNode>(node_param)); + break; } - else + case ANEURALNETWORKS_RESHAPE: { - throw std::runtime_error{"Explicit padding in AvgPool2D is not supported, yet"}; - } - - break; - } - case ANEURALNETWORKS_CONCATENATION: - { - using GraphNode = neurun::graph::operation::Concat::Node; + using GraphNode = neurun::model::operation::ReshapeNode; - graph.addOperation(nnfw::make_unique<GraphNode>(node_param)); + graph.addOperation(nnfw::cpp14::make_unique<GraphNode>(node_param)); - break; - } - case ANEURALNETWORKS_RESHAPE: - { - using GraphNode = neurun::graph::operation::Reshape::Node; - - graph.addOperation(nnfw::make_unique<GraphNode>(node_param)); - - break; - } - case ANEURALNETWORKS_FULLY_CONNECTED: - { - using GraphNode = neurun::graph::operation::FullyConnected::Node; + break; + } + case ANEURALNETWORKS_FULLY_CONNECTED: + { + using GraphNode = neurun::model::operation::FullyConnectedNode; - graph.addOperation(nnfw::make_unique<GraphNode>(node_param)); + graph.addOperation(nnfw::cpp14::make_unique<GraphNode>(node_param)); - break; - } - case ANEURALNETWORKS_SOFTMAX: - { - using GraphNode = neurun::graph::operation::Softmax::Node; + break; + } + case ANEURALNETWORKS_SOFTMAX: + { + using GraphNode = neurun::model::operation::SoftmaxNode; - graph.addOperation(nnfw::make_unique<GraphNode>(node_param)); + graph.addOperation(nnfw::cpp14::make_unique<GraphNode>(node_param)); - break; - } - default: - throw std::runtime_error{"Not supported operation"}; - }; + break; + } + default: + throw std::runtime_error{"Not supported operation"}; + }; + } + catch (const std::exception &e) + { + return ANEURALNETWORKS_BAD_STATE; + } return ANEURALNETWORKS_NO_ERROR; } @@ -350,9 +380,16 @@ int ANeuralNetworksModel_addOperationEx(ANeuralNetworksModel *model, return ANEURALNETWORKS_BAD_STATE; } + const ANeuralNetworksOperationTypeEx FIRST_OPERATION = ANEURALNETWORKS_GATHER_EX; + const ANeuralNetworksOperationTypeEx LAST_OPERATION = ANEURALNETWORKS_PRELU_EX; + if ((type < FIRST_OPERATION) || (type > LAST_OPERATION)) + { + return ANEURALNETWORKS_BAD_DATA; + } + for (uint32_t i = 0; i < outputCount; i++) { - const ::neurun::graph::operand::Index ind{outputs[i]}; + const ::neurun::model::operand::Index ind{outputs[i]}; auto &obj = model->deref().operands().at(ind); if (!obj.setAsOperationOutput()) @@ -367,11 +404,20 @@ int ANeuralNetworksModel_addOperationEx(ANeuralNetworksModel *model, return ANEURALNETWORKS_BAD_DATA; } - switch (type) + try { - default: - throw std::runtime_error{"Not supported operation"}; + switch (type) + { + default: + throw std::runtime_error{"Not supported operation"}; + } } + catch (const std::exception &e) + { + return ANEURALNETWORKS_BAD_STATE; + } + + return ANEURALNETWORKS_NO_ERROR; } int ANeuralNetworksModel_identifyInputsAndOutputs(ANeuralNetworksModel *model, uint32_t inputCount, @@ -388,7 +434,7 @@ int ANeuralNetworksModel_identifyInputsAndOutputs(ANeuralNetworksModel *model, u return ANEURALNETWORKS_BAD_STATE; } - // NOTE ::neurun::graph::operand::Index uses int as its underlying type as various NNAPI + // NOTE ::neurun::model::operand::Index uses int as its underlying type as various NNAPI // functions such as ANeuralNetworksModel_setOperandValue use int to represent operand index // // ANeuralNetworksModel_identifyInputsAndOutputs, however, uses uint32_t to represent operand @@ -397,7 +443,7 @@ int ANeuralNetworksModel_identifyInputsAndOutputs(ANeuralNetworksModel *model, u // Below, static_cast<int>(...) is introduced to eliminate compiler warning. for (uint32_t n = 0; n < inputCount; ++n) { - const neurun::graph::operand::Index ind{static_cast<uint32_t>(inputs[n])}; + const neurun::model::operand::Index ind{static_cast<uint32_t>(inputs[n])}; model->deref().addInput(ind); auto &obj = model->deref().operands().at(ind); @@ -409,7 +455,7 @@ int ANeuralNetworksModel_identifyInputsAndOutputs(ANeuralNetworksModel *model, u for (uint32_t n = 0; n < outputCount; ++n) { - const neurun::graph::operand::Index ind{static_cast<uint32_t>(outputs[n])}; + const neurun::model::operand::Index ind{static_cast<uint32_t>(outputs[n])}; model->deref().addOutput(ind); auto &obj = model->deref().operands().at(ind); diff --git a/runtimes/neurun/src/frontend/wrapper/compilation.cc b/runtimes/neurun/src/frontend/wrapper/compilation.cc index 4ff33faa5..e4aa99f7a 100644 --- a/runtimes/neurun/src/frontend/wrapper/compilation.cc +++ b/runtimes/neurun/src/frontend/wrapper/compilation.cc @@ -14,53 +14,18 @@ * limitations under the License. */ -#include <NeuralNetworks.h> - -#include <algorithm> - -#include <arm_compute/core/CL/ICLTensor.h> - -#include <arm_compute/runtime/IFunction.h> -#include <arm_compute/runtime/CL/CLScheduler.h> - -#include "internal/Convert.h" -#include "backend/acl_cl/kernel/View.h" -#include "backend/acl_cl/TensorBuilder.h" -#include "internal/nnapi/kernel/Reader.h" -#include "internal/Padding.h" -#include "backend/IInitializerGenerator.h" -#include "backend/IStageGenerator.h" - #include "compilation.h" -#include "model.h" -#include "logging.h" - -#include "graph/dumper/Dumper.h" -#include "codegen/IPlanBuilder.h" -#include "codegen/Planner.h" -#include "codegen/PlanBuilder.h" - -#include "linear/Linear.h" int ANeuralNetworksCompilation::finish() { - auto &plan = this->plan(); - const auto &operands = plan.model().operands(); - - plan.model().lower(); - auto linear = plan.model().linearize(); - - // Dump ops - linear->accept(neurun::graph::dumper::Dumper{}); - - neurun::codegen::PlanBuilder plan_builder{plan}; - - auto tensor_builders = linear->markTensors(); - - linear->accept(neurun::codegen::Planner{operands, plan_builder}); - - // TODO Add optimization passes - plan_builder.finalize(tensor_builders); + try + { + _compiler->compile(); + } + catch (const std::exception &e) + { + return ANEURALNETWORKS_BAD_STATE; + } return ANEURALNETWORKS_NO_ERROR; } diff --git a/runtimes/neurun/src/frontend/wrapper/compilation.h b/runtimes/neurun/src/frontend/wrapper/compilation.h index 20d5a3d98..d4ba32ea5 100644 --- a/runtimes/neurun/src/frontend/wrapper/compilation.h +++ b/runtimes/neurun/src/frontend/wrapper/compilation.h @@ -17,27 +17,27 @@ #ifndef __COMPILATION_H__ #define __COMPILATION_H__ -#include "codegen/Plan.h" +#include "compiler/Compiler.h" #include "graph/Graph.h" struct ANeuralNetworksCompilation { public: ANeuralNetworksCompilation(const std::shared_ptr<neurun::graph::Graph> &model) - : _plan{new neurun::codegen::Plan{model}} + : _compiler{new neurun::compiler::Compiler{model}} { // DO NOTHING } public: - neurun::codegen::Plan &plan(void) { return *_plan; } + neurun::compiler::Plan &plan(void) { return _compiler->plan(); } public: - void publish(std::shared_ptr<const neurun::codegen::Plan> &plan) { plan = _plan; } + void publish(std::shared_ptr<const neurun::compiler::Plan> &plan) { _compiler->release(plan); } int finish(); private: - std::shared_ptr<neurun::codegen::Plan> _plan; + std::shared_ptr<neurun::compiler::Compiler> _compiler; }; #endif diff --git a/runtimes/neurun/src/frontend/wrapper/execution.h b/runtimes/neurun/src/frontend/wrapper/execution.h index 374201eb2..b68a7b967 100644 --- a/runtimes/neurun/src/frontend/wrapper/execution.h +++ b/runtimes/neurun/src/frontend/wrapper/execution.h @@ -17,28 +17,28 @@ #ifndef __EXECUTION_H__ #define __EXECUTION_H__ -#include "codegen/Plan.h" +#include "compiler/Plan.h" #include "exec/Source.h" #include "exec/Sink.h" struct ANeuralNetworksExecution { public: - ANeuralNetworksExecution(const std::shared_ptr<const neurun::codegen::Plan> &plan) : _plan{plan} + ANeuralNetworksExecution(const std::shared_ptr<const neurun::compiler::Plan> &plan) : _plan{plan} { _sources.resize(_plan->model().getInputs().size()); _sinks.resize(_plan->model().getOutputs().size()); } public: - const neurun::codegen::Plan &plan(void) const { return *_plan; } + const neurun::compiler::Plan &plan(void) const { return *_plan; } private: - std::shared_ptr<const neurun::codegen::Plan> _plan; + std::shared_ptr<const neurun::compiler::Plan> _plan; public: // TODO Use InputIndex instead of int - void source(int n, std::unique_ptr<neurun::exec::Source> &&source) + void source(int n, std::unique_ptr<neurun::exec::ISource> &&source) { _sources.at(n) = std::move(source); } @@ -48,22 +48,22 @@ public: } public: - const neurun::exec::Source &source(int n) const { return *(_sources.at(n)); } + const neurun::exec::ISource &source(int n) const { return *(_sources.at(n)); } public: // TODO Use OutputIndex instead of int - void sink(int n, std::unique_ptr<neurun::exec::Sink> &&sink) { _sinks.at(n) = std::move(sink); } + void sink(int n, std::unique_ptr<neurun::exec::ISink> &&sink) { _sinks.at(n) = std::move(sink); } template <typename T, typename... Args> void sink(int n, Args &&... args) { sink(n, std::unique_ptr<T>{new T{std::forward<Args>(args)...}}); } public: - const neurun::exec::Sink &sink(int n) const { return *(_sinks.at(n)); } + const neurun::exec::ISink &sink(int n) const { return *(_sinks.at(n)); } private: - std::vector<std::unique_ptr<neurun::exec::Source>> _sources; - std::vector<std::unique_ptr<neurun::exec::Sink>> _sinks; + std::vector<std::unique_ptr<neurun::exec::ISource>> _sources; + std::vector<std::unique_ptr<neurun::exec::ISink>> _sinks; }; #endif diff --git a/runtimes/neurun/src/frontend/wrapper/model.cc b/runtimes/neurun/src/frontend/wrapper/model.cc index c7ccbc60a..a7a9275fc 100644 --- a/runtimes/neurun/src/frontend/wrapper/model.cc +++ b/runtimes/neurun/src/frontend/wrapper/model.cc @@ -21,7 +21,8 @@ // // ANeuralNetworksModel // -ANeuralNetworksModel::ANeuralNetworksModel() : _model{new neurun::graph::Graph} +ANeuralNetworksModel::ANeuralNetworksModel() + : _model{new neurun::graph::Graph}, _optional_operands{} { // DO NOTHING } @@ -34,7 +35,24 @@ ResultCode ANeuralNetworksModel::finish() return ANEURALNETWORKS_BAD_STATE; } + fillOptionalOperand(); + _model->finishBuilding(); return ANEURALNETWORKS_NO_ERROR; } + +void ANeuralNetworksModel::fillOptionalOperand(void) +{ + _model->operations().iterate( + [&](const ::neurun::model::operation::Index &, ::neurun::model::operation::Node &node) { + for (auto input : node.getInputs()) + { + // TODO fill default value for optional operands + if (_optional_operands.find(input) != _optional_operands.end()) + { + throw std::runtime_error{"Optional operand is not supported yet"}; + } + } + }); +} diff --git a/runtimes/neurun/src/frontend/wrapper/model.h b/runtimes/neurun/src/frontend/wrapper/model.h index 3c7b027dc..2386a648d 100644 --- a/runtimes/neurun/src/frontend/wrapper/model.h +++ b/runtimes/neurun/src/frontend/wrapper/model.h @@ -30,12 +30,18 @@ public: neurun::graph::Graph &deref(void) { return *_model; } ResultCode finish(); bool isFinished() { return !_model->isBuildingPhase(); } - -public: void release(std::shared_ptr<neurun::graph::Graph> &model) { model = _model; } + void setOptionalOperand(const neurun::model::operand::Index idx) + { + _optional_operands.insert(idx); + } + +private: + void fillOptionalOperand(void); private: std::shared_ptr<neurun::graph::Graph> _model; + std::unordered_set<neurun::model::operand::Index> _optional_operands; }; #endif // __MODEL_H__ diff --git a/runtimes/neurun/src/graph/Graph.cc b/runtimes/neurun/src/graph/Graph.cc index 07194ff7e..832e2b887 100644 --- a/runtimes/neurun/src/graph/Graph.cc +++ b/runtimes/neurun/src/graph/Graph.cc @@ -19,116 +19,62 @@ #include <algorithm> #include <bitset> -#include "logging.h" -#include "verifier/IVerifier.h" -#include "nnfw/std/memory.h" +#include "util/logging.h" +#include "verifier/Verifier.h" +#include "cpp14/memory.h" #include "linear/Linear.h" #include "operation/LowerInfo.h" #include "operand/LowerInfo.h" #include "operand/Shape4DConvert.h" -#include "codegen/BackendResolver.h" -#include "backend/IBackendConfig.h" +#include "compiler/BackendResolver.h" +#include "backend/interface/IConfig.h" +#include "pass/PermutationInsertionPass.h" +#include "pass/PermutationEliminationPass.h" namespace neurun { namespace graph { -operand::Index Graph::addOperand(const operand::Shape &shape, const operand::TypeInfo &type) -{ - return _operands.append(shape, type); -} +Graph::Graph(void) = default; -operation::Index Graph::addOperation(std::unique_ptr<operation::Node> &&node) +Graph::~Graph(void) = default; + +model::operand::Index Graph::addOperand(const model::operand::Shape &shape, + const model::operand::TypeInfo &type) { - assert(_phase == Phase::BUILDING); - return _operations.append(std::move(node)); + return _model->operands.append(shape, type); } -// TODO : If operand's use-def information is introduced, -// Following API and implements would be refactored. -/** - * @brief Insert operation into between an operand and next operation. - * - * @param prev_operand_index is an previous operand index of insertion. - * @param next_operation_index is an next operation index of insertion. - * @param node is an operation::Node to insert. - * - * @return operation::Index - */ -operation::Index Graph::insertOperation(const operand::Index &prev_operand_index, - const operation::Index &next_operation_index, - std::unique_ptr<operation::Node> &&node) +model::operation::Index Graph::addOperation(std::unique_ptr<model::operation::Node> &&node) { - assert(_phase != Phase::BUILDING); - auto &next_operation = _operations.at(next_operation_index); - auto next_input_indexes = next_operation.getInputs(); - - assert(next_input_indexes.contains(prev_operand_index)); - assert(node->getInputs().size() == 0); // node to be inserted must not have any inputs - - node->setInputs({prev_operand_index}); - - // For multi input operation (ex. concat) - operand::IndexSet index_set; - auto cur_output_indexes = node->getOutputs(); - assert(cur_output_indexes.size() == 1); // Assume output of inserted node size always 1 - auto cur_output_index = cur_output_indexes.at(operand::IO::Index{0}); - // TODO : If the API for setting input one by one is introduced, it would be changed to simple. - for (auto next_input_index : next_input_indexes) - { - if (prev_operand_index == next_input_index) - { - index_set.append(cur_output_index); - } - else - { - index_set.append(next_input_index); - } - } - - next_operation.setInputs(index_set); - - operation::Index node_index = _operations.append(std::move(node)); - - // Update Use/Def info - { - _operands.at(prev_operand_index).removeUse(next_operation_index); - _operands.at(cur_output_index).appendUse(next_operation_index); - - _operands.at(prev_operand_index).appendUse(node_index); - - auto node_output_indexes = _operations.at(node_index).getOutputs(); - assert(node_output_indexes.size() == 1); - auto node_output_index = node_output_indexes.at(operand::IO::Index{0}); - _operands.at(node_output_index).appendDef(node_index); - } - - return node_index; + assert(isBuildingPhase()); + return _model->operations.append(std::move(node)); } -void Graph::setOperandValue(const operand::Index &ind, std::unique_ptr<operand::Data> &&data) +void Graph::setOperandValue(const model::operand::Index &ind, + std::unique_ptr<model::operand::Data> &&data) { - assert(_phase == Phase::BUILDING); - assert(_operands.exist(ind)); - _operands.at(ind).data(std::move(data)); + assert(isBuildingPhase()); + assert(_model->operands.exist(ind)); + _model->operands.at(ind).data(std::move(data)); } -void Graph::addInput(const operand::Index &ind) +void Graph::addInput(const model::operand::Index &ind) { - assert(_phase == Phase::BUILDING); - _inputs.append(ind); + assert(isBuildingPhase()); + _model->inputs.append(ind); } -void Graph::addOutput(const operand::Index &ind) +void Graph::addOutput(const model::operand::Index &ind) { - assert(_phase == Phase::BUILDING); - _outputs.append(ind); + assert(isBuildingPhase()); + _model->outputs.append(ind); } void Graph::finishBuilding(void) { - assert(_phase == Phase::BUILDING); + assert(isBuildingPhase()); _phase = Phase::MODEL; // Initialize operand use-def @@ -136,8 +82,8 @@ void Graph::finishBuilding(void) // Call graph verifications for the MODEL phase { - verifier::DAGChecker dag_checker; - dag_checker.verify(*this); + assert(verifier::DAGChecker().verify(*this)); + assert(verifier::EdgeConsistencyChecker().verify(*this)); } } @@ -148,106 +94,174 @@ void Graph::lower(void) // Lower { // operand::LowerInfo holder - std::unordered_map<operand::Index, std::unique_ptr<operand::LowerInfo>> operands_lower_info; + std::unordered_map<model::operand::Index, std::unique_ptr<operand::LowerInfo>> + operands_lower_info; - _operands.iterate([&](const operand::Index &index, const operand::Object &object) { + _model->operands.iterate([&](const model::operand::Index &index, + const model::operand::Object &object) { operands_lower_info[index] = - nnfw::make_unique<operand::LowerInfo>(operand::asShape4D(object.shape())); + nnfw::cpp14::make_unique<operand::LowerInfo>(graph::operand::asShape4D(object.shape())); }); - auto _backend_resolver = codegen::BackendResolver(_operands); + _backend_resolver = nnfw::cpp14::make_unique<compiler::BackendResolver>(_model->operands); + + _model->operations.iterate( + [&](const model::operation::Index &index, model::operation::Node &node) { + auto backend = _backend_resolver->getBackend(typeid(node)); + + // Operation LowerInfo + setLowerInfo(index, nnfw::cpp14::make_unique<graph::operation::LowerInfo>(backend)); - _operations.iterate([&](const operation::Index &, operation::Node &node) { - auto backend = _backend_resolver.getBackend(typeid(node)); + // LowerInfo for in/output operands + for (auto operand : node.getInputs()) + { + auto &&lower_info = operands_lower_info.at(operand); + lower_info->addUseBackend(backend); + } + for (auto operand : node.getOutputs()) + { + auto &&lower_info = operands_lower_info.at(operand); + lower_info->addDefBackend(backend); + } + }); + + // Add def backend to model input/output operand as default backend + for (auto index : getInputs()) + { + auto &&lower_info = operands_lower_info.at(index); + lower_info->addDefBackend(_backend_resolver->getDefaultBackend()); + } - // Operation LowerInfo - node.lower_info(nnfw::make_unique<operation::LowerInfo>(backend)); + for (auto index : getOutputs()) + { + auto &&lower_info = operands_lower_info.at(index); + lower_info->addUseBackend(_backend_resolver->getDefaultBackend()); + } - // LowerInfo for in/output operands + // Add DefBackend constants same as UseBackend + // NOTE This assumes a constant operand is used by only one operation + _model->operations.iterate([&](const model::operation::Index &, model::operation::Node &node) { + // LowerInfo for input operands for (auto operand : node.getInputs()) { auto &&lower_info = operands_lower_info.at(operand); - lower_info->addUseLayout(backend.config()->getOperandLayout()); - } - for (auto operand : node.getOutputs()) - { - auto &&lower_info = operands_lower_info.at(operand); - lower_info->addDefLayout(backend.config()->getOperandLayout()); + if (lower_info->def_backends().empty()) + { + lower_info->addDefBackend(lower_info->use_backends().getOnlyElement()); + } } }); // Set LowerInfo for each operand from the operand::LowerInfo holder - _operands.iterate([&](const operand::Index &index, operand::Object &object) { + _model->operands.iterate([&](const model::operand::Index &index, + model::operand::Object &object) { object.lower_info(std::move(operands_lower_info[index])); // Dump operand LowerInfo + // TODO Extract this dumping procedure to be reusable + if (!object.lower_info()->def_backends().empty() || + !object.lower_info()->use_backends().empty()) { - auto layouts_to_string = [](const operand::LayoutSet &layouts) { + auto backends_to_string = [](const operand::BackendSet &backends) { std::string str; - for (auto layout : layouts) + for (auto backend : backends) { - const char *name = ""; - if (layout == operand::Layout::NHWC) - name = "NHWC"; - if (layout == operand::Layout::NCHW) - name = "NCHW"; - str += name; + str += backend->config()->id(); + str += " "; + } + return "{ " + str + "}"; + }; + + auto operation_index_to_string = [](const model::operation::IndexList &operations) { + std::string str; + for (auto op : operations.list()) + { + str += std::to_string(op.value()); str += " "; } return "{ " + str + "}"; }; const auto &lower_info = object.lower_info(); - const auto &shape = lower_info->shape(); - std::string def_layouts = layouts_to_string(lower_info->def_layouts()); - std::string use_layouts = layouts_to_string(lower_info->use_layouts()); + const auto &shape = object.shape(); + const auto &lower_shape = lower_info->shape(); + std::string def_ops = operation_index_to_string(object.getDef()); + std::string use_ops = operation_index_to_string(object.getUses()); + std::string def_layouts = backends_to_string(lower_info->def_backends()); + std::string use_layouts = backends_to_string(lower_info->use_backends()); VERBOSE(Lower) << "* Operand #" << index.value() << " LowerInfo" << std::endl; - VERBOSE(Lower) << " - 4D Shape (NHWC) : { " << shape.n() << " " << shape.h() << " " - << shape.w() << " " << shape.c() << " " + VERBOSE(Lower) << " - Shape : { " << shape.dim(0) << " " + << (shape.rank() > 1 ? shape.dim(1) : 0) << " " + << (shape.rank() > 2 ? shape.dim(2) : 0) << " " + << (shape.rank() > 3 ? shape.dim(3) : 0) << " " << "}" << std::endl; - VERBOSE(Lower) << " - Def Layout : " << def_layouts << std::endl; - VERBOSE(Lower) << " - Use Layout : " << use_layouts << std::endl; + VERBOSE(Lower) << " - Def Operations : " << def_ops << std::endl; + VERBOSE(Lower) << " - Use Operations : " << use_ops << std::endl; + VERBOSE(Lower) << " - Lower Info" << std::endl; + VERBOSE(Lower) << " - 4D Shape (NHWC) : { " << lower_shape.n() << " " << lower_shape.h() + << " " << lower_shape.w() << " " << lower_shape.c() << " " + << "}" << std::endl; + VERBOSE(Lower) << " - Def Backends : " << def_layouts << std::endl; + VERBOSE(Lower) << " - Use Backends : " << use_layouts << std::endl; } }); } - // Graph verifications for the LOWERED phase + // Run PermutationInsertionPass { - verifier::DAGChecker dag_checker; - dag_checker.verify(*this); + pass::PermutationInsertionPass pi_pass(*this); + pi_pass.run(); + pass::PermutationEliminationPass pe_pass(*this); + pe_pass.run(); } - _phase = Phase::LOWERED; + // Graph verifications for the LOWERED phase + { + assert(verifier::DAGChecker().verify(*this)); + assert(verifier::EdgeConsistencyChecker().verify(*this)); + } } std::unique_ptr<linear::Linear> Graph::linearize(void) { - assert(_phase == Phase::LOWERED); + assert(_phase == Phase::MODEL); - auto linear = nnfw::make_unique<linear::Linear>(*this); + auto linear = nnfw::cpp14::make_unique<linear::Linear>(*this); // TODO Move the operations and operands to linear object - - _phase = Phase::LINEARIZED; - return std::move(linear); } void Graph::initializeUseDef() { - operations().iterate([&](const operation::Index &index, const operation::Node &node) -> void { - auto outputs = node.getOutputs(); - for (auto output : outputs) - { - operands().at(output).appendDef(index); - } + operations().iterate( + [&](const model::operation::Index &index, const model::operation::Node &node) -> void { + auto outputs = node.getOutputs(); + for (auto output : outputs) + { + operands().at(output).appendDef(index); + } + + auto inputs = node.getInputs(); + for (auto input : inputs) + { + operands().at(input).appendUse(index); + } + }); +} - auto inputs = node.getInputs(); - for (auto input : inputs) - { - operands().at(input).appendUse(index); - } - }); +const operation::LowerInfo *Graph::getLowerInfo(const model::operation::Index &index) const +{ + auto itr = _operation_lower_info.find(index); + if (itr == _operation_lower_info.end()) + return nullptr; + return itr->second.get(); +} + +void Graph::setLowerInfo(const model::operation::Index &index, + std::unique_ptr<operation::LowerInfo> &&lower_info) +{ + _operation_lower_info.insert(std::make_pair(index, std::move(lower_info))); } } // namespace graph @@ -273,7 +287,8 @@ template class Graph::PostDfsIterator<false>; template <bool is_const> void Graph::DefaultIterator<is_const>::iterate(GraphRef graph, const IterFn &fn) const { - graph._operations.iterate([&](const operation::Index &, NodeRef node) -> void { fn(node); }); + graph.operations().iterate( + [&](const model::operation::Index &index, NodeRef node) -> void { fn(index, node); }); } // @@ -285,30 +300,34 @@ void Graph::PostDfsIterator<is_const>::iterate(GraphRef graph, const IterFn &fn) { assert(!graph.isBuildingPhase()); // Restrict iteration condition - std::vector<bool> visited(graph._operations.size(), false); + std::unordered_map<model::operation::Index, bool> visited; + graph.operations().iterate( + [&](const model::operation::Index &index, NodeRef) { visited[index] = false; }); - std::function<void(const operation::Index &, NodeRef)> dfs_recursive = - [&](const operation::Index &index, NodeRef node) -> void { - if (visited[index.asInt()]) + std::function<void(const model::operation::Index &, NodeRef)> dfs_recursive = + [&](const model::operation::Index &index, NodeRef node) -> void { + if (visited[index]) return; - visited[index.asInt()] = true; + visited[index] = true; for (auto output : node.getOutputs()) { - const auto &operand = graph._operands.at(output); + const auto &operand = graph.operands().at(output); for (const auto &use : operand.getUses().list()) { - dfs_recursive(use, graph._operations.at(use)); + dfs_recursive(use, graph.operations().at(use)); } } - fn(node); + fn(index, node); }; - graph._operations.iterate(dfs_recursive); + graph.operations().iterate(dfs_recursive); // All of the operations(nodes) must have been visited. - assert(std::all_of(visited.begin(), visited.end(), [](bool v) { return v; })); + assert(std::all_of( + visited.begin(), visited.end(), + [](const std::pair<const model::operation::Index, bool> &v) { return v.second; })); } } // namespace graph diff --git a/runtimes/neurun/src/graph/Graph.h b/runtimes/neurun/src/graph/Graph.h index dd1489a93..afcfdce12 100644 --- a/runtimes/neurun/src/graph/Graph.h +++ b/runtimes/neurun/src/graph/Graph.h @@ -19,10 +19,8 @@ #include <functional> -#include "graph/operation/Node.h" -#include "graph/operation/Set.h" -#include "graph/operand/IndexSet.h" -#include "graph/operand/Set.h" +#include "model/operation/Node.h" +#include "graph/Model.h" namespace neurun { @@ -34,6 +32,14 @@ class Linear; namespace neurun { +namespace compiler +{ +class BackendResolver; +} // namespace compiler +} // namespace neurun + +namespace neurun +{ namespace graph { @@ -43,9 +49,7 @@ private: enum class Phase { BUILDING, - MODEL, - LOWERED, - LINEARIZED // Everything is moved to Linear object so this Graph object is no longer effective + MODEL }; public: @@ -53,9 +57,10 @@ public: { public: using GraphRef = typename std::conditional<is_const, const Graph &, Graph &>::type; - using NodeRef = - typename std::conditional<is_const, const operation::Node &, operation::Node &>::type; - using IterFn = std::function<void(NodeRef)>; + using IndexRef = const model::operation::Index &; + using NodeRef = typename std::conditional<is_const, const model::operation::Node &, + model::operation::Node &>::type; + using IterFn = std::function<void(IndexRef, NodeRef)>; public: virtual ~Iterator() = default; @@ -66,6 +71,7 @@ public: { public: using GraphRef = typename Iterator<is_const>::GraphRef; + using IndexRef = typename Iterator<is_const>::IndexRef; using NodeRef = typename Iterator<is_const>::NodeRef; using IterFn = typename Iterator<is_const>::IterFn; @@ -78,6 +84,7 @@ public: { public: using GraphRef = typename Iterator<is_const>::GraphRef; + using IndexRef = typename Iterator<is_const>::IndexRef; using NodeRef = typename Iterator<is_const>::NodeRef; using IterFn = typename Iterator<is_const>::IterFn; @@ -87,20 +94,21 @@ public: using PostDfsConstIterator = PostDfsIterator<true>; public: - Graph(void) = default; + Graph(void); + ~Graph(void); // Graph Building public: - operand::Index addOperand(const operand::Shape &shape, const operand::TypeInfo &type); - operation::Index addOperation(std::unique_ptr<operation::Node> &&node); - operation::Index insertOperation(const operand::Index &prev_operand_index, - const operation::Index &next_operation_index, - std::unique_ptr<operation::Node> &&node); - void setOperandValue(const operand::Index &ind, std::unique_ptr<operand::Data> &&data); - void addInput(const operand::Index &ind); - void addOutput(const operand::Index &ind); + model::operand::Index addOperand(const model::operand::Shape &shape, + const model::operand::TypeInfo &type); + model::operation::Index addOperation(std::unique_ptr<model::operation::Node> &&node); + void setOperandValue(const model::operand::Index &ind, + std::unique_ptr<model::operand::Data> &&data); + void addInput(const model::operand::Index &ind); + void addOutput(const model::operand::Index &ind); void finishBuilding(void); void lower(void); + void removeOperand(const model::operand::Index &ind) { _model->operands.remove(ind); } std::unique_ptr<linear::Linear> linearize(void); bool isBuildingPhase(void) const { return _phase == Phase::BUILDING; } @@ -109,18 +117,33 @@ private: // Accessors public: - const operand::IndexSet &getInputs() const { return _inputs; } - const operand::IndexSet &getOutputs() const { return _outputs; } - const operand::Set &operands() const { return _operands; } - operand::Set &operands() { return _operands; } // TODO Remove this non-const accessor - const operation::Set &operations() const { return _operations; } + const model::operand::IndexSet &getInputs() const { return _model->inputs; } + model::operand::IndexSet &getInputs() { return _model->inputs; } + const model::operand::IndexSet &getOutputs() const { return _model->outputs; } + model::operand::IndexSet &getOutputs() { return _model->outputs; } + const model::operand::Set &operands() const { return _model->operands; } + model::operand::Set &operands() + { + return _model->operands; + } // TODO Remove this non-const accessor + const model::operation::Set &operations() const { return _model->operations; } + model::operation::Set &operations() { return _model->operations; } + const compiler::BackendResolver *backend_resolver() const { return _backend_resolver.get(); } private: Phase _phase{Phase::BUILDING}; - operation::Set _operations; - operand::Set _operands; - operand::IndexSet _inputs; - operand::IndexSet _outputs; + std::unique_ptr<Model> _model{new Model}; + + // For LOWERED phase +public: + const operation::LowerInfo *getLowerInfo(const model::operation::Index &index) const; + void setLowerInfo(const model::operation::Index &index, + std::unique_ptr<operation::LowerInfo> &&lower_info); + +private: + std::unique_ptr<compiler::BackendResolver> _backend_resolver; + std::unordered_map<model::operation::Index, std::unique_ptr<operation::LowerInfo>> + _operation_lower_info; }; } // namespace graph diff --git a/runtimes/neurun/src/graph/Index.h b/runtimes/neurun/src/graph/Index.h index 864aaffd0..3263d12ad 100644 --- a/runtimes/neurun/src/graph/Index.h +++ b/runtimes/neurun/src/graph/Index.h @@ -18,6 +18,7 @@ #define __NEURUN_GRAPH_INDEX_H__ #include <functional> +#include <limits> #include <stdint.h> namespace neurun @@ -27,7 +28,11 @@ namespace graph template <typename T, typename DummyTag> class Index { +private: + static const T UNDEFINED = std::numeric_limits<T>::max(); + public: + explicit Index(void) : _index{UNDEFINED} {} explicit Index(T o) : _index{o} {} explicit Index(int32_t o) : _index{static_cast<T>(o)} {} // For legacy code compatibility Index(const Index &o) : _index{o._index} {} diff --git a/runtimes/neurun/src/graph/Model.h b/runtimes/neurun/src/graph/Model.h new file mode 100644 index 000000000..20bb713af --- /dev/null +++ b/runtimes/neurun/src/graph/Model.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2018 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 __NEURUN_GRAPH_MODEL_H__ +#define __NEURUN_GRAPH_MODEL_H__ + +#include "model/operation/Set.h" +#include "model/operand/IndexSet.h" +#include "model/operand/Set.h" + +namespace neurun +{ +namespace graph +{ + +struct Model +{ + model::operation::Set operations; + model::operand::Set operands; + model::operand::IndexSet inputs; + model::operand::IndexSet outputs; +}; + +} // namespace graph +} // namespace neurun + +#endif // __NEURUN_GRAPH_MODEL_H__ diff --git a/runtimes/neurun/src/graph/dumper/Dumper.cc b/runtimes/neurun/src/graph/dumper/Dumper.cc index 3788317ce..efffc5849 100644 --- a/runtimes/neurun/src/graph/dumper/Dumper.cc +++ b/runtimes/neurun/src/graph/dumper/Dumper.cc @@ -18,7 +18,7 @@ #include <string> -#include "logging.h" +#include "util/logging.h" namespace neurun { @@ -27,9 +27,9 @@ namespace graph namespace dumper { -using namespace neurun::graph::operation; +using namespace neurun::model::operation; -void Dumper::visit(const Conv2D::Implicit::Node &node) +void Dumper::visit(const Conv2DNode &node) { VERBOSE(LIR) << "* Conv2D(Implicit)" << std::endl; VERBOSE(LIR) << " - Inputs : IFM(" << node.getInputs().at(0).value() << ") Kernel(" @@ -38,21 +38,21 @@ void Dumper::visit(const Conv2D::Implicit::Node &node) VERBOSE(LIR) << " - Output : OFM(" << node.getOutputs().at(0).value() << ")" << std::endl; } -void Dumper::visit(const MaxPool2D::Implicit::Node &node) +void Dumper::visit(const MaxPool2DNode &node) { VERBOSE(LIR) << "* MaxPool2D(Implicit)" << std::endl; VERBOSE(LIR) << " - Inputs : IFM(" << node.getInputs().at(0).value() << ")" << std::endl; VERBOSE(LIR) << " - Output : OFM(" << node.getOutputs().at(0).value() << ")" << std::endl; } -void Dumper::visit(const AvgPool2D::Implicit::Node &node) +void Dumper::visit(const AvgPool2DNode &node) { VERBOSE(LIR) << "* AvgPool2D(Implicit)" << std::endl; VERBOSE(LIR) << " - Inputs : IFM(" << node.getInputs().at(0).value() << ")" << std::endl; VERBOSE(LIR) << " - Output : OFM(" << node.getOutputs().at(0).value() << ")" << std::endl; } -void Dumper::visit(const Concat::Node &node) +void Dumper::visit(const ConcatNode &node) { VERBOSE(LIR) << "* Concat" << std::endl; std::string inputs; @@ -64,7 +64,7 @@ void Dumper::visit(const Concat::Node &node) VERBOSE(LIR) << " - Output : OFM(" << node.getOutputs().at(0).value() << ")" << std::endl; } -void Dumper::visit(const FullyConnected::Node &node) +void Dumper::visit(const FullyConnectedNode &node) { VERBOSE(LIR) << "* FullyConnected" << std::endl; VERBOSE(LIR) << " - Inputs : IFM(" << node.getInputs().at(0).value() << ") Weight(" @@ -73,7 +73,7 @@ void Dumper::visit(const FullyConnected::Node &node) VERBOSE(LIR) << " - Output : OFM(" << node.getOutputs().at(0).value() << ")" << std::endl; } -void Dumper::visit(const Reshape::Node &node) +void Dumper::visit(const ReshapeNode &node) { VERBOSE(LIR) << "* Reshape" << std::endl; // TODO The shape index should be "node.getInputs().at(1).value()" but not valid for now @@ -83,36 +83,28 @@ void Dumper::visit(const Reshape::Node &node) VERBOSE(LIR) << " - Output : OFM(" << node.getOutputs().at(0).value() << ")" << std::endl; } -void Dumper::visit(const Softmax::Node &node) +void Dumper::visit(const SoftmaxNode &node) { VERBOSE(LIR) << "* Softmax" << std::endl; VERBOSE(LIR) << " - Inputs : IFM(" << node.getInputs().at(0).value() << ")" << std::endl; VERBOSE(LIR) << " - Output : OFM(" << node.getOutputs().at(0).value() << ")" << std::endl; } -void Dumper::visit(const NOP::Node &node) -{ - VERBOSE(LIR) << "* NOP" << std::endl; - std::string inputs, outputs; - for (auto i : node.getInputs()) - { - inputs += std::to_string(i.value()) + ","; - } - VERBOSE(LIR) << " - Inputs : IFM(" << inputs << ")" << std::endl; - for (auto i : node.getOutputs()) - { - outputs += std::to_string(i.value()) + ","; - } - VERBOSE(LIR) << " - Outputs : OFM(" << outputs << ")" << std::endl; -} - -void Dumper::visit(const Permute::Node &node) +void Dumper::visit(const PermuteNode &node) { VERBOSE(LIR) << "* Permute" << std::endl; VERBOSE(LIR) << " - Inputs : IFM(" << node.getInputs().at(0).value() << ")" << std::endl; VERBOSE(LIR) << " - Output : OFM(" << node.getOutputs().at(0).value() << ")" << std::endl; } +void Dumper::visit(const AddNode &node) +{ + VERBOSE(LIR) << "* Add" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(0).value() << ", " + << node.getInputs().at(1).value() << ")" << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + } // namespace dumper } // namespace graph } // namespace neurun diff --git a/runtimes/neurun/src/graph/dumper/Dumper.h b/runtimes/neurun/src/graph/dumper/Dumper.h index dee490cbd..8c079a11d 100644 --- a/runtimes/neurun/src/graph/dumper/Dumper.h +++ b/runtimes/neurun/src/graph/dumper/Dumper.h @@ -17,7 +17,7 @@ #ifndef __NEURUN_GRAPH_DUMPER_H__ #define __NEURUN_GRAPH_DUMPER_H__ -#include "graph/operation/NodeVisitor.h" +#include "model/operation/NodeVisitor.h" namespace neurun { @@ -26,21 +26,21 @@ namespace graph namespace dumper { -class Dumper : public graph::operation::NodeVisitor +class Dumper : public model::operation::NodeVisitor { public: Dumper() = default; public: - void visit(const graph::operation::Conv2D::Implicit::Node &node) override; - void visit(const graph::operation::MaxPool2D::Implicit::Node &node) override; - void visit(const graph::operation::AvgPool2D::Implicit::Node &node) override; - void visit(const graph::operation::Concat::Node &node) override; - void visit(const graph::operation::FullyConnected::Node &node) override; - void visit(const graph::operation::Reshape::Node &node) override; - void visit(const graph::operation::Softmax::Node &node) override; - void visit(const graph::operation::NOP::Node &node) override; - void visit(const graph::operation::Permute::Node &node) override; + void visit(const model::operation::Conv2DNode &node) override; + void visit(const model::operation::MaxPool2DNode &node) override; + void visit(const model::operation::AvgPool2DNode &node) override; + void visit(const model::operation::ConcatNode &node) override; + void visit(const model::operation::FullyConnectedNode &node) override; + void visit(const model::operation::ReshapeNode &node) override; + void visit(const model::operation::SoftmaxNode &node) override; + void visit(const model::operation::PermuteNode &node) override; + void visit(const model::operation::AddNode &node) override; }; } // namespace dumper diff --git a/runtimes/neurun/src/graph/operand/BackendSet.cc b/runtimes/neurun/src/graph/operand/BackendSet.cc new file mode 100644 index 000000000..9a284d722 --- /dev/null +++ b/runtimes/neurun/src/graph/operand/BackendSet.cc @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2018 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 "BackendSet.h" + +#include <cassert> + +namespace neurun +{ +namespace graph +{ +namespace operand +{ + +BackendSet::BackendSet(std::initializer_list<const backend::Backend *> backends) +{ + for (auto backend : backends) + { + _set.insert(backend); + } +} + +const backend::Backend *BackendSet::getOnlyElement() const +{ + assert(_set.size() == 1u); + return *_set.begin(); +} + +BackendSet BackendSet::operator|(const BackendSet &other) const +{ + auto ret = *this; + for (auto backend : other) + { + ret.add(backend); + } + return ret; +} + +BackendSet BackendSet::operator&(const BackendSet &other) const +{ + BackendSet ret; + for (auto backend : other) + { + if (contains(backend)) + { + ret.add(backend); + } + } + return ret; +} + +BackendSet BackendSet::operator-(const BackendSet &other) const +{ + auto ret = *this; + for (auto backend : other) + { + ret.remove(backend); + } + return ret; +} + +} // namespace operand +} // namespace graph +} // namespace neurun diff --git a/runtimes/neurun/src/graph/operand/BackendSet.h b/runtimes/neurun/src/graph/operand/BackendSet.h new file mode 100644 index 000000000..8b457a084 --- /dev/null +++ b/runtimes/neurun/src/graph/operand/BackendSet.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2018 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 __NEURUN_GRAPH_OPERAND_BACKEND_SET_H__ +#define __NEURUN_GRAPH_OPERAND_BACKEND_SET_H__ + +#include <initializer_list> +#include <unordered_set> + +namespace neurun +{ +namespace backend +{ +class Backend; +} // namespace backend +} // namespace neurun + +namespace neurun +{ +namespace graph +{ +namespace operand +{ + +class BackendSet +{ +public: + BackendSet() = default; + BackendSet(std::initializer_list<const backend::Backend *> backends); + +public: + void add(const backend::Backend *backend) { _set.insert(backend); } + void remove(const backend::Backend *backend) { _set.erase(backend); } + uint32_t size() const { return static_cast<uint32_t>(_set.size()); } + bool empty() const { return _set.empty(); } + bool contains(const backend::Backend *backend) const { return _set.find(backend) != _set.end(); } + const backend::Backend *getOnlyElement() const; + +public: + BackendSet operator|(const BackendSet &other) const; // Union + BackendSet operator&(const BackendSet &other) const; // Intersect + BackendSet operator-(const BackendSet &other) const; // Minus + +public: + std::unordered_set<const backend::Backend *>::const_iterator begin() const + { + return _set.begin(); + } + std::unordered_set<const backend::Backend *>::const_iterator end() const { return _set.end(); } + +private: + std::unordered_set<const backend::Backend *> _set; +}; + +} // namespace operand +} // namespace graph +} // namespace neurun + +#endif // __NEURUN_GRAPH_OPERAND_BACKEND_SET_H__ diff --git a/runtimes/neurun/src/graph/operand/LowerInfo.h b/runtimes/neurun/src/graph/operand/LowerInfo.h index d91c29fb7..7900e54d9 100644 --- a/runtimes/neurun/src/graph/operand/LowerInfo.h +++ b/runtimes/neurun/src/graph/operand/LowerInfo.h @@ -19,7 +19,7 @@ #include <stdint.h> -#include "LayoutSet.h" +#include "BackendSet.h" namespace neurun { @@ -60,17 +60,19 @@ public: public: const Shape4D &shape(void) const { return _shape; } - const LayoutSet &def_layouts(void) const { return _def_layouts; } - const LayoutSet &use_layouts(void) const { return _use_layouts; } + const BackendSet &def_backends(void) const { return _def_backends; } + const BackendSet &use_backends(void) const { return _use_backends; } public: - void addDefLayout(const Layout &layout) { _def_layouts.add(layout); } - void addUseLayout(const Layout &layout) { _use_layouts.add(layout); } + void addDefBackend(const backend::Backend *backend) { _def_backends.add(backend); } + void addUseBackend(const backend::Backend *backend) { _use_backends.add(backend); } + void removeDefBackend(const backend::Backend *backend) { _def_backends.remove(backend); } + void removeUseBackend(const backend::Backend *backend) { _use_backends.remove(backend); } private: Shape4D _shape; - LayoutSet _def_layouts; - LayoutSet _use_layouts; + BackendSet _def_backends; + BackendSet _use_backends; }; } // namespace operand diff --git a/runtimes/neurun/src/graph/operand/ParentInfo.h b/runtimes/neurun/src/graph/operand/ParentInfo.h new file mode 100644 index 000000000..5e6f56237 --- /dev/null +++ b/runtimes/neurun/src/graph/operand/ParentInfo.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2018 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 ParentInfo.h + * @brief This file contains ParentInfo class and internal Coordinate4D class + * to represent subsumption between operand + */ + +#ifndef __NEURUN_GRAPH_OPERAND_PARENT_INFO_H__ +#define __NEURUN_GRAPH_OPERAND_PARENT_INFO_H__ + +#include <stdint.h> + +#include "model/operand/Index.h" +#include "util/feature/Coordinate4D.h" + +namespace neurun +{ +namespace graph +{ +namespace operand +{ + +using neurun::util::feature::Coordinate4D; + +/** + * @brief Class to represent parent operand in child operand + */ +class ParentInfo +{ +public: + /** + * @brief Construct a new ParentInfo object + * @param[in] parent Index of parent operand + * @param[in] coordinate Offset of child operand in parent operand + * @return + */ + ParentInfo(const model::operand::Index parent, const Coordinate4D &coordinate) + : _parent{parent}, _coordinate{coordinate} + { + // DO NOTHING + } + +public: + /** + * @brief Return parent index + * @return Parent index + */ + model::operand::Index parent(void) const { return _parent; } + /** + * @brief Retern offset in parent + * @return Offset + */ + Coordinate4D offset(void) const { return _coordinate; } + +private: + model::operand::Index _parent; + Coordinate4D _coordinate; +}; + +} // namespace operand +} // namespace graph +} // namespace neurun + +#endif // __NEURUN_GRAPH_OPERAND_PARENT_INFO_H__ diff --git a/runtimes/neurun/src/graph/operand/Shape4DConvert.h b/runtimes/neurun/src/graph/operand/Shape4DConvert.h index b840d19b8..73cf0903a 100644 --- a/runtimes/neurun/src/graph/operand/Shape4DConvert.h +++ b/runtimes/neurun/src/graph/operand/Shape4DConvert.h @@ -26,7 +26,7 @@ namespace graph namespace operand { -inline LowerInfo::Shape4D asShape4D(const Shape &shape) +inline LowerInfo::Shape4D asShape4D(const model::operand::Shape &shape) { switch (shape.rank()) { @@ -34,16 +34,16 @@ inline LowerInfo::Shape4D asShape4D(const Shape &shape) return LowerInfo::Shape4D(1, 1, 1, 1); case 1u: - return LowerInfo::Shape4D(1, 1, 1, shape.dim(0)); + return LowerInfo::Shape4D(shape.dim(0), 1, 1, 1); case 2u: - return LowerInfo::Shape4D(1, 1, shape.dim(1), shape.dim(0)); + return LowerInfo::Shape4D(shape.dim(0), shape.dim(1), 1, 1); case 3u: - return LowerInfo::Shape4D(1, shape.dim(2), shape.dim(1), shape.dim(0)); + return LowerInfo::Shape4D(shape.dim(0), shape.dim(1), shape.dim(2), 1); case 4u: - return LowerInfo::Shape4D(shape.dim(3), shape.dim(2), shape.dim(1), shape.dim(0)); + return LowerInfo::Shape4D(shape.dim(0), shape.dim(1), shape.dim(2), shape.dim(3)); default: throw "Unsupported rank > 4"; diff --git a/runtimes/neurun/src/graph/operation/AvgPool2D.h b/runtimes/neurun/src/graph/operation/AvgPool2D.h deleted file mode 100644 index a856b9cd4..000000000 --- a/runtimes/neurun/src/graph/operation/AvgPool2D.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2018 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 __NEURUN_GRAPH_OPERATION_AVGPOOL2D_H__ -#define __NEURUN_GRAPH_OPERATION_AVGPOOL2D_H__ - -#include <memory> - -#include "graph/operation/Node.h" - -namespace neurun -{ -namespace graph -{ -namespace operation -{ -namespace AvgPool2D -{ -namespace Implicit -{ - -struct Param -{ - int32_t kw_index; - int32_t kh_index; - - int32_t hstride_index; - int32_t vstride_index; - - int32_t padding_index; - int32_t activation_index; -}; - -class Node : public graph::operation::Node -{ -public: - Node(const graph::operation::Node::InitParam &init_param); - -public: - virtual void accept(NodeVisitor &&) const override; - -public: - virtual void setInputs(const operand::IndexSet &indexes) override; - virtual void setOutputs(const operand::IndexSet &indexes) override; - -public: - const Param ¶m() const { return _param; } - -private: - Param _param; -}; - -} // namespace Implicit -} // namespace AvgPool2D -} // namespace operation -} // namespace graph -} // namespace neurun - -#endif // __NEURUN_GRAPH_OPERATION_AVGPOOL2D_H__ diff --git a/runtimes/neurun/src/graph/operation/LowerInfo.cc b/runtimes/neurun/src/graph/operation/LowerInfo.cc index 2998b1922..7862fd0c9 100644 --- a/runtimes/neurun/src/graph/operation/LowerInfo.cc +++ b/runtimes/neurun/src/graph/operation/LowerInfo.cc @@ -23,7 +23,7 @@ namespace graph namespace operation { -LowerInfo::LowerInfo(const backend::Backend &backend) : _backend(backend) +LowerInfo::LowerInfo(const backend::Backend *backend) : _backend(backend) { // DO NOTHING } diff --git a/runtimes/neurun/src/graph/operation/LowerInfo.h b/runtimes/neurun/src/graph/operation/LowerInfo.h index f3fbbf178..e920b0eb9 100644 --- a/runtimes/neurun/src/graph/operation/LowerInfo.h +++ b/runtimes/neurun/src/graph/operation/LowerInfo.h @@ -31,11 +31,11 @@ namespace operation class LowerInfo { public: - LowerInfo(const backend::Backend &backend); - const backend::Backend &backend() const { return _backend; } + LowerInfo(const backend::Backend *backend); + const backend::Backend *backend() const { return _backend; } private: - backend::Backend _backend; + const backend::Backend *_backend; }; } // namespace operation diff --git a/runtimes/neurun/src/graph/operation/NodeVisitor.h b/runtimes/neurun/src/graph/operation/NodeVisitor.h deleted file mode 100644 index 28d19b0af..000000000 --- a/runtimes/neurun/src/graph/operation/NodeVisitor.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2018 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 __NEURUN_GRAPH_OPERATION_NODE_VISITOR_H__ -#define __NEURUN_GRAPH_OPERATION_NODE_VISITOR_H__ - -#include "Conv2D.h" -#include "MaxPool2D.h" -#include "AvgPool2D.h" -#include "Concat.h" -#include "Reshape.h" -#include "FullyConnected.h" -#include "Softmax.h" -#include "NOP.h" -#include "Permute.h" - -namespace neurun -{ -namespace graph -{ -namespace operation -{ - -struct NodeVisitor -{ - virtual ~NodeVisitor() = default; - - virtual void visit(const Conv2D::Implicit::Node &) = 0; - virtual void visit(const MaxPool2D::Implicit::Node &) = 0; - virtual void visit(const AvgPool2D::Implicit::Node &) = 0; - virtual void visit(const Concat::Node &) = 0; - virtual void visit(const Reshape::Node &) = 0; - virtual void visit(const FullyConnected::Node &) = 0; - virtual void visit(const Softmax::Node &) = 0; - virtual void visit(const NOP::Node &) = 0; - virtual void visit(const Permute::Node &) = 0; -}; - -} // namespace operation -} // namespace graph -} // namespace neurun - -#endif // __NEURUN_GRAPH_OPERATION_NODE_VISITOR_H__ diff --git a/runtimes/neurun/src/graph/operation/Permute.cc b/runtimes/neurun/src/graph/operation/Permute.cc deleted file mode 100644 index 2688e5e5f..000000000 --- a/runtimes/neurun/src/graph/operation/Permute.cc +++ /dev/null @@ -1,41 +0,0 @@ -#include "Permute.h" - -#include <cassert> - -#include "NodeVisitor.h" - -namespace neurun -{ -namespace graph -{ -namespace operation -{ -namespace Permute -{ - -void Node::accept(NodeVisitor &&v) const { v.visit(*this); } - -Node::Node(const operand::Index &input, const operand::Index &output) -{ - setInputs({input}); - setOutputs({output}); -} - -void Node::setInputs(const operand::IndexSet &indexes) -{ - assert(indexes.size() == 1); - - graph::operation::Node::setInputs(indexes); -} - -void Node::setOutputs(const operand::IndexSet &indexes) -{ - assert(indexes.size() == 1); - - graph::operation::Node::setOutputs(indexes); -} - -} // namespace Permute -} // namespace operation -} // namespace graph -} // namespace neurun diff --git a/runtimes/neurun/src/graph/operation/Permute.h b/runtimes/neurun/src/graph/operation/Permute.h deleted file mode 100644 index 540f869b1..000000000 --- a/runtimes/neurun/src/graph/operation/Permute.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef __NEURUN_GRAPH_OPERATION_PERMUTE_PERMUTE_H__ -#define __NEURUN_GRAPH_OPERATION_PERMUTE_PERMUTE_H__ - -#include "graph/operation/Node.h" - -namespace neurun -{ -namespace graph -{ -namespace operation -{ -namespace Permute -{ - -class Node : public graph::operation::Node -{ -public: - virtual void accept(NodeVisitor &&) const override; - -public: - Node(const operand::Index &input, const operand::Index &output); - -public: - virtual void setInputs(const operand::IndexSet &indexes) override; - virtual void setOutputs(const operand::IndexSet &indexes) override; -}; - -} // namespace Permute -} // namespace operation -} // namespace graph -} // namespace neurun - -#endif // __NEURUN_GRAPH_OPERATION_PERMUTE_PERMUTE_H__ diff --git a/runtimes/neurun/src/graph/operation/NOP.cc b/runtimes/neurun/src/graph/pass/OperandPass.cc index 18c3246ce..3c24d3830 100644 --- a/runtimes/neurun/src/graph/operation/NOP.cc +++ b/runtimes/neurun/src/graph/pass/OperandPass.cc @@ -14,23 +14,23 @@ * limitations under the License. */ -#include "NOP.h" +#include "OperandPass.h" -#include "NodeVisitor.h" -#include "LowerInfo.h" +#include "graph/Graph.h" namespace neurun { namespace graph { -namespace operation -{ -namespace NOP +namespace pass { -void Node::accept(NodeVisitor &&v) const { v.visit(*this); } +void OperandPass::run() +{ + _graph.operands().iterate([&](const model::operand::Index &index, + model::operand::Object &object) { callback(index, object); }); +} -} // namespace NOP -} // namespace operation +} // namespace pass } // namespace graph } // namespace neurun diff --git a/runtimes/neurun/src/graph/pass/OperandPass.h b/runtimes/neurun/src/graph/pass/OperandPass.h new file mode 100644 index 000000000..b84391082 --- /dev/null +++ b/runtimes/neurun/src/graph/pass/OperandPass.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2018 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 __NEURUN_GRAPH_PASS_OPERAND_PASS_H__ +#define __NEURUN_GRAPH_PASS_OPERAND_PASS_H__ + +#include "Pass.h" +#include "model/operand/Index.h" + +namespace neurun +{ +namespace model +{ +namespace operand +{ +class Object; +} // namespace operand +} // namespace graph +} // namespace neurun + +namespace neurun +{ +namespace graph +{ +namespace pass +{ + +class OperandPass : public Pass +{ +public: + using Pass::Pass; + +public: + virtual std::string id() = 0; + virtual void run() override final; + virtual void callback(const model::operand::Index &i, model::operand::Object &o) = 0; +}; + +} // namespace pass +} // namespace graph +} // namespace neurun + +#endif // __NEURUN_GRAPH_PASS_OPERAND_PASS_H__ diff --git a/runtimes/neurun/src/graph/operation/Node.cc b/runtimes/neurun/src/graph/pass/OperationPass.cc index f472bc08c..e71f79188 100644 --- a/runtimes/neurun/src/graph/operation/Node.cc +++ b/runtimes/neurun/src/graph/pass/OperationPass.cc @@ -14,28 +14,23 @@ * limitations under the License. */ -#include "Node.h" +#include "OperationPass.h" -#include "LowerInfo.h" +#include "graph/Graph.h" namespace neurun { namespace graph { -namespace operation +namespace pass { -Node::Node() = default; - -Node::~Node() = default; - -void Node::lower_info(std::unique_ptr<LowerInfo> &&lower_info) +void OperationPass::run() { - _lower_info = std::move(lower_info); + _graph.operations().iterate([&](const model::operation::Index &index, + model::operation::Node &node) { callback(index, node); }); } -const LowerInfo *Node::lower_info() const { return _lower_info.get(); } - -} // namespace operation +} // namespace pass } // namespace graph } // namespace neurun diff --git a/runtimes/neurun/src/graph/pass/OperationPass.h b/runtimes/neurun/src/graph/pass/OperationPass.h new file mode 100644 index 000000000..e86f1aa57 --- /dev/null +++ b/runtimes/neurun/src/graph/pass/OperationPass.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2018 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 OperationPass.h + * @brief This file contains OperationPass class + */ + +#ifndef __NEURUN_GRAPH_PASS_OPERATION_PASS_H__ +#define __NEURUN_GRAPH_PASS_OPERATION_PASS_H__ + +#include "Pass.h" + +#include "model/operation/Index.h" +#include "model/operation/Node.h" + +namespace neurun +{ +namespace graph +{ +namespace pass +{ + +/** + * @brief Class to iterate over operations and calls callback() method + */ +class OperationPass : public Pass +{ +public: + using Pass::Pass; + +public: + /** + * @brief Returns string id for this pass. Same with class name. + * + * @return string id + */ + virtual std::string id() = 0; + + /** + * @brief Run the pass + */ + virtual void run() override final; + + /** + * @brief The function that will be executed for each operations + * + * @param i[in] Index of the operation node + * @param n[in] The operation node + */ + virtual void callback(const model::operation::Index &i, model::operation::Node &n) = 0; +}; + +} // namespace pass +} // namespace graph +} // namespace neurun + +#endif // __NEURUN_GRAPH_PASS_OPERATION_PASS_H__ diff --git a/runtimes/neurun/src/backend/cpu/MemoryAllocator.cc b/runtimes/neurun/src/graph/pass/Pass.cc index 13d2a7ffc..4c3436961 100644 --- a/runtimes/neurun/src/backend/cpu/MemoryAllocator.cc +++ b/runtimes/neurun/src/graph/pass/Pass.cc @@ -14,4 +14,15 @@ * limitations under the License. */ -//#include "internal/cpu/MemoryAllocator.h" +#include "Pass.h" + +namespace neurun +{ +namespace graph +{ +namespace pass +{ + +} // namespace pass +} // namespace graph +} // namespace neurun diff --git a/runtimes/neurun/src/graph/pass/Pass.h b/runtimes/neurun/src/graph/pass/Pass.h new file mode 100644 index 000000000..4200936d1 --- /dev/null +++ b/runtimes/neurun/src/graph/pass/Pass.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2018 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 __NEURUN_GRAPH_PASS_PASS_H__ +#define __NEURUN_GRAPH_PASS_PASS_H__ + +#include <string> + +namespace neurun +{ +namespace graph +{ +class Graph; +} // namespace graph +} // namespace neurun + +namespace neurun +{ +namespace graph +{ +namespace pass +{ + +class Pass +{ +public: + Pass(Graph &graph) : _graph{graph} {} + virtual ~Pass() = default; + +public: + virtual std::string id() = 0; + virtual void run() = 0; + +protected: + Graph &_graph; +}; + +} // namespace pass +} // namespace graph +} // namespace neurun + +#endif // __NEURUN_GRAPH_PASS_PASS_H__ diff --git a/runtimes/neurun/src/graph/pass/PermutationEliminationPass.cc b/runtimes/neurun/src/graph/pass/PermutationEliminationPass.cc new file mode 100644 index 000000000..848f6b574 --- /dev/null +++ b/runtimes/neurun/src/graph/pass/PermutationEliminationPass.cc @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2018 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 "PermutationEliminationPass.h" + +#include "model/operand/Object.h" +#include "graph/Graph.h" +#include "backend/interface/IConfig.h" +#include "util/logging.h" +#include "compiler/BackendResolver.h" + +namespace neurun +{ +namespace graph +{ +namespace pass +{ +void PermutationEliminationPass::callback(const model::operand::Index &inp_index, + model::operand::Object &object) +{ + if (_graph.getInputs().contains(inp_index)) + { + eliminateInput(inp_index, object); + } + else if (_graph.getOutputs().contains(inp_index)) + { + eliminateOutput(inp_index, object); + } +} + +void PermutationEliminationPass::eliminateInput(const model::operand::Index &inp_index, + model::operand::Object &object) +{ + auto &model_inputs = _graph.getInputs(); + + // get uses of the model's given input + auto uses = object.getUses(); + + // input must be used just by permutation + if (uses.size() != 1) + { + return; + } + + for (auto input_use : uses.list()) + { + auto &perm_operation = _graph.operations().at(input_use); + auto perm_inputs = perm_operation.getInputs(); + + auto perm_outputs = perm_operation.getOutputs(); + + if (!isPermuteLayerToEliminate(perm_inputs, perm_outputs, true)) + { + return; + } + + assert(perm_inputs.at(0) == inp_index); + + VERBOSE(PermutationEliminationPass::EliminateInput) << "remove NHWC_TO_NCHW permutation\n"; + + // set model's new input, which was output of permutation + model_inputs.replace(inp_index, perm_outputs.at(0)); + + // remove model's input, which is also input of permutation + _graph.removeOperand(inp_index); + + // remove permutation operation + _graph.operations().remove(input_use); + + VERBOSE(PermutationEliminationPass::EliminateInput) + << inp_index.value() << " is model's input and is removed. New input is " + << perm_outputs.at(0).value() << "\n" + << input_use.value() << " is removed permutation operation\n"; + } +} + +void PermutationEliminationPass::eliminateOutput(const model::operand::Index &out_index, + model::operand::Object &object) +{ + auto &model_outputs = _graph.getOutputs(); + + // get defs of the model's given output + auto defs = object.getDef(); + + // output must use just permutation + if (defs.size() != 1) + { + return; + } + + for (auto output_def : defs.list()) + { + auto &perm_operation = _graph.operations().at(output_def); + auto perm_outputs = perm_operation.getOutputs(); + + auto perm_inputs = perm_operation.getInputs(); + if (!isPermuteLayerToEliminate(perm_inputs, perm_outputs, false)) + { + return; + } + + assert(perm_outputs.at(0) == out_index); + + VERBOSE(PermutationEliminationPass::EliminateOutput) << "remove NCHW_TO_NHWC permutation\n"; + + // Update operations' output that is used by permute operand + for (auto perm_input_index : perm_inputs) + { + auto &perm_input_operand = _graph.operands().at(perm_input_index); + perm_input_operand.removeUse(output_def); + } + + // set model's new output, which was input of permutation + model_outputs.replace(out_index, perm_inputs.at(0)); + + // remove model's output, which is also output of permutation + _graph.removeOperand(out_index); + + // remove permutation operation + _graph.operations().remove(output_def); + + VERBOSE(PermutationEliminationPass::EliminateOutput) + << out_index.value() << " is model's output and is removed. New output is " + << perm_inputs.at(0).value() << "\n" + << output_def.value() << " is removed permutation operation\n"; + } +} + +bool PermutationEliminationPass::isPermuteLayerToEliminate( + const model::operand::IndexSet &inp_indexes, const model::operand::IndexSet &out_indexes, + bool is_for_model_input) +{ + auto input_def_backends = _graph.operands().at(inp_indexes.at(0)).lower_info()->def_backends(); + auto output_def_backends = _graph.operands().at(out_indexes.at(0)).lower_info()->def_backends(); + + auto input_layout = input_def_backends.getOnlyElement()->config()->getOperandLayout(); + auto output_layout = output_def_backends.getOnlyElement()->config()->getOperandLayout(); + + if (input_def_backends.size() != 1 || output_def_backends.size() != 1) + { + return false; + } + + // all operands' backend must be the same + for (auto index : inp_indexes) + { + auto op_backend_set = _graph.operands().at(index).lower_info()->def_backends(); + if (op_backend_set.size() != 1 || + input_layout != op_backend_set.getOnlyElement()->config()->getOperandLayout()) + { + return false; + } + } + // all operands' backend must be the same + for (auto index : out_indexes) + { + auto op_backend_set = _graph.operands().at(index).lower_info()->def_backends(); + if (op_backend_set.size() != 1 || + output_layout != op_backend_set.getOnlyElement()->config()->getOperandLayout()) + { + return false; + } + } + + if (is_for_model_input) + { + // check if this is NHWC_TO_NCHW permutation: must have single input, which is model's input + return (inp_indexes.size() == 1 && input_layout == graph::operand::Layout::NHWC && + output_layout == graph::operand::Layout::NCHW); + } + + // check if this is NCHW_TO_NHWC permutation: must have single output, which is model's output + return (out_indexes.size() == 1 && input_layout == graph::operand::Layout::NCHW && + output_layout == graph::operand::Layout::NHWC); +} + +} // namespace pass +} // namespace graph +} // namespace neurun diff --git a/runtimes/neurun/src/graph/pass/PermutationEliminationPass.h b/runtimes/neurun/src/graph/pass/PermutationEliminationPass.h new file mode 100644 index 000000000..2b528c479 --- /dev/null +++ b/runtimes/neurun/src/graph/pass/PermutationEliminationPass.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2018 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 __NEURUN_GRAPH_PASS_PERMUTATION_ELIMINATION_PASS_H__ +#define __NEURUN_GRAPH_PASS_PERMUTATION_ELIMINATION_PASS_H__ + +#include "OperandPass.h" +#include "model/operand/Object.h" +#include "model/operand/IndexSet.h" + +namespace neurun +{ +namespace graph +{ +namespace pass +{ + +class PermutationEliminationPass : public OperandPass +{ +public: + using OperandPass::OperandPass; + +public: + virtual std::string id() override { return "PermutationEliminationPass"; } + + virtual void callback(const model::operand::Index &index, model::operand::Object &object); + +private: + /** + * @brief Remove Permute operation that permutates input + * + * Note: This function aslo removes model's input and + * sets output of permutation as model's new input + * + * @param inp_index is the target operand index for the elimination + * @param object is the target operand object for the elimination + * + * @return + */ + void eliminateInput(const model::operand::Index &inp_index, model::operand::Object &object); + + /** + * @brief Remove Permute operation that permutates output of a model + * + * Note: This function aslo removes model's output and + * sets input of permutation as model's new output + * + * @param out_index is the target operand index for the elimination + * @param object is the target operand object for the elimination + * + * @return + */ + void eliminateOutput(const model::operand::Index &out_index, model::operand::Object &object); + + /** + * @brief Determine if passed operands are permute layer's input and output, that must be + * eliminated + * + * @param inp_index indexes of the input operand to operation + * @param out_index indexes of the output operand to operation + * @param is_for_model_input checking for model's input or output + * + * @return if it is permutation layer + */ + bool isPermuteLayerToEliminate(const model::operand::IndexSet &inp_indexes, + const model::operand::IndexSet &out_indexes, + bool is_for_model_input); +}; + +} // namespace pass +} // namespace graph +} // namespace neurun + +#endif // __NEURUN_GRAPH_PASS_PERMUTATION_ELIMINATION_PASS_H__ diff --git a/runtimes/neurun/src/graph/pass/PermutationInsertionPass.cc b/runtimes/neurun/src/graph/pass/PermutationInsertionPass.cc new file mode 100644 index 000000000..9b833b8c5 --- /dev/null +++ b/runtimes/neurun/src/graph/pass/PermutationInsertionPass.cc @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2018 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 "PermutationInsertionPass.h" + +#include <cassert> +#include <utility> +#include <unordered_map> + +#include "model/operand/Object.h" +#include "graph/operation/LowerInfo.h" +#include "graph/Graph.h" +#include "backend/interface/IConfig.h" +#include "util/logging.h" +#include "cpp14/memory.h" +#include "model/operation/PermuteNode.h" +#include "graph/operand/Shape4DConvert.h" +#include "compiler/BackendResolver.h" + +namespace neurun +{ +namespace graph +{ +namespace pass +{ + +void PermutationInsertionPass::callback(const model::operand::Index &index, + model::operand::Object &object) +{ + auto &&operand_li = object.lower_info(); + assert(operand_li); + + // NOTE Later, constants also will have Def + // Ignore constants + if (operand_li->def_backends().size() == 0) + { + return; + } + + std::list<model::operation::Index> permute_indexes; + + // Build a map for all necessary type of operands + std::unordered_map<const backend::Backend *, model::operand::Index> backend_to_index; + { + assert(operand_li->def_backends().size() == 1); + for (auto backend : operand_li->def_backends()) + { + backend_to_index.insert({backend, index}); + } + + auto insert_set = operand_li->use_backends() - operand_li->def_backends(); + for (auto backend : insert_set) + { + const auto permute_operation_index = insertPermute(index, backend); + permute_indexes.push_back(permute_operation_index); + VERBOSE(PermutationInsertionPass) << "Insert 'Permute' operation for operand " + << index.value() << std::endl; + const auto &permute_operation = _graph.operations().at(permute_operation_index); + const auto permuted_operand_index = permute_operation.getOutputs().at(0); + backend_to_index.insert({backend, permuted_operand_index}); + } + } + + // Update operations' input that uses this operand + { + std::list<model::operation::Index> remove_list; + + auto uses = object.getUses(); + for (auto use : uses.list()) + { + // If permute operation, ignore it + if (std::find(permute_indexes.begin(), permute_indexes.end(), use) != permute_indexes.end()) + continue; + + auto &operation = _graph.operations().at(use); + auto operation_li = _graph.getLowerInfo(use); + assert(operation_li); + auto backend = operation_li->backend(); + + auto use_node_inputs = operation.getInputs(); + assert(use_node_inputs.contains(index)); + + auto new_index = backend_to_index.at(backend); + if (index != new_index) + { + // Update from operation + operation.replaceInput(index, new_index); + + // Update from operand + remove_list.push_back( + use); // Removal should be done in another loop since we are in the loop + _graph.operands().at(new_index).appendUse(use); + } + } + + for (auto &operation : remove_list) + { + object.removeUse(operation); + } + } +} + +model::operation::Index +PermutationInsertionPass::insertPermute(const model::operand::Index &operand_index, + const backend::Backend *backend) +{ + assert(!_graph.isBuildingPhase()); + + auto &operand = _graph.operands().at(operand_index); + + // Generate output operand and permute operation + auto out_operand_index = _graph.addOperand(operand.shape(), operand.typeInfo()); + auto &out_operand = _graph.operands().at(out_operand_index); + out_operand.setAsOperationOutput(); + // change model output if operand_index is model output index + auto &model_outputs = _graph.getOutputs(); + if (model_outputs.contains(operand_index)) + { + model_outputs.replace(operand_index, out_operand_index); + } + out_operand.setAsOperationOutput(); + auto out_operand_li = + nnfw::cpp14::make_unique<operand::LowerInfo>(operand::asShape4D(operand.shape())); + out_operand_li->addDefBackend(backend); + out_operand_li->addUseBackend(backend); + out_operand.lower_info(std::move(out_operand_li)); + + // Update LowerInfo of input operand + operand.lower_info()->removeUseBackend(backend); + operand.lower_info()->addUseBackend(operand.lower_info()->def_backends().getOnlyElement()); + + using PermuteNode = model::operation::PermuteNode; + + // Find Permutation Type + auto type = [&]() { + auto input_layout = + operand.lower_info()->def_backends().getOnlyElement()->config()->getOperandLayout(); + auto output_layout = + out_operand.lower_info()->def_backends().getOnlyElement()->config()->getOperandLayout(); + + if (input_layout == graph::operand::Layout::NHWC && + output_layout == graph::operand::Layout::NCHW) + { + return PermuteNode::Type::NHWC_TO_NCHW; + } + else if (input_layout == graph::operand::Layout::NCHW && + output_layout == graph::operand::Layout::NHWC) + { + return PermuteNode::Type::NCHW_TO_NHWC; + } + else + { + return PermuteNode::Type::COPY; + } + }(); + + // Insert permute operation to the graph + auto insert_node = nnfw::cpp14::make_unique<PermuteNode>(operand_index, out_operand_index, type); + + auto node_index = _graph.operations().append(std::move(insert_node)); + const auto &node = _graph.operations().at(node_index); + + _graph.setLowerInfo(node_index, nnfw::cpp14::make_unique<graph::operation::LowerInfo>( + _graph.backend_resolver()->getDefaultBackend())); + + // Update Use/Def info + { + _graph.operands().at(operand_index).appendUse(node_index); + + auto node_out_indexes = node.getOutputs(); + auto node_out_index = node_out_indexes.at(model::operand::IO::Index{0}); + _graph.operands().at(node_out_index).appendDef(node_index); + } + return node_index; +} +} // namespace pass +} // namespace graph +} // namespace neurun diff --git a/runtimes/neurun/src/graph/pass/PermutationInsertionPass.h b/runtimes/neurun/src/graph/pass/PermutationInsertionPass.h new file mode 100644 index 000000000..b2d417e82 --- /dev/null +++ b/runtimes/neurun/src/graph/pass/PermutationInsertionPass.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2018 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 __NEURUN_GRAPH_PASS_PERMUTATION_INSERTION_PASS_H__ +#define __NEURUN_GRAPH_PASS_PERMUTATION_INSERTION_PASS_H__ + +#include "OperandPass.h" +#include "model/operand/Object.h" //for model::operation::Index + +namespace neurun +{ +namespace graph +{ +namespace pass +{ + +class PermutationInsertionPass : public OperandPass +{ +public: + using OperandPass::OperandPass; + +public: + virtual std::string id() override { return "PermutationInsertionPass"; } + virtual void callback(const model::operand::Index &index, model::operand::Object &object); + + /** + * @brief Insert Permute operation that has given operand as input + * + * @param operand_index is the target operand index for the insertion + * @param backend is the output operand's backend type + * + * @return model::operation::Index + */ + model::operation::Index insertPermute(const model::operand::Index &operand_index, + const backend::Backend *backend); + +private: +}; + +} // namespace pass +} // namespace graph +} // namespace neurun + +#endif // __NEURUN_GRAPH_PASS_PERMUTATION_INSERTION_PASS_H__ diff --git a/runtimes/neurun/src/graph/verifier/IVerifier.cc b/runtimes/neurun/src/graph/verifier/IVerifier.cc deleted file mode 100644 index f8402695a..000000000 --- a/runtimes/neurun/src/graph/verifier/IVerifier.cc +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2018 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 "IVerifier.h" - -#include "graph/Graph.h" - -namespace neurun -{ -namespace graph -{ -namespace verifier -{ - -bool DAGChecker::verify(const Graph &graph) const -{ - auto &operations = graph.operations(); - bool cyclic = false; - std::vector<bool> visited(operations.size(), false); - std::vector<bool> on_stack(operations.size(), false); - - std::function<void(const operation::Index &index, const operation::Node &)> dfs_recursive = - [&](const operation::Index &index, const operation::Node &node) -> void { - if (on_stack[index.value()]) - cyclic = true; - if (visited[index.value()]) - return; - visited[index.value()] = true; - on_stack[index.value()] = true; - - auto outputs = node.getOutputs(); - for (auto output : outputs) - { - // TODO Fix traversing algorithm - // Every time need to search for operations that has `outgoing` as incoming from all - // operations but we can hold that info cached - operations.iterate([&](const operation::Index &cand_index, const operation::Node &cand_node) { - auto inputs = cand_node.getInputs(); - for (auto input : inputs) - { - if (output == input) - { - dfs_recursive(cand_index, cand_node); - } - } - }); - } - - on_stack[index.value()] = false; - }; - - operations.iterate(dfs_recursive); - - return !cyclic; -} - -} // namespace verifier -} // namespace graph -} // namespace neurun diff --git a/runtimes/neurun/src/graph/verifier/Verifier.cc b/runtimes/neurun/src/graph/verifier/Verifier.cc new file mode 100644 index 000000000..a5b53af85 --- /dev/null +++ b/runtimes/neurun/src/graph/verifier/Verifier.cc @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2018 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 "Verifier.h" + +#include "graph/Graph.h" + +#include "util/logging.h" + +namespace neurun +{ +namespace graph +{ +namespace verifier +{ + +// +// DAGChecker +// + +bool DAGChecker::verify(const Graph &graph) const +{ + auto &operations = graph.operations(); + bool cyclic = false; + + std::unordered_map<model::operation::Index, bool> visited; + operations.iterate([&](const model::operation::Index &index, const model::operation::Node &) { + visited[index] = false; + }); + std::unordered_map<model::operation::Index, bool> on_stack = visited; // Copy from visited + + std::function<void(const model::operation::Index &index, const model::operation::Node &)> + dfs_recursive = + [&](const model::operation::Index &index, const model::operation::Node &node) -> void { + if (on_stack[index]) + cyclic = true; + if (visited[index]) + return; + visited[index] = true; + on_stack[index] = true; + + for (auto output : node.getOutputs()) + { + const auto &operand = graph.operands().at(output); + for (const auto &use : operand.getUses().list()) + { + dfs_recursive(use, graph.operations().at(use)); + } + } + + on_stack[index] = false; + }; + + operations.iterate(dfs_recursive); + + return !cyclic; +} + +// +// EdgeConsistencyVerifier +// + +bool EdgeConsistencyChecker::verify(const Graph &graph) const +{ + auto &operations = graph.operations(); + uint32_t mismatches = 0; + operations.iterate([&](const model::operation::Index &index, const model::operation::Node &node) { + for (auto operand_index : node.getInputs()) + { + auto &operand = graph.operands().at(operand_index); + mismatches += (operand.getUses().contains(index) ? 0 : 1); + } + for (auto operand_index : node.getOutputs()) + { + auto &operand = graph.operands().at(operand_index); + mismatches += (operand.getDef().contains(index) ? 0 : 1); + } + }); + return mismatches == 0; +} + +} // namespace verifier +} // namespace graph +} // namespace neurun diff --git a/runtimes/neurun/src/graph/verifier/IVerifier.h b/runtimes/neurun/src/graph/verifier/Verifier.h index 17fe03f24..5f1f79ee6 100644 --- a/runtimes/neurun/src/graph/verifier/IVerifier.h +++ b/runtimes/neurun/src/graph/verifier/Verifier.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef __NEURUN_GRAPH_VERIFIER_I_VERIFIER_H__ -#define __NEURUN_GRAPH_VERIFIER_I_VERIFIER_H__ +#ifndef __NEURUN_GRAPH_VERIFIER_VERIFIER_H__ +#define __NEURUN_GRAPH_VERIFIER_VERIFIER_H__ namespace neurun { @@ -55,8 +55,14 @@ public: virtual bool verify(const Graph &graph) const override; }; +class EdgeConsistencyChecker : public IVerifier +{ +public: + virtual bool verify(const Graph &graph) const override; +}; + } // namespace verifier } // namespace graph } // namespace neurun -#endif // __NEURUN_GRAPH_VERIFIER_I_VERIFIER_H__ +#endif // __NEURUN_GRAPH_VERIFIER_VERIFIER_H__ diff --git a/runtimes/neurun/src/internal/Convert.cc b/runtimes/neurun/src/internal/Convert.cc deleted file mode 100644 index c0260b04e..000000000 --- a/runtimes/neurun/src/internal/Convert.cc +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2018 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 "Convert.h" - -namespace internal -{ - -::arm_compute::TensorShape asTensorShape(int32_t h, int32_t w) -{ - return ::arm_compute::TensorShape(w, h); -} - -::arm_compute::TensorShape asTensorShape(const nnfw::util::feature::Shape &shape) -{ - return ::arm_compute::TensorShape(shape.W, shape.H, shape.C, shape.N); -} - -::arm_compute::TensorShape asTensorShape(const nnfw::util::kernel::Shape &shape) -{ - return ::arm_compute::TensorShape(shape.W, shape.H, shape.C, shape.N); -} - -::arm_compute::TensorInfo asTensorInfo(const nnfw::util::feature::Shape &shape) -{ - return ::arm_compute::TensorInfo(asTensorShape(shape), 1, ::arm_compute::DataType::F32); -} - -::arm_compute::TensorInfo asTensorInfo(const nnfw::util::kernel::Shape &shape) -{ - return ::arm_compute::TensorInfo(asTensorShape(shape), 1, ::arm_compute::DataType::F32); -} - -::arm_compute::TensorInfo asTensorInfo(int32_t size) -{ - return ::arm_compute::TensorInfo(::arm_compute::TensorShape(size), 1, - ::arm_compute::DataType::F32); -} - -::arm_compute::TensorInfo asTensorInfo(int32_t h, int32_t w) -{ - return ::arm_compute::TensorInfo(::arm_compute::TensorShape(w, h), 1, - ::arm_compute::DataType::F32); -} - -} // namespace internal diff --git a/runtimes/neurun/src/internal/Convert.h b/runtimes/neurun/src/internal/Convert.h deleted file mode 100644 index f279133aa..000000000 --- a/runtimes/neurun/src/internal/Convert.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2018 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 __INTERNAL_CONVERT_H__ -#define __INTERNAL_CONVERT_H__ - -#include <arm_compute/core/TensorInfo.h> -#include <arm_compute/core/TensorShape.h> - -#include "util/feature/Shape.h" -#include "util/kernel/Shape.h" - -namespace internal -{ - -::arm_compute::TensorShape asTensorShape(int32_t h, int32_t w); -::arm_compute::TensorShape asTensorShape(const nnfw::util::feature::Shape &shape); -::arm_compute::TensorShape asTensorShape(const nnfw::util::kernel::Shape &shape); - -::arm_compute::TensorInfo asTensorInfo(const nnfw::util::feature::Shape &shape); -::arm_compute::TensorInfo asTensorInfo(const nnfw::util::kernel::Shape &shape); -::arm_compute::TensorInfo asTensorInfo(int32_t size); -::arm_compute::TensorInfo asTensorInfo(int32_t h, int32_t w); - -} // namespace internal - -#endif // __INTERNAL_CONVERT_H__ diff --git a/runtimes/neurun/src/internal/nnapi/feature/Reader.h b/runtimes/neurun/src/internal/nnapi/feature/Reader.h deleted file mode 100644 index eb513512d..000000000 --- a/runtimes/neurun/src/internal/nnapi/feature/Reader.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2018 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 __INTERNAL_NNAPI_FEATURE_READER_H__ -#define __INTERNAL_NNAPI_FEATURE_READER_H__ - -#include "internal/nnapi/feature/Utils.h" - -#include "util/feature/Reader.h" - -namespace internal -{ -namespace nnapi -{ -namespace feature -{ - -template <typename T> class Reader; - -template <> class Reader<float> final : public nnfw::util::feature::Reader<float> -{ -public: - Reader(const ::nnfw::util::feature::Shape &shape, const uint8_t *ptr, size_t len) - : _shape{shape}, _ptr{ptr}, _len{len} - { - // DO NOTHING - } - -public: - const nnfw::util::feature::Shape &shape(void) const { return _shape; } - -public: - float at(uint32_t ch, uint32_t row, uint32_t col) const override - { - uint32_t index = index_of(_shape, ch, row, col); - - const auto arr = reinterpret_cast<const float *>(_ptr); - - return arr[index]; - } - float at(uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) const override - { - uint32_t index = index_of(_shape, batch, ch, row, col); - - const auto arr = reinterpret_cast<const float *>(_ptr); - - return arr[index]; - } - -private: - nnfw::util::feature::Shape _shape; - -private: - const uint8_t *_ptr; - const size_t _len; -}; - -} // namespace feature -} // namespace nnapi -} // namespace internal - -#endif // __INTERNAL_NNAPI_FEATURE_READER_H__ diff --git a/runtimes/neurun/src/internal/nnapi/kernel/Reader.h b/runtimes/neurun/src/internal/nnapi/kernel/Reader.h deleted file mode 100644 index 9d93800bf..000000000 --- a/runtimes/neurun/src/internal/nnapi/kernel/Reader.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2018 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 __INTERNAL_NNAPI_KERNEL_READER_H__ -#define __INTERNAL_NNAPI_KERNEL_READER_H__ - -#include "util/kernel/Shape.h" -#include "util/kernel/Reader.h" - -namespace internal -{ -namespace nnapi -{ -namespace kernel -{ - -template <typename T> class Reader final : public nnfw::util::kernel::Reader<T> -{ -public: - Reader(const ::nnfw::util::kernel::Shape &shape, const uint8_t *base, size_t size) - : _shape{shape}, _base{base}, _size{size} - { - // DO NOTHING - } - -public: - const nnfw::util::kernel::Shape &shape(void) const { return _shape; } - -public: - T at(uint32_t nth, uint32_t ch, uint32_t row, uint32_t col) const override - { - // NNAPI uses NHWC ordering - uint32_t index = 0; - - index += nth * _shape.H * _shape.W * _shape.C; - index += row * _shape.W * _shape.C; - index += col * _shape.C; - index += ch; - - const T *ptr = reinterpret_cast<const T *>(_base); - - return ptr[index]; - } - -private: - nnfw::util::kernel::Shape _shape; - -private: - const uint8_t *_base; - const size_t _size; -}; - -} // namespace kernel -} // namespace nnapi -} // namespace internal - -#endif // __INTERNAL_NNAPI_KERNEL_READER_H__ diff --git a/runtimes/neurun/src/internal/nnapi/kernel/View.h b/runtimes/neurun/src/internal/nnapi/kernel/View.h deleted file mode 100644 index 86d19b87f..000000000 --- a/runtimes/neurun/src/internal/nnapi/kernel/View.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2018 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 __INTERNAL_NNAPI_KERNEL_VIEW_H__ -#define __INTERNAL_NNAPI_KERNEL_VIEW_H__ - -#include "util/kernel/Shape.h" -#include "util/kernel/Reader.h" - -#include <arm_compute/core/ITensor.h> - -namespace internal -{ -namespace nnapi -{ -namespace kernel -{ - -template <typename T> class View final : public nnfw::util::kernel::Reader<float> -{ -public: - View(::arm_compute::ITensor *tensor) : _tensor{tensor} - { - assert(tensor->info()->data_type() == ::arm_compute::DataType::F32); - - _shape.N = tensor->info()->dimension(3); - _shape.C = tensor->info()->dimension(2); - _shape.H = tensor->info()->dimension(1); - _shape.W = tensor->info()->dimension(0); - } - -public: - const nnfw::util::kernel::Shape &shape(void) const { return _shape; } - -public: - float at(uint32_t nth, uint32_t row, uint32_t col, uint32_t ch) const override - { - // NNAPI uses NHWC ordering - uint32_t index = 0; - - index += nth * _shape.H * _shape.W * _shape.C; - index += row * _shape.W * _shape.C; - index += col * _shape.C; - index += ch; - - float *ptr = reinterpret_cast<float *>(_tensor->buffer()); - - return ptr[index]; - } - - float &at(uint32_t nth, uint32_t row, uint32_t col, uint32_t ch) - { - // NNAPI uses NHWC ordering - uint32_t index = 0; - - index += nth * _shape.H * _shape.W * _shape.C; - index += row * _shape.W * _shape.C; - index += col * _shape.C; - index += ch; - - float *ptr = reinterpret_cast<float *>(_tensor->buffer()); - - return ptr[index]; - } - -private: - nnfw::util::kernel::Shape _shape; - ::arm_compute::ITensor *_tensor; -}; - -} // namespace kernel -} // namespace nnapi -} // namespace internal - -#endif // __INTERNAL_NNAPI_KERNEL_VIEW_H__ diff --git a/runtimes/neurun/src/kernel/acl_cl/CLFunction.h b/runtimes/neurun/src/kernel/acl_cl/CLFunction.h new file mode 100644 index 000000000..f34210c8a --- /dev/null +++ b/runtimes/neurun/src/kernel/acl_cl/CLFunction.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2018 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 __NEURUN_KERNEL_ACL_CL_CL_FUNCTION_H__ +#define __NEURUN_KERNEL_ACL_CL_CL_FUNCTION_H__ + +#include "exec/interface/IFunction.h" +#include <arm_compute/runtime/IFunction.h> +#include <memory> + +namespace neurun +{ +namespace kernel +{ +namespace acl_cl +{ + +class CLFunction : public ::neurun::exec::IFunction +{ +public: + CLFunction() = delete; + +public: + CLFunction(std::unique_ptr<::arm_compute::IFunction> &&func) + : _func(std::forward<std::unique_ptr<::arm_compute::IFunction>>(func)) + { + // DO NOTHING + } + +public: + void run() override { _func->run(); } + void prepare() override { _func->prepare(); } + +private: + std::unique_ptr<::arm_compute::IFunction> _func; +}; + +} // namespace acl_cl +} // namespace kernel +} // namespace neurun + +#endif // __NEURUN_KERNEL_ACL_CL_CL_FUNCTION_H__ diff --git a/runtimes/neurun/src/kernel/acl_cl/CMakeLists.txt b/runtimes/neurun/src/kernel/acl_cl/CMakeLists.txt index 857fe6fe6..0658effea 100644 --- a/runtimes/neurun/src/kernel/acl_cl/CMakeLists.txt +++ b/runtimes/neurun/src/kernel/acl_cl/CMakeLists.txt @@ -4,11 +4,9 @@ add_library(${LIB_NEURUN_KERNEL_ACL_CL} STATIC ${SOURCES}) target_include_directories(${LIB_NEURUN_KERNEL_ACL_CL} PUBLIC ${NNFW_INCLUDE_DIR}) target_include_directories(${LIB_NEURUN_KERNEL_ACL_CL} PUBLIC ${NEURUN_INCLUDE_DIR}) -target_include_directories(${LIB_NEURUN_KERNEL_ACL_CL} PUBLIC ${CMAKE_SOURCE_DIR}/externals/tensorflow) # TODO We should not need this target_link_libraries(${LIB_NEURUN_KERNEL_ACL_CL} arm_compute) -target_link_libraries(${LIB_NEURUN_KERNEL_ACL_CL} tensorflow-lite) # TODO We should not need this -target_link_libraries(${LIB_NEURUN_KERNEL_ACL_CL} ${LIB_NEURUN_KERNEL_CPU}) # TODO We should not need this +target_link_libraries(${LIB_NEURUN_KERNEL_ACL_CL} nnfw_lib_misc) set_target_properties(${LIB_NEURUN_KERNEL_ACL_CL} PROPERTIES POSITION_INDEPENDENT_CODE ON) set_target_properties(${LIB_NEURUN_KERNEL_ACL_CL} PROPERTIES OUTPUT_NAME kernel_acl_cl) diff --git a/runtimes/neurun/src/kernel/acl_cl/ConcatLayer.cc b/runtimes/neurun/src/kernel/acl_cl/ConcatLayer.cc index b75ac90f0..3844317ab 100644 --- a/runtimes/neurun/src/kernel/acl_cl/ConcatLayer.cc +++ b/runtimes/neurun/src/kernel/acl_cl/ConcatLayer.cc @@ -18,23 +18,23 @@ #include <arm_compute/runtime/CL/CLScheduler.h> -#include "backend/acl_cl/kernel/View.h" -#include "logging.h" +#include "util/feature/nchw/View.h" +#include "util/logging.h" namespace { -bool matchSizeExceptAxis(const ::arm_compute::ICLTensor *t1, const ::arm_compute::ICLTensor *t2, - uint32_t axis) +bool matchSizeExceptAxis(const ::neurun::backend::acl_cl::operand::ICLTensor *t1, + const ::neurun::backend::acl_cl::operand::ICLTensor *t2, uint32_t axis) { - assert(t1->info()->num_dimensions() <= 4); - assert(t2->info()->num_dimensions() <= 4); + assert(t1->num_dimensions() <= 4); + assert(t2->num_dimensions() <= 4); for (uint32_t i = 0; i < 4; i++) { if (axis == i) continue; - if (t1->info()->dimension(i) != t2->info()->dimension(i)) + if (t1->dimension(i) != t2->dimension(i)) return false; } return true; @@ -66,10 +66,10 @@ bool ConcatLayer::concatenationFloat32() for (auto input : _input_allocs) { assert(matchSizeExceptAxis(_output_alloc, input, _axis)); - axis_sum += input->info()->dimension(_axis); + axis_sum += input->dimension(_axis); } - assert(_output_alloc->info()->dimension(_axis) == axis_sum); + assert(_output_alloc->dimension(_axis) == axis_sum); } VERBOSE(Concat_RUN) << "START Concat" << std::endl; @@ -81,12 +81,12 @@ bool ConcatLayer::concatenationFloat32() auto &queue = ::arm_compute::CLScheduler::get().queue(); _output_alloc->map(queue); - ::internal::arm_compute::kernel::View<float> output_view{_output_alloc}; + util::feature::nchw::View<float> output_view{_output_alloc}; for (auto input : _input_allocs) { input->map(queue); - const ::internal::arm_compute::kernel::View<float> input_reader{input}; + const util::feature::nchw::View<float> input_reader{input}; for (uint32_t n = 0; n < input_reader.shape().N; n++) { @@ -124,8 +124,9 @@ bool ConcatLayer::concatenationFloat32() return true; } -void ConcatLayer::configure(const std::vector<::arm_compute::ICLTensor *> &input_allocs, - int32_t axis, ::arm_compute::ICLTensor *output_alloc) +void ConcatLayer::configure( + const std::vector<::neurun::backend::acl_cl::operand::ICLTensor *> &input_allocs, int32_t axis, + ::neurun::backend::acl_cl::operand::ICLTensor *output_alloc) { _input_allocs = input_allocs; _output_alloc = output_alloc; diff --git a/runtimes/neurun/src/kernel/acl_cl/ConcatLayer.h b/runtimes/neurun/src/kernel/acl_cl/ConcatLayer.h index 4767721fa..d468a6dfb 100644 --- a/runtimes/neurun/src/kernel/acl_cl/ConcatLayer.h +++ b/runtimes/neurun/src/kernel/acl_cl/ConcatLayer.h @@ -14,17 +14,17 @@ * limitations under the License. */ -#ifndef __INTERNAL_KERNEL_ACL_CL_CONCAT_LAYER_H__ -#define __INTERNAL_KERNEL_ACL_CL_CONCAT_LAYER_H__ +#ifndef __NEURUN_KERNEL_ACL_CL_CONCAT_LAYER_H__ +#define __NEURUN_KERNEL_ACL_CL_CONCAT_LAYER_H__ #include <NeuralNetworks.h> -#include <arm_compute/core/CL/ICLTensor.h> #include <arm_compute/runtime/IFunction.h> -#include "graph/operand/DataType.h" +#include "model/operand/DataType.h" +#include "backend/acl_cl/operand/ICLTensor.h" -using OperandType = neurun::graph::operand::DataType; +using OperandType = neurun::model::operand::DataType; namespace neurun { @@ -44,9 +44,9 @@ public: ConcatLayer(); public: - void configure(const std::vector<::arm_compute::ICLTensor *> &input_allocs, + void configure(const std::vector<::neurun::backend::acl_cl::operand::ICLTensor *> &input_allocs, int32_t axis /* NNAPI tensor axis from NHWC order */, - ::arm_compute::ICLTensor *output_alloc); + ::neurun::backend::acl_cl::operand::ICLTensor *output_alloc); void run(); @@ -54,8 +54,8 @@ private: bool concatenationFloat32(); private: - std::vector<::arm_compute::ICLTensor *> _input_allocs; - ::arm_compute::ICLTensor *_output_alloc; + std::vector<::neurun::backend::acl_cl::operand::ICLTensor *> _input_allocs; + ::neurun::backend::acl_cl::operand::ICLTensor *_output_alloc; int32_t _axis; OperandType _input_type; }; @@ -64,4 +64,4 @@ private: } // namespace kernel } // namespace neurun -#endif // __INTERNAL_KERNEL_ACL_CL_CONCAT_LAYER_H__ +#endif // __NEURUN_KERNEL_ACL_CL_CONCAT_LAYER_H__ diff --git a/runtimes/neurun/src/kernel/acl_cl/TensorConvertFromCommonLayer.cc b/runtimes/neurun/src/kernel/acl_cl/TensorConvertFromCommonLayer.cc deleted file mode 100644 index fa1d77579..000000000 --- a/runtimes/neurun/src/kernel/acl_cl/TensorConvertFromCommonLayer.cc +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2018 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. - */ - -// -// THIS FILE IS UNUSED BUT LEFT FOR FUTURE REFERNCE -// - -#if 0 - -#include "TensorConvertFromCommonLayer.h" - -#include "internal/nnapi/feature/Reader.h" -#include "backend/acl_cl/feature/View.h" - -#include <util/feature/IndexIterator.h> -#include <arm_compute/runtime/CL/CLScheduler.h> - -namespace neurun -{ -namespace kernel -{ -namespace acl_cl -{ - -bool TensorConvertFromCommonLayer::convert() -{ - auto inputBuffer = _inputTensor->buffer(); - auto inputSize = _inputTensor->info()->total_size(); - - auto &queue = ::arm_compute::CLScheduler::get().queue(); - - _outputTensor->map(queue); - - if (_tensorShape.rank() == 2) - { - const auto len = _tensorShape.dim(1); - - auto base = reinterpret_cast<const float *>(inputBuffer); - - for (int32_t n = 0; n < len; ++n) - { - auto from = base + n; - auto into = - reinterpret_cast<float *>(_outputTensor->ptr_to_element(::arm_compute::Coordinates{n})); - - *into = *from; - } - } - else if (_tensorShape.rank() == 4) - { - auto featureShape = _tensorShape.asFeature(); - - const ::internal::nnapi::feature::Reader<float> from{featureShape, inputBuffer, inputSize}; - ::internal::arm_compute::feature::View<float> into{_outputTensor}; - - ::nnfw::util::feature::iterate(featureShape) - << [&](uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) { - const auto value = from.at(batch, ch, row, col); - into.at(batch, ch, row, col) = value; - }; - } - - _outputTensor->unmap(queue); -} - -void TensorConvertFromCommonLayer::configure(::internal::common::Tensor *inputTensor, - ::arm_compute::ICLTensor *outputTensor, - const ::neurun::graph::operand::Shape &tensorShape) -{ - _inputTensor = inputTensor; - _outputTensor = outputTensor; - _tensorShape = tensorShape; -} - -void TensorConvertFromCommonLayer::run() { convert(); } - -} // namespace acl_cl -} // namespace kernel -} // namespace neurun - -#endif diff --git a/runtimes/neurun/src/kernel/acl_cl/TensorConvertFromCommonLayer.h b/runtimes/neurun/src/kernel/acl_cl/TensorConvertFromCommonLayer.h deleted file mode 100644 index bd031a106..000000000 --- a/runtimes/neurun/src/kernel/acl_cl/TensorConvertFromCommonLayer.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2018 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. - */ - -// -// THIS FILE IS UNUSED BUT LEFT FOR FUTURE REFERNCE -// - -#if 0 - -#ifndef __INTERNAL_KERNELS_ACL_CL_TENSOR_CONVERT_FROM_COMMON_LAYER_H__ -#define __INTERNAL_KERNELS_ACL_CL_TENSOR_CONVERT_FROM_COMMON_LAYER_H__ - -#include <NeuralNetworks.h> - -#include <arm_compute/runtime/IFunction.h> -#include <arm_compute/core/CL/ICLTensor.h> - -#include "internal/Model.h" -#include "internal/common/Tensor.h" - -namespace neurun -{ -namespace kernel -{ -namespace acl_cl -{ - -class TensorConvertFromCommonLayer : public ::arm_compute::IFunction -{ -public: - TensorConvertFromCommonLayer() {} - -public: - bool convert(); - - void configure(::internal::common::Tensor *inputTensor, ::arm_compute::ICLTensor *outputTensor, - const ::neurun::graph::operand::Shape &tensorShape); - - void run(); - -private: - ::internal::common::Tensor *_inputTensor; - ::arm_compute::ICLTensor *_outputTensor; - - ::neurun::graph::operand::Shape _tensorShape{1}; -}; - -} // namespace acl_cl -} // namespace kernel -} // namespace neurun - -#endif // __INTERNAL_KERNELS_ACL_CL_TENSOR_CONVERT_FROM_COMMON_LAYER_H__ - -#endif diff --git a/runtimes/neurun/src/kernel/acl_cl/TensorConvertToCommonLayer.cc b/runtimes/neurun/src/kernel/acl_cl/TensorConvertToCommonLayer.cc deleted file mode 100644 index 985524bc3..000000000 --- a/runtimes/neurun/src/kernel/acl_cl/TensorConvertToCommonLayer.cc +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2018 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. - */ - -// -// THIS FILE IS UNUSED BUT LEFT FOR FUTURE REFERNCE -// - -#if 0 - -#include "TensorConvertToCommonLayer.h" - -#include "backend/acl_cl/feature/View.h" -#include "internal/nnapi/feature/View.h" - -#include <util/feature/IndexIterator.h> -#include <arm_compute/runtime/CL/CLScheduler.h> - -namespace neurun -{ -namespace kernel -{ -namespace acl_cl -{ - -bool TensorConvertToCommonLayer::convert() -{ - auto outputBuffer = _outputTensor->buffer(); - auto outputSize = _outputTensor->info()->total_size(); - - auto &queue = ::arm_compute::CLScheduler::get().queue(); - - _inputTensor->map(queue); - - if (_tensorShape.rank() == 2) - { - const auto len = _tensorShape.dim(1); - - auto base = reinterpret_cast<float *>(outputBuffer); - - for (int32_t n = 0; n < len; ++n) - { - auto from = reinterpret_cast<const float *>( - _inputTensor->ptr_to_element(::arm_compute::Coordinates{n})); - auto into = base + n; - - *into = *from; - } - } - else if (_tensorShape.rank() == 4) - { - auto featureShape = _tensorShape.asFeature(); - - const ::internal::arm_compute::feature::View<float> from{_inputTensor}; - ::internal::nnapi::feature::View<float> into{featureShape, outputBuffer, outputSize}; - - ::nnfw::util::feature::iterate(featureShape) - << [&](uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) { - const auto value = from.at(batch, ch, row, col); - into.at(batch, ch, row, col) = value; - }; - } - - _inputTensor->unmap(queue); -} - -void TensorConvertToCommonLayer::configure(::arm_compute::ICLTensor *inputTensor, - ::internal::common::Tensor *outputTensor, - const ::neurun::graph::operand::Shape &tensorShape) -{ - _inputTensor = inputTensor; - _outputTensor = outputTensor; - _tensorShape = tensorShape; -} - -void TensorConvertToCommonLayer::run() { convert(); } - -} // namespace acl_cl -} // namespace kernel -} // namespace neurun - -#endif diff --git a/runtimes/neurun/src/kernel/acl_cl/TensorConvertToCommonLayer.h b/runtimes/neurun/src/kernel/acl_cl/TensorConvertToCommonLayer.h deleted file mode 100644 index 576f1ee71..000000000 --- a/runtimes/neurun/src/kernel/acl_cl/TensorConvertToCommonLayer.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2018 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. - */ - -// -// THIS FILE IS UNUSED BUT LEFT FOR FUTURE REFERNCE -// - -#if 0 - -#ifndef __INTERNAL_KERNELS_ACL_CL_TENSOR_CONVERT_TO_COMMON_LAYER_H__ -#define __INTERNAL_KERNELS_ACL_CL_TENSOR_CONVERT_TO_COMMON_LAYER_H__ - -#include <NeuralNetworks.h> - -#include <arm_compute/runtime/IFunction.h> -#include <arm_compute/core/CL/ICLTensor.h> - -#include "internal/Model.h" -#include "internal/common/Tensor.h" - -namespace neurun -{ -namespace kernel -{ -namespace acl_cl -{ - -class TensorConvertToCommonLayer : public ::arm_compute::IFunction -{ -public: - TensorConvertToCommonLayer() {} - -public: - bool convert(); - - void configure(::arm_compute::ICLTensor *inputTensor, ::internal::common::Tensor *outputTensor, - const ::neurun::graph::operand::Shape &tensorShape); - - void run(); - -private: - ::arm_compute::ICLTensor *_inputTensor; - ::internal::common::Tensor *_outputTensor; - - ::neurun::graph::operand::Shape _tensorShape{1}; -}; - -} // namespace acl_cl -} // namespace kernel -} // namespace neurun - -#endif // __INTERNAL_KERNELS_ACL_CL_TENSOR_CONVERT_TO_COMMON_LAYER_H__ - -#endif diff --git a/runtimes/neurun/src/kernel/cpu/AvgPoolLayer.cc b/runtimes/neurun/src/kernel/cpu/AvgPoolLayer.cc index 2a6a84e10..f434a6dec 100644 --- a/runtimes/neurun/src/kernel/cpu/AvgPoolLayer.cc +++ b/runtimes/neurun/src/kernel/cpu/AvgPoolLayer.cc @@ -27,14 +27,14 @@ namespace kernel namespace cpu { -#define AVGPOOLING_PARAMETERS \ - uint32_t height = getSizeOfDimension(_inputShape, 1); \ - uint32_t width = getSizeOfDimension(_inputShape, 2); \ - uint32_t outHeight = getSizeOfDimension(_outputShape, 1); \ - uint32_t outWidth = getSizeOfDimension(_outputShape, 2); \ - \ - uint32_t paddingHeight = (uint32_t)_paddingTop; \ - uint32_t paddingWidth = (uint32_t)_paddingLeft; +#define AVGPOOLING_PARAMETERS \ + tflite::PoolParams op_params; \ + op_params.stride_height = _strideHeight; \ + op_params.stride_width = _strideWidth; \ + op_params.filter_height = _kernelHeight; \ + op_params.filter_width = _kernelWidth; \ + op_params.padding_values.height = (int8_t)_paddingTop; \ + op_params.padding_values.width = (int8_t)_paddingLeft; AvgPoolLayer::AvgPoolLayer() : _inputData(nullptr), _outputData(nullptr), _inputShape(), _outputShape(), _paddingLeft(0), @@ -47,31 +47,31 @@ AvgPoolLayer::AvgPoolLayer() bool AvgPoolLayer::averagePoolFloat32() { - AVGPOOLING_PARAMETERS float output_activation_min, output_activation_max; CalculateActivationRangeFloat(_activation, &output_activation_min, &output_activation_max); + op_params.float_activation_min = output_activation_min; + op_params.float_activation_max = output_activation_max; - ::tflite::optimized_ops::AveragePool( - reinterpret_cast<const float *>(_inputData), convertShapeToDims(_inputShape), _strideWidth, - _strideHeight, paddingWidth, paddingHeight, _kernelWidth, _kernelHeight, - output_activation_min, output_activation_max, reinterpret_cast<float *>(_outputData), - convertShapeToDims(_outputShape)); + ::tflite::optimized_ops::AveragePool(op_params, convertShapeToTFLiteShape(_inputShape), + reinterpret_cast<const float *>(_inputData), + convertShapeToTFLiteShape(_outputShape), + reinterpret_cast<float *>(_outputData)); return true; } bool AvgPoolLayer::averagePoolQuant8() { - AVGPOOLING_PARAMETERS int32_t output_activation_min = 0; int32_t output_activation_max = 0; CalculateActivationRangeUint8(_activation, _outputShape, &output_activation_min, &output_activation_max); + op_params.quantized_activation_min = output_activation_min; + op_params.quantized_activation_max = output_activation_max; - ::tflite::optimized_ops::AveragePool(_inputData, convertShapeToDims(_inputShape), _strideWidth, - _strideHeight, paddingWidth, paddingHeight, _kernelWidth, - _kernelHeight, output_activation_min, output_activation_max, - _outputData, convertShapeToDims(_outputShape)); + ::tflite::optimized_ops::AveragePool(op_params, convertShapeToTFLiteShape(_inputShape), + _inputData, convertShapeToTFLiteShape(_outputShape), + _outputData); return true; } diff --git a/runtimes/neurun/src/kernel/cpu/AvgPoolLayer.h b/runtimes/neurun/src/kernel/cpu/AvgPoolLayer.h index 9f390a9e1..280f7ae5f 100644 --- a/runtimes/neurun/src/kernel/cpu/AvgPoolLayer.h +++ b/runtimes/neurun/src/kernel/cpu/AvgPoolLayer.h @@ -19,7 +19,7 @@ #include <NeuralNetworks.h> -#include <arm_compute/runtime/IFunction.h> +#include "exec/interface/IFunction.h" #include "kernel/cpu/OperationUtils.h" @@ -30,7 +30,7 @@ namespace kernel namespace cpu { -class AvgPoolLayer : public ::arm_compute::IFunction +class AvgPoolLayer : public ::neurun::exec::IFunction { public: AvgPoolLayer(); diff --git a/runtimes/neurun/src/kernel/cpu/CMakeLists.txt b/runtimes/neurun/src/kernel/cpu/CMakeLists.txt index dddf154c3..436cb898c 100644 --- a/runtimes/neurun/src/kernel/cpu/CMakeLists.txt +++ b/runtimes/neurun/src/kernel/cpu/CMakeLists.txt @@ -6,8 +6,8 @@ target_include_directories(${LIB_NEURUN_KERNEL_CPU} PUBLIC ${NNFW_INCLUDE_DIR}) target_include_directories(${LIB_NEURUN_KERNEL_CPU} PUBLIC ${NEURUN_INCLUDE_DIR}) target_include_directories(${LIB_NEURUN_KERNEL_CPU} PUBLIC ${CMAKE_SOURCE_DIR}/externals/tensorflow) -target_link_libraries(${LIB_NEURUN_KERNEL_CPU} arm_compute) # TODO We should not need this target_link_libraries(${LIB_NEURUN_KERNEL_CPU} tensorflow-lite) +target_link_libraries(${LIB_NEURUN_KERNEL_CPU} nnfw_lib_misc) set_target_properties(${LIB_NEURUN_KERNEL_CPU} PROPERTIES POSITION_INDEPENDENT_CODE ON) set_target_properties(${LIB_NEURUN_KERNEL_CPU} PROPERTIES OUTPUT_NAME kernel_cpu) diff --git a/runtimes/neurun/src/kernel/cpu/ConcatLayer.cc b/runtimes/neurun/src/kernel/cpu/ConcatLayer.cc index 5fe5e3993..be093b437 100644 --- a/runtimes/neurun/src/kernel/cpu/ConcatLayer.cc +++ b/runtimes/neurun/src/kernel/cpu/ConcatLayer.cc @@ -24,6 +24,7 @@ namespace neurun { namespace kernel { + namespace cpu { @@ -36,13 +37,21 @@ ConcatLayer::ConcatLayer() bool ConcatLayer::concatenationFloat32() { - int num_inputs = _inputShapes.size(); - std::vector<::tflite::Dims<4> *> inputDimsPtr(num_inputs); - std::vector<::tflite::Dims<4>> inputDims(num_inputs); - for (int i = 0; i < num_inputs; i++) + uint32_t num_inputs = _inputShapes.size(); + + tflite::ConcatenationParams op_params; + op_params.axis = _axis; + op_params.inputs_count = num_inputs; + + std::vector<::tflite::RuntimeShape *> inputDimsPtr; + std::vector<::tflite::RuntimeShape> inputDims; + inputDimsPtr.reserve(num_inputs); + inputDims.reserve(num_inputs); + + for (uint32_t i = 0; i < num_inputs; i++) { - inputDims[i] = convertShapeToDims(_inputShapes[i]); - inputDimsPtr[i] = &inputDims[i]; + inputDims.push_back(convertShapeToTFLiteShape(_inputShapes[i])); + inputDimsPtr.push_back(&inputDims[i]); } std::vector<const float *> inputFloatPtrs; @@ -52,24 +61,44 @@ bool ConcatLayer::concatenationFloat32() inputFloatPtrs.emplace_back(reinterpret_cast<const float *>(ptr)); } - ::tflite::optimized_ops::Concatenation<::tflite::FusedActivationFunctionType::kNone, float>( - getNumberOfDimensions(_outputShape) - _axis - 1, inputFloatPtrs.data(), inputDimsPtr.data(), - num_inputs, reinterpret_cast<float *>(_outputData), convertShapeToDims(_outputShape)); + ::tflite::optimized_ops::Concatenation<float>( + op_params, inputDimsPtr.data(), inputFloatPtrs.data(), + convertShapeToTFLiteShape(_outputShape), reinterpret_cast<float *>(_outputData)); return true; } bool ConcatLayer::concatenationQuant8() { int num_inputs = _inputShapes.size(); - std::vector<::tflite::Dims<4> *> inputDimsPtr(num_inputs); - std::vector<::tflite::Dims<4>> inputDims(num_inputs); - for (int i = 0; i < num_inputs; i++) + + std::vector<int32_t> input_zeropoints(num_inputs); + std::vector<float> input_scales(num_inputs); + for (uint32_t i = 0; i < num_inputs; i++) { - inputDims[i] = convertShapeToDims(_inputShapes[i]); - inputDimsPtr[i] = &inputDims[i]; + input_zeropoints[i] = _inputShapes[i].offset; + input_scales[i] = _inputShapes[i].scale; } - ::tflite::optimized_ops::Concatenation<::tflite::FusedActivationFunctionType::kNone, uint8_t>( - getNumberOfDimensions(_outputShape) - _axis - 1, _inputDataPtrs.data(), inputDimsPtr.data(), - num_inputs, _outputData, convertShapeToDims(_outputShape)); + + tflite::ConcatenationParams op_params; + op_params.axis = _axis; + op_params.inputs_count = num_inputs; + op_params.input_zeropoint = input_zeropoints.data(); + op_params.input_scale = input_scales.data(); + op_params.output_zeropoint = _outputShape.offset; + op_params.output_scale = _outputShape.scale; + + std::vector<::tflite::RuntimeShape *> inputDimsPtr; + std::vector<::tflite::RuntimeShape> inputDims; + inputDimsPtr.reserve(num_inputs); + inputDims.reserve(num_inputs); + for (uint32_t i = 0; i < num_inputs; i++) + { + inputDims.push_back(convertShapeToTFLiteShape(_inputShapes[i])); + inputDimsPtr.push_back(&inputDims[i]); + } + + ::tflite::optimized_ops::Concatenation<uint8_t>( + op_params, inputDimsPtr.data(), _inputDataPtrs.data(), + convertShapeToTFLiteShape(_outputShape), _outputData); return true; } diff --git a/runtimes/neurun/src/kernel/cpu/ConcatLayer.h b/runtimes/neurun/src/kernel/cpu/ConcatLayer.h index 9aacab5e8..64f813508 100644 --- a/runtimes/neurun/src/kernel/cpu/ConcatLayer.h +++ b/runtimes/neurun/src/kernel/cpu/ConcatLayer.h @@ -20,7 +20,7 @@ #include <NeuralNetworks.h> -#include <arm_compute/runtime/IFunction.h> +#include "exec/interface/IFunction.h" #include "kernel/cpu/OperationUtils.h" @@ -31,7 +31,7 @@ namespace kernel namespace cpu { -class ConcatLayer : public ::arm_compute::IFunction +class ConcatLayer : public ::neurun::exec::IFunction { public: ConcatLayer(); diff --git a/runtimes/neurun/src/kernel/cpu/ConvolutionLayer.cc b/runtimes/neurun/src/kernel/cpu/ConvolutionLayer.cc index 81e88e0f0..c694fa75f 100644 --- a/runtimes/neurun/src/kernel/cpu/ConvolutionLayer.cc +++ b/runtimes/neurun/src/kernel/cpu/ConvolutionLayer.cc @@ -33,55 +33,51 @@ static constexpr int kStaticBufferSize = 1605632; static char static_scratch_buffer[kStaticBufferSize]; static std::mutex executionMutex; -#define ANDROID_NN_CONV_PARAMETERS(Type) \ - uint32_t height = getSizeOfDimension(_inputShape, 1); \ - uint32_t width = getSizeOfDimension(_inputShape, 2); \ - uint32_t kernelHeight = getSizeOfDimension(_kernelShape, 1); \ - uint32_t kernelWidth = getSizeOfDimension(_kernelShape, 2); \ - uint32_t outHeight = getSizeOfDimension(_outputShape, 1); \ - uint32_t outWidth = getSizeOfDimension(_outputShape, 2); \ - uint32_t inDepth = getSizeOfDimension(_inputShape, 3); \ - \ - uint32_t paddingHeight = (uint32_t)_paddingTop; \ - uint32_t paddingWidth = (uint32_t)_paddingLeft; \ - \ - ::tflite::Dims<4> im2colDim; \ - im2colDim.sizes[3] = (int)getSizeOfDimension(_outputShape, 0); \ - im2colDim.sizes[2] = (int)getSizeOfDimension(_outputShape, 1); \ - im2colDim.sizes[1] = (int)getSizeOfDimension(_outputShape, 2); \ - im2colDim.sizes[0] = (int)inDepth * kernelHeight * kernelWidth; \ - \ - im2colDim.strides[0] = 1; \ - for (int i = 1; i < 4; i++) \ - { \ - im2colDim.strides[i] = im2colDim.strides[i - 1] * im2colDim.sizes[i - 1]; \ - } \ - Type *im2colData = nullptr; \ - uint64_t im2colByteSize = sizeof(Type); \ - std::unique_ptr<Type[]> im2colGuard; \ - for (int i = 0; i < 4; i++) \ - { \ - im2colByteSize *= im2colDim.sizes[i]; \ - } \ - /* http://b/77982879, tflite::optimized_ops::Conv uses int for offsets */ \ - if (im2colByteSize >= 0x7fffffff) \ - { \ - std::cout << "Conv size is too large, not enough memory" << std::endl; \ - return false; \ - } \ - if (im2colByteSize <= kStaticBufferSize) \ - { \ - im2colData = reinterpret_cast<Type *>(static_scratch_buffer); \ - } \ - else \ - { \ - im2colData = new (std::nothrow) Type[im2colByteSize / sizeof(Type)]; \ - if (im2colData == nullptr) \ - { \ - std::cout << "Conv size is too large, not enough memory" << std::endl; \ - return false; \ - } \ - im2colGuard.reset(im2colData); \ +#define ANDROID_NN_CONV_PARAMETERS(Type) \ + uint32_t height = getSizeOfDimension(_inputShape, 1); \ + uint32_t width = getSizeOfDimension(_inputShape, 2); \ + uint32_t kernelHeight = getSizeOfDimension(_kernelShape, 1); \ + uint32_t kernelWidth = getSizeOfDimension(_kernelShape, 2); \ + uint32_t outHeight = getSizeOfDimension(_outputShape, 1); \ + uint32_t outWidth = getSizeOfDimension(_outputShape, 2); \ + uint32_t inDepth = getSizeOfDimension(_inputShape, 3); \ + \ + uint32_t paddingHeight = (uint32_t)_paddingTop; \ + uint32_t paddingWidth = (uint32_t)_paddingLeft; \ + \ + Shape im2colShape; \ + im2colShape.dimensions.resize(4); \ + im2colShape.dimensions[0] = getSizeOfDimension(_outputShape, 0); \ + im2colShape.dimensions[1] = getSizeOfDimension(_outputShape, 1); \ + im2colShape.dimensions[2] = getSizeOfDimension(_outputShape, 2); \ + im2colShape.dimensions[3] = inDepth * kernelHeight * kernelWidth; \ + \ + Type *im2colData = nullptr; \ + uint64_t im2colByteSize = sizeof(Type); \ + std::unique_ptr<Type[]> im2colGuard; \ + for (int i = 0; i < 4; i++) \ + { \ + im2colByteSize *= im2colShape.dimensions[i]; \ + } \ + /* http://b/77982879, tflite::optimized_ops::Conv uses int for offsets */ \ + if (im2colByteSize >= 0x7fffffff) \ + { \ + std::cout << "Conv size is too large, not enough memory" << std::endl; \ + return false; \ + } \ + if (im2colByteSize <= kStaticBufferSize) \ + { \ + im2colData = reinterpret_cast<Type *>(static_scratch_buffer); \ + } \ + else \ + { \ + im2colData = new (std::nothrow) Type[im2colByteSize / sizeof(Type)]; \ + if (im2colData == nullptr) \ + { \ + std::cout << "Conv size is too large, not enough memory" << std::endl; \ + return false; \ + } \ + im2colGuard.reset(im2colData); \ } ConvolutionLayer::ConvolutionLayer() @@ -112,19 +108,32 @@ bool ConvolutionLayer::convFloat32() float output_activation_min, output_activation_max; CalculateActivationRangeFloat(_activation, &output_activation_min, &output_activation_max); int32_t dilationWidthFactor = 1, dilationHeightFactor = 1; + + ::tflite::ConvParams op_params; + op_params.padding_type = ::tflite::PaddingType::kSame; + op_params.padding_values.width = paddingWidth; + op_params.padding_values.height = paddingHeight; + op_params.stride_width = _strideWidth; + op_params.stride_height = _strideHeight; + op_params.dilation_width_factor = dilationWidthFactor; + op_params.dilation_height_factor = dilationHeightFactor; + op_params.float_activation_min = output_activation_min; + op_params.float_activation_max = output_activation_max; + ::tflite::optimized_ops::Conv( - reinterpret_cast<const float *>(_inputData), convertShapeToDims(_inputShape), - reinterpret_cast<const float *>(_kernelData), convertShapeToDims(_kernelShape), - reinterpret_cast<const float *>(_biasData), convertShapeToDims(_biasShape), _strideWidth, - _strideHeight, dilationWidthFactor, dilationHeightFactor, paddingWidth, paddingHeight, - output_activation_min, output_activation_max, reinterpret_cast<float *>(_outputData), - convertShapeToDims(_outputShape), im2colDataToPass, im2colDim); + op_params, convertShapeToTFLiteShape(_inputShape), + reinterpret_cast<const float *>(_inputData), convertShapeToTFLiteShape(_kernelShape), + reinterpret_cast<const float *>(_kernelData), convertShapeToTFLiteShape(_biasShape), + reinterpret_cast<const float *>(_biasData), convertShapeToTFLiteShape(_outputShape), + reinterpret_cast<float *>(_outputData), convertShapeToTFLiteShape(im2colShape), + im2colDataToPass); return true; } bool ConvolutionLayer::convQuant8() { ANDROID_NN_CONV_PARAMETERS(uint8_t) + int32_t inputOffset = -_inputShape.offset; int32_t kernelOffset = -_kernelShape.offset; int32_t outputOffset = _outputShape.offset; @@ -141,6 +150,24 @@ bool ConvolutionLayer::convQuant8() } CalculateActivationRangeUint8(_activation, _outputShape, &output_activation_min, &output_activation_max); + int32_t dilationWidthFactor = 1, dilationHeightFactor = 1; + + ::tflite::ConvParams op_params; + op_params.padding_type = ::tflite::PaddingType::kSame; + op_params.padding_values.width = paddingWidth; + op_params.padding_values.height = paddingHeight; + op_params.stride_width = _strideWidth; + op_params.stride_height = _strideHeight; + op_params.dilation_width_factor = dilationWidthFactor; + op_params.dilation_height_factor = dilationHeightFactor; + op_params.input_offset = inputOffset; + op_params.weights_offset = kernelOffset; + op_params.output_offset = outputOffset; + op_params.output_multiplier = output_multiplier; + op_params.output_shift = output_shift; + op_params.quantized_activation_min = output_activation_min; + op_params.quantized_activation_max = output_activation_max; + static gemmlowp::GemmContext gemm_context; // Prevent concurrent executions that may access the scratch buffer and // gemm_context. @@ -148,11 +175,10 @@ bool ConvolutionLayer::convQuant8() // Alow gemmlowp automatically decide how many threads to use. gemm_context.set_max_num_threads(0); ::tflite::optimized_ops::Conv( - _inputData, convertShapeToDims(_inputShape), inputOffset, _kernelData, - convertShapeToDims(_kernelShape), kernelOffset, reinterpret_cast<const int32_t *>(_biasData), - convertShapeToDims(_biasShape), _strideWidth, _strideHeight, paddingWidth, paddingHeight, - outputOffset, output_multiplier, output_shift, output_activation_min, output_activation_max, - _outputData, convertShapeToDims(_outputShape), im2colData, im2colDim, &gemm_context); + op_params, convertShapeToTFLiteShape(_inputShape), _inputData, + convertShapeToTFLiteShape(_kernelShape), _kernelData, convertShapeToTFLiteShape(_biasShape), + reinterpret_cast<const int32_t *>(_biasData), convertShapeToTFLiteShape(_outputShape), + _outputData, convertShapeToTFLiteShape(im2colShape), im2colData, &gemm_context); return true; } diff --git a/runtimes/neurun/src/kernel/cpu/ConvolutionLayer.h b/runtimes/neurun/src/kernel/cpu/ConvolutionLayer.h index b7afbcec6..9b7f55ff1 100644 --- a/runtimes/neurun/src/kernel/cpu/ConvolutionLayer.h +++ b/runtimes/neurun/src/kernel/cpu/ConvolutionLayer.h @@ -19,7 +19,7 @@ #include <NeuralNetworks.h> -#include <arm_compute/runtime/IFunction.h> +#include "exec/interface/IFunction.h" #include "kernel/cpu/OperationUtils.h" @@ -30,7 +30,7 @@ namespace kernel namespace cpu { -class ConvolutionLayer : public ::arm_compute::IFunction +class ConvolutionLayer : public ::neurun::exec::IFunction { public: ConvolutionLayer(); diff --git a/runtimes/neurun/src/kernel/cpu/FullyConnectedLayer.cc b/runtimes/neurun/src/kernel/cpu/FullyConnectedLayer.cc index 41b9afc0c..abe82db5e 100644 --- a/runtimes/neurun/src/kernel/cpu/FullyConnectedLayer.cc +++ b/runtimes/neurun/src/kernel/cpu/FullyConnectedLayer.cc @@ -44,64 +44,39 @@ FullyConnectedLayer::FullyConnectedLayer() static std::mutex executionMutex; bool FullyConnectedLayer::fullyConnectedFloat32() { - float output_activation_min, output_activation_max; - CalculateActivationRangeFloat(_activation, &output_activation_min, &output_activation_max); - // b/80425683, optimized implementation produces incorrect results when the - // number of input elements is the squre of batch_size. - uint32_t batch_size = getSizeOfDimension(_outputShape, 0); - uint32_t input_n_elements = getNumberOfElements(_inputShape); - if (batch_size * batch_size == input_n_elements) + int total_input_size = 1; + for (int i = 0; i < _inputShape.dimensions.size(); i++) { - ::tflite::reference_ops::FullyConnected( - reinterpret_cast<const float *>(_inputData), convertShapeToDims(_inputShape), - reinterpret_cast<const float *>(_weightsData), convertShapeToDims(_weightsShape), - reinterpret_cast<const float *>(_biasData), convertShapeToDims(_biasShape), - output_activation_min, output_activation_max, reinterpret_cast<float *>(_outputData), - convertShapeToDims(_outputShape)); - } - else - { - ::tflite::optimized_ops::FullyConnected( - reinterpret_cast<const float *>(_inputData), convertShapeToDims(_inputShape), - reinterpret_cast<const float *>(_weightsData), convertShapeToDims(_weightsShape), - reinterpret_cast<const float *>(_biasData), convertShapeToDims(_biasShape), - output_activation_min, output_activation_max, reinterpret_cast<float *>(_outputData), - convertShapeToDims(_outputShape)); + total_input_size *= _inputShape.dimensions[i]; } + + int input_size = _weightsShape.dimensions[1]; + const int batch_size = total_input_size / input_size; + const int num_units = _weightsShape.dimensions[0]; + + TfLiteFusedActivation act = convertFusedActivation(_activation); + + ::tflite::tensor_utils::VectorBatchVectorAssign(reinterpret_cast<const float *>(_biasData), + num_units, batch_size, + reinterpret_cast<float *>(_outputData)); + + // Compute output += weight * input + ::tflite::tensor_utils::MatrixBatchVectorMultiplyAccumulate( + reinterpret_cast<const float *>(_weightsData), num_units, input_size, + reinterpret_cast<const float *>(_inputData), batch_size, + reinterpret_cast<float *>(_outputData), /*result_stride=*/1); + + // Apply activation function + ::tflite::tensor_utils::ApplyActivationToVector(reinterpret_cast<float *>(_outputData), + batch_size * num_units, act, + reinterpret_cast<float *>(_outputData)); + return true; } bool FullyConnectedLayer::fullyConnectedQuant8() { - int32_t inputOffset = -_inputShape.offset; - int32_t weightsOffset = -_weightsShape.offset; - int32_t outputOffset = _outputShape.offset; - float real_multiplier = 0.0; - int32_t output_multiplier = 0; - int32_t output_shift = 0; - int32_t output_activation_min = 0; - int32_t output_activation_max = 0; - // Caution : 'Convolution' can make misleading. It seems it is just math term. - if (!GetQuantizedConvolutionMultipler(_inputShape, _weightsShape, _biasShape, _outputShape, - &real_multiplier) || - !QuantizeMultiplierSmallerThanOne(real_multiplier, &output_multiplier, &output_shift)) - { - return false; - } - CalculateActivationRangeUint8(_activation, _outputShape, &output_activation_min, - &output_activation_max); - static gemmlowp::GemmContext gemm_context; - // Prevent concurrent executions that access gemm_context. - std::unique_lock<std::mutex> lock(executionMutex); - // Alow gemmlowp automatically decide how many threads to use. - gemm_context.set_max_num_threads(0); - ::tflite::optimized_ops::FullyConnected( - _inputData, convertShapeToDims(_inputShape), inputOffset, _weightsData, - convertShapeToDims(_weightsShape), weightsOffset, - reinterpret_cast<const int32_t *>(_biasData), convertShapeToDims(_biasShape), outputOffset, - output_multiplier, output_shift, output_activation_min, output_activation_max, _outputData, - convertShapeToDims(_outputShape), &gemm_context); - return true; + throw std::runtime_error{"FullyConnectedLayer : Not tested for TENSOR_QUANT8_ASYMM"}; } void FullyConnectedLayer::configure(uint8_t *inputData, const Shape inputShape, diff --git a/runtimes/neurun/src/kernel/cpu/FullyConnectedLayer.h b/runtimes/neurun/src/kernel/cpu/FullyConnectedLayer.h index b1ba172b0..20a388349 100644 --- a/runtimes/neurun/src/kernel/cpu/FullyConnectedLayer.h +++ b/runtimes/neurun/src/kernel/cpu/FullyConnectedLayer.h @@ -19,7 +19,7 @@ #include <NeuralNetworks.h> -#include <arm_compute/runtime/IFunction.h> +#include "exec/interface/IFunction.h" #include "kernel/cpu/OperationUtils.h" @@ -30,7 +30,7 @@ namespace kernel namespace cpu { -class FullyConnectedLayer : public ::arm_compute::IFunction +class FullyConnectedLayer : public ::neurun::exec::IFunction { public: FullyConnectedLayer(); diff --git a/runtimes/neurun/src/kernel/cpu/MaxPoolLayer.cc b/runtimes/neurun/src/kernel/cpu/MaxPoolLayer.cc index 3d96bb401..c4a288b07 100644 --- a/runtimes/neurun/src/kernel/cpu/MaxPoolLayer.cc +++ b/runtimes/neurun/src/kernel/cpu/MaxPoolLayer.cc @@ -26,14 +26,14 @@ namespace kernel namespace cpu { -#define MAXPOOLING_PARAMETERS \ - uint32_t height = getSizeOfDimension(_inputShape, 1); \ - uint32_t width = getSizeOfDimension(_inputShape, 2); \ - uint32_t outHeight = getSizeOfDimension(_outputShape, 1); \ - uint32_t outWidth = getSizeOfDimension(_outputShape, 2); \ - \ - uint32_t paddingHeight = (uint32_t)_paddingTop; \ - uint32_t paddingWidth = (uint32_t)_paddingLeft; +#define MAXPOOLING_PARAMETERS \ + tflite::PoolParams op_params; \ + op_params.stride_height = _strideHeight; \ + op_params.stride_width = _strideWidth; \ + op_params.filter_height = _kernelHeight; \ + op_params.filter_width = _kernelWidth; \ + op_params.padding_values.height = (int8_t)_paddingTop; \ + op_params.padding_values.width = (int8_t)_paddingLeft; MaxPoolLayer::MaxPoolLayer() : _inputData(nullptr), _outputData(nullptr), _inputShape(), _outputShape(), _paddingLeft(0), @@ -46,31 +46,30 @@ MaxPoolLayer::MaxPoolLayer() bool MaxPoolLayer::maxPoolFloat32() { - MAXPOOLING_PARAMETERS float output_activation_min, output_activation_max; CalculateActivationRangeFloat(_activation, &output_activation_min, &output_activation_max); + op_params.float_activation_min = output_activation_min; + op_params.float_activation_max = output_activation_max; - ::tflite::optimized_ops::MaxPool( - reinterpret_cast<const float *>(_inputData), convertShapeToDims(_inputShape), _strideWidth, - _strideHeight, paddingWidth, paddingHeight, _kernelWidth, _kernelHeight, - output_activation_min, output_activation_max, reinterpret_cast<float *>(_outputData), - convertShapeToDims(_outputShape)); + ::tflite::optimized_ops::MaxPool(op_params, convertShapeToTFLiteShape(_inputShape), + reinterpret_cast<const float *>(_inputData), + convertShapeToTFLiteShape(_outputShape), + reinterpret_cast<float *>(_outputData)); return true; } bool MaxPoolLayer::maxPoolQuant8() { - MAXPOOLING_PARAMETERS int32_t output_activation_min = 0; int32_t output_activation_max = 0; CalculateActivationRangeUint8(_activation, _outputShape, &output_activation_min, &output_activation_max); + op_params.quantized_activation_min = output_activation_min; + op_params.quantized_activation_max = output_activation_max; - ::tflite::optimized_ops::MaxPool(_inputData, convertShapeToDims(_inputShape), _strideWidth, - _strideHeight, paddingWidth, paddingHeight, _kernelWidth, - _kernelHeight, output_activation_min, output_activation_max, - _outputData, convertShapeToDims(_outputShape)); + ::tflite::optimized_ops::MaxPool(op_params, convertShapeToTFLiteShape(_inputShape), _inputData, + convertShapeToTFLiteShape(_outputShape), _outputData); return true; } diff --git a/runtimes/neurun/src/kernel/cpu/MaxPoolLayer.h b/runtimes/neurun/src/kernel/cpu/MaxPoolLayer.h index b42efb9f6..2b185550b 100644 --- a/runtimes/neurun/src/kernel/cpu/MaxPoolLayer.h +++ b/runtimes/neurun/src/kernel/cpu/MaxPoolLayer.h @@ -19,7 +19,7 @@ #include <NeuralNetworks.h> -#include <arm_compute/runtime/IFunction.h> +#include "exec/interface/IFunction.h" #include "kernel/cpu/OperationUtils.h" @@ -30,7 +30,7 @@ namespace kernel namespace cpu { -class MaxPoolLayer : public ::arm_compute::IFunction +class MaxPoolLayer : public ::neurun::exec::IFunction { public: MaxPoolLayer(); diff --git a/runtimes/neurun/src/kernel/cpu/OperationUtils.cc b/runtimes/neurun/src/kernel/cpu/OperationUtils.cc index 5ec2f8e62..b28508c27 100644 --- a/runtimes/neurun/src/kernel/cpu/OperationUtils.cc +++ b/runtimes/neurun/src/kernel/cpu/OperationUtils.cc @@ -184,7 +184,7 @@ int32_t CalculateInputRadius(int input_integer_bits, int input_left_shift) return static_cast<int32_t>(std::floor(max_input_rescaled)); } -Shape getShape(const ::neurun::graph::operand::Object &o) +Shape getShape(const ::neurun::model::operand::Object &o) { Shape shape; diff --git a/runtimes/neurun/src/kernel/cpu/OperationUtils.h b/runtimes/neurun/src/kernel/cpu/OperationUtils.h index 5914d04e3..3610990a5 100644 --- a/runtimes/neurun/src/kernel/cpu/OperationUtils.h +++ b/runtimes/neurun/src/kernel/cpu/OperationUtils.h @@ -23,11 +23,13 @@ #include <limits> #include <vector> +#include "tensorflow/contrib/lite/c/builtin_op_data.h" #include "tensorflow/contrib/lite/kernels/internal/types.h" -#include "graph/operand/Object.h" -#include "graph/operand/DataType.h" +#include "tensorflow/contrib/lite/kernels/internal/tensor.h" +#include "model/operand/Object.h" +#include "model/operand/DataType.h" -using OperandType = neurun::graph::operand::DataType; +using OperandType = neurun::model::operand::DataType; namespace neurun { @@ -75,6 +77,51 @@ inline ::tflite::Dims<4> convertShapeToDims(const Shape &shape) return dims; } +inline ::tflite::RuntimeShape convertShapeToTFLiteShape(const Shape &shape) +{ + std::vector<int32_t> raw_shape; + raw_shape.resize(4); + + for (uint32_t i = 0; i < 4; ++i) + { + if (i >= shape.dimensions.size()) + { + raw_shape[i] = 1; + } + else + { + raw_shape[i] = shape.dimensions[i]; + } + } + + return ::tflite::GetTensorShape(raw_shape); +} + +inline TfLiteFusedActivation convertFusedActivation(FuseCode act) +{ + if (act == ANEURALNETWORKS_FUSED_NONE) + { + return kTfLiteActNone; + } + + if (act == ANEURALNETWORKS_FUSED_RELU) + { + return kTfLiteActRelu; + } + + if (act == ANEURALNETWORKS_FUSED_RELU1) + { + return kTfLiteActRelu1; + } + + if (act == ANEURALNETWORKS_FUSED_RELU6) + { + return kTfLiteActRelu6; + } + + return kTfLiteActNone; +} + __wur bool QuantizeMultiplierSmallerThanOne(double double_multiplier, int32_t *quantized_multiplier, int32_t *right_shift); @@ -92,7 +139,7 @@ void CalculateActivationRangeUint8(int32_t activation, const Shape &outputShape, int32_t CalculateInputRadius(int input_integer_bits, int input_left_shift); -Shape getShape(const ::neurun::graph::operand::Object &o); +Shape getShape(const ::neurun::model::operand::Object &o); uint32_t sizeOfData(OperandType type, const std::vector<uint32_t> &dimensions); diff --git a/runtimes/neurun/src/kernel/cpu/PermuteLayer.cc b/runtimes/neurun/src/kernel/cpu/PermuteLayer.cc new file mode 100644 index 000000000..ba8c5ab92 --- /dev/null +++ b/runtimes/neurun/src/kernel/cpu/PermuteLayer.cc @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2018 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 "PermuteLayer.h" + +#include "util/feature/nhwc/Reader.h" +#include "util/feature/nhwc/View.h" +#include "util/feature/nchw/View.h" +#include "util/feature/Coordinate4D.h" + +#include <misc/feature/IndexIterator.h> + +namespace neurun +{ +namespace kernel +{ +namespace cpu +{ + +using Type = model::operation::PermuteNode::Type; + +void PermuteLayer::configure(std::shared_ptr<::neurun::backend::operand::IObject> input, + std::shared_ptr<::neurun::backend::operand::IObject> output, + const model::operand::Shape &shape, Type type) +{ + _input = input; + _output = output; + _shape = shape; + _type = type; +} + +void PermuteLayer::run() +{ + auto rank = _shape.rank(); + + switch (_type) + { + case Type::NHWC_TO_NCHW: + { + auto fn = [&](::neurun::backend::operand::ITensor &tensor) { + auto input_tensor = _input->ptr(); + + auto input_buffer = input_tensor->buffer(); + auto input_size = input_tensor->total_size(); + + auto output_buffer = tensor.buffer(); + auto output_size = tensor.total_size(); + switch (rank) + { + case 0: + case 1: + { + memcpy(output_buffer, input_buffer, input_size); + break; + } + case 2: + { + auto matrix_shape = _shape.asMatrix(); + + for (auto h = 0; h < matrix_shape.H; ++h) + { + neurun::util::feature::Coordinate4D coord{0, h, 0, 0}; + memcpy(output_buffer + tensor.calcOffset(coord), input_buffer + h * matrix_shape.W, + matrix_shape.W * sizeof(float)); + } + break; + } + case 3: + { + const int32_t depth = _shape.dim(0); + const int32_t height = _shape.dim(1); + const int32_t width = _shape.dim(2); + + for (auto c = 0; c < depth; ++c) + { + for (auto h = 0; h < height; ++h) + { + neurun::util::feature::Coordinate4D coord{0, h, 0, c}; + memcpy(output_buffer + tensor.calcOffset(coord), + input_buffer + c * height * width + h * width, width * sizeof(float)); + } + } + break; + } + case 4: + { + auto feature = _shape.asFeature(); + + const util::feature::nhwc::Reader<float> from{ + feature, reinterpret_cast<const float *>(input_buffer), input_size}; + util::feature::nchw::View<float> into{&tensor}; + + ::nnfw::misc::feature::iterate(feature) + << [&](uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) { + const auto value = from.at(batch, ch, row, col); + into.at(batch, ch, row, col) = value; + }; + break; + } + default: + throw "NYI"; + break; + } + }; + _output->access(fn); + break; + } + case Type::NCHW_TO_NHWC: + { + auto fn = [&](::neurun::backend::operand::ITensor &tensor) { + auto input_buffer = tensor.buffer(); + auto input_size = tensor.total_size(); + + auto output_tensor = _output->ptr(); + + auto output_buffer = output_tensor->buffer(); + auto output_size = output_tensor->total_size(); + + switch (rank) + { + case 0: + case 1: + { + memcpy(output_buffer, input_buffer, output_size); + break; + } + case 2: + { + auto matrix_shape = _shape.asMatrix(); + + for (auto h = 0; h < matrix_shape.H; ++h) + { + neurun::util::feature::Coordinate4D coord{0, h, 0, 0}; + memcpy(output_buffer + h * matrix_shape.W, input_buffer + tensor.calcOffset(coord), + matrix_shape.W * sizeof(float)); + } + break; + } + case 3: + { + const int32_t depth = _shape.dim(0); + const int32_t height = _shape.dim(1); + const int32_t width = _shape.dim(2); + + for (auto c = 0; c < depth; ++c) + { + for (auto h = 0; h < height; ++h) + { + neurun::util::feature::Coordinate4D coord{0, h, 0, c}; + memcpy(output_buffer + c * height * width + h * width, + input_buffer + tensor.calcOffset(coord), width * sizeof(float)); + } + } + break; + } + case 4: + { + auto feature = _shape.asFeature(); + + const util::feature::nchw::View<float> from{&tensor}; + util::feature::nhwc::View<float> into{feature, reinterpret_cast<float *>(output_buffer), + output_size}; + + ::nnfw::misc::feature::iterate(feature) + << [&](uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) { + const auto value = from.at(batch, ch, row, col); + into.at(batch, ch, row, col) = value; + }; + break; + } + default: + throw "NYI"; + break; + } + }; + _input->access(fn); + break; + } + case Type::COPY: + // If two different backends using same tensor layout, we need this. + throw "NYI"; + break; + } +} + +} // namespace cpu +} // namespace kernel +} // namespace neurun diff --git a/runtimes/neurun/src/kernel/cpu/PermuteLayer.h b/runtimes/neurun/src/kernel/cpu/PermuteLayer.h new file mode 100644 index 000000000..d9e1709bc --- /dev/null +++ b/runtimes/neurun/src/kernel/cpu/PermuteLayer.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2018 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 __NEURUN_KERNEL_CPU_PERMUTE_LAYER_H__ +#define __NEURUN_KERNEL_CPU_PERMUTE_LAYER_H__ + +#include <NeuralNetworks.h> + +#include "exec/interface/IFunction.h" + +#include "util/feature/nhwc/View.h" +#include "OperationUtils.h" +#include "backend/interface/operand/IObject.h" +#include "model/operation/PermuteNode.h" + +namespace neurun +{ +namespace kernel +{ +namespace cpu +{ + +class PermuteLayer : public ::neurun::exec::IFunction +{ +public: + PermuteLayer() = default; + +public: + void configure(std::shared_ptr<::neurun::backend::operand::IObject> input, + std::shared_ptr<::neurun::backend::operand::IObject> output, + const model::operand::Shape &shape, model::operation::PermuteNode::Type type); + void run(); + +private: + std::shared_ptr<::neurun::backend::operand::IObject> _input; + std::shared_ptr<::neurun::backend::operand::IObject> _output; + model::operand::Shape _shape; + model::operation::PermuteNode::Type _type; +}; + +} // namespace cpu +} // namespace kernel +} // namespace neurun + +#endif // __NEURUN_KERNEL_CPU_PERMUTE_LAYER_H__ diff --git a/runtimes/neurun/src/kernel/cpu/ReshapeLayer.h b/runtimes/neurun/src/kernel/cpu/ReshapeLayer.h index 395cc1d7f..51d0bacee 100644 --- a/runtimes/neurun/src/kernel/cpu/ReshapeLayer.h +++ b/runtimes/neurun/src/kernel/cpu/ReshapeLayer.h @@ -19,7 +19,7 @@ #include <NeuralNetworks.h> -#include <arm_compute/runtime/IFunction.h> +#include "exec/interface/IFunction.h" #include "kernel/cpu/OperationUtils.h" @@ -30,7 +30,7 @@ namespace kernel namespace cpu { -class ReshapeLayer : public ::arm_compute::IFunction +class ReshapeLayer : public ::neurun::exec::IFunction { public: ReshapeLayer(); diff --git a/runtimes/neurun/src/kernel/cpu/SoftMaxLayer.cc b/runtimes/neurun/src/kernel/cpu/SoftMaxLayer.cc index 4f5a69f2e..c998c65f6 100644 --- a/runtimes/neurun/src/kernel/cpu/SoftMaxLayer.cc +++ b/runtimes/neurun/src/kernel/cpu/SoftMaxLayer.cc @@ -33,45 +33,86 @@ SoftMaxLayer::SoftMaxLayer() // DO NOTHING } +// Performs softmax along the input of size (input_size * batch_size). +void Softmax(const float *in, const int input_size, const int batch_size, const float beta, + float *out) +{ + TF_LITE_ASSERT(input_size > 0); + + // For each batch + for (int b = 0; b < batch_size; b++) + { + // Find the max coeff. + float max_coeff = in[0]; + for (int i = 1; i < input_size; i++) + { + if (in[i] > max_coeff) + max_coeff = in[i]; + } + + // Compute the normalized sum of exps. + float exp_sum = 0.0; + for (int i = 0; i < input_size; i++) + { + out[i] = std::exp((in[i] - max_coeff) * beta); + exp_sum += out[i]; + } + + // Divide by the sum of exps. + float reciprocal_sum_exp = 1.f / exp_sum; + for (int i = 0; i < input_size; i++) + { + out[i] *= reciprocal_sum_exp; + } + + // Advance in and out pointers for the next batch. + in += input_size; + out += input_size; + } +} + bool SoftMaxLayer::softmaxFloat32() { - ::tflite::Dims<4> dim; + Shape shapeIn4D; + if (getNumberOfDimensions(_inputShape) == 2) { uint32_t batch_size = getSizeOfDimension(_inputShape, 0); uint32_t input_size = getNumberOfElements(_inputShape) / batch_size; - Shape shapeIn4D; - shapeIn4D.dimensions = {batch_size, 1, 1, input_size}; - dim = convertShapeToDims(shapeIn4D); + Softmax(reinterpret_cast<const float *>(_inputData), input_size, batch_size, _beta, + reinterpret_cast<float *>(_outputData)); } else if (getNumberOfDimensions(_inputShape) == 4) { - dim = convertShapeToDims(_inputShape); + ::tflite::SoftmaxParams op_params; + op_params.beta = _beta; + ::tflite::optimized_ops::Softmax(op_params, convertShapeToTFLiteShape(_inputShape), + reinterpret_cast<const float *>(_inputData), + convertShapeToTFLiteShape(_outputShape), + reinterpret_cast<float *>(_outputData)); } else { std::cout << "only 2D and 4D tensors supported" << std::endl; return false; } - ::tflite::optimized_ops::Softmax(reinterpret_cast<const float *>(_inputData), dim, _beta, - reinterpret_cast<float *>(_outputData), dim); + return true; } bool SoftMaxLayer::softmaxQuant8() { - ::tflite::Dims<4> dim; + Shape shapeIn4D = _inputShape; + if (getNumberOfDimensions(_inputShape) == 2) { uint32_t batch_size = getSizeOfDimension(_inputShape, 0); uint32_t input_size = getNumberOfElements(_inputShape) / batch_size; - Shape shapeIn4D; shapeIn4D.dimensions = {batch_size, 1, 1, input_size}; - dim = convertShapeToDims(shapeIn4D); } else if (getNumberOfDimensions(_inputShape) == 4) { - dim = convertShapeToDims(_inputShape); + shapeIn4D = _inputShape; } else { @@ -94,8 +135,13 @@ bool SoftMaxLayer::softmaxQuant8() return false; } float diff_min = -1.0f * CalculateInputRadius(kScaledDiffIntegerBits, input_left_shift); - ::tflite::optimized_ops::Softmax(_inputData, dim, input_multiplier, input_left_shift, diff_min, - _outputData, dim); + + ::tflite::SoftmaxParams op_params; + op_params.input_multiplier = input_multiplier; + op_params.input_left_shift = input_left_shift; + op_params.diff_min = diff_min; + ::tflite::optimized_ops::Softmax(op_params, convertShapeToTFLiteShape(shapeIn4D), _inputData, + convertShapeToTFLiteShape(shapeIn4D), _outputData); return true; } diff --git a/runtimes/neurun/src/kernel/cpu/SoftMaxLayer.h b/runtimes/neurun/src/kernel/cpu/SoftMaxLayer.h index 8057be52f..df1aa4044 100644 --- a/runtimes/neurun/src/kernel/cpu/SoftMaxLayer.h +++ b/runtimes/neurun/src/kernel/cpu/SoftMaxLayer.h @@ -19,7 +19,7 @@ #include <NeuralNetworks.h> -#include <arm_compute/runtime/IFunction.h> +#include "exec/interface/IFunction.h" #include "kernel/cpu/OperationUtils.h" @@ -30,7 +30,7 @@ namespace kernel namespace cpu { -class SoftMaxLayer : public ::arm_compute::IFunction +class SoftMaxLayer : public ::neurun::exec::IFunction { public: SoftMaxLayer(); diff --git a/runtimes/neurun/src/kernel/cpu/TensorConvertFromCommonLayer.cc b/runtimes/neurun/src/kernel/cpu/TensorConvertFromCommonLayer.cc deleted file mode 100644 index 00e914732..000000000 --- a/runtimes/neurun/src/kernel/cpu/TensorConvertFromCommonLayer.cc +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2018 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. - */ - -// -// THIS FILE IS UNUSED BUT LEFT FOR FUTURE REFERNCE -// - -#if 0 - -#include "TensorConvertFromCommonLayer.h" - -#include "internal/nnapi/feature/Reader.h" -#include "internal/nnapi/feature/View.h" - -#include <util/feature/IndexIterator.h> - -namespace neurun -{ -namespace kernel -{ -namespace cpu -{ - -bool TensorConvertFromCommonLayer::convert() -{ - auto inputBuffer = _inputTensor->buffer(); - auto inputSize = _inputTensor->info()->total_size(); - - auto outputBuffer = _outputTensor->buffer(); - auto outputSize = _outputTensor->info()->total_size(); - - if (_tensorShape.rank() == 2) - { - const auto len = _tensorShape.dim(1); - - auto base = reinterpret_cast<const float *>(inputBuffer); - - for (int32_t n = 0; n < len; ++n) - { - auto from = base + n; - auto into = - reinterpret_cast<float *>(_outputTensor->ptr_to_element(::arm_compute::Coordinates{n})); - - *into = *from; - } - } - else if (_tensorShape.rank() == 4) - { - auto featureShape = _tensorShape.asFeature(); - - const ::internal::nnapi::feature::Reader<float> from{featureShape, inputBuffer, inputSize}; - ::internal::nnapi::feature::View<float> into{featureShape, outputBuffer, outputSize}; - - ::nnfw::util::feature::iterate(featureShape) - << [&](uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) { - const auto value = from.at(batch, ch, row, col); - into.at(batch, ch, row, col) = value; - }; - } -} - -void TensorConvertFromCommonLayer::configure(::internal::common::Tensor *inputTensor, - ::internal::cpu::Tensor *outputTensor, - const Shape &tensorShape) -{ - _inputTensor = inputTensor; - _outputTensor = outputTensor; - _tensorShape = tensorShape; -} - -void TensorConvertFromCommonLayer::run() { convert(); } - -} // namespace cpu -} // namespace kernel -} // namespace neurun - -#endif diff --git a/runtimes/neurun/src/kernel/cpu/TensorConvertFromCommonLayer.h b/runtimes/neurun/src/kernel/cpu/TensorConvertFromCommonLayer.h deleted file mode 100644 index 56f7bcf32..000000000 --- a/runtimes/neurun/src/kernel/cpu/TensorConvertFromCommonLayer.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2018 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. - */ - -// -// THIS FILE IS UNUSED BUT LEFT FOR FUTURE REFERNCE -// - -#if 0 - -#ifndef __NEURUN_KERNEL_CPU_TENSOR_CONVERT_FROM_COMMON_LAYER_H__ -#define __NEURUN_KERNEL_CPU_TENSOR_CONVERT_FROM_COMMON_LAYER_H__ - -#include <NeuralNetworks.h> - -#include <arm_compute/runtime/IFunction.h> - -#include "internal/Model.h" -#include "internal/common/Tensor.h" -#include "internal/cpu.h" - -namespace neurun -{ -namespace kernel -{ -namespace cpu -{ - -class TensorConvertFromCommonLayer : public ::arm_compute::IFunction -{ -public: - TensorConvertFromCommonLayer() {} - -public: - bool convert(); - - void configure(::internal::common::Tensor *inputTensor, ::internal::cpu::Tensor *outputTensor, - const Shape &tensorShape); - - void run(); - -private: - ::internal::common::Tensor *_inputTensor; - ::internal::cpu::Tensor *_outputTensor; - - Shape _tensorShape{1}; -}; - -} // namespace cpu -} // namespace kernel -} // namespace neurun - -#endif // __NEURUN_KERNEL_CPU_TENSOR_CONVERT_FROM_COMMON_LAYER_H__ - -#endif diff --git a/runtimes/neurun/src/kernel/cpu/TensorConvertToCommonLayer.cc b/runtimes/neurun/src/kernel/cpu/TensorConvertToCommonLayer.cc deleted file mode 100644 index 7d721f494..000000000 --- a/runtimes/neurun/src/kernel/cpu/TensorConvertToCommonLayer.cc +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2018 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. - */ - -// -// THIS FILE IS UNUSED BUT LEFT FOR FUTURE REFERNCE -// - -#if 0 - -#include "TensorConvertToCommonLayer.h" - -#include "internal/nnapi/feature/Reader.h" -#include "internal/nnapi/feature/View.h" - -#include <util/feature/IndexIterator.h> - -namespace neurun -{ -namespace kernel -{ -namespace cpu -{ - -bool TensorConvertToCommonLayer::convert() -{ - auto inputBuffer = _inputTensor->buffer(); - auto inputSize = _inputTensor->info()->total_size(); - - auto outputBuffer = _outputTensor->buffer(); - auto outputSize = _outputTensor->info()->total_size(); - - if (_tensorShape.rank() == 2) - { - const auto len = _tensorShape.dim(1); - - auto base = reinterpret_cast<float *>(outputBuffer); - - for (int32_t n = 0; n < len; ++n) - { - auto from = reinterpret_cast<const float *>( - _inputTensor->ptr_to_element(::arm_compute::Coordinates{n})); - auto into = base + n; - - *into = *from; - } - } - else if (_tensorShape.rank() == 4) - { - auto featureShape = _tensorShape.asFeature(); - - const ::internal::nnapi::feature::Reader<float> from{featureShape, inputBuffer, inputSize}; - ::internal::nnapi::feature::View<float> into{featureShape, outputBuffer, outputSize}; - - ::nnfw::util::feature::iterate(featureShape) - << [&](uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) { - const auto value = from.at(batch, ch, row, col); - into.at(batch, ch, row, col) = value; - }; - } -} - -void TensorConvertToCommonLayer::configure(::internal::cpu::Tensor *inputTensor, - ::internal::common::Tensor *outputTensor, - const Shape &tensorShape) -{ - _inputTensor = inputTensor; - _outputTensor = outputTensor; - _tensorShape = tensorShape; -} - -void TensorConvertToCommonLayer::run() { convert(); } - -} // namespace cpu -} // namespace kernel -} // namespace neurun - -#endif diff --git a/runtimes/neurun/src/kernel/cpu/TensorConvertToCommonLayer.h b/runtimes/neurun/src/kernel/cpu/TensorConvertToCommonLayer.h deleted file mode 100644 index 7e96d1aff..000000000 --- a/runtimes/neurun/src/kernel/cpu/TensorConvertToCommonLayer.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2018 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. - */ - -// -// THIS FILE IS UNUSED BUT LEFT FOR FUTURE REFERNCE -// - -#if 0 - -#ifndef __NEURUN_KERNEL_CPU_TENSOR_CONVERT_TO_COMMON_LAYER_H__ -#define __NEURUN_KERNEL_CPU_TENSOR_CONVERT_TO_COMMON_LAYER_H__ - -#include <NeuralNetworks.h> - -#include <arm_compute/runtime/IFunction.h> - -#include "internal/Model.h" -#include "internal/common/Tensor.h" -#include "internal/cpu.h" - -namespace neurun -{ -namespace kernel -{ -namespace cpu -{ - -class TensorConvertToCommonLayer : public ::arm_compute::IFunction -{ -public: - TensorConvertToCommonLayer() {} - -public: - bool convert(); - - void configure(::internal::cpu::Tensor *inputTensor, ::internal::common::Tensor *outputTensor, - const Shape &tensorShape); - - void run(); - -private: - ::internal::cpu::Tensor *_inputTensor; - ::internal::common::Tensor *_outputTensor; - - Shape _tensorShape{1}; -}; - -} // namespace cpu -} // namespace kernel -} // namespace neurun - -#endif // __NEURUN_KERNEL_CPU_TENSOR_CONVERT_TO_COMMON_LAYER_H__ - -#endif diff --git a/runtimes/neurun/src/linear/Linear.cc b/runtimes/neurun/src/linear/Linear.cc index 2ffcbdb93..6452bbd49 100644 --- a/runtimes/neurun/src/linear/Linear.cc +++ b/runtimes/neurun/src/linear/Linear.cc @@ -14,19 +14,26 @@ * limitations under the License. */ +#include <algorithm> + #include "Linear.h" #include "graph/Graph.h" #include "graph/operation/LowerInfo.h" -#include "backend/IStageGenerator.h" +#include "backend/interface/IStageGenerator.h" +#include "backend/interface/IConfig.h" +#include "compiler/SubTensorInfo.h" +#include "compiler/TensorInfo.h" + +#include "util/logging.h" namespace neurun { namespace linear { -Linear::Linear(const graph::Graph &graph) +Linear::Linear(const graph::Graph &graph) : _graph(graph) { // Linearize with topological sort // @@ -36,38 +43,157 @@ Linear::Linear(const graph::Graph &graph) // 3. Reverse the order of nodes graph::Graph::PostDfsConstIterator().iterate( - graph, [&](const neurun::graph::operation::Node &node) { _operations.emplace_back(&node); }); + graph, [&](const model::operation::Index &index, const model::operation::Node &node) { + const auto lower_info = graph.getLowerInfo(index); + _operations.emplace_back(&node, lower_info); + }); std::reverse(std::begin(_operations), std::end(_operations)); } -void Linear::accept(graph::operation::NodeVisitor &&visitor) const +void Linear::accept(model::operation::NodeVisitor &&visitor) const { for (const auto op : _operations) { - op->accept(std::move(visitor)); + op.node->accept(std::move(visitor)); } } -backend::TensorBuilderSet Linear::markTensors() const +backend::TensorBuilderSet Linear::planTensors() { + using ITensorBuilderPtr = std::shared_ptr<backend::ITensorBuilder>; + using FnOnTensorBuilder = + std::function<void(const model::operand::Index &ind, ITensorBuilderPtr)>; + + const auto &operands = _graph.operands(); + auto iterTensorBuilders = [&operands](const model::operand::Index &ind, FnOnTensorBuilder fn) { + const auto &obj = operands.at(ind); + for (auto backend : obj.lower_info()->def_backends()) + { + auto tensor_builder = backend->tensor_builder(); + fn(ind, tensor_builder); + } + }; + backend::TensorBuilderSet tensor_builders; + + std::unordered_map<model::operand::Index, uint32_t> uses_map; + std::vector<model::operand::Index> constants; + + _graph.operands().iterate( + [&](const model::operand::Index &ind, const model::operand::Object &obj) { + uses_map[ind] = obj.getUses().size(); + + // If a tensor is a constant, increase the use of the tensor. + // It makes the tensor not be dealloced. + if (obj.getUsage() == model::operand::OperandUsage::CONSTANT) + { + constants.push_back(ind); + uses_map[ind]++; + } + + for (auto backend : obj.lower_info()->def_backends()) + { + bool isSubTensor = false; + auto tensor_builder = backend->tensor_builder(); + + if (backend->config()->SupportSubTensorAlloc()) + { + const auto parentInfo = obj.parent_info(); + if (parentInfo != nullptr) + { + isSubTensor = true; + } + } + + if (isSubTensor) + { + const compiler::SubTensorInfo info(obj); + tensor_builder->registerSubTensorInfo(ind, info); + } + else + { + const auto info = compiler::TensorInfo(obj.shape(), obj.typeInfo()); + tensor_builder->registerTensorInfo(ind, info); + } + + // Prepare tensor builders to be returned + tensor_builders.insert(tensor_builder); + } + }); + + // If a tensor is model output, increase the use of the tensor. + // This aim is same to above one. + for (const auto &ind : _graph.getOutputs()) + { + uses_map[ind]++; + } + + // Allocate constant operands first + VERBOSE(LINEAR) << "TENSORS as CONSTANT" << std::endl; + for (const auto &ind : constants) + { + iterTensorBuilders(ind, [](const model::operand::Index &ind, ITensorBuilderPtr tensor_builder) { + tensor_builder->notifyFirstUse(ind); + }); + } + + // Allocate Model's inputs + VERBOSE(LINEAR) << "TENSORS as MODEL INPUT" << std::endl; + for (const auto &ind : _graph.getInputs()) + { + iterTensorBuilders(ind, [](const model::operand::Index &ind, ITensorBuilderPtr tensor_builder) { + tensor_builder->notifyFirstUse(ind); + }); + } + + // At each operation, + // 1. Scan USE of inputs. Decrease the USE and deallocate if the USE is 0 + // 2. Scan DEF of outputs. If the DEF, allocate it + VERBOSE(LINEAR) << "TENSORS" << std::endl; for (const auto op : _operations) { - const auto tensor_builder = op->lower_info()->backend().stage_gen()->tensor_builder(); - for (const auto &ind : op->getInputs()) + for (const auto &ind : op.node->getOutputs()) { - tensor_builder->mark(ind); - tensor_builders.insert(tensor_builder); + const auto &obj = operands.at(ind); + if (obj.getDef().size()) + { + iterTensorBuilders(ind, + [](const model::operand::Index &ind, ITensorBuilderPtr tensor_builder) { + tensor_builder->notifyFirstUse(ind); + }); + } } - for (const auto &ind : op->getOutputs()) + + for (const auto &ind : op.node->getInputs()) { - tensor_builder->mark(ind); - tensor_builders.insert(tensor_builder); + uses_map[ind]--; + if (uses_map[ind] == 0) + { + iterTensorBuilders(ind, + [](const model::operand::Index &ind, ITensorBuilderPtr tensor_builder) { + tensor_builder->notifyLastUse(ind); + }); + } } } + + // Now, model outputs should be not deallocated + assert(std::all_of(_graph.getOutputs().begin(), _graph.getOutputs().end(), + [&uses_map](const model::operand::Index &ind) { return uses_map[ind] > 0; })); + + // Set subtensor information + // Todo: move this phase outside as optimization phase return tensor_builders; } +void Linear::iterate(const std::function<void(const Element &element)> &fn) const +{ + for (const auto op : _operations) + { + fn(op); + } +} + } // namespace linear } // namespace neurun diff --git a/runtimes/neurun/src/linear/Linear.h b/runtimes/neurun/src/linear/Linear.h index ffbc68ecb..fb3f539d4 100644 --- a/runtimes/neurun/src/linear/Linear.h +++ b/runtimes/neurun/src/linear/Linear.h @@ -19,8 +19,8 @@ #include <vector> -#include "graph/operation/Node.h" -#include "backend/ITensorBuilder.h" +#include "model/operation/Node.h" +#include "backend/interface/ITensorBuilder.h" namespace neurun { @@ -46,6 +46,17 @@ namespace neurun namespace linear { +struct Element +{ + const model::operation::Node *node; + const graph::operation::LowerInfo *lower_info; + + Element(const model::operation::Node *node, const graph::operation::LowerInfo *lower_info) + : node{node}, lower_info{lower_info} + { + } +}; + class Linear { public: @@ -55,14 +66,16 @@ public: Linear(const Linear &linear) = delete; public: - void accept(graph::operation::NodeVisitor &&visitor) const; + void accept(model::operation::NodeVisitor &&visitor) const; // TODO Should not return TensorBuilderSet - virtual backend::TensorBuilderSet markTensors() const; + backend::TensorBuilderSet planTensors(); + + void iterate(const std::function<void(const Element &element)> &fn) const; -public: private: - std::vector<const graph::operation::Node *> _operations; + const graph::Graph &_graph; + std::vector<Element> _operations; }; } // namespace linear diff --git a/runtimes/neurun/src/graph/operand/Data.h b/runtimes/neurun/src/model/operand/Data.h index e36a9a2ae..506cb185a 100644 --- a/runtimes/neurun/src/graph/operand/Data.h +++ b/runtimes/neurun/src/model/operand/Data.h @@ -14,14 +14,14 @@ * limitations under the License. */ -#ifndef __NEURUN_GRAPH_OPERAND_DATA_H__ -#define __NEURUN_GRAPH_OPERAND_DATA_H__ +#ifndef __NEURUN_MODEL_OPERAND_DATA_H__ +#define __NEURUN_MODEL_OPERAND_DATA_H__ #include <algorithm> namespace neurun { -namespace graph +namespace model { namespace operand { @@ -72,7 +72,7 @@ private: }; } // namespace operand -} // namespace graph +} // namespace model } // namespace neurun -#endif // __NEURUN_GRAPH_OPERAND_DATA_H__ +#endif // __NEURUN_MODEL_OPERAND_DATA_H__ diff --git a/runtimes/neurun/src/graph/operand/DataType.h b/runtimes/neurun/src/model/operand/DataType.h index 8878901fd..d75a0dbf1 100644 --- a/runtimes/neurun/src/graph/operand/DataType.h +++ b/runtimes/neurun/src/model/operand/DataType.h @@ -14,12 +14,12 @@ * limitations under the License. */ -#ifndef __NEURUN_GRAPH_OPERAND_DATATYPE_H__ -#define __NEURUN_GRAPH_OPERAND_DATATYPE_H__ +#ifndef __NEURUN_MODEL_OPERAND_DATATYPE_H__ +#define __NEURUN_MODEL_OPERAND_DATATYPE_H__ namespace neurun { -namespace graph +namespace model { namespace operand { @@ -37,7 +37,7 @@ enum class DataType }; } // namespace operand -} // namespace graph +} // namespace model } // namespace neurun -#endif // __NEURUN_GRAPH_OPERAND_DATATYPE_H__ +#endif // __NEURUN_MODEL_OPERAND_DATATYPE_H__ diff --git a/runtimes/neurun/src/graph/operand/Index.h b/runtimes/neurun/src/model/operand/Index.h index a6850d061..1c84ba451 100644 --- a/runtimes/neurun/src/graph/operand/Index.h +++ b/runtimes/neurun/src/model/operand/Index.h @@ -14,14 +14,14 @@ * limitations under the License. */ -#ifndef __NEURUN_GRAPH_OPERAND_INDEX_H__ -#define __NEURUN_GRAPH_OPERAND_INDEX_H__ +#ifndef __NEURUN_MODEL_OPERAND_INDEX_H__ +#define __NEURUN_MODEL_OPERAND_INDEX_H__ #include "graph/Index.h" namespace neurun { -namespace graph +namespace model { namespace operand { @@ -29,12 +29,12 @@ namespace operand using Index = ::neurun::graph::Index<uint32_t, struct IndexTag>; } // namespace operand -} // namespace graph +} // namespace model } // namespace neurun namespace neurun { -namespace graph +namespace model { namespace operand { @@ -45,7 +45,7 @@ using Index = ::neurun::graph::Index<uint32_t, struct IndexTag>; } // namespace IO } // namespace operand -} // namespace graph +} // namespace model } // namespace neurun -#endif // __NEURUN_GRAPH_OPERAND_INDEX_H__ +#endif // __NEURUN_MODEL_OPERAND_INDEX_H__ diff --git a/runtimes/neurun/src/graph/operand/IndexSet.cc b/runtimes/neurun/src/model/operand/IndexSet.cc index 037965a6d..b83d314e4 100644 --- a/runtimes/neurun/src/graph/operand/IndexSet.cc +++ b/runtimes/neurun/src/model/operand/IndexSet.cc @@ -20,7 +20,7 @@ namespace neurun { -namespace graph +namespace model { namespace operand { @@ -51,6 +51,11 @@ bool IndexSet::contains(const Index &index) const return std::find(_set.begin(), _set.end(), index) != _set.end(); } +void IndexSet::replace(const Index &from, const Index &to) +{ + std::replace(_set.begin(), _set.end(), from, to); +} + } // namespace operand -} // namespace graph +} // namespace model } // namespace neurun diff --git a/runtimes/neurun/src/graph/operand/IndexSet.h b/runtimes/neurun/src/model/operand/IndexSet.h index 2d37de788..e8827de9c 100644 --- a/runtimes/neurun/src/graph/operand/IndexSet.h +++ b/runtimes/neurun/src/model/operand/IndexSet.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef __NEURUN_GRAPH_OPERAND_INDEX_SET_H__ -#define __NEURUN_GRAPH_OPERAND_INDEX_SET_H__ +#ifndef __NEURUN_MODEL_OPERAND_INDEX_SET_H__ +#define __NEURUN_MODEL_OPERAND_INDEX_SET_H__ #include <initializer_list> #include <vector> @@ -24,7 +24,7 @@ namespace neurun { -namespace graph +namespace model { namespace operand { @@ -45,6 +45,7 @@ public: const Index &at(IO::Index set_index) const { return _set.at(set_index.asInt()); } const Index &at(uint32_t index) const { return _set.at(index); } bool contains(const Index &index) const; + void replace(const Index &from, const Index &to); public: std::vector<Index>::const_iterator begin(void) const { return _set.begin(); } @@ -55,7 +56,7 @@ private: }; } // namespace operand -} // namespace graph +} // namespace model } // namespace neurun -#endif // __NEURUN_GRAPH_OPERAND_INDEX_SET_H__ +#endif // __NEURUN_MODEL_OPERAND_INDEX_SET_H__ diff --git a/runtimes/neurun/src/graph/operand/Object.cc b/runtimes/neurun/src/model/operand/Object.cc index 7b95cea97..63cf29bd3 100644 --- a/runtimes/neurun/src/graph/operand/Object.cc +++ b/runtimes/neurun/src/model/operand/Object.cc @@ -18,7 +18,7 @@ namespace neurun { -namespace graph +namespace model { namespace operand { @@ -73,7 +73,7 @@ bool Object::setUsage(const OperandUsage usage) return true; } -void Object::appendUse(const ::neurun::graph::operation::Index &idx) +void Object::appendUse(const ::neurun::model::operation::Index &idx) { assert(_usage != OperandUsage::NOT_DEFINED); assert(!_uses.contains(idx)); @@ -81,7 +81,7 @@ void Object::appendUse(const ::neurun::graph::operation::Index &idx) _uses.append(idx); } -void Object::removeUse(const ::neurun::graph::operation::Index &idx) +void Object::removeUse(const ::neurun::model::operation::Index &idx) { assert(_usage != OperandUsage::NOT_DEFINED); assert(_uses.contains(idx)); @@ -89,7 +89,7 @@ void Object::removeUse(const ::neurun::graph::operation::Index &idx) _uses.remove(idx); } -void Object::appendDef(const ::neurun::graph::operation::Index &idx) +void Object::appendDef(const ::neurun::model::operation::Index &idx) { assert(_usage != OperandUsage::NOT_DEFINED && _usage != OperandUsage::CONSTANT); assert(_def.size() == 0); @@ -97,7 +97,7 @@ void Object::appendDef(const ::neurun::graph::operation::Index &idx) _def.append(idx); } -void Object::removeDef(const ::neurun::graph::operation::Index &idx) +void Object::removeDef(const ::neurun::model::operation::Index &idx) { assert(_usage != OperandUsage::NOT_DEFINED); assert(_def.contains(idx)); @@ -105,13 +105,24 @@ void Object::removeDef(const ::neurun::graph::operation::Index &idx) _def.remove(idx); } -void Object::lower_info(std::unique_ptr<LowerInfo> &&lower_info) +void Object::lower_info(std::unique_ptr<graph::operand::LowerInfo> &&lower_info) { _lower_info = std::move(lower_info); } -const LowerInfo *Object::lower_info() const { return _lower_info.get(); } +const graph::operand::LowerInfo *Object::lower_info() const { return _lower_info.get(); } + +graph::operand::LowerInfo *Object::lower_info() { return _lower_info.get(); } + +void Object::parent_info(std::unique_ptr<graph::operand::ParentInfo> &&parent_info) +{ + _parent_info = std::move(parent_info); +} + +const graph::operand::ParentInfo *Object::parent_info() const { return _parent_info.get(); } + +graph::operand::ParentInfo *Object::parent_info() { return _parent_info.get(); } } // namespace operand -} // namespace graph +} // namespace model } // namespace neurun diff --git a/runtimes/neurun/src/graph/operand/Object.h b/runtimes/neurun/src/model/operand/Object.h index 17e46ab28..eb5f6275e 100644 --- a/runtimes/neurun/src/graph/operand/Object.h +++ b/runtimes/neurun/src/model/operand/Object.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef __NEURUN_GRAPH_OPERAND_OBJECT_H__ -#define __NEURUN_GRAPH_OPERAND_OBJECT_H__ +#ifndef __NEURUN_MODEL_OPERAND_OBJECT_H__ +#define __NEURUN_MODEL_OPERAND_OBJECT_H__ #include <cassert> #include <cstdint> @@ -25,12 +25,13 @@ #include "Shape.h" #include "Data.h" #include "TypeInfo.h" -#include "LowerInfo.h" -#include "graph/operation/IndexList.h" +#include "graph/operand/LowerInfo.h" // TODO Remove this dependency +#include "graph/operand/ParentInfo.h" // TODO Remove this dependency +#include "model/operation/IndexList.h" namespace neurun { -namespace graph +namespace model { namespace operand { @@ -62,6 +63,7 @@ public: bool setAsOperationOutput() { return setUsage(OperandUsage::OPERATION_OUTPUT); } bool usageIsDefined(void) const { return _usage != OperandUsage::NOT_DEFINED; } bool isModelInput(void) const { return _usage == OperandUsage::MODEL_INPUT; } + OperandUsage getUsage() const { return _usage; } const operation::IndexList &getUses() const { return _uses; } const operation::IndexList &getDef() const { return _def; } @@ -94,8 +96,24 @@ public: } public: - void lower_info(std::unique_ptr<LowerInfo> &&lower_info); - const LowerInfo *lower_info() const; + void lower_info(std::unique_ptr<graph::operand::LowerInfo> &&lower_info); + const graph::operand::LowerInfo *lower_info() const; + graph::operand::LowerInfo *lower_info(); + /** + * @brief Set parent information + * @param[in] parent_info Parent information + */ + void parent_info(std::unique_ptr<graph::operand::ParentInfo> &&parent_info); + /** + * @brief Return parent information pointer as constant + * @return Parent information pointer + */ + const graph::operand::ParentInfo *parent_info() const; + /** + * @brief Return parent information pointer + * @return Perent information pointer + */ + graph::operand::ParentInfo *parent_info(); private: const Shape _shape; @@ -106,11 +124,12 @@ private: operation::IndexList _uses; operation::IndexList _def; // size is 0 (constant) or 1 (from def operation) - std::unique_ptr<LowerInfo> _lower_info; + std::unique_ptr<graph::operand::LowerInfo> _lower_info; + std::unique_ptr<graph::operand::ParentInfo> _parent_info; }; } // namespace operand -} // namespace graph +} // namespace model } // namespace neurun -#endif // __NEURUN_GRAPH_OPERAND_OBJECT_H__ +#endif // __NEURUN_MODEL_OPERAND_OBJECT_H__ diff --git a/runtimes/neurun/src/graph/operand/Set.cc b/runtimes/neurun/src/model/operand/Set.cc index 60dad2336..d93c21514 100644 --- a/runtimes/neurun/src/graph/operand/Set.cc +++ b/runtimes/neurun/src/model/operand/Set.cc @@ -16,11 +16,11 @@ #include "Set.h" -#include "nnfw/std/memory.h" +#include "cpp14/memory.h" namespace neurun { -namespace graph +namespace model { namespace operand { @@ -36,7 +36,7 @@ Index Set::append(const Shape &shape, const TypeInfo &type) { auto index = generateIndex(); - _objects[index] = nnfw::make_unique<Object>(shape, type); + _objects[index] = nnfw::cpp14::make_unique<Object>(shape, type); return index; } @@ -57,12 +57,28 @@ void Set::iterate(const std::function<void(const Index &, const Object &)> &fn) void Set::iterate(const std::function<void(const Index &, Object &)> &fn) { + // TODO Remove this workaround + // This implementation is a workaround in case of adding operands while iteration + // + // // Original Implementation (We probably should be back to this) + // for (auto &e : _objects) + // { + // fn(e.first, *e.second); + // } + + std::list<Index> l; + for (auto &e : _objects) { - fn(e.first, *e.second); + l.push_back(e.first); + } + + for (auto index : l) + { + fn(index, *_objects[index]); } } } // namespace operand -} // namespace graph +} // namespace model } // namespace neurun diff --git a/runtimes/neurun/src/graph/operand/Set.h b/runtimes/neurun/src/model/operand/Set.h index c8266fed0..9dff7ec3c 100644 --- a/runtimes/neurun/src/graph/operand/Set.h +++ b/runtimes/neurun/src/model/operand/Set.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef __NEURUN_GRAPH_OPERAND_SET_H__ -#define __NEURUN_GRAPH_OPERAND_SET_H__ +#ifndef __NEURUN_MODEL_OPERAND_SET_H__ +#define __NEURUN_MODEL_OPERAND_SET_H__ #include <memory> #include <unordered_map> @@ -25,7 +25,7 @@ namespace neurun { -namespace graph +namespace model { namespace operand { @@ -37,6 +37,7 @@ public: public: Index append(const Shape &, const TypeInfo &); + void remove(const Index &index) { _objects.erase(index); }; public: const Object &at(const Index &) const; @@ -54,7 +55,7 @@ private: }; } // namespace operand -} // namespace graph +} // namespace model } // namespace neurun -#endif // __NEURUN_GRAPH_OPERAND_SET_H__ +#endif // __NEURUN_MODEL_OPERAND_SET_H__ diff --git a/runtimes/neurun/src/graph/operand/Shape.cc b/runtimes/neurun/src/model/operand/Shape.cc index f6d7a6999..f74c48d88 100644 --- a/runtimes/neurun/src/graph/operand/Shape.cc +++ b/runtimes/neurun/src/model/operand/Shape.cc @@ -20,7 +20,7 @@ namespace neurun { -namespace graph +namespace model { namespace operand { @@ -34,7 +34,17 @@ int32_t Shape::asVector(void) const return dim(0); } -nnfw::util::feature::Shape Shape::asFeature(void) const +nnfw::misc::matrix::Shape Shape::asMatrix(void) const +{ + assert(rank() == 2); + + const auto height = dim(0); + const auto width = dim(1); + + return nnfw::misc::matrix::Shape(height, width); +} + +nnfw::misc::feature::Shape Shape::asFeature(void) const { assert(rank() == 4); @@ -48,10 +58,10 @@ nnfw::util::feature::Shape Shape::asFeature(void) const const auto height = dim(1); const auto width = dim(2); - return nnfw::util::feature::Shape(batch, depth, height, width); + return nnfw::misc::feature::Shape(batch, depth, height, width); } -nnfw::util::kernel::Shape Shape::asKernel(void) const +nnfw::misc::kernel::Shape Shape::asKernel(void) const { assert(rank() == 4); @@ -65,9 +75,20 @@ nnfw::util::kernel::Shape Shape::asKernel(void) const const auto height = dim(1); const auto width = dim(2); - return nnfw::util::kernel::Shape(count, depth, height, width); + return nnfw::misc::kernel::Shape(count, depth, height, width); +} + +nnfw::misc::tensor::Shape Shape::asTensor(void) const +{ + nnfw::misc::tensor::Shape shape{}; + for (uint32_t i = 0; i < rank(); ++i) + { + shape.append(dim(i)); + } + + return shape; // this shape represents shape of NNAPI } } // namespace operand -} // namespace graph +} // namespace model } // namespace neurun diff --git a/runtimes/neurun/src/graph/operand/Shape.h b/runtimes/neurun/src/model/operand/Shape.h index 3ae970e85..b80f647d5 100644 --- a/runtimes/neurun/src/graph/operand/Shape.h +++ b/runtimes/neurun/src/model/operand/Shape.h @@ -14,18 +14,20 @@ * limitations under the License. */ -#ifndef __NEURUN_GRAPH_OPERAND_SHAPE_H__ -#define __NEURUN_GRAPH_OPERAND_SHAPE_H__ +#ifndef __NEURUN_MODEL_OPERAND_SHAPE_H__ +#define __NEURUN_MODEL_OPERAND_SHAPE_H__ #include <vector> #include <cstdint> -#include "util/feature/Shape.h" -#include "util/kernel/Shape.h" +#include "misc/feature/Shape.h" +#include "misc/kernel/Shape.h" +#include "misc/matrix/Shape.h" +#include "misc/tensor/Shape.h" namespace neurun { -namespace graph +namespace model { namespace operand { @@ -33,7 +35,7 @@ namespace operand struct Shape { public: - Shape(uint32_t rank); + Shape(uint32_t rank = 0); public: uint32_t rank(void) const { return _dims.size(); } @@ -45,15 +47,17 @@ public: public: int32_t asVector(void) const; - nnfw::util::feature::Shape asFeature(void) const; - nnfw::util::kernel::Shape asKernel(void) const; + nnfw::misc::matrix::Shape asMatrix(void) const; + nnfw::misc::feature::Shape asFeature(void) const; + nnfw::misc::kernel::Shape asKernel(void) const; + nnfw::misc::tensor::Shape asTensor(void) const; private: std::vector<int32_t> _dims; }; } // namespace operand -} // namespace graph +} // namespace model } // namespace neurun -#endif // __NEURUN_GRAPH_OPERAND_SHAPE_H__ +#endif // __NEURUN_MODEL_OPERAND_SHAPE_H__ diff --git a/runtimes/neurun/src/graph/operand/TypeInfo.cc b/runtimes/neurun/src/model/operand/TypeInfo.cc index 5642b1e8f..0b9f63c93 100644 --- a/runtimes/neurun/src/graph/operand/TypeInfo.cc +++ b/runtimes/neurun/src/model/operand/TypeInfo.cc @@ -18,18 +18,18 @@ namespace neurun { -namespace graph +namespace model { namespace operand { DataType TypeInfo::typeFromOperandCode(OperandCode type) { - // Now neurun::graph::operand::DataType share same enum value with OperandCode + // Now neurun::model::operand::DataType share same enum value with OperandCode // in NeuralNetworks.h. return static_cast<DataType>(static_cast<uint32_t>(type)); } } // namespace operand -} // namespace graph +} // namespace model } // namespace neurun diff --git a/runtimes/neurun/src/graph/operand/TypeInfo.h b/runtimes/neurun/src/model/operand/TypeInfo.h index 41f4453e5..d16172a09 100644 --- a/runtimes/neurun/src/graph/operand/TypeInfo.h +++ b/runtimes/neurun/src/model/operand/TypeInfo.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef __NEURUN_GRAPH_OPERAND_TYPEINFO_H__ -#define __NEURUN_GRAPH_OPERAND_TYPEINFO_H__ +#ifndef __NEURUN_MODEL_OPERAND_TYPEINFO_H__ +#define __NEURUN_MODEL_OPERAND_TYPEINFO_H__ #include <cstdint> @@ -25,7 +25,7 @@ namespace neurun { -namespace graph +namespace model { namespace operand { @@ -33,6 +33,8 @@ namespace operand class TypeInfo { public: + TypeInfo() = default; + TypeInfo(OperandCode type, float scale, int32_t offset) : _type(typeFromOperandCode(type)), _scale(scale), _offset(offset) { @@ -45,7 +47,7 @@ public: int32_t offset() const { return _offset; } private: - // Now neurun::graph::operand::DataType share same enum value with OperandCode + // Now neurun::model::operand::DataType share same enum value with OperandCode // in NeuralNetworks.h. // If we don't share same value, we must fix this mapping function. DataType typeFromOperandCode(OperandCode type); @@ -56,7 +58,7 @@ private: int32_t _offset; }; } // namespace operand -} // namespace graph +} // namespace model } // namespace neurun -#endif // __NEURUN_GRAPH_OPERAND_TYPEINFO_H__ +#endif // __NEURUN_MODEL_OPERAND_TYPEINFO_H__ diff --git a/runtimes/neurun/src/model/operation/AddNode.cc b/runtimes/neurun/src/model/operation/AddNode.cc new file mode 100644 index 000000000..0c9d4e09b --- /dev/null +++ b/runtimes/neurun/src/model/operation/AddNode.cc @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2018 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 "AddNode.h" + +#include <cassert> + +#include "NodeVisitor.h" + +namespace neurun +{ +namespace model +{ +namespace operation +{ + +void AddNode::accept(NodeVisitor &&v) const { v.visit(*this); } + +AddNode::AddNode(const model::operation::Node::InitParam &init_param) + : model::operation::Node{OperandConstraint::createExact(2u)} +{ + assert(init_param.input_count == 2); + assert(init_param.output_count == 1); + + // Each input should be interpreted as follows: + // + // 0 -> Lefthand side operand + // 1 -> Righthand side operand + + setInputs({init_param.inputs[0], init_param.inputs[1]}); + setOutputs({init_param.outputs[0]}); +} + +} // namespace operation +} // namespace model +} // namespace neurun diff --git a/runtimes/neurun/src/graph/operation/Reshape.h b/runtimes/neurun/src/model/operation/AddNode.h index 168719b46..533fb0ab3 100644 --- a/runtimes/neurun/src/graph/operation/Reshape.h +++ b/runtimes/neurun/src/model/operation/AddNode.h @@ -14,38 +14,41 @@ * limitations under the License. */ -#ifndef __NEURUN_GRAPH_OPERATION_RESHAPE_H__ -#define __NEURUN_GRAPH_OPERATION_RESHAPE_H__ +#ifndef __NEURUN_MODEL_OPERATION_ADD_NODE_H__ +#define __NEURUN_MODEL_OPERATION_ADD_NODE_H__ -#include <memory> - -#include "graph/operation/Node.h" +#include "model/operation/Node.h" namespace neurun { -namespace graph +namespace model { namespace operation { -namespace Reshape -{ -class Node : public graph::operation::Node +class AddNode : public model::operation::Node { public: - virtual void accept(NodeVisitor &&) const override; + AddNode(const model::operation::Node::InitParam &init_param); -public: - Node(const graph::operation::Node::InitParam &init_param); + enum Input + { + LHS = 0, + RHS + }; + + struct Param + { + operand::Index activation_index; + }; public: - virtual void setInputs(const operand::IndexSet &indexes) override; - virtual void setOutputs(const operand::IndexSet &indexes) override; + virtual void accept(NodeVisitor &&) const override; + virtual std::string getName() const override { return "Add"; } }; -} // namespace Reshape } // namespace operation -} // namespace graph +} // namespace model } // namespace neurun -#endif // __NEURUN_GRAPH_OPERATION_RESHAPE_H__ +#endif // __NEURUN_MODEL_OPERATION_ADD_H__ diff --git a/runtimes/neurun/src/graph/operation/AvgPool2D.cc b/runtimes/neurun/src/model/operation/AvgPool2DNode.cc index b2612c6b5..8c688e60a 100644 --- a/runtimes/neurun/src/graph/operation/AvgPool2D.cc +++ b/runtimes/neurun/src/model/operation/AvgPool2DNode.cc @@ -14,27 +14,23 @@ * limitations under the License. */ -#include "AvgPool2D.h" +#include "AvgPool2DNode.h" #include <cassert> #include "NodeVisitor.h" -#include "LowerInfo.h" namespace neurun { -namespace graph +namespace model { namespace operation { -namespace AvgPool2D -{ -namespace Implicit -{ -void Node::accept(NodeVisitor &&v) const { v.visit(*this); } +void AvgPool2DNode::accept(NodeVisitor &&v) const { v.visit(*this); } -Node::Node(const graph::operation::Node::InitParam &init_param) +AvgPool2DNode::AvgPool2DNode(const model::operation::Node::InitParam &init_param) + : model::operation::Node{OperandConstraint::createExact(1u)} { assert(init_param.input_count == 7); assert(init_param.output_count == 1); @@ -52,31 +48,15 @@ Node::Node(const graph::operation::Node::InitParam &init_param) setInputs({init_param.inputs[0]}); setOutputs({init_param.outputs[0]}); - _param.padding_index = init_param.inputs[1]; - _param.hstride_index = init_param.inputs[2]; - _param.vstride_index = init_param.inputs[3]; - - _param.kw_index = init_param.inputs[4]; - _param.kh_index = init_param.inputs[5]; - _param.activation_index = init_param.inputs[6]; -} - -void Node::setInputs(const operand::IndexSet &indexes) -{ - assert(indexes.size() == 1); - - graph::operation::Node::setInputs(indexes); -} - -void Node::setOutputs(const operand::IndexSet &indexes) -{ - assert(indexes.size() == 1); + _param.padding_index = operand::Index{init_param.inputs[1]}; + _param.hstride_index = operand::Index{init_param.inputs[2]}; + _param.vstride_index = operand::Index{init_param.inputs[3]}; - graph::operation::Node::setOutputs(indexes); + _param.kw_index = operand::Index{init_param.inputs[4]}; + _param.kh_index = operand::Index{init_param.inputs[5]}; + _param.activation_index = operand::Index{init_param.inputs[6]}; } -} // namespace Implicit -} // namespace AvgPool2D } // namespace operation -} // namespace graph +} // namespace model } // namespace neurun diff --git a/runtimes/neurun/src/graph/operation/MaxPool2D.h b/runtimes/neurun/src/model/operation/AvgPool2DNode.h index 30f9b0b50..e66e6146e 100644 --- a/runtimes/neurun/src/graph/operation/MaxPool2D.h +++ b/runtimes/neurun/src/model/operation/AvgPool2DNode.h @@ -14,47 +14,45 @@ * limitations under the License. */ -#ifndef __NEURUN_GRAPH_OPERATION_MAXPOOL2D_H__ -#define __NEURUN_GRAPH_OPERATION_MAXPOOL2D_H__ +#ifndef __NEURUN_MODEL_OPERATION_AVGPOOL2D_NODE_H__ +#define __NEURUN_MODEL_OPERATION_AVGPOOL2D_NODE_H__ #include <memory> -#include "graph/operation/Node.h" +#include "model/operation/Node.h" namespace neurun { -namespace graph +namespace model { namespace operation { -namespace MaxPool2D -{ -namespace Implicit -{ -struct Param +class AvgPool2DNode : public model::operation::Node { - int32_t kw_index; - int32_t kh_index; +public: + AvgPool2DNode(const model::operation::Node::InitParam &init_param); - int32_t hstride_index; - int32_t vstride_index; + enum Input + { + INPUT = 0 + }; - int32_t padding_index; - int32_t activation_index; -}; + struct Param + { + operand::Index kw_index; + operand::Index kh_index; -class Node : public graph::operation::Node -{ -public: - virtual void accept(NodeVisitor &&) const override; + operand::Index hstride_index; + operand::Index vstride_index; -public: - Node(const graph::operation::Node::InitParam &init_param); + operand::Index padding_index; + operand::Index activation_index; + }; public: - virtual void setInputs(const operand::IndexSet &indexes) override; - virtual void setOutputs(const operand::IndexSet &indexes) override; + virtual void accept(NodeVisitor &&) const override; + virtual std::string getName() const override { return "AvgPool2D"; } public: const Param ¶m() const { return _param; } @@ -63,10 +61,8 @@ private: Param _param; }; -} // namespace Implicit -} // namespace MaxPool2D } // namespace operation -} // namespace graph +} // namespace model } // namespace neurun -#endif // __NEURUN_GRAPH_OPERATION_MAXPOOL2D_H__ +#endif // __NEURUN_MODEL_OPERATION_AVGPOOL2D_H__ diff --git a/runtimes/neurun/src/graph/operation/Concat.cc b/runtimes/neurun/src/model/operation/ConcatNode.cc index 952cf687c..23cfef294 100644 --- a/runtimes/neurun/src/graph/operation/Concat.cc +++ b/runtimes/neurun/src/model/operation/ConcatNode.cc @@ -14,27 +14,25 @@ * limitations under the License. */ -#include "Concat.h" +#include "ConcatNode.h" #include <cassert> #include "NodeVisitor.h" -#include "LowerInfo.h" namespace neurun { -namespace graph +namespace model { namespace operation { -namespace Concat -{ -void Node::accept(NodeVisitor &&v) const { v.visit(*this); } +void ConcatNode::accept(NodeVisitor &&v) const { v.visit(*this); } -Node::Node(const graph::operation::Node::InitParam &init_param) +ConcatNode::ConcatNode(const model::operation::Node::InitParam &init_param) + : model::operation::Node{OperandConstraint::createAtLeast(2u)} { - assert(init_param.input_count > 2); // At least one one input tensor and axis + assert(init_param.input_count >= 2); // At least one one input tensor and axis assert(init_param.output_count == 1); // When there are N + 1 inputs, each input should be interpreted as follows: @@ -53,17 +51,9 @@ Node::Node(const graph::operation::Node::InitParam &init_param) } setOutputs({init_param.outputs[0]}); - _param.axis_index = init_param.inputs[init_param.input_count - 1]; -} - -void Node::setOutputs(const operand::IndexSet &indexes) -{ - assert(indexes.size() == 1); - - graph::operation::Node::setOutputs(indexes); + _param.axis_index = operand::Index{init_param.inputs[init_param.input_count - 1]}; } -} // namespace Concat } // namespace operation -} // namespace graph +} // namespace model } // namespace neurun diff --git a/runtimes/neurun/src/graph/operation/Concat.h b/runtimes/neurun/src/model/operation/ConcatNode.h index dab17d031..b69ee2f23 100644 --- a/runtimes/neurun/src/graph/operation/Concat.h +++ b/runtimes/neurun/src/model/operation/ConcatNode.h @@ -14,37 +14,33 @@ * limitations under the License. */ -#ifndef __NEURUN_GRAPH_OPERATION_CONCAT_H__ -#define __NEURUN_GRAPH_OPERATION_CONCAT_H__ +#ifndef __NEURUN_MODEL_OPERATION_CONCAT_NODE_H__ +#define __NEURUN_MODEL_OPERATION_CONCAT_NODE_H__ #include <memory> -#include "graph/operation/Node.h" +#include "model/operation/Node.h" namespace neurun { -namespace graph +namespace model { namespace operation { -namespace Concat -{ - -struct Param -{ - int32_t axis_index; -}; -class Node : public graph::operation::Node +class ConcatNode : public model::operation::Node { public: - Node(const graph::operation::Node::InitParam &init_param); + ConcatNode(const model::operation::Node::InitParam &init_param); -public: - virtual void accept(NodeVisitor &&) const override; + struct Param + { + operand::Index axis_index; + }; public: - virtual void setOutputs(const operand::IndexSet &indexes) override; + virtual void accept(NodeVisitor &&) const override; + virtual std::string getName() const override { return "Concat"; } public: const Param ¶m() const { return _param; } @@ -53,9 +49,8 @@ private: Param _param; }; -} // namespace Concat } // namespace operation -} // namespace graph +} // namespace model } // namespace neurun -#endif // __NEURUN_GRAPH_OPERATION_CONCAT_H__ +#endif // __NEURUN_MODEL_OPERATION_CONCAT_H__ diff --git a/runtimes/neurun/src/graph/operation/Conv2D.cc b/runtimes/neurun/src/model/operation/Conv2DNode.cc index f88955db1..7eb2b183d 100644 --- a/runtimes/neurun/src/graph/operation/Conv2D.cc +++ b/runtimes/neurun/src/model/operation/Conv2DNode.cc @@ -14,27 +14,23 @@ * limitations under the License. */ -#include "Conv2D.h" +#include "Conv2DNode.h" #include <cassert> #include "NodeVisitor.h" -#include "LowerInfo.h" namespace neurun { -namespace graph +namespace model { namespace operation { -namespace Conv2D -{ -namespace Implicit -{ -void Node::accept(NodeVisitor &&v) const { v.visit(*this); } +void Conv2DNode::accept(NodeVisitor &&v) const { v.visit(*this); } -Node::Node(const graph::operation::Node::InitParam &init_param) +Conv2DNode::Conv2DNode(const model::operation::Node::InitParam &init_param) + : model::operation::Node{OperandConstraint::createExact(3u)} { assert(init_param.input_count == 7 && init_param.output_count == 1); @@ -52,28 +48,12 @@ Node::Node(const graph::operation::Node::InitParam &init_param) setInputs({init_param.inputs[0], init_param.inputs[1], init_param.inputs[2]}); setOutputs({init_param.outputs[0]}); - _param.padding_index = init_param.inputs[3]; - _param.hstride_index = init_param.inputs[4]; - _param.vstride_index = init_param.inputs[5]; - _param.activation_index = init_param.inputs[6]; -} - -void Node::setInputs(const operand::IndexSet &indexes) -{ - assert(indexes.size() == 3); - - graph::operation::Node::setInputs(indexes); -} - -void Node::setOutputs(const operand::IndexSet &indexes) -{ - assert(indexes.size() == 1); - - graph::operation::Node::setOutputs(indexes); + _param.padding_index = operand::Index{init_param.inputs[3]}; + _param.hstride_index = operand::Index{init_param.inputs[4]}; + _param.vstride_index = operand::Index{init_param.inputs[5]}; + _param.activation_index = operand::Index{init_param.inputs[6]}; } -} // namespace Implicit -} // namespace Conv2D } // namespace operation -} // namespace graph +} // namespace model } // namespace neurun diff --git a/runtimes/neurun/src/graph/operation/Conv2D.h b/runtimes/neurun/src/model/operation/Conv2DNode.h index f75058a30..34a95f0d9 100644 --- a/runtimes/neurun/src/graph/operation/Conv2D.h +++ b/runtimes/neurun/src/model/operation/Conv2DNode.h @@ -14,44 +14,44 @@ * limitations under the License. */ -#ifndef __NEURUN_GRAPH_OPERATION_CONV2D_H__ -#define __NEURUN_GRAPH_OPERATION_CONV2D_H__ +#ifndef __NEURUN_MODEL_OPERATION_CONV2D_NODE_H__ +#define __NEURUN_MODEL_OPERATION_CONV2D_NODE_H__ #include <memory> -#include "graph/operation/Node.h" +#include "model/operation/Node.h" namespace neurun { -namespace graph +namespace model { namespace operation { -namespace Conv2D -{ -namespace Implicit -{ -struct Param +class Conv2DNode : public model::operation::Node { - int32_t hstride_index; - int32_t vstride_index; +public: + Conv2DNode(const model::operation::Node::InitParam &); - int32_t padding_index; - int32_t activation_index; -}; + enum Input + { + INPUT = 0, + KERNEL, + BIAS + }; -class Node : public graph::operation::Node -{ -public: - Node(const graph::operation::Node::InitParam &); + struct Param + { + operand::Index hstride_index; + operand::Index vstride_index; -public: - virtual void accept(NodeVisitor &&) const override; + operand::Index padding_index; + operand::Index activation_index; + }; public: - virtual void setInputs(const operand::IndexSet &indexes) override; - virtual void setOutputs(const operand::IndexSet &indexes) override; + virtual void accept(NodeVisitor &&) const override; + virtual std::string getName() const override { return "Conv2D"; } public: const Param ¶m() const { return _param; } @@ -60,10 +60,8 @@ private: Param _param; }; -} // namespace Implicit -} // namespace Conv2D -} // namespace coperation -} // namespace graph +} // namespace operation +} // namespace model } // namespace neurun -#endif // __NEURUN_GRAPH_OPERATION_CONV2D_H__ +#endif // __NEURUN_MODEL_OPERATION_CONV2D_NODE_H__ diff --git a/runtimes/neurun/src/graph/operation/FullyConnected.cc b/runtimes/neurun/src/model/operation/FullyConnectedNode.cc index 0a6553d1e..0fde5182d 100644 --- a/runtimes/neurun/src/graph/operation/FullyConnected.cc +++ b/runtimes/neurun/src/model/operation/FullyConnectedNode.cc @@ -14,25 +14,23 @@ * limitations under the License. */ -#include "FullyConnected.h" +#include "FullyConnectedNode.h" #include <cassert> #include "NodeVisitor.h" -#include "LowerInfo.h" namespace neurun { -namespace graph +namespace model { namespace operation { -namespace FullyConnected -{ -void Node::accept(NodeVisitor &&v) const { v.visit(*this); } +void FullyConnectedNode::accept(NodeVisitor &&v) const { v.visit(*this); } -Node::Node(const graph::operation::Node::InitParam &init_param) +FullyConnectedNode::FullyConnectedNode(const model::operation::Node::InitParam &init_param) + : model::operation::Node{OperandConstraint::createExact(3u)} { assert(init_param.input_count == 4 && init_param.output_count == 1); @@ -46,24 +44,9 @@ Node::Node(const graph::operation::Node::InitParam &init_param) setInputs({init_param.inputs[0], init_param.inputs[1], init_param.inputs[2]}); setOutputs({init_param.outputs[0]}); - _param.activation_index = init_param.inputs[3]; -} - -void Node::setInputs(const operand::IndexSet &indexes) -{ - assert(indexes.size() == 3); - - graph::operation::Node::setInputs(indexes); -} - -void Node::setOutputs(const operand::IndexSet &indexes) -{ - assert(indexes.size() == 1); - - graph::operation::Node::setOutputs(indexes); + _param.activation_index = operand::Index{init_param.inputs[3]}; } -} // namespace FullyConnected } // namespace operation -} // namespace graph +} // namespace model } // namespace neurun diff --git a/runtimes/neurun/src/graph/operation/FullyConnected.h b/runtimes/neurun/src/model/operation/FullyConnectedNode.h index a1f920e4b..9820ddc8c 100644 --- a/runtimes/neurun/src/graph/operation/FullyConnected.h +++ b/runtimes/neurun/src/model/operation/FullyConnectedNode.h @@ -14,38 +14,40 @@ * limitations under the License. */ -#ifndef __NEURUN_GRAPH_OPERATION_FULLYCONNECTED_H__ -#define __NEURUN_GRAPH_OPERATION_FULLYCONNECTED_H__ +#ifndef __NEURUN_MODEL_OPERATION_FULLYCONNECTED_NODE_H__ +#define __NEURUN_MODEL_OPERATION_FULLYCONNECTED_NODE_H__ #include <memory> -#include "graph/operation/Node.h" +#include "model/operation/Node.h" namespace neurun { -namespace graph +namespace model { namespace operation { -namespace FullyConnected -{ - -struct Param -{ - int32_t activation_index; -}; -class Node : public graph::operation::Node +class FullyConnectedNode : public model::operation::Node { public: - Node(const graph::operation::Node::InitParam &init_param); + FullyConnectedNode(const model::operation::Node::InitParam &init_param); -public: - virtual void accept(NodeVisitor &&) const override; + enum Input + { + INPUT = 0, + WEIGHT, + BIAS + }; + + struct Param + { + operand::Index activation_index; + }; public: - virtual void setInputs(const operand::IndexSet &indexes) override; - virtual void setOutputs(const operand::IndexSet &indexes) override; + virtual void accept(NodeVisitor &&) const override; + virtual std::string getName() const override { return "FullyConnected"; } public: const Param ¶m() const { return _param; } @@ -54,9 +56,8 @@ private: Param _param; }; -} // namespace FullyConnected } // namespace operation -} // namespace graph +} // namespace model } // namespace neurun -#endif // __NEURUN_GRAPH_OPERATION_FULLYCONNECTED_H__ +#endif // __NEURUN_MODEL_OPERATION_FULLYCONNECTED_NODE_H__ diff --git a/runtimes/neurun/src/graph/operation/Index.h b/runtimes/neurun/src/model/operation/Index.h index 3902d039b..e03dd74d6 100644 --- a/runtimes/neurun/src/graph/operation/Index.h +++ b/runtimes/neurun/src/model/operation/Index.h @@ -14,14 +14,14 @@ * limitations under the License. */ -#ifndef __NEURUN_GRAPH_OPERATION_INDEX_H__ -#define __NEURUN_GRAPH_OPERATION_INDEX_H__ +#ifndef __NEURUN_MODEL_OPERATION_INDEX_H__ +#define __NEURUN_MODEL_OPERATION_INDEX_H__ #include "graph/Index.h" namespace neurun { -namespace graph +namespace model { namespace operation { @@ -29,7 +29,7 @@ namespace operation using Index = ::neurun::graph::Index<uint32_t, struct IndexTag>; } // namespace operation -} // namespace graph +} // namespace model } // namespace neurun -#endif // __NEURUN_GRAPH_OPERATION_INDEX_H__ +#endif // __NEURUN_MODEL_OPERATION_INDEX_H__ diff --git a/runtimes/neurun/src/graph/operation/IndexList.cc b/runtimes/neurun/src/model/operation/IndexList.cc index cdc5997ea..e46987036 100644 --- a/runtimes/neurun/src/graph/operation/IndexList.cc +++ b/runtimes/neurun/src/model/operation/IndexList.cc @@ -20,7 +20,7 @@ namespace neurun { -namespace graph +namespace model { namespace operation { @@ -30,11 +30,11 @@ IndexList::IndexList(std::initializer_list<Index> list) : _list(list) // DO NOTHING } -bool IndexList::contains(const ::neurun::graph::operation::Index &index) const +bool IndexList::contains(const ::neurun::model::operation::Index &index) const { return std::find(_list.begin(), _list.end(), index) != _list.end(); } } // namespace operation -} // namespace graph +} // namespace model } // namespace neurun diff --git a/runtimes/neurun/src/graph/operation/IndexList.h b/runtimes/neurun/src/model/operation/IndexList.h index cfac46abc..c0af29829 100644 --- a/runtimes/neurun/src/graph/operation/IndexList.h +++ b/runtimes/neurun/src/model/operation/IndexList.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef __NEURUN_GRAPH_OPERATION_INDEX_LIST_H__ -#define __NEURUN_GRAPH_OPERATION_INDEX_LIST_H__ +#ifndef __NEURUN_MODEL_OPERATION_INDEX_LIST_H__ +#define __NEURUN_MODEL_OPERATION_INDEX_LIST_H__ #include <initializer_list> #include <list> @@ -24,7 +24,7 @@ namespace neurun { -namespace graph +namespace model { namespace operation { @@ -49,7 +49,7 @@ private: }; } // namespace operation -} // namespace graph +} // namespace model } // namespace neurun -#endif // __NEURUN_GRAPH_OPERATION_INDEX_LIST_H__ +#endif // __NEURUN_MODEL_OPERATION_INDEX_LIST_H__ diff --git a/runtimes/neurun/src/graph/operation/MaxPool2D.cc b/runtimes/neurun/src/model/operation/MaxPool2DNode.cc index 76648baf6..3d3686b0e 100644 --- a/runtimes/neurun/src/graph/operation/MaxPool2D.cc +++ b/runtimes/neurun/src/model/operation/MaxPool2DNode.cc @@ -14,27 +14,23 @@ * limitations under the License. */ -#include "MaxPool2D.h" +#include "MaxPool2DNode.h" #include <cassert> #include "NodeVisitor.h" -#include "LowerInfo.h" namespace neurun { -namespace graph +namespace model { namespace operation { -namespace MaxPool2D -{ -namespace Implicit -{ -void Node::accept(NodeVisitor &&v) const { v.visit(*this); } +void MaxPool2DNode::accept(NodeVisitor &&v) const { v.visit(*this); } -Node::Node(const graph::operation::Node::InitParam &init_param) +MaxPool2DNode::MaxPool2DNode(const model::operation::Node::InitParam &init_param) + : model::operation::Node{OperandConstraint::createExact(1u)} { assert(init_param.input_count == 7); assert(init_param.output_count == 1); @@ -52,31 +48,15 @@ Node::Node(const graph::operation::Node::InitParam &init_param) setInputs({init_param.inputs[0]}); setOutputs({init_param.outputs[0]}); - _param.padding_index = init_param.inputs[1]; - _param.hstride_index = init_param.inputs[2]; - _param.vstride_index = init_param.inputs[3]; - - _param.kw_index = init_param.inputs[4]; - _param.kh_index = init_param.inputs[5]; - _param.activation_index = init_param.inputs[6]; -} - -void Node::setInputs(const operand::IndexSet &indexes) -{ - assert(indexes.size() == 1); - - graph::operation::Node::setInputs(indexes); -} - -void Node::setOutputs(const operand::IndexSet &indexes) -{ - assert(indexes.size() == 1); + _param.padding_index = operand::Index{init_param.inputs[1]}; + _param.hstride_index = operand::Index{init_param.inputs[2]}; + _param.vstride_index = operand::Index{init_param.inputs[3]}; - graph::operation::Node::setOutputs(indexes); + _param.kw_index = operand::Index{init_param.inputs[4]}; + _param.kh_index = operand::Index{init_param.inputs[5]}; + _param.activation_index = operand::Index{init_param.inputs[6]}; } -} // namespace Implicit -} // namespace MaxPool2D } // namespace operation -} // namespace graph +} // namespace model } // namespace neurun diff --git a/runtimes/neurun/src/model/operation/MaxPool2DNode.h b/runtimes/neurun/src/model/operation/MaxPool2DNode.h new file mode 100644 index 000000000..96d1210a7 --- /dev/null +++ b/runtimes/neurun/src/model/operation/MaxPool2DNode.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2018 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 __NEURUN_MODEL_OPERATION_MAXPOOL2D_NODE_H__ +#define __NEURUN_MODEL_OPERATION_MAXPOOL2D_NODE_H__ + +#include <memory> + +#include "model/operation/Node.h" + +namespace neurun +{ +namespace model +{ +namespace operation +{ + +class MaxPool2DNode : public model::operation::Node +{ +public: + MaxPool2DNode(const model::operation::Node::InitParam &init_param); + + enum Input + { + INPUT = 0 + }; + + struct Param + { + operand::Index kw_index; + operand::Index kh_index; + + operand::Index hstride_index; + operand::Index vstride_index; + + operand::Index padding_index; + operand::Index activation_index; + }; + +public: + virtual void accept(NodeVisitor &&) const override; + virtual std::string getName() const override { return "MaxPool2D"; } + +public: + const Param ¶m() const { return _param; } + +private: + Param _param; +}; + +} // namespace operation +} // namespace model +} // namespace neurun + +#endif // __NEURUN_MODEL_OPERATION_MAXPOOL2D_NODE_H__ diff --git a/runtimes/neurun/src/model/operation/Node.Include.h b/runtimes/neurun/src/model/operation/Node.Include.h new file mode 100644 index 000000000..95e78c7b5 --- /dev/null +++ b/runtimes/neurun/src/model/operation/Node.Include.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2018 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. + */ + +// This file has no ifdef guard intentionally + +#include "Conv2DNode.h" +#include "MaxPool2DNode.h" +#include "AvgPool2DNode.h" +#include "ConcatNode.h" +#include "ReshapeNode.h" +#include "FullyConnectedNode.h" +#include "SoftmaxNode.h" +#include "PermuteNode.h" +#include "AddNode.h" diff --git a/runtimes/neurun/src/model/operation/Node.cc b/runtimes/neurun/src/model/operation/Node.cc new file mode 100644 index 000000000..76397afde --- /dev/null +++ b/runtimes/neurun/src/model/operation/Node.cc @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2018 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 "Node.h" + +#include <cassert> + +#include "graph/operation/LowerInfo.h" + +namespace neurun +{ +namespace model +{ +namespace operation +{ + +Node::Node(OperandConstraint input_constr) : _input_constr{input_constr} {} + +Node::~Node() = default; + +void Node::setInputs(const operand::IndexSet &indexes) +{ + assert(_input_constr.check(indexes.size())); + _inputs = indexes; +} + +void Node::setOutputs(const operand::IndexSet &indexes) { _outputs = indexes; } + +void Node::replaceInput(const operand::Index &from, const operand::Index &to) +{ + _inputs.replace(from, to); +} + +void Node::replaceOutput(const operand::Index &from, const operand::Index &to) +{ + _outputs.replace(from, to); +} + +} // namespace operation +} // namespace model +} // namespace neurun diff --git a/runtimes/neurun/src/graph/operation/Node.h b/runtimes/neurun/src/model/operation/Node.h index 9e98184e3..76f0d2d00 100644 --- a/runtimes/neurun/src/graph/operation/Node.h +++ b/runtimes/neurun/src/model/operation/Node.h @@ -14,12 +14,14 @@ * limitations under the License. */ -#ifndef __NEURUN_GRAPH_OPERATION_NODE_H__ -#define __NEURUN_GRAPH_OPERATION_NODE_H__ +#ifndef __NEURUN_MODEL_OPERATION_NODE_H__ +#define __NEURUN_MODEL_OPERATION_NODE_H__ #include <memory> -#include "graph/operand/IndexSet.h" +#include "model/operand/Object.h" +#include "model/operand/IndexSet.h" +#include "OperandConstraint.h" namespace neurun { @@ -27,8 +29,18 @@ namespace graph { namespace operation { - class LowerInfo; +} // namespace operation +} // namespace graph +} // namespace neurun + +namespace neurun +{ +namespace model +{ +namespace operation +{ + struct NodeVisitor; class Node @@ -43,31 +55,30 @@ public: }; public: - Node(); + Node(OperandConstraint input_constr); virtual ~Node(); public: virtual void accept(NodeVisitor &&) const = 0; + virtual std::string getName() const = 0; public: - virtual const operand::IndexSet &getInputs() const { return _inputs; } - virtual const operand::IndexSet &getOutputs() const { return _outputs; } + void replaceInput(const operand::Index &from, const operand::Index &to); + void replaceOutput(const operand::Index &from, const operand::Index &to); + const operand::IndexSet &getInputs() const { return _inputs; } + const operand::IndexSet &getOutputs() const { return _outputs; } // It's for only input/output tensors but const data. - virtual void setInputs(const operand::IndexSet &indexes) { _inputs = indexes; } - virtual void setOutputs(const operand::IndexSet &indexes) { _outputs = indexes; } - -public: - void lower_info(std::unique_ptr<LowerInfo> &&lower_info); - const LowerInfo *lower_info() const; + void setInputs(const operand::IndexSet &indexes); + void setOutputs(const operand::IndexSet &indexes); private: operand::IndexSet _inputs; operand::IndexSet _outputs; - std::unique_ptr<LowerInfo> _lower_info; + OperandConstraint _input_constr; }; } // namespace operation -} // namespace graph +} // namespace model } // namespace neurun -#endif // __NEURUN_GRAPH_OPERATION_NODE_H__ +#endif // __NEURUN_MODEL_OPERATION_NODE_H__ diff --git a/runtimes/neurun/src/model/operation/NodeVisitor.h b/runtimes/neurun/src/model/operation/NodeVisitor.h new file mode 100644 index 000000000..8420de998 --- /dev/null +++ b/runtimes/neurun/src/model/operation/NodeVisitor.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2018 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 __NEURUN_MODEL_OPERATION_NODE_VISITOR_H__ +#define __NEURUN_MODEL_OPERATION_NODE_VISITOR_H__ + +#include "Node.Include.h" + +namespace neurun +{ +namespace model +{ +namespace operation +{ + +struct NodeVisitor +{ + virtual ~NodeVisitor() = default; + +#define OP(InternalName, IsNnApi, NnApiName) \ + virtual void visit(const InternalName &) {} +#include "model/operation/Op.lst" +#undef OP +}; + +} // namespace operation +} // namespace model +} // namespace neurun + +#endif // __NEURUN_MODEL_OPERATION_NODE_VISITOR_H__ diff --git a/runtimes/neurun/src/graph/operation/Op.lst b/runtimes/neurun/src/model/operation/Op.lst index 23b4123cb..23f4b5118 100644 --- a/runtimes/neurun/src/graph/operation/Op.lst +++ b/runtimes/neurun/src/model/operation/Op.lst @@ -20,11 +20,13 @@ // NOTE The relation between "Internal Name" and "NN API Name" is "1 : N". -// Internal Name | NN API Name -OP(Conv2D::Implicit , CONV_2D) -OP(AvgPool2D::Implicit , AVERAGE_POOL_2D) -OP(MaxPool2D::Implicit , MAX_POOL_2D) -OP(Concat , CONCATENATION) -OP(FullyConnected , FULLY_CONNECTED) -OP(Reshape , RESHAPE) -OP(Softmax , SOFTMAX) +// Internal Name | NN API? | NN API Name +OP(AddNode , true , ADD) +OP(Conv2DNode , true , CONV_2D) +OP(AvgPool2DNode , true , AVERAGE_POOL_2D) +OP(MaxPool2DNode , true , MAX_POOL_2D) +OP(ConcatNode , true , CONCATENATION) +OP(FullyConnectedNode , true , FULLY_CONNECTED) +OP(ReshapeNode , true , RESHAPE) +OP(SoftmaxNode , true , SOFTMAX) +OP(PermuteNode , false , NOT_AVAILABLE) diff --git a/runtimes/neurun/src/model/operation/OperandConstraint.cc b/runtimes/neurun/src/model/operation/OperandConstraint.cc new file mode 100644 index 000000000..5c69de928 --- /dev/null +++ b/runtimes/neurun/src/model/operation/OperandConstraint.cc @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2018 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 "OperandConstraint.h" + +namespace neurun +{ +namespace model +{ +namespace operation +{ + +} // namespace operation +} // namespace model +} // namespace neurun diff --git a/runtimes/neurun/src/model/operation/OperandConstraint.h b/runtimes/neurun/src/model/operation/OperandConstraint.h new file mode 100644 index 000000000..d1cd8aa2c --- /dev/null +++ b/runtimes/neurun/src/model/operation/OperandConstraint.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2018 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 __NEURUN_MODEL_OPERATION_OPERAND_CONSTRAINT_H__ +#define __NEURUN_MODEL_OPERATION_OPERAND_CONSTRAINT_H__ + +#include <stdint.h> +#include <limits> +#include <set> + +namespace neurun +{ +namespace model +{ +namespace operation +{ + +class OperandConstraint +{ +private: + static const uint32_t INF = std::numeric_limits<uint32_t>::max(); + +public: + static OperandConstraint createAny() { return OperandConstraint{0u, INF}; } + static OperandConstraint createExact(uint32_t exact) { return OperandConstraint{exact, exact}; } + static OperandConstraint createAtMost(uint32_t end) { return OperandConstraint{0u, end}; } + static OperandConstraint createAtLeast(uint32_t begin) { return OperandConstraint{begin, INF}; } + static OperandConstraint createInRange(uint32_t begin, uint32_t end) + { + return OperandConstraint{begin, end}; + } + +private: + OperandConstraint(uint32_t begin, uint32_t end) : _begin{begin}, _end{end} {} + +public: + bool check(uint32_t ind) const { return _begin <= ind && ind <= _end; } + +private: + uint32_t _begin; + uint32_t _end; +}; + +} // namespace operation +} // namespace model +} // namespace neurun + +#endif // __NEURUN_MODEL_OPERATION_OPERAND_CONSTRAINT_H__ diff --git a/runtimes/neurun/src/model/operation/PermuteNode.cc b/runtimes/neurun/src/model/operation/PermuteNode.cc new file mode 100644 index 000000000..174d2a86b --- /dev/null +++ b/runtimes/neurun/src/model/operation/PermuteNode.cc @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2018 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 "PermuteNode.h" + +#include <cassert> + +#include "NodeVisitor.h" + +namespace neurun +{ +namespace model +{ +namespace operation +{ + +void PermuteNode::accept(NodeVisitor &&v) const { v.visit(*this); } + +PermuteNode::PermuteNode(const operand::Index &input, const operand::Index &output, Type type) + : model::operation::Node{OperandConstraint::createExact(1u)}, _param{type} +{ + setInputs({input}); + setOutputs({output}); +} + +} // namespace operation +} // namespace model +} // namespace neurun diff --git a/runtimes/neurun/src/model/operation/PermuteNode.h b/runtimes/neurun/src/model/operation/PermuteNode.h new file mode 100644 index 000000000..b589975be --- /dev/null +++ b/runtimes/neurun/src/model/operation/PermuteNode.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2018 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 __NEURUN_MODEL_OPERATION_PERMUTE_NODE_H__ +#define __NEURUN_MODEL_OPERATION_PERMUTE_NODE_H__ + +#include "model/operation/Node.h" + +namespace neurun +{ +namespace model +{ +namespace operation +{ + +class PermuteNode : public model::operation::Node +{ +public: + enum class Type + { + NHWC_TO_NCHW, + NCHW_TO_NHWC, + COPY + }; + + struct Param + { + Type type; + }; + +public: + virtual void accept(NodeVisitor &&) const override; + virtual std::string getName() const override { return "Permute"; } + +public: + PermuteNode(const operand::Index &input, const operand::Index &output, Type type); + +public: + const Param ¶m() const { return _param; } + +private: + Param _param; +}; + +} // namespace operation +} // namespace model +} // namespace neurun + +#endif // __NEURUN_MODEL_OPERATION_PERMUTE_NODE_H__ diff --git a/runtimes/neurun/src/graph/operation/Reshape.cc b/runtimes/neurun/src/model/operation/ReshapeNode.cc index e6bc2117f..616b8cd65 100644 --- a/runtimes/neurun/src/graph/operation/Reshape.cc +++ b/runtimes/neurun/src/model/operation/ReshapeNode.cc @@ -14,25 +14,23 @@ * limitations under the License. */ -#include "Reshape.h" +#include "ReshapeNode.h" #include <cassert> #include "NodeVisitor.h" -#include "LowerInfo.h" namespace neurun { -namespace graph +namespace model { namespace operation { -namespace Reshape -{ -void Node::accept(NodeVisitor &&v) const { v.visit(*this); } +void ReshapeNode::accept(NodeVisitor &&v) const { v.visit(*this); } -Node::Node(const graph::operation::Node::InitParam &init_param) +ReshapeNode::ReshapeNode(const model::operation::Node::InitParam &init_param) + : model::operation::Node{OperandConstraint::createExact(1u)} { assert(init_param.input_count == 2 && init_param.output_count == 1); @@ -47,21 +45,6 @@ Node::Node(const graph::operation::Node::InitParam &init_param) setOutputs({init_param.outputs[0]}); } -void Node::setInputs(const operand::IndexSet &indexes) -{ - assert(indexes.size() == 1); // TODO Should be 2 (See also the constructor) - - graph::operation::Node::setInputs(indexes); -} - -void Node::setOutputs(const operand::IndexSet &indexes) -{ - assert(indexes.size() == 1); - - graph::operation::Node::setOutputs(indexes); -} - -} // namespace Reshape } // namespace operation -} // namespace graph +} // namespace model } // namespace neurun diff --git a/runtimes/neurun/src/graph/operation/NOP.h b/runtimes/neurun/src/model/operation/ReshapeNode.h index 51b0f6f71..1758e9ec8 100644 --- a/runtimes/neurun/src/graph/operation/NOP.h +++ b/runtimes/neurun/src/model/operation/ReshapeNode.h @@ -14,34 +14,37 @@ * limitations under the License. */ -#ifndef __NEURUN_GRAPH_OPERATION_NOP_H__ -#define __NEURUN_GRAPH_OPERATION_NOP_H__ +#ifndef __NEURUN_MODEL_OPERATION_RESHAPE_NODE_H__ +#define __NEURUN_MODEL_OPERATION_RESHAPE_NODE_H__ #include <memory> -#include "graph/operation/Node.h" +#include "model/operation/Node.h" namespace neurun { -namespace graph +namespace model { namespace operation { -namespace NOP -{ -class Node : public graph::operation::Node +class ReshapeNode : public model::operation::Node { public: - Node(const graph::operation::Node::InitParam &) {} + ReshapeNode(const model::operation::Node::InitParam &init_param); + + enum Input + { + INPUT = 0 + }; public: virtual void accept(NodeVisitor &&) const override; + virtual std::string getName() const override { return "Reshape"; } }; -} // namespace NOP } // namespace operation -} // namespace graph +} // namespace model } // namespace neurun -#endif // __NEURUN_GRAPH_OPERATION_NOP_H__ +#endif // __NEURUN_MODEL_OPERATION_RESHAPE_NODE_H__ diff --git a/runtimes/neurun/src/graph/operation/Set.cc b/runtimes/neurun/src/model/operation/Set.cc index a1ddfa6d4..14bd4f584 100644 --- a/runtimes/neurun/src/graph/operation/Set.cc +++ b/runtimes/neurun/src/model/operation/Set.cc @@ -20,7 +20,7 @@ namespace neurun { -namespace graph +namespace model { namespace operation { @@ -63,5 +63,5 @@ void Set::iterate(const std::function<void(const Index &, Node &)> &fn) } } // namespace operation -} // namespace graph +} // namespace model } // namespace neurun diff --git a/runtimes/neurun/src/graph/operation/Set.h b/runtimes/neurun/src/model/operation/Set.h index bc6913ff4..eebf91e65 100644 --- a/runtimes/neurun/src/graph/operation/Set.h +++ b/runtimes/neurun/src/model/operation/Set.h @@ -14,19 +14,19 @@ * limitations under the License. */ -#ifndef __NEURUN_GRAPH_OPERATION_SET_H__ -#define __NEURUN_GRAPH_OPERATION_SET_H__ +#ifndef __NEURUN_MODEL_OPERATION_SET_H__ +#define __NEURUN_MODEL_OPERATION_SET_H__ #include <memory> -#include "graph/operation/Index.h" +#include "model/operation/Index.h" #include "Node.h" #include <unordered_map> namespace neurun { -namespace graph +namespace model { namespace operation { @@ -38,6 +38,7 @@ public: public: Index append(std::unique_ptr<Node> &&node); + void remove(const Index &index) { _nodes.erase(index); }; public: const Node &at(const Index &) const; @@ -56,7 +57,7 @@ private: }; } // namespace operation -} // namespace graph +} // namespace model } // namespace neurun -#endif // __NEURUN_GRAPH_OPERATION_SET_H__ +#endif // __NEURUN_MODEL_OPERATION_SET_H__ diff --git a/runtimes/neurun/src/graph/operation/Softmax.cc b/runtimes/neurun/src/model/operation/SoftmaxNode.cc index 3b3c8661f..d157aa4a7 100644 --- a/runtimes/neurun/src/graph/operation/Softmax.cc +++ b/runtimes/neurun/src/model/operation/SoftmaxNode.cc @@ -14,25 +14,23 @@ * limitations under the License. */ -#include "Softmax.h" +#include "SoftmaxNode.h" #include <cassert> #include "NodeVisitor.h" -#include "LowerInfo.h" namespace neurun { -namespace graph +namespace model { namespace operation { -namespace Softmax -{ -void Node::accept(NodeVisitor &&v) const { v.visit(*this); } +void SoftmaxNode::accept(NodeVisitor &&v) const { v.visit(*this); } -Node::Node(const graph::operation::Node::InitParam &init_param) +SoftmaxNode::SoftmaxNode(const model::operation::Node::InitParam &init_param) + : model::operation::Node{OperandConstraint::createExact(1u)} { assert(init_param.input_count == 2 && init_param.output_count == 1); @@ -44,24 +42,9 @@ Node::Node(const graph::operation::Node::InitParam &init_param) setInputs({init_param.inputs[0]}); setOutputs({init_param.outputs[0]}); - _param.scale_index = init_param.inputs[1]; -} - -void Node::setInputs(const operand::IndexSet &indexes) -{ - assert(indexes.size() == 1); - - graph::operation::Node::setInputs(indexes); -} - -void Node::setOutputs(const operand::IndexSet &indexes) -{ - assert(indexes.size() == 1); - - graph::operation::Node::setOutputs(indexes); + _param.scale_index = operand::Index{init_param.inputs[1]}; } -} // namespace Softmax } // namespace operation -} // namespace graph +} // namespace model } // namespace neurun diff --git a/runtimes/neurun/src/graph/operation/Softmax.h b/runtimes/neurun/src/model/operation/SoftmaxNode.h index e87a27518..4a5a72e5a 100644 --- a/runtimes/neurun/src/graph/operation/Softmax.h +++ b/runtimes/neurun/src/model/operation/SoftmaxNode.h @@ -14,38 +14,37 @@ * limitations under the License. */ -#ifndef __NEURUN_GRAPH_OPERATION_SOFTMAX_H__ -#define __NEURUN_GRAPH_OPERATION_SOFTMAX_H__ +#ifndef __NEURUN_MODEL_OPERATION_SOFTMAX_NODE_H__ +#define __NEURUN_MODEL_OPERATION_SOFTMAX_NODE_H__ #include <memory> -#include "graph/operation/Node.h" +#include "model/operation/Node.h" namespace neurun { -namespace graph +namespace model { namespace operation { -namespace Softmax -{ - -struct Param -{ - int32_t scale_index; -}; -class Node : public graph::operation::Node +class SoftmaxNode : public model::operation::Node { public: - virtual void accept(NodeVisitor &&) const override; + SoftmaxNode(const model::operation::Node::InitParam &init_param); + enum Input + { + INPUT = 0 + }; -public: - Node(const graph::operation::Node::InitParam &init_param); + struct Param + { + operand::Index scale_index; + }; public: - virtual void setInputs(const operand::IndexSet &indexes) override; - virtual void setOutputs(const operand::IndexSet &indexes) override; + virtual void accept(NodeVisitor &&) const override; + virtual std::string getName() const override { return "SoftMax"; } public: const Param ¶m() const { return _param; } @@ -54,9 +53,8 @@ private: Param _param; }; -} // namespace Softmax } // namespace operation -} // namespace graph +} // namespace model } // namespace neurun -#endif // __NEURUN_GRAPH_OPERATION_SOFTMAX_H__ +#endif // __NEURUN_MODEL_OPERATION_SOFTMAX_NODE_H__ diff --git a/runtimes/neurun/src/internal/Padding.cc b/runtimes/neurun/src/util/Padding.cc index 200fa1a02..a24c9ddf7 100644 --- a/runtimes/neurun/src/internal/Padding.cc +++ b/runtimes/neurun/src/util/Padding.cc @@ -14,11 +14,13 @@ * limitations under the License. */ -#include "internal/Padding.h" +#include "util/Padding.h" #include <algorithm> -namespace internal +namespace neurun +{ +namespace util { Padding valid_padding(void) @@ -42,8 +44,8 @@ Padding valid_padding(void) return padding; } -Padding same_padding(const nnfw::util::feature::Shape &ifm_shape, - const nnfw::util::feature::Shape &ofm_shape, const Stride &stride, uint32_t kw, +Padding same_padding(const nnfw::misc::feature::Shape &ifm_shape, + const nnfw::misc::feature::Shape &ofm_shape, const Stride &stride, uint32_t kw, uint32_t kh) { Padding padding; @@ -69,4 +71,5 @@ Padding same_padding(const nnfw::util::feature::Shape &ifm_shape, return padding; } -} // namespace internal +} // namespace util +} // namespace neurun diff --git a/runtimes/neurun/src/internal/Padding.h b/runtimes/neurun/src/util/Padding.h index 84e081a78..05a14eb31 100644 --- a/runtimes/neurun/src/internal/Padding.h +++ b/runtimes/neurun/src/util/Padding.h @@ -14,14 +14,16 @@ * limitations under the License. */ -#ifndef __INTERNAL_PADDING_H__ -#define __INTERNAL_PADDING_H__ +#ifndef __NEURUN_UTIL_PADDING_H__ +#define __NEURUN_UTIL_PADDING_H__ #include <stdint.h> -#include <util/feature/Shape.h> +#include <misc/feature/Shape.h> -namespace internal +namespace neurun +{ +namespace util { struct Padding @@ -39,10 +41,11 @@ struct Stride }; Padding valid_padding(void); -Padding same_padding(const nnfw::util::feature::Shape &ifm_shape, - const nnfw::util::feature::Shape &ofm_shape, const Stride &stride, uint32_t kw, +Padding same_padding(const nnfw::misc::feature::Shape &ifm_shape, + const nnfw::misc::feature::Shape &ofm_shape, const Stride &stride, uint32_t kw, uint32_t kh); -} // namespace internal +} // namespace util +} // namespace neurun -#endif // __INTERNAL_PADDING_H__ +#endif // __NEURUN_UTIL_PADDING_H__ diff --git a/runtimes/neurun/src/util/Utils.cc b/runtimes/neurun/src/util/Utils.cc new file mode 100644 index 000000000..def02db69 --- /dev/null +++ b/runtimes/neurun/src/util/Utils.cc @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2018 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 "Utils.h" + +#include <cassert> + +namespace neurun +{ +namespace util +{ + +const char *to_string(const PaddingCode &code) +{ + assert((ANEURALNETWORKS_PADDING_SAME == code) || (ANEURALNETWORKS_PADDING_VALID == code)); + + switch (code) + { + case ANEURALNETWORKS_PADDING_SAME: + return "ANEURALNETWORKS_PADDING_SAME"; + case ANEURALNETWORKS_PADDING_VALID: + return "ANEURALNETWORKS_PADDING_VALID"; + } + + return nullptr; +} + +} // namespace util +} // namespace neurun diff --git a/runtimes/neurun/src/util/Utils.h b/runtimes/neurun/src/util/Utils.h new file mode 100644 index 000000000..a1e5bf0ba --- /dev/null +++ b/runtimes/neurun/src/util/Utils.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2018 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 Utils.h + * @brief This file contains utility functions + * @ingroup COM_AI_RUNTIME + */ + +#ifndef __NEURUN_UTIL_UTILS_H__ +#define __NEURUN_UTIL_UTILS_H__ + +#include "NeuralNetworks.h" + +namespace neurun +{ +namespace util +{ + +/** + * @brief Converts a PaddingCode to const char* + * @param[in] code The PaddingCode to be converted + * @return A string holding the converted value + */ +const char *to_string(const PaddingCode &code); + +} // namespace util +} // namespace neurun + +#endif // __NEURUN_UTIL_UTILS_H__ diff --git a/runtimes/neurun/src/util/config/Config.lst b/runtimes/neurun/src/util/config/Config.lst new file mode 100644 index 000000000..e029ebe37 --- /dev/null +++ b/runtimes/neurun/src/util/config/Config.lst @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018 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 CONFIG +#error Define CONFIG before including this file +#endif + +// Name | Type | Default +CONFIG(GRAPH_DOT_DUMP , int , "0") +CONFIG(BACKENDS , std::string , "cpu;acl_cl") +CONFIG(OP_BACKEND_ALLOPS , std::string , "none") +CONFIG(DISABLE_COMPILE , bool , "0") + + +// Auto-generate all operations + +#define OP(InternalName, IsNnApi, NnApiName) \ + CONFIG(OP_BACKEND_ ## NnApiName, std::string, "acl_cl") +#include "model/operation/Op.lst" +#undef OP + diff --git a/runtimes/neurun/src/util/config/ConfigManager.cc b/runtimes/neurun/src/util/config/ConfigManager.cc new file mode 100644 index 000000000..46b80311c --- /dev/null +++ b/runtimes/neurun/src/util/config/ConfigManager.cc @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2018 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 "ConfigManager.h" + +#include <cstdlib> + +namespace neurun +{ +namespace config +{ + +ConfigManager &ConfigManager::instance() +{ + static ConfigManager manager; + return manager; +} + +ConfigManager::ConfigManager() +{ + auto fetch_from_env_var = [&](const std::string &key) { + const char *value = std::getenv(key.c_str()); + if (value != nullptr) + { + _map[key] = value; + } + }; + +#define CONFIG(Name, Type, Default) \ + _map.insert({std::string{#Name}, std::string{Default}}); \ + fetch_from_env_var(#Name); + +#include "Config.lst" + +#undef CONFIG +} + +template <> bool ConfigManager::get<bool>(const std::string &key) const +{ + auto raw = _map.at(key); + + static const std::array<std::string, 5> false_list{"0", "OFF", "FALSE", "N", "NO"}; + auto false_found = std::find(false_list.begin(), false_list.end(), raw); + + return (false_found == false_list.end()); +} + +template <> int ConfigManager::get<int>(const std::string &key) const +{ + auto raw = _map.at(key); + return std::stoi(raw); +} + +template <> std::string ConfigManager::get<std::string>(const std::string &key) const +{ + auto raw = _map.at(key); + return raw; +} + +} // namespace config +} // namespace neurun diff --git a/runtimes/neurun/src/util/config/ConfigManager.h b/runtimes/neurun/src/util/config/ConfigManager.h new file mode 100644 index 000000000..78db03dc1 --- /dev/null +++ b/runtimes/neurun/src/util/config/ConfigManager.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2018 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 __NEURUN_CONFIG_CONFIG_MANAGER_H__ +#define __NEURUN_CONFIG_CONFIG_MANAGER_H__ + +#include <algorithm> +#include <string> +#include <unordered_map> + +/** + * @file ConfigManager.h + * @brief This file contains neurun::config::ConfigManager class + */ + +namespace neurun +{ +namespace config +{ + +/** + * @brief Class that manages configurations + */ + +class ConfigManager +{ +public: + static ConfigManager &instance(); + +private: + /** + * @brief Construct a new ConfigManager object. Fetch variables from Environment Variables. + */ + ConfigManager(); + +public: + /** + * @brief Return the configuration value of given key + * + * @tparam T Type of the config + * @param key String key value + * + * @return The configuration value of given key value + */ + template <typename T> T get(const std::string &key) const; + +private: + std::unordered_map<std::string, std::string> _map; +}; + +template <> bool ConfigManager::get<bool>(const std::string &key) const; +template <> int ConfigManager::get<int>(const std::string &key) const; +template <> std::string ConfigManager::get<std::string>(const std::string &key) const; + +} // namespace config +} // namespace neurun + +#endif // __NEURUN_CONFIG_CONFIG_MANAGER_H__ diff --git a/runtimes/neurun/src/util/feature/Coordinate4D.h b/runtimes/neurun/src/util/feature/Coordinate4D.h new file mode 100644 index 000000000..27d6f7b9e --- /dev/null +++ b/runtimes/neurun/src/util/feature/Coordinate4D.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2018 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 __NEURUN_UTIL_FEATURE_COORDINATE_4D_H__ +#define __NEURUN_UTIL_FEATURE_COORDINATE_4D_H__ + +#include <stdint.h> + +namespace neurun +{ +namespace util +{ +namespace feature +{ + +/** + * @brief Class to represent position(offset) of subtensor.\n + * Assume that parent and child are already lowered (can get Shape4D). + */ +class Coordinate4D +{ +public: + /** + * @brief Construct a new Coordinate4D object + */ + Coordinate4D(void) : _n{0}, _h{0}, _w{0}, _c{0} + { + // DO NOTHING + } + /** + * @brief Construct a new Coordinate4D object + * @param[in] n Batch offset + * @param[in] h Height offset + * @param[in] w Width offset + * @param[in] c Channel offset + * @return + */ + Coordinate4D(int32_t n, int32_t h, int32_t w, int32_t c) : _n{n}, _h{h}, _w{w}, _c{c} + { + // DO NOTHING + } + +public: + /** + * @brief Return batch offset + * @return Batch offset + */ + int32_t n(void) const { return _n; } + /** + * @brief Return height offset + * @return Height offset + */ + int32_t h(void) const { return _h; } + /** + * @brief Return width offset + * @return Width offset + */ + int32_t w(void) const { return _w; } + /** + * @brief Return channel offset + * @return Channel offset + */ + int32_t c(void) const { return _c; } + +private: + int32_t _n; + int32_t _h; + int32_t _w; + int32_t _c; +}; + +} // namespace feature +} // namespace util +} // namespace neurun + +#endif // __NEURUN_UTIL_FEATURE_COORDINATE_4D_H__ diff --git a/runtimes/neurun/src/util/feature/nchw/View.h b/runtimes/neurun/src/util/feature/nchw/View.h new file mode 100644 index 000000000..048fdecd8 --- /dev/null +++ b/runtimes/neurun/src/util/feature/nchw/View.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2018 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 __NEURUN_UTIL_FEATURE_NCHW_VIEW_H__ +#define __NEURUN_UTIL_FEATURE_NCHW_VIEW_H__ + +#include "misc/feature/Reader.h" +#include "misc/feature/Shape.h" + +#include "backend/interface/operand/ITensor.h" +#include "util/feature/Coordinate4D.h" + +#include <cassert> + +namespace neurun +{ +namespace util +{ +namespace feature +{ +namespace nchw +{ + +template <typename T> class View final : public nnfw::misc::feature::Reader<T> +{ +public: + View(::neurun::backend::operand::ITensor *tensor) : _tensor{tensor} + { + // TODO Validate whether tensor is a feature map, or not + _shape.N = tensor->dimension(3); + _shape.C = tensor->dimension(2); + _shape.H = tensor->dimension(1); + _shape.W = tensor->dimension(0); + } + +public: + const ::nnfw::misc::feature::Shape &shape(void) const { return _shape; } + +public: + T at(uint32_t ch, uint32_t row, uint32_t col) const override + { + const auto offset = feature_index_to_byte_offset(0, ch, row, col); + + T *ptr = reinterpret_cast<T *>(_tensor->buffer() + offset); + + return *ptr; + } + T at(uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) const override + { + const auto offset = feature_index_to_byte_offset(batch, ch, row, col); + + T *ptr = reinterpret_cast<T *>(_tensor->buffer() + offset); + + return *ptr; + } + +public: + T &at(uint32_t ch, uint32_t row, uint32_t col) + { + const auto offset = feature_index_to_byte_offset(0, ch, row, col); + + T *ptr = reinterpret_cast<T *>(_tensor->buffer() + offset); + + return *ptr; + } + T &at(uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) + { + const auto offset = feature_index_to_byte_offset(batch, ch, row, col); + + T *ptr = reinterpret_cast<T *>(_tensor->buffer() + offset); + + return *ptr; + } + +private: + size_t feature_index_to_byte_offset(uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) const + { + return _tensor->calcOffset( + neurun::util::feature::Coordinate4D{static_cast<int32_t>(batch), static_cast<int32_t>(row), + static_cast<int32_t>(col), static_cast<int32_t>(ch)}); + } + +private: + ::nnfw::misc::feature::Shape _shape; + ::neurun::backend::operand::ITensor *_tensor; +}; + +} // namespace nchw +} // namespace feature +} // namespace util +} // namespace neurun + +#endif // __NEURUN_UTIL_FEATURE_NCHW_VIEW_H__ diff --git a/runtimes/neurun/src/util/feature/nhwc/Reader.h b/runtimes/neurun/src/util/feature/nhwc/Reader.h new file mode 100644 index 000000000..85b8cab74 --- /dev/null +++ b/runtimes/neurun/src/util/feature/nhwc/Reader.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2018 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 __NEURUN_UTIL_FEATURE_NHWC_READER_H__ +#define __NEURUN_UTIL_FEATURE_NHWC_READER_H__ + +#include "Utils.h" + +#include "misc/feature/Reader.h" + +namespace neurun +{ +namespace util +{ +namespace feature +{ +namespace nhwc +{ + +template <typename T> class Reader final : public nnfw::misc::feature::Reader<T> +{ +public: + Reader(const ::nnfw::misc::feature::Shape &shape, const T *ptr, size_t len) + : _shape{shape}, _ptr{ptr} + { + (void)len; // Workaround for unused variable in release mode + assert(shape.N * shape.C * shape.H * shape.W * sizeof(T) == len); + } + +public: + const nnfw::misc::feature::Shape &shape(void) const { return _shape; } + +public: + T at(uint32_t ch, uint32_t row, uint32_t col) const override + { + uint32_t index = index_of(_shape, ch, row, col); + + return _ptr[index]; + } + T at(uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) const override + { + uint32_t index = index_of(_shape, batch, ch, row, col); + + return _ptr[index]; + } + +private: + nnfw::misc::feature::Shape _shape; + +private: + const T *_ptr; +}; + +} // namespace nhwc +} // namespace feature +} // namespace util +} // namespace neurun + +#endif // __NEURUN_UTIL_FEATURE_NHWC_READER_H__ diff --git a/runtimes/neurun/src/internal/nnapi/feature/Utils.h b/runtimes/neurun/src/util/feature/nhwc/Utils.h index e6e1e71bd..3dab4261c 100644 --- a/runtimes/neurun/src/internal/nnapi/feature/Utils.h +++ b/runtimes/neurun/src/util/feature/nhwc/Utils.h @@ -14,19 +14,21 @@ * limitations under the License. */ -#ifndef __INTERNAL_NNAPI_FEATURE_UTILS_H__ -#define __INTERNAL_NNAPI_FEATURE_UTILS_H__ +#ifndef __NEURUN_UTIL_FEATURE_NHWC_UTILS_H__ +#define __NEURUN_UTIL_FEATURE_NHWC_UTILS_H__ -#include "util/feature/Shape.h" +#include "misc/feature/Shape.h" -namespace internal +namespace neurun { -namespace nnapi +namespace util { namespace feature { +namespace nhwc +{ -inline uint32_t index_of(const ::nnfw::util::feature::Shape &shape, uint32_t ch, uint32_t row, +inline uint32_t index_of(const ::nnfw::misc::feature::Shape &shape, uint32_t ch, uint32_t row, uint32_t col) { uint32_t res = 0; @@ -39,7 +41,7 @@ inline uint32_t index_of(const ::nnfw::util::feature::Shape &shape, uint32_t ch, return res; } -inline uint32_t index_of(const ::nnfw::util::feature::Shape &shape, uint32_t batch, uint32_t ch, +inline uint32_t index_of(const ::nnfw::misc::feature::Shape &shape, uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) { uint32_t res = 0; @@ -53,8 +55,9 @@ inline uint32_t index_of(const ::nnfw::util::feature::Shape &shape, uint32_t bat return res; } +} // namespace nhwc } // namespace feature -} // namespace nnapi -} // namespace internal +} // namespace util +} // namespace neurun -#endif // __INTERNAL_NNAPI_FEATURE_UTILS_H__ +#endif // __NEURUN_UTIL_FEATURE_NHWC_UTILS_H__ diff --git a/runtimes/neurun/src/internal/nnapi/feature/View.h b/runtimes/neurun/src/util/feature/nhwc/View.h index 60335dbf1..1b9be9e1d 100644 --- a/runtimes/neurun/src/internal/nnapi/feature/View.h +++ b/runtimes/neurun/src/util/feature/nhwc/View.h @@ -14,79 +14,75 @@ * limitations under the License. */ -#ifndef __INTERNAL_NNAPI_FEATURE_VIEW_H__ -#define __INTERNAL_NNAPI_FEATURE_VIEW_H__ +#ifndef __NEURUN_UTIL_FEATURE_NHWC_VIEW_H__ +#define __NEURUN_UTIL_FEATURE_NHWC_VIEW_H__ -#include "internal/nnapi/feature/Utils.h" +#include <cassert> -#include "util/feature/Reader.h" +#include "Utils.h" -namespace internal +#include "misc/feature/Reader.h" + +namespace neurun { -namespace nnapi +namespace util { namespace feature { +namespace nhwc +{ -template <typename T> class View final : public nnfw::util::feature::Reader<float> +template <typename T> class View final : public nnfw::misc::feature::Reader<T> { public: - View(const ::nnfw::util::feature::Shape &shape, uint8_t *ptr, size_t len) - : _shape{shape}, _ptr{ptr}, _len{len} + View(const ::nnfw::misc::feature::Shape &shape, T *ptr, size_t len) : _shape{shape}, _ptr{ptr} { - // DO NOTHING + (void)len; // Workaround for unused variable in release mode + assert(shape.N * shape.C * shape.H * shape.W * sizeof(T) == len); } public: - const nnfw::util::feature::Shape &shape(void) const { return _shape; } + const nnfw::misc::feature::Shape &shape(void) const { return _shape; } public: T at(uint32_t ch, uint32_t row, uint32_t col) const override { uint32_t index = index_of(_shape, ch, row, col); - T *arr = reinterpret_cast<T *>(_ptr); - - return arr[index]; + return _ptr[index]; } T at(uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) const override { uint32_t index = index_of(_shape, batch, ch, row, col); - T *arr = reinterpret_cast<T *>(_ptr); - - return arr[index]; + return _ptr[index]; } T &at(uint32_t ch, uint32_t row, uint32_t col) { uint32_t index = index_of(_shape, ch, row, col); - T *arr = reinterpret_cast<T *>(_ptr); - - return arr[index]; + return _ptr[index]; } T &at(uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) { uint32_t index = index_of(_shape, batch, ch, row, col); - T *arr = reinterpret_cast<T *>(_ptr); - - return arr[index]; + return _ptr[index]; } private: - nnfw::util::feature::Shape _shape; + nnfw::misc::feature::Shape _shape; private: - uint8_t *_ptr; - const size_t _len; + T *_ptr; }; +} // namespace nhwc } // namespace feature -} // namespace nnapi -} // namespace internal +} // namespace util +} // namespace neurun -#endif // __INTERNAL_NNAPI_FEATURE_VIEW_H__ +#endif // __NEURUN_UTIL_FEATURE_NHWC_VIEW_H__ diff --git a/runtimes/neurun/src/logging.h b/runtimes/neurun/src/util/logging.h index 950df7b52..62d563967 100644 --- a/runtimes/neurun/src/logging.h +++ b/runtimes/neurun/src/util/logging.h @@ -14,11 +14,15 @@ * limitations under the License. */ -#ifndef __NEURUN_LOGGING_H__ -#define __NEURUN_LOGGING_H__ +#ifndef __NEURUN_UTIL_LOGGING_H__ +#define __NEURUN_UTIL_LOGGING_H__ #include <iostream> +namespace neurun +{ +namespace util +{ namespace logging { @@ -45,9 +49,11 @@ private: static Context ctx; } // namespace logging +} // namespace util +} // namespace neurun -#define VERBOSE(name) \ - if (::logging::ctx.enabled()) \ +#define VERBOSE(name) \ + if (::neurun::util::logging::ctx.enabled()) \ std::cout << "[" << #name << "] " -#endif // __NEURUN_LOGGING_H__ +#endif // __NEURUN_UTIL_LOGGING_H__ diff --git a/runtimes/neurun/test/backend/cpu/MemoryPlanner.cc b/runtimes/neurun/test/backend/cpu/MemoryPlanner.cc new file mode 100644 index 000000000..04f2e5da4 --- /dev/null +++ b/runtimes/neurun/test/backend/cpu/MemoryPlanner.cc @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2018 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 <gtest/gtest.h> + +#include "backend/cpu/MemoryPlanner.h" +#include "model/operand/Index.h" + +TEST(Allocator, allocate_test) +{ + ::neurun::backend::cpu::Allocator allocator(1024); + ASSERT_NE(allocator.base(), nullptr); +} + +TEST(BumpPlanner, claim_test) +{ + ::neurun::backend::cpu::BumpPlanner planner; + + auto claim = [&planner](uint32_t index, size_t size, uint32_t expected_offset) { + ::neurun::model::operand::Index mem_idx(index); + planner.claim(mem_idx, size); + auto mem_blk = planner.memory_plans()[mem_idx]; + ASSERT_EQ(mem_blk.offset, expected_offset); + ASSERT_EQ(mem_blk.size, size); + }; + + claim(0, 10, 0); + claim(1, 20, 10); + claim(2, 30, 30); +} + +TEST(FirstFitPlanner, claim_release_test) +{ + ::neurun::backend::cpu::FirstFitPlanner planner; + + auto claim = [&planner](uint32_t index, size_t size, uint32_t expected_offset) { + ::neurun::model::operand::Index mem_idx(index); + planner.claim(mem_idx, size); + auto mem_blk = planner.memory_plans()[mem_idx]; + ASSERT_EQ(mem_blk.offset, expected_offset); + ASSERT_EQ(mem_blk.size, size); + }; + + auto release = [&planner](uint32_t index) { + ::neurun::model::operand::Index mem_idx(index); + planner.release(mem_idx); + }; + + // 0 CLAIM - 10 + claim(0, 10, 0); + + // 1 CLAIM - 20 + claim(1, 20, 10); + + // 2 CLAIM - 30 + claim(2, 30, 30); + + // 0 RELEASE - 10 + release(0); + + // 3 CLAIM - 20 + claim(3, 20, 60); + + // 4 CLAIM - 5 + claim(4, 5, 0); + + // 5 CLAIM - 10 + claim(5, 10, 80); + + // 6 CLAIM - 5 + claim(6, 5, 5); + + // 2 RELEASE - 30 + release(2); + + // 7 CLAIM - 35 + claim(7, 35, 90); + + // 8 CLAIM - 10 + claim(8, 10, 30); + + // 4 RELEASE - 5 + release(4); + + // 9 CLAIM - 10 + claim(9, 10, 40); + + // 10 CLAIM - 10 + claim(10, 10, 50); + + // 6 RELEASE + release(6); + + // 1 RELEASE + release(1); + + // 8 RELEASE + release(8); + + // 9 RELEASE + release(9); + + // 10 RELEASE + release(10); + + // 3 RELEASE + release(3); + + // 5 RELEASE + release(5); + + // 7 RELEASE + release(7); +} diff --git a/runtimes/neurun/test/graph/Graph.cc b/runtimes/neurun/test/graph/Graph.cc index 5de3c50d0..e6db3fe49 100644 --- a/runtimes/neurun/test/graph/Graph.cc +++ b/runtimes/neurun/test/graph/Graph.cc @@ -22,15 +22,15 @@ TEST(Graph, inputs_and_outputs) { ::neurun::graph::Graph graph; - ::neurun::graph::operand::Index index0{0u}; - ::neurun::graph::operand::Index index1{1u}; + ::neurun::model::operand::Index index0{0u}; + ::neurun::model::operand::Index index1{1u}; graph.addInput({index0}); graph.addInput({index1}); - ::neurun::graph::operand::Index index10{10u}; - ::neurun::graph::operand::Index index11{11u}; - ::neurun::graph::operand::Index index12{12u}; + ::neurun::model::operand::Index index10{10u}; + ::neurun::model::operand::Index index11{11u}; + ::neurun::model::operand::Index index12{12u}; graph.addOutput({index10}); graph.addOutput({index11}); @@ -39,9 +39,9 @@ TEST(Graph, inputs_and_outputs) ASSERT_EQ(graph.getInputs().size(), 2); ASSERT_EQ(graph.getOutputs().size(), 3); - ::neurun::graph::operand::IO::Index io_index0{0}; - ::neurun::graph::operand::IO::Index io_index1{1}; - ::neurun::graph::operand::IO::Index io_index2{2}; + ::neurun::model::operand::IO::Index io_index0{0}; + ::neurun::model::operand::IO::Index io_index1{1}; + ::neurun::model::operand::IO::Index io_index2{2}; ASSERT_EQ(graph.getInputs().at(io_index0), 0); ASSERT_EQ(graph.getInputs().at(io_index1), 1); diff --git a/runtimes/neurun/test/graph/operation/MockNode.h b/runtimes/neurun/test/graph/MockNode.h index 9456b97be..46a6274dd 100644 --- a/runtimes/neurun/test/graph/operation/MockNode.h +++ b/runtimes/neurun/test/graph/MockNode.h @@ -14,35 +14,34 @@ * limitations under the License. */ -#ifndef __NEURUN_TEST_GRAPH_OPERATION_MOCK_NODE_H__ -#define __NEURUN_TEST_GRAPH_OPERATION_MOCK_NODE_H__ +#ifndef __NEURUN_TEST_GRAPH_MOCK_NODE_H__ +#define __NEURUN_TEST_GRAPH_MOCK_NODE_H__ -#include "graph/operation/Node.h" -#include "graph/operand/IndexSet.h" +#include "model/operation/Node.h" +#include "model/operand/IndexSet.h" namespace neurun_test { namespace graph { -namespace operation -{ -class SimpleMockNode : public neurun::graph::operation::Node +class SimpleMockNode : public neurun::model::operation::Node { public: - SimpleMockNode(const neurun::graph::operand::IndexSet &inputs, - const neurun::graph::operand::IndexSet &outputs) + SimpleMockNode(const neurun::model::operand::IndexSet &inputs, + const neurun::model::operand::IndexSet &outputs) + : neurun::model::operation::Node{neurun::model::operation::OperandConstraint::createAny()} { setInputs(inputs); setOutputs(outputs); } public: - virtual void accept(neurun::graph::operation::NodeVisitor &&) const override {} + virtual void accept(neurun::model::operation::NodeVisitor &&) const override {} + virtual std::string getName() const override { return "SimpleMockNode"; } }; -} // namespace operation } // namespace graph } // namespace neurun_test -#endif // __NEURUN_TEST_GRAPH_OPERATION_MOCK_NODE_H__ +#endif // __NEURUN_TEST_GRAPH_MOCK_NODE_H__ diff --git a/runtimes/neurun/test/graph/operand/IndexSet.cc b/runtimes/neurun/test/graph/operand/IndexSet.cc index eeb4cef97..de4768cda 100644 --- a/runtimes/neurun/test/graph/operand/IndexSet.cc +++ b/runtimes/neurun/test/graph/operand/IndexSet.cc @@ -16,12 +16,12 @@ #include <gtest/gtest.h> -#include "graph/operand/IndexSet.h" +#include "model/operand/IndexSet.h" -using neurun::graph::operand::Index; -using neurun::graph::operand::IndexSet; +using neurun::model::operand::Index; +using neurun::model::operand::IndexSet; -TEST(graph_operand_IndexSet, index_set_test) +TEST(graph_operand_IndexSet, append) { IndexSet iset{0, 2, 4, 8}; @@ -31,8 +31,8 @@ TEST(graph_operand_IndexSet, index_set_test) ASSERT_EQ(iset.size(), 5); - neurun::graph::operand::IO::Index index1{1}; - neurun::graph::operand::IO::Index index2{4}; + neurun::model::operand::IO::Index index1{1}; + neurun::model::operand::IO::Index index2{4}; ASSERT_EQ(iset.at(index1), 2); ASSERT_EQ(iset.at(index2), 10); @@ -41,3 +41,12 @@ TEST(graph_operand_IndexSet, index_set_test) ASSERT_TRUE(iset.contains(Index{10})); ASSERT_FALSE(iset.contains(Index{11})); } + +TEST(graph_operand_IndexSet, replace) +{ + IndexSet iset{0, 1, 2, 3}; + + iset.replace(Index{1}, Index{9}); + ASSERT_FALSE(iset.contains(Index{1})); + ASSERT_TRUE(iset.contains(Index{9})); +} diff --git a/runtimes/neurun/test/graph/operand/LayoutSet.cc b/runtimes/neurun/test/graph/operand/LayoutSet.cc index 6ff21cb60..f83e76e30 100644 --- a/runtimes/neurun/test/graph/operand/LayoutSet.cc +++ b/runtimes/neurun/test/graph/operand/LayoutSet.cc @@ -1,3 +1,19 @@ +/* + * Copyright (c) 2018 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 <gtest/gtest.h> #include "graph/operand/LayoutSet.h" diff --git a/runtimes/neurun/test/graph/operand/Set.cc b/runtimes/neurun/test/graph/operand/Set.cc index 176cedc38..00b6a7222 100644 --- a/runtimes/neurun/test/graph/operand/Set.cc +++ b/runtimes/neurun/test/graph/operand/Set.cc @@ -16,33 +16,33 @@ #include <gtest/gtest.h> -#include "graph/operand/Set.h" +#include "model/operand/Set.h" TEST(graph_operand_Set, set_test) { - neurun::graph::operand::Set set; + neurun::model::operand::Set set; - ::neurun::graph::operand::Shape shape0{3}; + ::neurun::model::operand::Shape shape0{3}; shape0.dim(0) = 1; shape0.dim(1) = 2; shape0.dim(2) = 3; - ::neurun::graph::operand::Shape shape1{4}; + ::neurun::model::operand::Shape shape1{4}; shape1.dim(0) = 10; shape1.dim(1) = 20; shape1.dim(2) = 30; shape1.dim(3) = 40; - ::neurun::graph::operand::TypeInfo type{ANEURALNETWORKS_TENSOR_INT32, 0, 0}; + ::neurun::model::operand::TypeInfo type{ANEURALNETWORKS_TENSOR_INT32, 0, 0}; set.append(shape0, type); set.append(shape1, type); - ASSERT_EQ(set.exist(neurun::graph::operand::Index{0u}), true); - ASSERT_EQ(set.exist(neurun::graph::operand::Index{1u}), true); - ASSERT_EQ(set.exist(neurun::graph::operand::Index{2u}), false); + ASSERT_EQ(set.exist(neurun::model::operand::Index{0u}), true); + ASSERT_EQ(set.exist(neurun::model::operand::Index{1u}), true); + ASSERT_EQ(set.exist(neurun::model::operand::Index{2u}), false); - ASSERT_EQ(set.at(neurun::graph::operand::Index{0u}).shape().dim(0), 1); - ASSERT_EQ(set.at(neurun::graph::operand::Index{0u}).shape().dim(1), 2); - ASSERT_EQ(set.at(neurun::graph::operand::Index{0u}).shape().dim(2), 3); + ASSERT_EQ(set.at(neurun::model::operand::Index{0u}).shape().dim(0), 1); + ASSERT_EQ(set.at(neurun::model::operand::Index{0u}).shape().dim(1), 2); + ASSERT_EQ(set.at(neurun::model::operand::Index{0u}).shape().dim(2), 3); } diff --git a/runtimes/neurun/test/graph/operand/UseDef.cc b/runtimes/neurun/test/graph/operand/UseDef.cc index caaea1f6a..e3792f746 100644 --- a/runtimes/neurun/test/graph/operand/UseDef.cc +++ b/runtimes/neurun/test/graph/operand/UseDef.cc @@ -17,17 +17,17 @@ #include <gtest/gtest.h> #include "graph/Graph.h" -#include "graph/verifier/IVerifier.h" -#include "nnfw/std/memory.h" -#include "../operation/MockNode.h" +#include "graph/verifier/Verifier.h" +#include "cpp14/memory.h" +#include "../MockNode.h" #include <typeindex> namespace { -using IndexSet = neurun::graph::operand::IndexSet; -using MockNode = neurun_test::graph::operation::SimpleMockNode; +using IndexSet = neurun::model::operand::IndexSet; +using MockNode = neurun_test::graph::SimpleMockNode; } // namespace anonymous @@ -36,8 +36,8 @@ TEST(graph_operand_usedef, usedef_test) neurun::graph::Graph graph; neurun::graph::verifier::DAGChecker verifier; - neurun::graph::operand::Shape shape{1u}; - neurun::graph::operand::TypeInfo type{ANEURALNETWORKS_TENSOR_INT32, 0, 0}; + neurun::model::operand::Shape shape{1u}; + neurun::model::operand::TypeInfo type{ANEURALNETWORKS_TENSOR_INT32, 0, 0}; shape.dim(0) = 3; // Model Input/Output @@ -53,16 +53,16 @@ TEST(graph_operand_usedef, usedef_test) auto operand_index1 = graph.addOperand(shape, type); graph.operands().at(operand_index1).setAsOperationOutput(); auto mocknode_index1 = graph.addOperation( - nnfw::make_unique<MockNode>(IndexSet{input_operand}, IndexSet{operand_index1})); + nnfw::cpp14::make_unique<MockNode>(IndexSet{input_operand}, IndexSet{operand_index1})); // MockNode2 auto operand_index2 = graph.addOperand(shape, type); graph.operands().at(operand_index2).setAsOperationOutput(); auto mocknode_index2 = graph.addOperation( - nnfw::make_unique<MockNode>(IndexSet{input_operand}, IndexSet{operand_index2})); + nnfw::cpp14::make_unique<MockNode>(IndexSet{input_operand}, IndexSet{operand_index2})); // MockNode3(two input) - auto multiinput_index = graph.addOperation(nnfw::make_unique<MockNode>( + auto multiinput_index = graph.addOperation(nnfw::cpp14::make_unique<MockNode>( IndexSet{operand_index1, operand_index2}, IndexSet{output_operand})); graph.finishBuilding(); @@ -89,85 +89,3 @@ TEST(graph_operand_usedef, usedef_test) ASSERT_EQ(graph.operands().at(operand_index1).getUses().size(), 1); ASSERT_EQ(graph.operands().at(output_operand).getUses().size(), 0); } - -TEST(graph_operand_usedef, usedef_test_insertion) -{ - neurun::graph::Graph graph; - neurun::graph::verifier::DAGChecker verifier; - - neurun::graph::operand::Shape shape{1u}; - neurun::graph::operand::TypeInfo type{ANEURALNETWORKS_TENSOR_INT32, 0, 0}; - shape.dim(0) = 3; - - // Model Input/Output - auto input_operand = graph.addOperand(shape, type); - auto output_operand = graph.addOperand(shape, type); - - graph.addInput(input_operand); - graph.operands().at(input_operand).setAsModelInput(); - graph.addOutput(output_operand); - graph.operands().at(output_operand).setAsOperationOutput(); - - // MockNode1 - auto operand_index1 = graph.addOperand(shape, type); - graph.operands().at(operand_index1).setAsOperationOutput(); - auto mocknode_index1 = graph.addOperation( - nnfw::make_unique<MockNode>(IndexSet{input_operand}, IndexSet{operand_index1})); - - // MockNode2 - auto operand_index2 = graph.addOperand(shape, type); - graph.operands().at(operand_index2).setAsOperationOutput(); - auto mocknode_index2 = graph.addOperation( - nnfw::make_unique<MockNode>(IndexSet{input_operand}, IndexSet{operand_index2})); - - // MockNode3(two input) - auto multiinput_index = graph.addOperation(nnfw::make_unique<MockNode>( - IndexSet{operand_index1, operand_index2}, IndexSet{output_operand})); - - graph.finishBuilding(); - - // Insert node1 (between 1 and 2) - auto inserted_operand1 = graph.addOperand(shape, type); - graph.operands().at(inserted_operand1).setAsOperationOutput(); - auto inserted_index1 = - graph.insertOperation(input_operand, mocknode_index2, - nnfw::make_unique<MockNode>(IndexSet{}, IndexSet{inserted_operand1})); - - ASSERT_EQ(inserted_index1.asInt(), 3); - - // Insert node2 (between 2 and 3) - auto inserted_operand2 = graph.addOperand(shape, type); - graph.operands().at(inserted_operand2).setAsOperationOutput(); - auto inserted_index2 = - graph.insertOperation(operand_index2, multiinput_index, - nnfw::make_unique<MockNode>(IndexSet{}, IndexSet{inserted_operand2})); - - ASSERT_EQ(inserted_index2.asInt(), 4); - - ASSERT_EQ(verifier.verify(graph), true); - - // Check def - ASSERT_EQ(graph.operands().at(input_operand).getDef().size(), 0); - ASSERT_EQ(graph.operands().at(operand_index1).getDef().contains(mocknode_index1), true); - ASSERT_EQ(graph.operands().at(inserted_operand1).getDef().contains(inserted_index1), true); - ASSERT_EQ(graph.operands().at(operand_index2).getDef().contains(mocknode_index2), true); - ASSERT_EQ(graph.operands().at(inserted_operand2).getDef().contains(inserted_index2), true); - ASSERT_EQ(graph.operands().at(output_operand).getDef().contains(multiinput_index), true); - - // Check use - ASSERT_EQ(graph.operands().at(input_operand).getUses().contains(mocknode_index1), true); - ASSERT_EQ(graph.operands().at(input_operand).getUses().contains(inserted_index1), true); - ASSERT_EQ(graph.operands().at(input_operand).getUses().contains(mocknode_index2), false); - ASSERT_EQ(graph.operands().at(inserted_operand1).getUses().contains(mocknode_index2), true); - ASSERT_EQ(graph.operands().at(operand_index1).getUses().contains(multiinput_index), true); - ASSERT_EQ(graph.operands().at(operand_index2).getUses().contains(inserted_index2), true); - ASSERT_EQ(graph.operands().at(operand_index2).getUses().contains(multiinput_index), false); - ASSERT_EQ(graph.operands().at(inserted_operand2).getUses().contains(multiinput_index), true); - - ASSERT_EQ(graph.operands().at(input_operand).getUses().size(), 2); - ASSERT_EQ(graph.operands().at(inserted_operand1).getUses().size(), 1); - ASSERT_EQ(graph.operands().at(operand_index1).getUses().size(), 1); - ASSERT_EQ(graph.operands().at(inserted_operand2).getUses().size(), 1); - ASSERT_EQ(graph.operands().at(operand_index2).getUses().size(), 1); - ASSERT_EQ(graph.operands().at(output_operand).getUses().size(), 0); -} diff --git a/runtimes/neurun/test/graph/operation/Insert.cc b/runtimes/neurun/test/graph/operation/Insert.cc deleted file mode 100644 index dab89c2a6..000000000 --- a/runtimes/neurun/test/graph/operation/Insert.cc +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (c) 2018 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 <gtest/gtest.h> - -#include "graph/Graph.h" -#include "graph/verifier/IVerifier.h" -#include "nnfw/std/memory.h" -#include "graph/operand/Index.h" -#include "MockNode.h" - -#include <typeindex> - -using IOIndex = neurun::graph::operand::IO::Index; -using Index = neurun::graph::operand::Index; -using IndexSet = neurun::graph::operand::IndexSet; -using MockNode = neurun_test::graph::operation::SimpleMockNode; - -TEST(graph_operation_manipulation, operation_insertion) -{ - neurun::graph::Graph graph; - neurun::graph::verifier::DAGChecker verifier; - - neurun::graph::operand::Shape shape{1u}; - neurun::graph::operand::TypeInfo type{ANEURALNETWORKS_TENSOR_INT32, 0, 0}; - shape.dim(0) = 3; - - // Model Input/Output - auto input_operand = graph.addOperand(shape, type); - auto output_operand = graph.addOperand(shape, type); - - graph.addInput(input_operand); - graph.operands().at(input_operand).setAsModelInput(); - graph.addOutput(output_operand); - graph.operands().at(output_operand).setAsOperationOutput(); - - // MockNode1 - auto operand1 = graph.addOperand(shape, type); - graph.operands().at(operand1).setAsOperationOutput(); - auto mocknode_index1 = - graph.addOperation(nnfw::make_unique<MockNode>(IndexSet{input_operand}, IndexSet{operand1})); - // MockNode2 - auto operand2 = graph.addOperand(shape, type); - graph.operands().at(operand2).setAsOperationOutput(); - auto mocknode_index2 = - graph.addOperation(nnfw::make_unique<MockNode>(IndexSet{operand1}, IndexSet{operand2})); - // MockNode3 - auto mocknode_index3 = - graph.addOperation(nnfw::make_unique<MockNode>(IndexSet{operand2}, IndexSet{output_operand})); - - graph.finishBuilding(); - - ASSERT_EQ(verifier.verify(graph), true); - - // Insert node1 (between 1 and 2) - auto inserted_operand1 = graph.addOperand(shape, type); - graph.operands().at(inserted_operand1).setAsOperationOutput(); - auto inserted_index1 = - graph.insertOperation(operand1, mocknode_index2, - nnfw::make_unique<MockNode>(IndexSet{}, IndexSet{inserted_operand1})); - - ASSERT_EQ(inserted_index1.asInt(), 3); - - // Insert node2 (between 2 and 3) - auto inserted_operand2 = graph.addOperand(shape, type); - graph.operands().at(inserted_operand2).setAsOperationOutput(); - auto inserted_index2 = - graph.insertOperation(operand2, mocknode_index3, - nnfw::make_unique<MockNode>(IndexSet{}, IndexSet{inserted_operand2})); - - ASSERT_EQ(inserted_index2.asInt(), 4); - - // Check tensor indexes - const auto &operations = graph.operations(); - ASSERT_EQ(operations.at(mocknode_index1).getOutputs().at(Index{0}), - operations.at(inserted_index1).getInputs().at(Index{0})); - ASSERT_EQ(operations.at(inserted_index1).getOutputs().at(Index{0}), - operations.at(mocknode_index2).getInputs().at(Index{0})); - ASSERT_EQ(operations.at(mocknode_index2).getOutputs().at(Index{0}), - operations.at(inserted_index2).getInputs().at(Index{0})); - ASSERT_EQ(operations.at(inserted_index2).getOutputs().at(Index{0}), - operations.at(mocknode_index3).getInputs().at(Index{0})); - - ASSERT_EQ(verifier.verify(graph), true); -} - -TEST(graph_operation_manipulation, operation_insertion_multi_input) -{ - neurun::graph::Graph graph; - neurun::graph::verifier::DAGChecker verifier; - - neurun::graph::operand::Shape shape{1u}; - neurun::graph::operand::TypeInfo type{ANEURALNETWORKS_TENSOR_INT32, 0, 0}; - shape.dim(0) = 3; - - // Model Input/Output - auto input_operand = graph.addOperand(shape, type); - auto output_operand = graph.addOperand(shape, type); - - graph.addInput(input_operand); - graph.operands().at(input_operand).setAsModelInput(); - graph.addOutput(output_operand); - graph.operands().at(output_operand).setAsOperationOutput(); - - // MockNode1 - auto operand1 = graph.addOperand(shape, type); - graph.operands().at(operand1).setAsOperationOutput(); - auto mocknode_index1 = - graph.addOperation(nnfw::make_unique<MockNode>(IndexSet{input_operand}, IndexSet{operand1})); - // MockNode2 - auto operand2 = graph.addOperand(shape, type); - graph.operands().at(operand2).setAsOperationOutput(); - auto mocknode_index2 = - graph.addOperation(nnfw::make_unique<MockNode>(IndexSet{input_operand}, IndexSet{operand2})); - // MultiInputMockNode - auto multiinput_index = graph.addOperation( - nnfw::make_unique<MockNode>(IndexSet{operand1, operand2}, IndexSet{output_operand})); - - graph.finishBuilding(); - - ASSERT_EQ(verifier.verify(graph), true); - - // Insert node1 (between 1 and multi) - auto inserted_operand1 = graph.addOperand(shape, type); - graph.operands().at(inserted_operand1).setAsOperationOutput(); - auto inserted_index1 = - graph.insertOperation(operand1, multiinput_index, - nnfw::make_unique<MockNode>(IndexSet{}, IndexSet{inserted_operand1})); - - ASSERT_EQ(inserted_index1.asInt(), 3); - - // Insert node2 (between 2 and multi) - auto inserted_operand2 = graph.addOperand(shape, type); - graph.operands().at(inserted_operand2).setAsOperationOutput(); - auto inserted_index2 = - graph.insertOperation(operand2, multiinput_index, - nnfw::make_unique<MockNode>(IndexSet{}, IndexSet{inserted_operand2})); - - ASSERT_EQ(inserted_index2.asInt(), 4); - - // Check tensor indexes - const auto &operations = graph.operations(); - ASSERT_EQ(operations.at(mocknode_index1).getOutputs().at(Index{0}), - operations.at(inserted_index1).getInputs().at(Index{0})); - ASSERT_EQ(operations.at(inserted_index1).getOutputs().at(Index{0}), - operations.at(multiinput_index).getInputs().at(Index{0})); - ASSERT_EQ(operations.at(mocknode_index2).getOutputs().at(Index{0}), - operations.at(inserted_index2).getInputs().at(Index{0})); - ASSERT_EQ(operations.at(inserted_index2).getOutputs().at(Index{0}), - operations.at(multiinput_index).getInputs().at(Index{1})); - - ASSERT_EQ(verifier.verify(graph), true); -} diff --git a/runtimes/neurun/test/graph/operation/Set.cc b/runtimes/neurun/test/graph/operation/Set.cc index df680ff48..3560482ee 100644 --- a/runtimes/neurun/test/graph/operation/Set.cc +++ b/runtimes/neurun/test/graph/operation/Set.cc @@ -16,18 +16,18 @@ #include <gtest/gtest.h> -#include "MockNode.h" -#include "graph/operation/Set.h" +#include "../MockNode.h" +#include "model/operation/Set.h" -using neurun::graph::operation::Set; -using neurun::graph::operation::Node; -using neurun::graph::operation::Index; +using neurun::model::operation::Set; +using neurun::model::operation::Node; +using neurun::model::operation::Index; TEST(graph_operation_Set, operation_test) { Set set; - set.append(std::unique_ptr<Node>( - new neurun_test::graph::operation::SimpleMockNode({1, 2, 3, 4}, {5, 6, 7}))); + set.append( + std::unique_ptr<Node>(new neurun_test::graph::SimpleMockNode({1, 2, 3, 4}, {5, 6, 7}))); Index idx{0u}; ASSERT_EQ(set.at(idx).getInputs().size(), 4); ASSERT_EQ(set.at(idx).getOutputs().size(), 3); diff --git a/runtimes/neurun/test/graph/operation/SetIO.cc b/runtimes/neurun/test/graph/operation/SetIO.cc index c0a0c9099..a475bdcc9 100644 --- a/runtimes/neurun/test/graph/operation/SetIO.cc +++ b/runtimes/neurun/test/graph/operation/SetIO.cc @@ -17,24 +17,24 @@ #include <gtest/gtest.h> #include "graph/Graph.h" -#include "nnfw/std/memory.h" -#include "graph/operation/Conv2D.h" -#include "graph/operation/Concat.h" -#include "graph/operand/Index.h" -#include "graph/operand/IndexSet.h" +#include "cpp14/memory.h" +#include "model/operation/Conv2DNode.h" +#include "model/operation/ConcatNode.h" +#include "model/operand/Index.h" +#include "model/operand/IndexSet.h" #include <stdexcept> -using Index = neurun::graph::operand::IO::Index; -using IndexSet = neurun::graph::operand::IndexSet; -using GraphNodeInitParam = neurun::graph::operation::Node::InitParam; +using Index = neurun::model::operand::IO::Index; +using IndexSet = neurun::model::operand::IndexSet; +using GraphNodeInitParam = neurun::model::operation::Node::InitParam; TEST(graph_operation_setIO, operation_setIO_conv) { neurun::graph::Graph graph; - neurun::graph::operand::Shape shape{1u}; - neurun::graph::operand::TypeInfo type{ANEURALNETWORKS_TENSOR_INT32, 0, 0}; + neurun::model::operand::Shape shape{1u}; + neurun::model::operand::TypeInfo type{ANEURALNETWORKS_TENSOR_INT32, 0, 0}; shape.dim(0) = 3; // Add Conv @@ -45,9 +45,10 @@ TEST(graph_operation_setIO, operation_setIO_conv) } uint32_t outoperand = graph.addOperand(shape, type).asInt(); - using GraphNode = neurun::graph::operation::Conv2D::Implicit::Node; + using GraphNode = neurun::model::operation::Conv2DNode; - auto conv = nnfw::make_unique<GraphNode>(GraphNodeInitParam{7, params.data(), 1, &outoperand}); + auto conv = + nnfw::cpp14::make_unique<GraphNode>(GraphNodeInitParam{7, params.data(), 1, &outoperand}); ASSERT_EQ(conv->getInputs().at(Index{0}).asInt(), params[0]); conv->setInputs({8, 9, 10}); ASSERT_NE(conv->getInputs().at(Index{0}).asInt(), params[0]); @@ -58,8 +59,8 @@ TEST(graph_operation_setIO, operation_setIO_concat) { neurun::graph::Graph graph; - neurun::graph::operand::Shape shape{1u}; - neurun::graph::operand::TypeInfo type{ANEURALNETWORKS_TENSOR_INT32, 0, 0}; + neurun::model::operand::Shape shape{1u}; + neurun::model::operand::TypeInfo type{ANEURALNETWORKS_TENSOR_INT32, 0, 0}; shape.dim(0) = 3; // Add Concat @@ -70,9 +71,10 @@ TEST(graph_operation_setIO, operation_setIO_concat) } uint32_t outoperand = graph.addOperand(shape, type).asInt(); - using GraphNode = neurun::graph::operation::Concat::Node; + using GraphNode = neurun::model::operation::ConcatNode; - auto concat = nnfw::make_unique<GraphNode>(GraphNodeInitParam{7, params.data(), 1, &outoperand}); + auto concat = + nnfw::cpp14::make_unique<GraphNode>(GraphNodeInitParam{7, params.data(), 1, &outoperand}); ASSERT_EQ(concat->getInputs().size(), 6); ASSERT_EQ(concat->getInputs().at(Index{0}).asInt(), params[0]); diff --git a/runtimes/neurun/test/graph/verifier/Verifier.cc b/runtimes/neurun/test/graph/verifier/Verifier.cc index 68c8e8ec8..a37b0ac1f 100644 --- a/runtimes/neurun/test/graph/verifier/Verifier.cc +++ b/runtimes/neurun/test/graph/verifier/Verifier.cc @@ -16,32 +16,23 @@ #include <gtest/gtest.h> -#include "graph/operation/Node.h" +#include "model/operation/Node.h" #include "graph/Graph.h" -#include "graph/verifier/IVerifier.h" -#include "nnfw/std/memory.h" -#include "graph/operand/Object.h" +#include "graph/verifier/Verifier.h" +#include "cpp14/memory.h" +#include "model/operand/Object.h" +#include "../MockNode.h" -class MockNode : public neurun::graph::operation::Node -{ -public: - MockNode(const neurun::graph::operand::Index &input, const neurun::graph::operand::Index &output) - { - setInputs({input}); - setOutputs({output}); - } - -public: - virtual void accept(neurun::graph::operation::NodeVisitor &&) const override {} -}; +using IndexSet = neurun::model::operand::IndexSet; +using MockNode = neurun_test::graph::SimpleMockNode; TEST(Verifier, dag_checker) { neurun::graph::Graph graph; neurun::graph::verifier::DAGChecker verifier; - ::neurun::graph::operand::Shape shape{1u}; - ::neurun::graph::operand::TypeInfo type{ANEURALNETWORKS_TENSOR_INT32, 0, 0}; + ::neurun::model::operand::Shape shape{1u}; + ::neurun::model::operand::TypeInfo type{ANEURALNETWORKS_TENSOR_INT32, 0, 0}; shape.dim(0) = 3; auto operand1 = graph.addOperand(shape, type); @@ -52,13 +43,9 @@ TEST(Verifier, dag_checker) graph.addOutput(operand2); graph.operands().at(operand2).setAsOperationOutput(); - graph.addOperation(nnfw::make_unique<MockNode>(operand1, operand2)); + graph.addOperation(nnfw::cpp14::make_unique<MockNode>(IndexSet{operand1}, IndexSet{operand2})); - ASSERT_EQ(verifier.verify(graph), true); + graph.finishBuilding(); - // Create cycle - graph.operands().at(operand1).setAsOperationOutput(); - graph.addOperation(nnfw::make_unique<MockNode>(operand2, operand1)); - - ASSERT_EQ(verifier.verify(graph), false); + ASSERT_EQ(verifier.verify(graph), true); } |