diff options
Diffstat (limited to 'runtime/onert/backend/ruy')
19 files changed, 1270 insertions, 0 deletions
diff --git a/runtime/onert/backend/ruy/Backend.h b/runtime/onert/backend/ruy/Backend.h new file mode 100644 index 000000000..4077965c4 --- /dev/null +++ b/runtime/onert/backend/ruy/Backend.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_RUY_BACKEND_H__ +#define __ONERT_BACKEND_RUY_BACKEND_H__ + +#include "BackendContext.h" +#include "Config.h" +#include "KernelGenerator.h" + +#include <backend/Backend.h> + +#include <memory> + +namespace onert +{ +namespace backend +{ +namespace ruy +{ + +class Backend : public ::onert::backend::Backend +{ +public: + Backend() : _config{std::make_shared<Config>()} {} + + std::shared_ptr<IConfig> config() const override { return _config; } + + std::unique_ptr<onert::backend::BackendContext> newContext(ContextData &&data) const override + { + auto custom_kernel_builder = data.custom_kernel_builder; + auto &graph = *data.graph; + auto context = std::make_unique<BackendContext>(this, std::move(data)); + auto tr = std::make_shared<basic::TensorRegistry>(); + auto tb = std::make_shared<TensorBuilder>(tr); + context->tensor_registry = tr; + context->tensor_builder = tb; + context->kernel_gen = std::make_shared<KernelGenerator>(graph, tb, tr, custom_kernel_builder, + context->external_context()); + return context; + } + +private: + std::shared_ptr<IConfig> _config; +}; + +} // namespace ruy +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_RUY_BACKEND_H__ diff --git a/runtime/onert/backend/ruy/BackendContext.cc b/runtime/onert/backend/ruy/BackendContext.cc new file mode 100644 index 000000000..1943f70c7 --- /dev/null +++ b/runtime/onert/backend/ruy/BackendContext.cc @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "BackendContext.h" + +#include "TensorBuilder.h" +#include "KernelGenerator.h" +#include "util/logging.h" +#include "ir/Index.h" +#include "ir/OperandIndexMap.h" +#include "ir/OperandIndexSequence.h" +#include "backend/basic/BackendContextHelpers.h" + +namespace onert +{ +namespace backend +{ +namespace ruy +{ + +ITensorRegistry *BackendContext::genTensors() { return basic::genTensors(*this); } + +FunctionMap BackendContext::genKernels() +{ + FunctionMap ret; + + for (auto &&op_ind : _data.op_order) + { + auto fn_seq = kernel_gen->generate(op_ind); + ret.emplace_back(op_ind, std::move(fn_seq)); + } + + basic::initConsts(*this); + + // NOTE For memory optimization, we want to free some operand data + const_cast<ir::Graph &>(*_data.graph) + .operands() + .iterate([&](const ir::OperandIndex &, ir::Operand &obj) { obj.releaseData(); }); + + for (auto &&it : ret) + { + auto &fn_seq = it.second; + fn_seq->iterate([&](exec::IFunction &ifunc) { ifunc.prepare(); }); + } + + return ret; +} + +} // namespace ruy +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/ruy/BackendContext.h b/runtime/onert/backend/ruy/BackendContext.h new file mode 100644 index 000000000..0dc30f557 --- /dev/null +++ b/runtime/onert/backend/ruy/BackendContext.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_RUY_BACKEND_CONTEXT_H__ +#define __ONERT_BACKEND_RUY_BACKEND_CONTEXT_H__ + +#include <backend/BackendContext.h> +#include "TensorBuilder.h" +#include "KernelGenerator.h" +#include "ExternalContext.h" + +namespace onert +{ +namespace backend +{ +namespace ruy +{ + +class BackendContext : public onert::backend::BackendContext +{ +public: + BackendContext(const Backend *backend, ContextData &&data, + std::shared_ptr<ITensorRegistry> tensor_registry = nullptr, + std::shared_ptr<TensorBuilder> tensor_builder = nullptr, + std::shared_ptr<KernelGenerator> kernel_gen = nullptr) + : onert::backend::BackendContext(backend, std::move(data), tensor_registry), + tensor_builder{tensor_builder}, kernel_gen{kernel_gen}, _external_context(new ExternalContext) + { + } + + ITensorRegistry *genTensors() override; + + FunctionMap genKernels() override; + + std::shared_ptr<ExternalContext> external_context() { return _external_context; } + +private: + void planTensors(const std::vector<onert::ir::OperationIndex> &order, + const compiler::GraphLowerInfo &lower_info); + +public: + // TODO Make it private + std::shared_ptr<TensorBuilder> tensor_builder; + std::shared_ptr<KernelGenerator> kernel_gen; + +private: + // NOTE ruy context has a thread pool, and when multiple ruy contexts are created, + // the thread pool is also created in duplicate + // TODO Create one ruy context for session + std::shared_ptr<ExternalContext> _external_context; +}; + +} // namespace ruy +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_RUY_BACKEND_CONTEXT_H__ diff --git a/runtime/onert/backend/ruy/CMakeLists.txt b/runtime/onert/backend/ruy/CMakeLists.txt new file mode 100644 index 000000000..206acbfbf --- /dev/null +++ b/runtime/onert/backend/ruy/CMakeLists.txt @@ -0,0 +1,22 @@ +set(LIB_ONERT_BACKEND_RUY onert_backend_ruy) + +nnfw_find_package(Ruy REQUIRED) + +file(GLOB_RECURSE SOURCES "*.cc") + +add_library(${LIB_ONERT_BACKEND_RUY} SHARED ${SOURCES}) + +target_link_libraries(${LIB_ONERT_BACKEND_RUY} PRIVATE nnfw_lib_ruy) +target_link_libraries(${LIB_ONERT_BACKEND_RUY} PRIVATE onert_core) +target_link_libraries(${LIB_ONERT_BACKEND_RUY} PRIVATE nnfw_common) +target_link_libraries(${LIB_ONERT_BACKEND_RUY} PRIVATE nnfw_coverage) +target_link_libraries(${LIB_ONERT_BACKEND_RUY} PRIVATE ruy) + +set_target_properties(${LIB_ONERT_BACKEND_RUY} PROPERTIES OUTPUT_NAME backend_ruy) + +if(CMAKE_BUILD_TYPE_LC STREQUAL "release") + add_custom_command(TARGET ${LIB_ONERT_BACKEND_RUY} POST_BUILD + COMMAND ${CMAKE_STRIP} "--strip-unneeded" $<TARGET_FILE_NAME:${LIB_ONERT_BACKEND_RUY}>) +endif() + +install(TARGETS ${LIB_ONERT_BACKEND_RUY} DESTINATION lib) diff --git a/runtime/onert/backend/ruy/Config.cc b/runtime/onert/backend/ruy/Config.cc new file mode 100644 index 000000000..fbeb2f7f0 --- /dev/null +++ b/runtime/onert/backend/ruy/Config.cc @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Config.h" + +namespace onert +{ +namespace backend +{ +namespace ruy +{ + +bool Config::initialize() { return true; } + +ir::Layout Config::supportLayout(const ir::IOperation &, ir::Layout) { return ir::Layout::NHWC; } + +} // namespace ruy +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/ruy/Config.h b/runtime/onert/backend/ruy/Config.h new file mode 100644 index 000000000..fa6415b14 --- /dev/null +++ b/runtime/onert/backend/ruy/Config.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_RUY_CONFIG_H__ +#define __ONERT_BACKEND_RUY_CONFIG_H__ + +#include <backend/IConfig.h> +#include <memory> +#include <util/ITimer.h> + +namespace onert +{ +namespace backend +{ +namespace ruy +{ + +class Config : public IConfig +{ +public: + std::string id() override { return "ruy"; } + bool initialize() override; + ir::Layout supportLayout(const ir::IOperation &node, ir::Layout frontend_layout) override; + bool supportPermutation() override { return true; } + bool supportDynamicTensor() override { return true; } + bool supportFP16() override { return false; } + + std::unique_ptr<util::ITimer> timer() override { return std::make_unique<util::CPUTimer>(); } +}; + +} // namespace ruy +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_RUY_CONFIG_H__ diff --git a/runtime/onert/backend/ruy/ExternalContext.h b/runtime/onert/backend/ruy/ExternalContext.h new file mode 100644 index 000000000..c73ae636e --- /dev/null +++ b/runtime/onert/backend/ruy/ExternalContext.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_RUY_EXTERNAL_CONTEXT_H__ +#define __ONERT_BACKEND_RUY_EXTERNAL_CONTEXT_H__ + +#include <util/ConfigSource.h> +#include <ruy/context.h> + +#include <memory> + +namespace onert +{ +namespace backend +{ +namespace ruy +{ + +class ExternalContext +{ +private: + static const int kDefaultNumThreadpoolThreads = 4; + +public: + ExternalContext() : _ruy_context(new ::ruy::Context) + { + setMaxNumThreads(onert::util::getConfigInt(onert::util::config::RUY_THREADS)); + } + + void setMaxNumThreads(int max_num_threads) + { + const int target_num_threads = + max_num_threads > -1 ? max_num_threads : kDefaultNumThreadpoolThreads; + _ruy_context->set_max_num_threads(target_num_threads); + } + + ::ruy::Context *ruy_context() const { return _ruy_context.get(); } + +private: + const std::unique_ptr<::ruy::Context> _ruy_context; +}; + +} // namespace ruy +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_RUY_EXTERNAL_CONTEXT_H__ diff --git a/runtime/onert/backend/ruy/KernelGenerator.cc b/runtime/onert/backend/ruy/KernelGenerator.cc new file mode 100644 index 000000000..e5f2dbd39 --- /dev/null +++ b/runtime/onert/backend/ruy/KernelGenerator.cc @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "KernelGenerator.h" + +#include "ops/ConvolutionLayer.h" +#include "ops/FullyConnectedLayer.h" + +#include <backend/Backend.h> +#include <backend/IConfig.h> +#include <memory> +#include <util/Utils.h> +#include <util/logging.h> +#include <exec/DynamicShapeInferer.h> + +#include <stdexcept> + +namespace onert +{ +namespace backend +{ +namespace ruy +{ + +std::unique_ptr<exec::FunctionSequence> KernelGenerator::generate(ir::OperationIndex ind) +{ + auto ret = std::make_unique<exec::FunctionSequence>(); + + assert(_tensor_builder->dynamicTensorManager()); + assert(_tensor_reg); + + // Prepare to handle dynamic tensors later + auto dyn_ctx = std::make_shared<exec::FunctionSequence::DynamicTensorCtx>(); + { + dyn_ctx->op = &_operations_ctx.at(ind); + dyn_ctx->dynamic_shape_inferer = std::make_shared<exec::DynamicShapeInferer>(_ctx, _tensor_reg); + } + ret->dynamic_tensor_ctx(dyn_ctx); + + auto &op = _graph.operations().at(ind); + op.accept(*this); + assert(_return_fn); // _return_fn must have been generated + ret->append(std::move(_return_fn)); + + for (const auto &ind : (op.getInputs() | ir::Remove::UNDEFINED) + op.getOutputs()) + { + auto portable_tensor = _tensor_reg->getPortableTensor(ind); + if (portable_tensor) + { + assert(portable_tensor->layout() == ir::Layout::NHWC); + } + + auto tensor = _tensor_reg->getNativeTensor(ind); + if (tensor) + { + tensor->increase_ref(); + } + } + return ret; +} + +KernelGenerator::KernelGenerator( + const ir::Graph &graph, const std::shared_ptr<TensorBuilder> &tensor_builder, + const std::shared_ptr<basic::TensorRegistry> &tensor_reg, + const std::shared_ptr<backend::custom::IKernelBuilder> &kernel_builder, + const std::shared_ptr<ExternalContext> &external_context) + : basic::KernelGeneratorBase{graph}, + _ctx(graph.operands()), _operations_ctx{graph.operations()}, _current_layout{graph.layout()}, + _tensor_builder(tensor_builder), _tensor_reg{tensor_reg}, _kernel_builder(kernel_builder), + _external_context(external_context) +{ + // DO NOTHING +} + +void KernelGenerator::visit(const ir::operation::Conv2D &node) +{ + using ir::operation::Conv2D; + + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(Conv2D::Input::INPUT)}; + const auto ker_index{node.getInputs().at(Conv2D::Input::KERNEL)}; + const auto bias_index{node.getInputs().at(Conv2D::Input::BIAS)}; + + auto ofm_tensor = _tensor_reg->getPortableTensor(ofm_index); + auto ifm_tensor = _tensor_reg->getPortableTensor(ifm_index); + auto ker_tensor = _tensor_reg->getPortableTensor(ker_index); + auto bias_tensor = _tensor_reg->getPortableTensor(bias_index); + + const auto stride = node.param().stride; + const auto activation = node.param().activation; + const auto ¶m_padding = node.param().padding; + const auto dilation = node.param().dilation; + auto fn = std::make_unique<ops::ConvolutionLayer>(); + + if (_ctx.at(ifm_index).info().isDynamic() || _ctx.at(ker_index).info().isDynamic()) + { + fn->configure(ifm_tensor, ker_tensor, bias_tensor, param_padding.type, param_padding.param.left, + param_padding.param.right, param_padding.param.top, param_padding.param.bottom, + stride.horizontal, stride.vertical, dilation.width_factor, dilation.height_factor, + activation, ofm_tensor, _external_context); + + _return_fn = std::move(fn); + return; + } + const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(_current_layout); + const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(_current_layout); + // Kernel format is [depth_out, kernel_height, kernel_width, depth_in]. + const auto &ker_shape = _ctx.at(ker_index).shape(); + const auto ker_height = ker_shape.dim(1); + const auto ker_width = ker_shape.dim(2); + + const auto padding = + ir::calculatePadding(param_padding, ifm_shape, ofm_shape, stride, ker_width, ker_height, + dilation.width_factor, dilation.height_factor); + + fn->configure(ifm_tensor, ker_tensor, bias_tensor, param_padding.type, padding.left, + padding.right, padding.top, padding.bottom, stride.horizontal, stride.vertical, + dilation.width_factor, dilation.height_factor, activation, ofm_tensor, + _external_context); + + _return_fn = std::move(fn); +} + +void KernelGenerator::visit(const ir::operation::FullyConnected &node) +{ + using ir::operation::FullyConnected; + + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(FullyConnected::Input::INPUT)}; + const auto weight_index{node.getInputs().at(FullyConnected::Input::WEIGHT)}; + const auto bias_index{node.getInputs().at(FullyConnected::Input::BIAS)}; + const auto activation = node.param().activation; + const auto weights_format = node.param().weights_format; + + auto output_tensor = _tensor_reg->getPortableTensor(output_index); + auto input_tensor = _tensor_reg->getPortableTensor(input_index); + auto weight_tensor = _tensor_reg->getPortableTensor(weight_index); + auto bias_tensor = bias_index.undefined() ? nullptr : _tensor_reg->getPortableTensor(bias_index); + + auto fn = std::make_unique<ops::FullyConnectedLayer>(); + + fn->configure(input_tensor, weight_tensor, bias_tensor, activation, weights_format, output_tensor, + _external_context); + + _return_fn = std::move(fn); +} + +} // namespace ruy +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/ruy/KernelGenerator.h b/runtime/onert/backend/ruy/KernelGenerator.h new file mode 100644 index 000000000..31551c46c --- /dev/null +++ b/runtime/onert/backend/ruy/KernelGenerator.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_RUY_KERNEL_GENERATOR_H__ +#define __ONERT_BACKEND_RUY_KERNEL_GENERATOR_H__ + +#include "ExternalContext.h" +#include "TensorBuilder.h" +#include "backend/basic/TensorRegistry.h" +#include "Tensor.h" + +#include <backend/CustomKernelBuilder.h> +#include <backend/basic/KernelGeneratorBase.h> +#include <ir/Operands.h> +#include <ir/Operations.h> + +namespace onert +{ +namespace backend +{ +namespace ruy +{ + +class KernelGenerator : public basic::KernelGeneratorBase +{ +public: + KernelGenerator(const ir::Graph &graph, const std::shared_ptr<TensorBuilder> &tensor_builder, + const std::shared_ptr<basic::TensorRegistry> &tensor_reg, + const std::shared_ptr<custom::IKernelBuilder> &kernel_builder, + const std::shared_ptr<ExternalContext> &external_context); + + std::unique_ptr<exec::FunctionSequence> generate(ir::OperationIndex ind) override; + +private: + void visit(const ir::operation::Conv2D &) override; + void visit(const ir::operation::FullyConnected &) override; + +private: + const ir::Operands &_ctx; + const ir::Operations &_operations_ctx; + const ir::Layout _current_layout; + std::shared_ptr<TensorBuilder> _tensor_builder; + std::shared_ptr<basic::TensorRegistry> _tensor_reg; + std::shared_ptr<backend::custom::IKernelBuilder> _kernel_builder; + const std::shared_ptr<ExternalContext> _external_context; +}; + +} // namespace ruy +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_RUY_KERNEL_GENERATOR_H__ diff --git a/runtime/onert/backend/ruy/StaticTensorManager.h b/runtime/onert/backend/ruy/StaticTensorManager.h new file mode 100644 index 000000000..867e4dedb --- /dev/null +++ b/runtime/onert/backend/ruy/StaticTensorManager.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_RUY_STATICTENSOR_MANAGER_H__ +#define __ONERT_BACKEND_RUY_STATICTENSOR_MANAGER_H__ + +#include "backend/basic/StaticTensorManager.h" + +namespace onert +{ +namespace backend +{ +namespace ruy +{ + +using StaticTensorManager = basic::StaticTensorManager; + +} // namespace ruy +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_RUY_STATICTENSOR_MANAGER_H__ diff --git a/runtime/onert/backend/ruy/Tensor.h b/runtime/onert/backend/ruy/Tensor.h new file mode 100644 index 000000000..658086018 --- /dev/null +++ b/runtime/onert/backend/ruy/Tensor.h @@ -0,0 +1,37 @@ +/* + * 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 __ONERT_BACKEND_RUY_TENSOR_H__ +#define __ONERT_BACKEND_RUY_TENSOR_H__ + +#include <backend/basic/Tensor.h> +#include <ir/Data.h> + +namespace onert +{ +namespace backend +{ +namespace ruy +{ + +using Tensor = basic::Tensor; +using ExternalTensor = basic::ExternalTensor; + +} // namespace ruy +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_RUY_TENSOR_H__ diff --git a/runtime/onert/backend/ruy/TensorBuilder.h b/runtime/onert/backend/ruy/TensorBuilder.h new file mode 100644 index 000000000..15d4e5b29 --- /dev/null +++ b/runtime/onert/backend/ruy/TensorBuilder.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_RUY_TENSOR_BUILDER_H__ +#define __ONERT_BACKEND_RUY_TENSOR_BUILDER_H__ + +#include <backend/basic/TensorBuilder.h> + +namespace onert +{ +namespace backend +{ +namespace ruy +{ + +using TensorBuilder = basic::TensorBuilder; + +} // namespace ruy +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_RUY_TENSOR_BUILDER_H__ diff --git a/runtime/onert/backend/ruy/ops/ConvolutionLayer.cc b/runtime/onert/backend/ruy/ops/ConvolutionLayer.cc new file mode 100644 index 000000000..1a2441082 --- /dev/null +++ b/runtime/onert/backend/ruy/ops/ConvolutionLayer.cc @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ConvolutionLayer.h" + +#include "../Tensor.h" +#include "ir/Padding.h" + +namespace onert +{ +namespace backend +{ +namespace ruy +{ +namespace ops +{ +ConvolutionLayer::ConvolutionLayer() + : _input(nullptr), _kernel(nullptr), _bias(nullptr), _output(nullptr), + _paddingType(ir::PaddingType::EXPLICIT), _paddingLeft(0), _paddingTop(0), _paddingRight(0), + _paddingBottom(0), _strideWidth(0), _strideHeight(0), _dilationWidthFactor(1), + _dilationHeightFactor(1), _activation(ir::Activation::NONE), + _conv_kernel(new nnfw::ruy::Conv()), _prepare(false) +{ + // DO NOTHING +} + +ConvolutionLayer::~ConvolutionLayer() = default; + +void ConvolutionLayer::convFloat32() +{ + float output_activation_min = 0, output_activation_max = 0; + CalculateActivationRange(_activation, &output_activation_min, &output_activation_max); + + nnfw::ruy::ConvParams op_params; + op_params.padding_type = getPaddingType(_paddingType); + op_params.padding_values.width = _paddingLeft; + op_params.padding_values.height = _paddingTop; + 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; + + nnfw::ruy::Conv &kernel = *_conv_kernel; + kernel(op_params, getTensorShape(_input), reinterpret_cast<const float *>(_input->buffer()), + getTensorShape(_kernel), reinterpret_cast<const float *>(_kernel->buffer()), + getTensorShape(_bias), reinterpret_cast<const float *>(_bias->buffer()), + getTensorShape(_output), reinterpret_cast<float *>(_output->buffer()), + _external_context->ruy_context()); +} + +void ConvolutionLayer::configure(const IPortableTensor *input, const IPortableTensor *kernel, + const IPortableTensor *bias, const ir::PaddingType paddingType, + const uint32_t paddingLeft, const uint32_t paddingRight, + const uint32_t paddingTop, const uint32_t paddingBottom, + const uint32_t strideWidth, const uint32_t strideHeight, + const uint32_t dilationWidthFactor, + const uint32_t dilationHeightFactor, + const ir::Activation activation, IPortableTensor *output, + const std::shared_ptr<ExternalContext> &external_context) +{ + _input = input; + _kernel = kernel; + _bias = bias; + _paddingType = paddingType; + _paddingLeft = paddingLeft; + _paddingRight = paddingRight; + _paddingTop = paddingTop; + _paddingBottom = paddingBottom; + _strideWidth = strideWidth; + _strideHeight = strideHeight; + _dilationWidthFactor = dilationWidthFactor; + _dilationHeightFactor = dilationHeightFactor; + _activation = activation; + _output = output; + _external_context = external_context; +} + +void ConvolutionLayer::run() +{ + prepare(); + + if (_input->is_dynamic() || _kernel->is_dynamic()) + { + const auto ifm_shape = _input->getShape().asFeature(_input->layout()); + const auto ofm_shape = _output->getShape().asFeature(_input->layout()); + // Kernel format is [depth_out, kernel_height, kernel_width, depth_in]. + const auto ker_shape = _kernel->getShape(); + const auto ker_height = ker_shape.dim(1); + const auto ker_width = ker_shape.dim(2); + + ir::Stride stride; + stride.vertical = _strideWidth; + stride.horizontal = _strideWidth; + + ir::Padding param_padding; + param_padding.type = _paddingType; + param_padding.param.left = _paddingLeft; + param_padding.param.right = _paddingRight; + param_padding.param.top = _paddingTop; + param_padding.param.bottom = _paddingBottom; + + const auto padding = + ir::calculatePadding(param_padding, ifm_shape, ofm_shape, stride, ker_width, ker_height, + _dilationWidthFactor, _dilationHeightFactor); + + _paddingLeft = padding.left; + _paddingRight = padding.right; + _paddingTop = padding.top; + _paddingBottom = padding.bottom; + } + if (_input->data_type() == OperandType::FLOAT32) + { + convFloat32(); + } + else + { + throw std::runtime_error{"Conv: unsupported data type"}; + } +} + +void ConvolutionLayer::prepare() +{ + if (_prepare) + return; + + nnfw::ruy::Conv &kernel = *_conv_kernel; + if (_input->data_type() == OperandType::FLOAT32 && _kernel->is_constant()) + { + kernel.prepare(getTensorShape(_input), getTensorShape(_kernel), getTensorShape(_output), + _strideWidth, _strideHeight, _dilationWidthFactor, _dilationHeightFactor); + } + _prepare = true; +} + +} // namespace ops +} // namespace ruy +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/ruy/ops/ConvolutionLayer.h b/runtime/onert/backend/ruy/ops/ConvolutionLayer.h new file mode 100644 index 000000000..a55387b93 --- /dev/null +++ b/runtime/onert/backend/ruy/ops/ConvolutionLayer.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_RUY_OPS_CONVOLUTIONLAYER_H__ +#define __ONERT_BACKEND_RUY_OPS_CONVOLUTIONLAYER_H__ + +#include <backend/IPortableTensor.h> +#include "../ExternalContext.h" +#include "OperationUtils.h" + +#include <ruy/operation/Conv.h> +#include <exec/IFunction.h> +#include <functional> +#include <memory> + +namespace onert +{ +namespace backend +{ +namespace ruy +{ +namespace ops +{ + +class ConvolutionLayer : public ::onert::exec::IFunction +{ +public: + ConvolutionLayer(); + ~ConvolutionLayer(); + +public: + void convFloat32(); + + void configure(const IPortableTensor *input, const IPortableTensor *kernel, + const IPortableTensor *bias, ir::PaddingType _paddingType, + const uint32_t paddingLeft, const uint32_t paddingRight, const uint32_t paddingTop, + const uint32_t paddingBottom, const uint32_t strideWidth, + const uint32_t strideHeight, const uint32_t dilationWidthFactor, + const uint32_t dilationHeightFactor, const ir::Activation activation, + IPortableTensor *output, const std::shared_ptr<ExternalContext> &external_context); + + void run() override; + + void prepare() override; + +private: + const IPortableTensor *_input; + const IPortableTensor *_kernel; + const IPortableTensor *_bias; + IPortableTensor *_output; + + ir::PaddingType _paddingType; + uint32_t _paddingLeft; + uint32_t _paddingTop; + uint32_t _paddingRight; + uint32_t _paddingBottom; + + uint32_t _strideWidth; + uint32_t _strideHeight; + uint32_t _dilationWidthFactor; + uint32_t _dilationHeightFactor; + + ir::Activation _activation; + + std::unique_ptr<nnfw::ruy::Conv> _conv_kernel; + + bool _prepare; + + std::shared_ptr<ExternalContext> _external_context; +}; + +} // namespace ops +} // namespace ruy +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_RUY_OPS_CONVOLUTIONLAYER_H__ diff --git a/runtime/onert/backend/ruy/ops/FullyConnectedLayer.cc b/runtime/onert/backend/ruy/ops/FullyConnectedLayer.cc new file mode 100644 index 000000000..9c9f31179 --- /dev/null +++ b/runtime/onert/backend/ruy/ops/FullyConnectedLayer.cc @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "FullyConnectedLayer.h" + +#include "../Tensor.h" +#include <ruy/operation/FullyConnected.h> +#include <ruy/TensorUtils.h> + +namespace onert +{ +namespace backend +{ +namespace ruy +{ +namespace ops +{ + +FullyConnectedLayer::FullyConnectedLayer() + : _input(nullptr), _weights(nullptr), _bias(nullptr), _output(nullptr), + _activation(ir::Activation::NONE), _external_context(nullptr) +{ + // DO NOTHING +} + +FullyConnectedLayer::~FullyConnectedLayer() = default; + +void FullyConnectedLayer::fullyConnectedFloat32() +{ + float output_activation_min = 0, output_activation_max = 0; + CalculateActivationRange(_activation, &output_activation_min, &output_activation_max); + nnfw::ruy::FullyConnectedParams op_params; + + op_params.float_activation_min = output_activation_min; + op_params.float_activation_max = output_activation_max; + op_params.activation = convertActivationType(_activation); + op_params.lhs_cacheable = _weights->is_constant(); + op_params.rhs_cacheable = _input->is_constant(); + + nnfw::ruy::FullyConnected( + op_params, getTensorShape(_input), reinterpret_cast<const float *>(_input->buffer()), + getTensorShape(_weights), reinterpret_cast<const float *>(_weights->buffer()), + getTensorShape(_bias), reinterpret_cast<const float *>(_bias ? _bias->buffer() : nullptr), + getTensorShape(_output), reinterpret_cast<float *>(_output->buffer()), + _external_context->ruy_context()); +} + +void FullyConnectedLayer::configure(const IPortableTensor *input, const IPortableTensor *weights, + const IPortableTensor *bias, ir::Activation activation, + ir::FullyConnectedWeightsFormat weights_format, + IPortableTensor *output, + const std::shared_ptr<ExternalContext> &external_context) +{ + UNUSED_RELEASE(weights_format); + _input = input; + _weights = weights; + _bias = bias; + _activation = activation; + _output = output; + _external_context = external_context; +} + +void FullyConnectedLayer::run() +{ + if (_input->data_type() == OperandType::FLOAT32) + { + fullyConnectedFloat32(); + } + else + { + throw std::runtime_error{"FullyConnected: unsupported data type"}; + } +} + +void FullyConnectedLayer::prepare() +{ + if (_bias && _bias->is_constant()) + { + const int bias_size = getTensorShape(_bias).FlatSize(); + if (nnfw::ruy::IsZeroVector(reinterpret_cast<float *>(_bias->buffer()), bias_size)) + { + _bias = nullptr; + } + } +} + +} // namespace ops +} // namespace ruy +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/ruy/ops/FullyConnectedLayer.h b/runtime/onert/backend/ruy/ops/FullyConnectedLayer.h new file mode 100644 index 000000000..33d560f0b --- /dev/null +++ b/runtime/onert/backend/ruy/ops/FullyConnectedLayer.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_RUY_OPS_FULLYCONNECTEDLAYER_H__ +#define __ONERT_BACKEND_RUY_OPS_FULLYCONNECTEDLAYER_H__ + +#include <backend/IPortableTensor.h> +#include "../ExternalContext.h" +#include "OperationUtils.h" + +#include <exec/IFunction.h> + +namespace onert +{ +namespace backend +{ +namespace ruy +{ +namespace ops +{ + +class FullyConnectedLayer : public ::onert::exec::IFunction +{ +public: + FullyConnectedLayer(); + ~FullyConnectedLayer(); + +public: + void fullyConnectedFloat32(); + + void configure(const IPortableTensor *input, const IPortableTensor *weights, + const IPortableTensor *bias, ir::Activation activation, + ir::FullyConnectedWeightsFormat weights_format, IPortableTensor *output, + const std::shared_ptr<ExternalContext> &external_context); + + void run() override; + + void prepare() override; + +private: + const IPortableTensor *_input; + const IPortableTensor *_weights; + const IPortableTensor *_bias; + IPortableTensor *_output; + + ir::Activation _activation; + + std::shared_ptr<ExternalContext> _external_context; +}; + +} // namespace ops +} // namespace ruy +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_RUY_OPS_FULLYCONNECTEDLAYER_H__ diff --git a/runtime/onert/backend/ruy/ops/OperationUtils.cc b/runtime/onert/backend/ruy/ops/OperationUtils.cc new file mode 100644 index 000000000..929107b1a --- /dev/null +++ b/runtime/onert/backend/ruy/ops/OperationUtils.cc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "OperationUtils.h" + +namespace onert +{ +namespace backend +{ +namespace ruy +{ +namespace ops +{ + +nnfw::ruy::PaddingType getPaddingType(ir::PaddingType ir_padding_type) +{ + switch (ir_padding_type) + { + case ir::PaddingType::EXPLICIT: + return nnfw::ruy::PaddingType::kNone; + case ir::PaddingType::SAME: + return nnfw::ruy::PaddingType::kSame; + case ir::PaddingType::VALID: + return nnfw::ruy::PaddingType::kValid; + default: + throw std::runtime_error("Wrong padding type."); + break; + } +} + +} // namespace ops +} // namespace ruy +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/ruy/ops/OperationUtils.h b/runtime/onert/backend/ruy/ops/OperationUtils.h new file mode 100644 index 000000000..716400c1f --- /dev/null +++ b/runtime/onert/backend/ruy/ops/OperationUtils.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_RUY_OPS_OPERATION_UTILS_H__ +#define __ONERT_BACKEND_RUY_OPS_OPERATION_UTILS_H__ + +#include <backend/IPortableTensor.h> +#include <ir/DataType.h> +#include <ir/Padding.h> +#include <util/CalculateActivationRange.h> + +#include <ruy/Shape.h> +#include <ruy/Types.h> + +#include <limits> + +using OperandType = onert::ir::DataType; +using namespace onert::util; + +namespace onert +{ +namespace backend +{ +namespace ruy +{ +namespace ops +{ + +inline nnfw::ruy::Shape getTensorShape(const IPortableTensor *tensor) +{ + if (tensor == nullptr) + return nnfw::ruy::Shape(); + + const ir::Shape &shape = tensor->get_info().shape(); + + assert(tensor->layout() == ir::Layout::NHWC); + + auto rank = shape.rank(); + nnfw::ruy::Shape ret(rank); + auto data = ret.DimsData(); + for (int i = 0; i < rank; ++i) + { + data[i] = shape.dim(i); + } + return ret; +} + +inline nnfw::ruy::FusedActivationFunctionType convertActivationType(const ir::Activation activation) +{ + switch (activation) + { + case ir::Activation::NONE: + return nnfw::ruy::FusedActivationFunctionType::kNone; + case ir::Activation::RELU: + return nnfw::ruy::FusedActivationFunctionType::kRelu; + case ir::Activation::RELU1: + return nnfw::ruy::FusedActivationFunctionType::kRelu1; + case ir::Activation::RELU6: + return nnfw::ruy::FusedActivationFunctionType::kRelu6; + case ir::Activation::TANH: + return nnfw::ruy::FusedActivationFunctionType::kTanh; + case ir::Activation::SIGMOID: + return nnfw::ruy::FusedActivationFunctionType::kSigmoid; + default: + throw std::runtime_error{"RUY backend: Cannot convert activation type"}; + } +} + +nnfw::ruy::PaddingType getPaddingType(ir::PaddingType ir_padding_type); + +} // namespace ops +} // namespace ruy +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_RUY_OPS_OPERATION_UTILS_H__ diff --git a/runtime/onert/backend/ruy/ruy.cc b/runtime/onert/backend/ruy/ruy.cc new file mode 100644 index 000000000..4f33590e9 --- /dev/null +++ b/runtime/onert/backend/ruy/ruy.cc @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Backend.h" + +extern "C" { + +onert::backend::Backend *onert_backend_create() { return new onert::backend::ruy::Backend; } + +void onert_backend_destroy(onert::backend::Backend *backend) { delete backend; } +} |