diff options
Diffstat (limited to 'runtime/neurun/backend/srcn')
36 files changed, 3388 insertions, 0 deletions
diff --git a/runtime/neurun/backend/srcn/Backend.h b/runtime/neurun/backend/srcn/Backend.h new file mode 100644 index 000000000..bc76a7ed2 --- /dev/null +++ b/runtime/neurun/backend/srcn/Backend.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __NEURUN_BACKEND_SRCN_BACKEND_H__ +#define __NEURUN_BACKEND_SRCN_BACKEND_H__ + +#include <memory> +#include <backend/Backend.h> +#include <ir/Operands.h> + +#include "Config.h" +#include "ConstantInitializer.h" +#include "KernelGenerator.h" +#include "ShapeFixer.h" +#include "TensorRegister.h" + +namespace neurun +{ +namespace backend +{ +namespace srcn +{ + +class Backend : public ::neurun::backend::Backend +{ +public: + Backend() : _config{std::make_shared<Config>()} {} + + std::shared_ptr<IConfig> config() const override { return _config; } + + std::unique_ptr<BackendContext> + newContext(const ir::Operands &operands, + const std::shared_ptr<custom::IKernelBuilder> &kb) const override + { + auto tensor_builder = std::make_shared<TensorBuilder>(); + return std::unique_ptr<BackendContext>{new BackendContext{ + this, tensor_builder, std::make_shared<ConstantInitializer>(operands, tensor_builder), + std::make_shared<KernelGenerator>(operands, tensor_builder, kb), + std::make_shared<ShapeFixer>(operands, tensor_builder), + std::make_shared<TensorRegister>(operands, tensor_builder)}}; + } + +private: + std::shared_ptr<IConfig> _config; +}; + +} // namespace srcn +} // namespace backend +} // namespace neurun + +#endif // __NEURUN_BACKEND_SRCN_BACKEND_H__ diff --git a/runtime/neurun/backend/srcn/CMakeLists.txt b/runtime/neurun/backend/srcn/CMakeLists.txt new file mode 100644 index 000000000..3b0440c8e --- /dev/null +++ b/runtime/neurun/backend/srcn/CMakeLists.txt @@ -0,0 +1,21 @@ +if(NOT BUILD_SRCN_KERNEL) + message(STATUS "Skip building SRCN backend: SRCN kernel library is not build") + return() +endif() + +set(LIB_NEURUN_BACKEND_SRCN neurun_backend_srcn) + +file(GLOB_RECURSE SOURCES "*.cc") + +add_library(${LIB_NEURUN_BACKEND_SRCN} SHARED ${SOURCES}) + +target_link_libraries(${LIB_NEURUN_BACKEND_SRCN} PUBLIC nnfw_lib_cpp14) +target_link_libraries(${LIB_NEURUN_BACKEND_SRCN} PRIVATE nnfw_lib_srcn) +target_link_libraries(${LIB_NEURUN_BACKEND_SRCN} PRIVATE neurun_core) +target_link_libraries(${LIB_NEURUN_BACKEND_SRCN} PRIVATE ${LIB_NEURUN_BACKEND_CPU_COMMON}) +target_link_libraries(${LIB_NEURUN_BACKEND_SRCN} PRIVATE nnfw_common) +target_link_libraries(${LIB_NEURUN_BACKEND_SRCN} PRIVATE nnfw_coverage) + +set_target_properties(${LIB_NEURUN_BACKEND_SRCN} PROPERTIES OUTPUT_NAME backend_srcn) + +install(TARGETS ${LIB_NEURUN_BACKEND_SRCN} DESTINATION lib) diff --git a/runtime/neurun/backend/srcn/Config.cc b/runtime/neurun/backend/srcn/Config.cc new file mode 100644 index 000000000..6865657e7 --- /dev/null +++ b/runtime/neurun/backend/srcn/Config.cc @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Config.h" + +namespace neurun +{ +namespace backend +{ +namespace srcn +{ + +bool Config::initialize() { return true; } + +} // namespace srcn +} // namespace backend +} // namespace neurun diff --git a/runtime/neurun/backend/srcn/Config.h b/runtime/neurun/backend/srcn/Config.h new file mode 100644 index 000000000..efc77fde2 --- /dev/null +++ b/runtime/neurun/backend/srcn/Config.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __NEURUN_BACKEND_SRCN_CONFIG_H__ +#define __NEURUN_BACKEND_SRCN_CONFIG_H__ + +#include <backend/IConfig.h> + +namespace neurun +{ +namespace backend +{ +namespace srcn +{ + +class Config : public IConfig +{ +public: + std::string id() override { return "srcn"; } + bool initialize() override; + bool SupportPermutation() override { return false; } + bool SupportSubTensorAlloc() override + { + // NOTE srcn allocator cannot support subtensor allocation yet + return false; + } +}; + +} // namespace srcn +} // namespace backend +} // namespace neurun + +#endif // __NEURUN_BACKEND_SRCN_CONFIG_H__ diff --git a/runtime/neurun/backend/srcn/ConstantInitializer.cc b/runtime/neurun/backend/srcn/ConstantInitializer.cc new file mode 100644 index 000000000..f03628b1f --- /dev/null +++ b/runtime/neurun/backend/srcn/ConstantInitializer.cc @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ConstantInitializer.h" + +#include "kernel/OperationUtils.h" + +namespace +{ + +template <typename T> +static void PermuteKernel(const neurun::ir::Operand &model_obj, + neurun::backend::operand::ITensor &obj, + const std::vector<int32_t> &permutation) +{ + const auto shape = model_obj.shape(); + auto base = reinterpret_cast<const T *>(model_obj.data().base()); + + assert(shape.rank() == 4); + assert(permutation.size() == 4); + assert(permutation[0] != permutation[1] && permutation[0] != permutation[2] && + permutation[0] != permutation[3]); + assert(permutation[1] != permutation[2] && permutation[1] != permutation[3]); + assert(permutation[2] != permutation[3]); + assert(permutation[0] < 4 && permutation[1] < 4 && permutation[2] < 4 && permutation[3] < 4); + + obj.access([&](::neurun::backend::operand::ITensor &tensor) { + if (permutation[0] == 0 && permutation[1] == 1 && permutation[2] == 2 && permutation[3] == 3) + { + memcpy(tensor.buffer(), base, shape.num_elements() * sizeof(T)); + } + else + { + const int32_t dim0 = shape.dim(0); + const int32_t dim1 = shape.dim(1); + const int32_t dim2 = shape.dim(2); + const int32_t dim3 = shape.dim(3); + for (auto i = 0; i < dim0; ++i) + { + for (auto j = 0; j < dim1; ++j) + { + for (auto k = 0; k < dim2; ++k) + { + for (auto l = 0; l < dim3; ++l) + { + Coordinates frontend_coords{i, j, k, l}; + Coordinates coords = frontend_coords; + coords.set(0, frontend_coords[permutation[0]]); + coords.set(1, frontend_coords[permutation[1]]); + coords.set(2, frontend_coords[permutation[2]]); + coords.set(3, frontend_coords[permutation[3]]); + T *into = reinterpret_cast<T *>(tensor.buffer() + tensor.calcOffset(coords)); + T value = *(base + i * dim1 * dim2 * dim3 + j * dim2 * dim3 + k * dim3 + l); + *into = value; + } + } + } + } + } + }); +} +} + +namespace neurun +{ +namespace backend +{ +namespace srcn +{ + +ConstantInitializer::ConstantInitializer(const ir::Operands &operands, + const std::shared_ptr<TensorBuilder> &tensor_builder) + : _operands{operands}, _tensor_builder{tensor_builder} +{ + // DO NOTHING +} + +void ConstantInitializer::registerPermuteKernelInitializer(const ir::OperandIndex &index, + const ir::Operand &obj, + const std::vector<int32_t> &permutation) +{ + // For only CONSTANTS + if (!obj.isConstant()) + return; + + VERBOSE(FillOperandData) << "[SRCN] Fill data for operand " << index.value() << std::endl; + + const auto type = obj.typeInfo().type(); + using ir::DataType; + using namespace std::placeholders; + + switch (type) + { + case DataType::FLOAT32: + _init_map[index] = std::bind(PermuteKernel<float>, _1, _2, permutation); + break; + case DataType::INT32: + _init_map[index] = std::bind(PermuteKernel<int32_t>, _1, _2, permutation); + break; + case DataType::UINT32: + _init_map[index] = std::bind(PermuteKernel<uint32_t>, _1, _2, permutation); + break; + case DataType::BOOL8: + case DataType::QUANT8_ASYMM: + _init_map[index] = std::bind(PermuteKernel<uint8_t>, _1, _2, permutation); + break; + case DataType::QUANT8_SYMM: + _init_map[index] = std::bind(PermuteKernel<int8_t>, _1, _2, permutation); + break; + default: + throw std::runtime_error("Not supported, yet"); + break; + } +} + +void ConstantInitializer::visit(const ir::operation::Conv2D &node) +{ + const auto &kernel_index = node.getInputs().at(ir::operation::Conv2D::KERNEL); + const auto &kernel_obj = _operands.at(kernel_index); + util::Coordinates permutation{0, 1, 2, 3}; + const auto frontend_layout = _current_subg_layout; + const auto backend_layout = _tensor_builder->tensorAt(kernel_index)->layout(); + assert(frontend_layout == ir::Layout::NHWC || frontend_layout == ir::Layout::NCHW); + assert(backend_layout == ir::Layout::NHWC || backend_layout == ir::Layout::NCHW); + const auto frontend_filter_layout = + frontend_layout == ir::Layout::NHWC ? kernel::FilterLayout::OHWI : kernel::FilterLayout::OIHW; + const auto backend_filter_layout = + backend_layout == ir::Layout::NHWC ? kernel::FilterLayout::HWIO : kernel::FilterLayout::OIHW; + registerPermuteKernelInitializer( + kernel_index, kernel_obj, + kernel::getFilterPermutation(frontend_filter_layout, backend_filter_layout)); +} + +void ConstantInitializer::visit(const ir::operation::DepthwiseConv2D &node) +{ + const auto &kernel_index = node.getInputs().at(ir::operation::DepthwiseConv2D::KERNEL); + const auto &kernel_obj = _operands.at(kernel_index); + util::Coordinates permutation{0, 1, 2, 3}; + const auto frontend_layout = _current_subg_layout; + const auto backend_layout = _tensor_builder->tensorAt(kernel_index)->layout(); + assert(frontend_layout == ir::Layout::NHWC || frontend_layout == ir::Layout::NCHW); + assert(backend_layout == ir::Layout::NHWC || backend_layout == ir::Layout::NCHW); + const auto frontend_filter_layout = + frontend_layout == ir::Layout::NHWC ? kernel::FilterLayout::OHWI : kernel::FilterLayout::OIHW; + const auto backend_filter_layout = + backend_layout == ir::Layout::NHWC ? kernel::FilterLayout::HWIO : kernel::FilterLayout::OIHW; + registerPermuteKernelInitializer( + kernel_index, kernel_obj, + kernel::getFilterPermutation(frontend_filter_layout, backend_filter_layout)); +} + +void ConstantInitializer::visit(const ir::operation::TransposeConv &node) +{ + // NOTE The srcn deconvolution layer takes a HWOI layout as kernel filter even though image layout + // is NHWC. + // This policy is the same with the tensorflow policy. + // So for using srcn library, we need to change kernel layout to HWOI from OHWI or OIHW in + // this case. + // Also the srcn deconvolution layer takes a OIHW layout as kernel filter if image's layout + // is NCHW + const auto &kernel_index = node.getInputs().at(ir::operation::TransposeConv::KERNEL); + const auto &kernel_obj = _operands.at(kernel_index); + const auto frontend_layout = _current_subg_layout; + const auto backend_layout = _tensor_builder->tensorAt(kernel_index)->layout(); + assert(frontend_layout == ir::Layout::NHWC || frontend_layout == ir::Layout::NCHW); + assert(backend_layout == ir::Layout::NHWC || backend_layout == ir::Layout::NCHW); + const auto frontend_filter_layout = + frontend_layout == ir::Layout::NHWC ? kernel::FilterLayout::OHWI : kernel::FilterLayout::OIHW; + const auto backend_filter_layout = + backend_layout == ir::Layout::NHWC ? kernel::FilterLayout::HWOI : kernel::FilterLayout::IOHW; + registerPermuteKernelInitializer( + kernel_index, kernel_obj, + kernel::getFilterPermutation(frontend_filter_layout, backend_filter_layout)); +} + +} // namespace srcn +} // namespace backend +} // namespace neurun diff --git a/runtime/neurun/backend/srcn/ConstantInitializer.h b/runtime/neurun/backend/srcn/ConstantInitializer.h new file mode 100644 index 000000000..eadfe2ae1 --- /dev/null +++ b/runtime/neurun/backend/srcn/ConstantInitializer.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __NEURUN_COMPILER_SRCN_CONSTANT_INITIALIZER_H__ +#define __NEURUN_COMPILER_SRCN_CONSTANT_INITIALIZER_H__ + +#include <backend/IConstantInitializer.h> +#include <ir/Operands.h> +#include "TensorBuilder.h" +#include <util/Coordinates.h> + +namespace neurun +{ +namespace backend +{ +namespace srcn +{ + +class ConstantInitializer : public IConstantInitializer +{ +public: + ConstantInitializer(const ir::Operands &operands, + const std::shared_ptr<TensorBuilder> &tensor_builder); + +public: + void registerPermuteKernelInitializer(const ir::OperandIndex &index, const ir::Operand &obj, + const std::vector<int32_t> &permutation); + +public: + void visit(const ir::operation::Conv2D &) override; + void visit(const ir::operation::DepthwiseConv2D &) override; + void visit(const ir::operation::TransposeConv &) override; + +private: + const ir::Operands &operands() const override { return _operands; } + std::shared_ptr<ITensorBuilder> tensor_builder() const override { return _tensor_builder; } + +private: + const ir::Operands &_operands; + std::shared_ptr<TensorBuilder> _tensor_builder; +}; + +} // namespace srcn +} // namespace backend +} // namespace neurun + +#endif // __NEURUN_COMPILER_SRCN_CONSTANT_INITIALIZER_H__ diff --git a/runtime/neurun/backend/srcn/Convert.cc b/runtime/neurun/backend/srcn/Convert.cc new file mode 100644 index 000000000..1d80b2c7c --- /dev/null +++ b/runtime/neurun/backend/srcn/Convert.cc @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Convert.h" + +#include <cassert> +#include <cpp14/memory.h> +#include <ir/DataType.h> +#include "Swizzle.h" +#include <vector> + +namespace neurun +{ +namespace backend +{ +namespace srcn +{ + +ir::Shape asKernelShape(const ir::Shape &shape, kernel::FilterLayout frontend_layout, + kernel::FilterLayout backend_layout) +{ + assert(shape.rank() == 4); + if (frontend_layout == backend_layout) + { + return ir::Shape{shape.dim(0), shape.dim(1), shape.dim(2), shape.dim(3)}; + } + + const auto permutation = getFilterPermutation(frontend_layout, backend_layout); + if (permutation.size() == 0) + { + throw std::runtime_error("Not supported FilterLayout"); + } + return ir::Shape{shape.dim(permutation[0]), shape.dim(permutation[1]), shape.dim(permutation[2]), + shape.dim(permutation[3])}; +} + +ir::Shape asTensorShape(const ir::Shape &shape, ir::Layout frontend_layout, + ir::Layout backend_layout) +{ + const uint32_t rank = shape.rank(); + + ir::Shape ret(rank); + for (uint32_t axis = 0; axis < rank; ++axis) + { + const auto ncnn_axis = ToNCNNAxis(rank, axis, frontend_layout, backend_layout); + ret.dim(ncnn_axis) = shape.dim(axis); + } + + return ret; +} + +ir::OperandInfo asTensorInfo(const ir::Shape &shape, const ir::TypeInfo &typeInfo, + ir::Layout frontend_layout, ir::Layout backend_layout) +{ + ir::OperandInfo info(asTensorShape(shape, frontend_layout, backend_layout), typeInfo); + + return info; +} + +} // namespace srcn +} // namespace backend +} // namespace neurun diff --git a/runtime/neurun/backend/srcn/Convert.h b/runtime/neurun/backend/srcn/Convert.h new file mode 100644 index 000000000..64be46e60 --- /dev/null +++ b/runtime/neurun/backend/srcn/Convert.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __NEURUN_BACKEND_SRCN_CONVERT_H__ +#define __NEURUN_BACKEND_SRCN_CONVERT_H__ + +#include "kernel/OperationUtils.h" +#include <ir/Layout.h> +#include <ir/Shape.h> +#include <ir/TypeInfo.h> +#include <ir/OperandInfo.h> + +namespace neurun +{ +namespace backend +{ +namespace srcn +{ + +ir::Shape asKernelShape(const ir::Shape &shape, kernel::FilterLayout frontend_layout, + kernel::FilterLayout backend_layout); + +ir::Shape asTensorShape(const ir::Shape &shape, ir::Layout frontend_layout, + ir::Layout backend_layout); + +ir::OperandInfo asTensorInfo(const ir::Shape &shape, const ir::TypeInfo &typeInfo, + ir::Layout frontend_layout, ir::Layout backend_layout); + +} // namespace srcn +} // namespace backend +} // namespace neurun + +#endif // __NEURUN_BACKEND_SRCN_CONVERT_H__ diff --git a/runtime/neurun/backend/srcn/KernelGenerator.cc b/runtime/neurun/backend/srcn/KernelGenerator.cc new file mode 100644 index 000000000..c096f9230 --- /dev/null +++ b/runtime/neurun/backend/srcn/KernelGenerator.cc @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "KernelGenerator.h" + +#include <stdexcept> + +#include "cpp14/memory.h" +#include "util/Padding.h" +#include "kernel/ConvolutionLayer.h" +#include "kernel/DepthwiseConvolutionLayer.h" +#include "kernel/InstanceNormLayer.h" +#include "kernel/TransposeConvLayer.h" +#include "kernel/AddLayer.h" + +#include <backend/Backend.h> +#include <backend/IConfig.h> + +#include "util/logging.h" + +#include "util/Utils.h" + +namespace neurun +{ +namespace backend +{ +namespace srcn +{ + +KernelGenerator::KernelGenerator(const ir::Operands &operand_ctx, + const std::shared_ptr<TensorBuilder> &tensor_builder, + const std::shared_ptr<custom::IKernelBuilder> &kb) + : _ctx(operand_ctx), _tensor_builder(tensor_builder), _kernel_builder(kb), + _current_subg_layout(ir::Layout::UNKNOWN) +{ + // DO NOTHING +} + +void KernelGenerator::visit(const ir::OpSequence &op_seq) +{ + _current_subg_layout = op_seq.getLayout(); + for (const auto &e : op_seq.operations()) + { + const auto &node = *(e.node); + _tensor_builder->preVisit(node); + node.accept(*this); + _tensor_builder->postVisit(node); + } +} + +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)}; + + const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(_current_subg_layout); + const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(_current_subg_layout); + // Kernel format is [depth_out, kernel_height, kernel_width, depth_in] if NHWC and [depth_out, + // depth_in, kernel_height, kernel_width] if NCHW. + const auto &ker_shape = _ctx.at(ker_index).shape().asFeature(_current_subg_layout); + const auto ker_height = ker_shape.H; + const auto ker_width = ker_shape.W; + const auto stride = node.param().stride; + const auto padding = neurun::util::calculatePadding(node.param().padding, ifm_shape, ofm_shape, + stride, ker_width, ker_height); + const int has_padding = padding.left + padding.right + padding.top + padding.bottom; + + auto ofm_alloc = _tensor_builder->at(ofm_index); + auto ifm_alloc = _tensor_builder->at(ifm_index); + auto ker_alloc = _tensor_builder->at(ker_index); + auto bias_alloc = _tensor_builder->at(bias_index); + const auto backend_layout = ifm_alloc->layout(); + assert(backend_layout == ofm_alloc->layout()); + + const auto ofm_backend_descr = ::neurun::backend::srcn::kernel::getTensorDescriptor( + _ctx.at(ofm_index), _current_subg_layout, backend_layout); + const auto ifm_backend_descr = ::neurun::backend::srcn::kernel::getTensorDescriptor( + _ctx.at(ifm_index), _current_subg_layout, backend_layout); + const auto ker_backend_descr = ::neurun::backend::srcn::kernel::getTensorDescriptor( + _ctx.at(ker_index), _current_subg_layout, backend_layout); + const auto bias_backend_descr = ::neurun::backend::srcn::kernel::getTensorDescriptor( + _ctx.at(bias_index), _current_subg_layout, backend_layout); + + auto fn = nnfw::cpp14::make_unique<::neurun::backend::srcn::kernel::ConvolutionLayer>(); + + // TODO Support activation + fn->configure(ifm_alloc->buffer(), ifm_backend_descr, ker_alloc->buffer(), ker_backend_descr, + bias_alloc->buffer(), bias_backend_descr, has_padding, padding.left, padding.right, + padding.top, padding.bottom, stride.horizontal, stride.vertical, + /*activation,*/ ofm_alloc->buffer(), ofm_backend_descr, backend_layout); + + _execution_builder->append(std::move(fn)); +} + +void KernelGenerator::visit(const ir::operation::InstanceNorm &node) +{ + using ir::operation::InstanceNorm; + + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(InstanceNorm::Input::INPUT)}; + const auto gamma_index{node.getInputs().at(InstanceNorm::Input::GAMMA)}; + const auto beta_index{node.getInputs().at(InstanceNorm::Input::BETA)}; + + const auto epsilon = node.param().epsilon; + const auto activation = node.param().activation; + + auto ofm_alloc = _tensor_builder->at(ofm_index); + auto ifm_alloc = _tensor_builder->at(ifm_index); + auto gamma_alloc = _tensor_builder->at(gamma_index); + auto beta_alloc = _tensor_builder->at(beta_index); + + const auto backend_layout = ofm_alloc->layout(); + + const auto ofm_backend_descr = ::neurun::backend::srcn::kernel::getTensorDescriptor( + _ctx.at(ofm_index), _current_subg_layout, backend_layout); + const auto ifm_backend_descr = ::neurun::backend::srcn::kernel::getTensorDescriptor( + _ctx.at(ifm_index), _current_subg_layout, backend_layout); + const auto gamma_backend_descr = ::neurun::backend::srcn::kernel::getTensorDescriptor( + _ctx.at(gamma_index), _current_subg_layout, backend_layout); + const auto beta_backend_descr = ::neurun::backend::srcn::kernel::getTensorDescriptor( + _ctx.at(beta_index), _current_subg_layout, backend_layout); + + auto fn = nnfw::cpp14::make_unique<::neurun::backend::srcn::kernel::InstanceNormLayer>(); + + fn->configure(ifm_alloc->buffer(), ifm_backend_descr, gamma_alloc->buffer(), gamma_backend_descr, + beta_alloc->buffer(), beta_backend_descr, ofm_alloc->buffer(), ofm_backend_descr, + epsilon, activation, backend_layout); + + _execution_builder->append(std::move(fn)); +} + +void KernelGenerator::visit(const ir::operation::DepthwiseConv2D &node) +{ + using ir::operation::DepthwiseConv2D; + + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(DepthwiseConv2D::Input::INPUT)}; + const auto ker_index{node.getInputs().at(DepthwiseConv2D::Input::KERNEL)}; + const auto bias_index{node.getInputs().at(DepthwiseConv2D::Input::BIAS)}; + + const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(_current_subg_layout); + const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(_current_subg_layout); + // Kernel format is [depth_out, kernel_height, kernel_width, depth_in] if NHWC and [depth_out, + // depth_in, kernel_height, kernel_width] if NCHW. + const auto &ker_shape = _ctx.at(ker_index).shape().asFeature(_current_subg_layout); + const auto ker_height = ker_shape.H; + const auto ker_width = ker_shape.W; + const auto stride = node.param().stride; + const auto padding = neurun::util::calculatePadding(node.param().padding, ifm_shape, ofm_shape, + stride, ker_width, ker_height); + const int padding_type = padding.left + padding.right + padding.top + padding.bottom; + + auto ofm_alloc = _tensor_builder->at(ofm_index); + auto ifm_alloc = _tensor_builder->at(ifm_index); + auto ker_alloc = _tensor_builder->at(ker_index); + auto bias_alloc = _tensor_builder->at(bias_index); + const auto backend_layout = ifm_alloc->layout(); + assert(backend_layout == ofm_alloc->layout()); + + const auto ofm_backend_descr = ::neurun::backend::srcn::kernel::getTensorDescriptor( + _ctx.at(ofm_index), _current_subg_layout, backend_layout); + const auto ifm_backend_descr = ::neurun::backend::srcn::kernel::getTensorDescriptor( + _ctx.at(ifm_index), _current_subg_layout, backend_layout); + const auto ker_backend_descr = ::neurun::backend::srcn::kernel::getTensorDescriptor( + _ctx.at(ker_index), _current_subg_layout, backend_layout); + const auto bias_backend_descr = ::neurun::backend::srcn::kernel::getTensorDescriptor( + _ctx.at(bias_index), _current_subg_layout, backend_layout); + + auto fn = nnfw::cpp14::make_unique<::neurun::backend::srcn::kernel::DepthwiseConvolutionLayer>(); + + // TODO Support activation + fn->configure(ifm_alloc->buffer(), ifm_backend_descr, ker_alloc->buffer(), ker_backend_descr, + bias_alloc->buffer(), bias_backend_descr, padding_type, padding.left, padding.right, + padding.top, padding.bottom, stride.horizontal, stride.vertical, + /*activation,*/ ofm_alloc->buffer(), ofm_backend_descr, backend_layout); + + _execution_builder->append(std::move(fn)); +} + +void KernelGenerator::visit(const ir::operation::TransposeConv &node) +{ + using ir::operation::TransposeConv; + + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(TransposeConv::Input::INPUT)}; + const auto ker_index{node.getInputs().at(TransposeConv::Input::KERNEL)}; + const auto output_shape_index{node.getInputs().at(TransposeConv::Input::OUTPUT_SHAPE)}; + + const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(_current_subg_layout); + const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(_current_subg_layout); + // Kernel format is [depth_out, kernel_height, kernel_width, depth_in] if NHWC and [depth_out, + // depth_in, kernel_height, kernel_width] if NCHW. + const auto &ker_shape = _ctx.at(ker_index).shape().asFeature(_current_subg_layout); + const auto ker_height = ker_shape.H; + const auto ker_width = ker_shape.W; + const auto stride = node.param().stride; + const int padding_type = (node.param().padding.type == ir::PaddingType::SAME); + const auto padding = neurun::util::calculatePadding(node.param().padding, ofm_shape, ifm_shape, + stride, ker_width, ker_height); + + auto ofm_alloc = _tensor_builder->at(ofm_index); + auto ifm_alloc = _tensor_builder->at(ifm_index); + auto ker_alloc = _tensor_builder->at(ker_index); + const auto backend_layout = ofm_alloc->layout(); + assert(backend_layout == ifm_alloc->layout()); + + const auto ofm_backend_descr = ::neurun::backend::srcn::kernel::getTensorDescriptor( + _ctx.at(ofm_index), _current_subg_layout, backend_layout); + const auto ifm_backend_descr = ::neurun::backend::srcn::kernel::getTensorDescriptor( + _ctx.at(ifm_index), _current_subg_layout, backend_layout); + const auto ker_backend_descr = ::neurun::backend::srcn::kernel::getTensorDescriptor( + _ctx.at(ker_index), _current_subg_layout, backend_layout); + + auto fn = nnfw::cpp14::make_unique<::neurun::backend::srcn::kernel::TransposeConvLayer>(); + + fn->configure(ifm_alloc->buffer(), ifm_backend_descr, ker_alloc->buffer(), ker_backend_descr, + padding_type, padding.left, padding.right, padding.top, padding.bottom, + stride.horizontal, stride.vertical, ofm_alloc->buffer(), ofm_backend_descr, + backend_layout); + + _execution_builder->append(std::move(fn)); +} + +void KernelGenerator::visit(const ir::operation::Add &node) +{ + using ir::operation::Add; + + const auto ofm_index{node.getOutputs().at(0)}; + const auto lhs_index{node.getInputs().at(Add::Input::LHS)}; + const auto rhs_index{node.getInputs().at(Add::Input::RHS)}; + + const auto activation = node.param().activation; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto lhs_alloc = _tensor_builder->at(lhs_index).get(); + auto rhs_alloc = _tensor_builder->at(rhs_index).get(); + + const auto backend_layout = ofm_alloc->layout(); + assert(backend_layout == lhs_alloc->layout() && backend_layout == rhs_alloc->layout()); + + const auto ofm_backend_descr = ::neurun::backend::srcn::kernel::getTensorDescriptor( + _ctx.at(ofm_index), _current_subg_layout, backend_layout); + const auto lhs_backend_descr = ::neurun::backend::srcn::kernel::getTensorDescriptor( + _ctx.at(lhs_index), _current_subg_layout, backend_layout); + const auto rhs_backend_descr = ::neurun::backend::srcn::kernel::getTensorDescriptor( + _ctx.at(rhs_index), _current_subg_layout, backend_layout); + + auto fn = nnfw::cpp14::make_unique<::neurun::backend::srcn::kernel::AddLayer>(); + + fn->configure(lhs_alloc->buffer(), lhs_backend_descr, rhs_alloc->buffer(), rhs_backend_descr, + activation, ofm_alloc->buffer(), ofm_backend_descr, backend_layout); + + _execution_builder->append(std::move(fn)); +} + +} // namespace srcn +} // namespace backend +} // namespace neurun diff --git a/runtime/neurun/backend/srcn/KernelGenerator.h b/runtime/neurun/backend/srcn/KernelGenerator.h new file mode 100644 index 000000000..879aeaf5b --- /dev/null +++ b/runtime/neurun/backend/srcn/KernelGenerator.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __NEURUN_BACKEND_SRCN_KERNEL_GENERATOR_H__ +#define __NEURUN_BACKEND_SRCN_KERNEL_GENERATOR_H__ + +#include "backend/IKernelGenerator.h" +#include "ir/Operands.h" +#include "operand/Tensor.h" +#include "backend/CustomKernelBuilder.h" +#include "TensorBuilder.h" + +namespace neurun +{ +namespace backend +{ +namespace srcn +{ + +class KernelGenerator : public IKernelGenerator +{ +public: + KernelGenerator(const ir::Operands &ctx, const std::shared_ptr<TensorBuilder> &tensor_builder, + const std::shared_ptr<custom::IKernelBuilder> &kb); + + using IKernelGenerator::visit; + + void visit(const ir::OpSequence &) override; + void visit(const ir::operation::Conv2D &) override; + void visit(const ir::operation::DepthwiseConv2D &) override; + void visit(const ir::operation::InstanceNorm &) override; + void visit(const ir::operation::TransposeConv &) override; + void visit(const ir::operation::Add &) override; + +private: + const ir::Operands &_ctx; + std::shared_ptr<TensorBuilder> _tensor_builder; + std::shared_ptr<custom::IKernelBuilder> _kernel_builder; + ir::Layout _current_subg_layout; +}; + +} // namespace srcn +} // namespace backend +} // namespace neurun + +#endif // __NEURUN_BACKEND_SRCN_KERNEL_GENERATOR_H__ diff --git a/runtime/neurun/backend/srcn/MemoryManager.cc b/runtime/neurun/backend/srcn/MemoryManager.cc new file mode 100644 index 000000000..aa07ab168 --- /dev/null +++ b/runtime/neurun/backend/srcn/MemoryManager.cc @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "MemoryManager.h" + +#include <cassert> + +#include <MemoryPlannerFactory.h> +#include "util/logging.h" +#include "util/ConfigSource.h" + +namespace neurun +{ +namespace backend +{ +namespace srcn +{ + +MemoryManager::MemoryManager() : _mem_planner{createMemoryPlanner()} +{ + // DO NOTHING +} + +MemoryManager::MemoryManager(const std::string planner_id) + : _mem_planner{createMemoryPlanner(planner_id)} +{ + // DO NOTHING +} + +cpu_common::IMemoryPlanner *MemoryManager::createMemoryPlanner() +{ + auto planner_id = util::getConfigString(util::config::CPU_MEMORY_PLANNER); + return cpu_common::MemoryPlannerFactory::get().create(planner_id); +} + +cpu_common::IMemoryPlanner *MemoryManager::createMemoryPlanner(const std::string planner_id) +{ + return cpu_common::MemoryPlannerFactory::get().create(planner_id); +} + +void MemoryManager::buildTensor(const ir::OperandIndex &ind, const ir::OperandInfo &info, + ir::Layout layout) +{ + auto tensor = std::make_shared<operand::Tensor>(info, layout); + _tensors[ind] = tensor; +} + +void MemoryManager::claimPlan(const ir::OperandIndex &ind, uint32_t size) +{ + _mem_planner->claim(ind, size); +} + +void MemoryManager::releasePlan(const ir::OperandIndex &ind) { _mem_planner->release(ind); } + +void MemoryManager::allocate(void) +{ + _mem_alloc = std::make_shared<cpu_common::Allocator>(_mem_planner->capacity()); + assert(_mem_alloc->base()); + + for (auto &mem_plan : _mem_planner->memory_plans()) + { + auto ind = mem_plan.first; + auto mem_blk = mem_plan.second; + + uint8_t *buffer = _mem_alloc->base() + mem_blk.offset; + auto tensor = _tensors[ind]; + tensor->setBuffer(buffer); + + VERBOSE(CPU_MEMORYMANAGER) << "TENSOR(#" << ind.value() << "): " << static_cast<void *>(buffer) + << std::endl; + + // If we do not make tensor here currently, kernel generation would cause segmentation fault. + // See also : Comments in `allocate` method. + } +} + +} // namespace srcn +} // namespace backend +} // namespace neurun diff --git a/runtime/neurun/backend/srcn/MemoryManager.h b/runtime/neurun/backend/srcn/MemoryManager.h new file mode 100644 index 000000000..05fa07622 --- /dev/null +++ b/runtime/neurun/backend/srcn/MemoryManager.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __NEURUN_BACKEND_SRCN_MEMORY_MANAGER_H__ +#define __NEURUN_BACKEND_SRCN_MEMORY_MANAGER_H__ + +#include "backend/IMemoryManager.h" +#include <MemoryPlanner.h> +#include "operand/Tensor.h" +#include "ir/OperandIndexMap.h" + +namespace neurun +{ +namespace backend +{ +namespace srcn +{ + +class MemoryManager : public backend::IMemoryManager +{ +public: + MemoryManager(); + MemoryManager(const std::string); + virtual ~MemoryManager() = default; + + void allocate(void) override; + void deallocate(void) override { _mem_alloc->release(); } + + void buildTensor(const ir::OperandIndex &ind, const ir::OperandInfo &info, ir::Layout layout); + void claimPlan(const ir::OperandIndex &ind, uint32_t size); + void releasePlan(const ir::OperandIndex &ind); + + ir::OperandIndexMap<std::shared_ptr<operand::Tensor>> &tensors(void) { return _tensors; } + +private: + cpu_common::IMemoryPlanner *createMemoryPlanner(); + cpu_common::IMemoryPlanner *createMemoryPlanner(std::string); + +private: + ir::OperandIndexMap<std::shared_ptr<operand::Tensor>> _tensors; + ir::OperandIndexMap<cpu_common::Block> _tensor_mem_map; + std::shared_ptr<cpu_common::IMemoryPlanner> _mem_planner; + std::shared_ptr<cpu_common::Allocator> _mem_alloc; +}; + +} // namespace srcn +} // namespace backend +} // namespace neurun + +#endif // __NEURUN_BACKEND_SRCN_MEMORY_MANAGER_H__ diff --git a/runtime/neurun/backend/srcn/PluginClassesAllocator.cc b/runtime/neurun/backend/srcn/PluginClassesAllocator.cc new file mode 100644 index 000000000..9efc6aaaa --- /dev/null +++ b/runtime/neurun/backend/srcn/PluginClassesAllocator.cc @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <util/logging.h> + +#include "Backend.h" + +extern "C" { +neurun::backend::Backend *neurun_backend_create() +{ + VERBOSE(neurun_backend_create) << "'srcn' loaded\n"; + return new neurun::backend::srcn::Backend; +} + +void neurun_backend_destroy(neurun::backend::Backend *backend) +{ + VERBOSE(neurun_backend_create) << "'srcn' unloaded\n"; + delete backend; +} +} diff --git a/runtime/neurun/backend/srcn/ShapeFixer.cc b/runtime/neurun/backend/srcn/ShapeFixer.cc new file mode 100644 index 000000000..0ef190f28 --- /dev/null +++ b/runtime/neurun/backend/srcn/ShapeFixer.cc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ShapeFixer.h" + +#include <stdexcept> + +namespace neurun +{ +namespace backend +{ +namespace srcn +{ + +ShapeFixer::ShapeFixer(const ir::Operands &operand_ctx, + const std::shared_ptr<TensorBuilder> &tensor_builder) + : _ctx(operand_ctx), _tensor_builder(tensor_builder) +{ + assert(tensor_builder); +} + +void ShapeFixer::visit(const ir::operation::Conv2D &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::DepthwiseConv2D &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::InstanceNorm &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::TransposeConv &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Add &) { /* DO NOTHING */} + +} // namespace srcn +} // namespace backend +} // namespace neurun diff --git a/runtime/neurun/backend/srcn/ShapeFixer.h b/runtime/neurun/backend/srcn/ShapeFixer.h new file mode 100644 index 000000000..7da1ae731 --- /dev/null +++ b/runtime/neurun/backend/srcn/ShapeFixer.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __NEURUN_BACKEND_SRCN_SHAPE_FIXER_H__ +#define __NEURUN_BACKEND_SRCN_SHAPE_FIXER_H__ + +#include <backend/IShapeFixer.h> + +#include "ir/Operands.h" +#include "operand/Tensor.h" +#include "TensorBuilder.h" + +namespace neurun +{ +namespace backend +{ +namespace srcn +{ + +class ShapeFixer : public IShapeFixer +{ +public: + ShapeFixer(const ir::Operands &ctx, const std::shared_ptr<TensorBuilder> &tensor_builder); + + void visit(const ir::operation::Conv2D &) override; + void visit(const ir::operation::DepthwiseConv2D &) override; + void visit(const ir::operation::InstanceNorm &) override; + void visit(const ir::operation::TransposeConv &) override; + void visit(const ir::operation::Add &) override; + +private: + const ir::Operands &_ctx; + std::shared_ptr<TensorBuilder> _tensor_builder; +}; + +} // namespace srcn +} // namespace backend +} // namespace neurun + +#endif // __NEURUN_BACKEND_SRCN_SHAPE_FIXER_H__ diff --git a/runtime/neurun/backend/srcn/Swizzle.h b/runtime/neurun/backend/srcn/Swizzle.h new file mode 100644 index 000000000..d1f922367 --- /dev/null +++ b/runtime/neurun/backend/srcn/Swizzle.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __NEURUN_BACKEND_SRCN_SWIZZLE_H__ +#define __NEURUN_BACKEND_SRCN_SWIZZLE_H__ + +#include <cassert> +#include <ir/Layout.h> + +namespace neurun +{ +namespace backend +{ +namespace srcn +{ + +// Convert axis in ncnn order +inline uint32_t ToNCNNAxis(uint32_t rank, uint32_t axis, + const ir::Layout org_layout = ir::Layout::UNKNOWN, + const ir::Layout ncnn_layout = ir::Layout::UNKNOWN) +{ + assert(rank > axis); + + if (rank >= 4 && org_layout == ir::Layout::NHWC && ncnn_layout == ir::Layout::NCHW) + { + // NHWC -> NCHW + // DEPTH + if (axis == 3) + { + return 1; + } + // WIDTH + if (axis == 2) + { + return 3; + } + // HEIGHT + if (axis == 1) + { + return 2; + } + } + + if (rank >= 4 && org_layout == ir::Layout::NCHW && ncnn_layout == ir::Layout::NHWC) + { + // NCHW -> NHWC + // WIDTH + if (axis == 3) + { + return 2; + } + // HEIGHT + if (axis == 2) + { + return 1; + } + // DEPTH + if (axis == 1) + { + return 3; + } + } + + return axis; +} + +} // namespace srcn +} // namespace backend +} // namespace neurun + +#endif // __NEURUN_BACKEND_SRCN_SWIZZLE_H__ diff --git a/runtime/neurun/backend/srcn/TensorBuilder.cc b/runtime/neurun/backend/srcn/TensorBuilder.cc new file mode 100644 index 000000000..5ac25c33e --- /dev/null +++ b/runtime/neurun/backend/srcn/TensorBuilder.cc @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "TensorBuilder.h" + +#include <cassert> +#include "Convert.h" +#include "util/logging.h" + +namespace neurun +{ +namespace backend +{ +namespace srcn +{ + +TensorBuilder::TensorBuilder() : _tensor_mgr{new TensorManager()} +{ + // DO NOTHING +} + +void TensorBuilder::registerTensorInfo(const ir::OperandIndex &ind, + const ir::OperandInfo &tensor_info, + ir::Layout backend_layout, bool as_const) +{ + _tensor_info_map.emplace(ind, tensor_info); + _tensor_layout_map.emplace(ind, backend_layout); + + if (as_const) + _constants.append(ind); +} + +void TensorBuilder::registerSubTensorInfo(const ir::OperandIndex &, const compiler::SubTensorInfo &) +{ + // Not supported yet + assert(false); +} + +void TensorBuilder::notifyFirstUse(const ir::OperandIndex &ind) +{ + assert(_tensor_info_map.find(ind) != _tensor_info_map.end()); + const auto &tensor_info = _tensor_info_map.at(ind); + const auto size = tensor_info.total_size(); + const auto &backend_layout = _tensor_layout_map.at(ind); + _tensor_mgr->buildTensor(ind, tensor_info, backend_layout, _constants.contains(ind)); + _tensor_mgr->claimPlan(ind, size); +} + +void TensorBuilder::notifyLastUse(const ir::OperandIndex &ind) { _tensor_mgr->releasePlan(ind); } + +bool TensorBuilder::isRegistered(const ir::OperandIndex &ind) const +{ + return _tensor_info_map.find(ind) != _tensor_info_map.end(); +} + +void TensorBuilder::prepare(void) +{ + _tensor_mgr->allocateConsts(); + _tensor_mgr->allocateNonconsts(); +} + +void TensorBuilder::allocateConsts() +{ + // NOTE For now nothing to do. Allocation is done in prepare stage, which is not appropriate + // This is because SRCN kernels require `ITensor`s to be allocated before Kernel Generation. +} + +void TensorBuilder::allocateNonconsts() +{ + // NOTE For now nothing to do. Allocation is done in prepare stage, which is not appropriate + // This is because SRCN kernels require `ITensor`s to be allocated before Kernel Generation. +} + +std::shared_ptr<::neurun::backend::operand::ITensor> +TensorBuilder::tensorAt(const ir::OperandIndex &ind) +{ + return _tensor_mgr->at(ind); +} + +void TensorBuilder::iterate(const IterateFunction &fn) { _tensor_mgr->iterate(fn); } + +std::shared_ptr<operand::Tensor> TensorBuilder::at(const ir::OperandIndex &ind) +{ + return _tensor_mgr->at(ind); +} + +std::unique_ptr<ITensorManager> TensorBuilder::releaseTensorManager(void) +{ + return std::move(_tensor_mgr); +} + +} // namespace srcn +} // namespace backend +} // namespace neurun diff --git a/runtime/neurun/backend/srcn/TensorBuilder.h b/runtime/neurun/backend/srcn/TensorBuilder.h new file mode 100644 index 000000000..38bd6dd89 --- /dev/null +++ b/runtime/neurun/backend/srcn/TensorBuilder.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_BACKEND_SRCN_TENSOR_BUILDER_H__ +#define __NEURUN_BACKEND_SRCN_TENSOR_BUILDER_H__ + +#include <unordered_map> + +#include <backend/ITensorBuilder.h> +#include "operand/Tensor.h" +#include "ir/OperandIndexMap.h" +#include "TensorManager.h" + +namespace neurun +{ +namespace backend +{ +namespace srcn +{ + +class TensorBuilder : public ITensorBuilder +{ +public: + TensorBuilder(); + + /** + * @brief Register tensor information to allocate on CPU backend + * @param[in] ind Operand index + * @param[in] info Operand information + * @param[in] layout Operand data layout + */ + void registerTensorInfo(const ir::OperandIndex &ind, const ir::OperandInfo &info, + ir::Layout backend_layout, bool as_const) override; + /** + * @brief Register subtensor information to allocate on CPU backend + * @param[in] ind Operand index + * @param[in] info Tensor information + */ + void registerSubTensorInfo(const ir::OperandIndex &ind, + const compiler::SubTensorInfo &info) override; + + void notifyFirstUse(const ir::OperandIndex &) override; + void notifyLastUse(const ir::OperandIndex &) override; + + bool isRegistered(const ir::OperandIndex &) const override; + + void prepare(void) override; + void allocateConsts() override; + void allocateNonconsts() override; + void postFunctionPrepare() override { /* DO NOTHING */} + void finalize() override { /* DO NOTHING */} + + std::shared_ptr<::neurun::backend::operand::ITensor> + tensorAt(const ir::OperandIndex &ind) override; + + void iterate(const IterateFunction &fn) override; + + void preVisit(const ir::Operation &) override { /* DO NOTHING */} + void postVisit(const ir::Operation &) override { /* DO NOTHING */} + + std::unique_ptr<ITensorManager> releaseTensorManager(void) override; + + std::shared_ptr<operand::Tensor> at(const ir::OperandIndex &ind); + +private: + std::unique_ptr<TensorManager> _tensor_mgr; + ir::OperandIndexMap<ir::OperandInfo> _tensor_info_map; + ir::OperandIndexMap<ir::Layout> _tensor_layout_map; + ir::OperandIndexSequence _constants; +}; + +} // namespace srcn +} // namespace backend +} // namespace neurun + +#endif // __NEURUN_BACKEND_SRCN_TENSOR_BUILDER_H__ diff --git a/runtime/neurun/backend/srcn/TensorManager.cc b/runtime/neurun/backend/srcn/TensorManager.cc new file mode 100644 index 000000000..717f1bbbc --- /dev/null +++ b/runtime/neurun/backend/srcn/TensorManager.cc @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "TensorManager.h" + +namespace neurun +{ +namespace backend +{ +namespace srcn +{ + +TensorManager::TensorManager() + : _const_mgr{new MemoryManager("Bump")}, _nonconst_mgr{new MemoryManager()} +{ + // DO NOTHING +} + +void TensorManager::allocateConsts(void) { _const_mgr->allocate(); } + +void TensorManager::allocateNonconsts(void) { _nonconst_mgr->allocate(); } + +void TensorManager::deallocateConsts(void) { _const_mgr->deallocate(); } + +void TensorManager::deallocateNonconsts(void) { _nonconst_mgr->deallocate(); } + +void TensorManager::buildTensor(const ir::OperandIndex &ind, const ir::OperandInfo &tensor_info, + ir::Layout layout, bool as_const) +{ + assert(_ind_to_mgr.find(ind) == _ind_to_mgr.end()); + if (as_const) + { + _const_mgr->buildTensor(ind, tensor_info, layout); + _ind_to_mgr.insert({ind, *_const_mgr}); + } + else + { + _nonconst_mgr->buildTensor(ind, tensor_info, layout); + _ind_to_mgr.insert({ind, *_nonconst_mgr}); + } +} + +void TensorManager::claimPlan(const ir::OperandIndex &ind, uint32_t size) +{ + assert(_ind_to_mgr.find(ind) != _ind_to_mgr.end()); + _ind_to_mgr.at(ind).claimPlan(ind, size); +} + +void TensorManager::releasePlan(const ir::OperandIndex &ind) +{ + assert(_ind_to_mgr.find(ind) != _ind_to_mgr.end()); + _ind_to_mgr.at(ind).releasePlan(ind); +} + +std::shared_ptr<operand::Tensor> TensorManager::at(const ir::OperandIndex &ind) +{ + assert(_ind_to_mgr.find(ind) != _ind_to_mgr.end()); + return _ind_to_mgr.at(ind).tensors().at(ind); +} + +ir::OperandIndexMap<std::shared_ptr<operand::Tensor>> &TensorManager::constTensors(void) +{ + return _const_mgr->tensors(); +} + +ir::OperandIndexMap<std::shared_ptr<operand::Tensor>> &TensorManager::nonconstTensors(void) +{ + return _nonconst_mgr->tensors(); +} + +void TensorManager::iterate(const std::function<void(const ir::OperandIndex &)> &fn) +{ + for (auto it : _nonconst_mgr->tensors()) + fn(it.first); + + for (auto it : _const_mgr->tensors()) + fn(it.first); +} + +} // namespace srcn +} // namespace backend +} // namespace neurun diff --git a/runtime/neurun/backend/srcn/TensorManager.h b/runtime/neurun/backend/srcn/TensorManager.h new file mode 100644 index 000000000..d4390d80c --- /dev/null +++ b/runtime/neurun/backend/srcn/TensorManager.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __NEURUN_BACKEND_SRCN_TENSOR_MANAGER_H__ +#define __NEURUN_BACKEND_SRCN_TENSOR_MANAGER_H__ + +#include "backend/ITensorManager.h" +#include "MemoryManager.h" +#include "ir/OperandIndexMap.h" + +namespace neurun +{ +namespace backend +{ +namespace srcn +{ + +class TensorManager : public backend::ITensorManager +{ +public: + TensorManager(); + virtual ~TensorManager() = default; + + void allocateConsts(void) override; + void allocateNonconsts(void) override; + void deallocateConsts(void) override; + void deallocateNonconsts(void) override; + + void buildTensor(const ir::OperandIndex &ind, const ir::OperandInfo &tensor_info, + ir::Layout layout, bool as_const); + + void claimPlan(const ir::OperandIndex &ind, uint32_t size); + void releasePlan(const ir::OperandIndex &ind); + + std::shared_ptr<operand::Tensor> at(const ir::OperandIndex &ind); + + ir::OperandIndexMap<std::shared_ptr<operand::Tensor>> &constTensors(void); + ir::OperandIndexMap<std::shared_ptr<operand::Tensor>> &nonconstTensors(void); + + void iterate(const std::function<void(const ir::OperandIndex &)> &fn); + +private: + std::unique_ptr<MemoryManager> _const_mgr; + std::unique_ptr<MemoryManager> _nonconst_mgr; + ir::OperandIndexMap<MemoryManager &> _ind_to_mgr; +}; + +} // namespace srcn +} // namespace backend +} // namespace neurun + +#endif // __NEURUN_BACKEND_SRCN_TENSOR_MANAGER_H__ diff --git a/runtime/neurun/backend/srcn/TensorRegister.cc b/runtime/neurun/backend/srcn/TensorRegister.cc new file mode 100644 index 000000000..8c2f59aef --- /dev/null +++ b/runtime/neurun/backend/srcn/TensorRegister.cc @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "TensorRegister.h" + +#include "Convert.h" +#include "kernel/OperationUtils.h" + +namespace neurun +{ +namespace backend +{ +namespace srcn +{ + +TensorRegister::TensorRegister(const ir::Operands &operands, + const std::shared_ptr<TensorBuilder> &tensor_builder) + : _operands{operands}, _tensor_builder{tensor_builder} +{ + assert(tensor_builder != nullptr); +} + +void TensorRegister::visit(const ir::operation::Conv2D &node) +{ + // General cases + defaultRegisterTensorInfo(node.getInputs().at(ir::operation::Conv2D::INPUT)); + defaultRegisterTensorInfo(node.getInputs().at(ir::operation::Conv2D::BIAS)); + defaultRegisterTensorInfo(node.getOutputs().at(0)); + + // Special case + const auto &kernel_index = node.getInputs().at(ir::operation::Conv2D::KERNEL); + const auto &kernel_obj = _operands.at(kernel_index); + + const auto frontend_layout = frontendLayout(); + assert(frontend_layout == ir::Layout::NCHW || frontend_layout == ir::Layout::NHWC); + const auto frontend_filter_layout = + frontend_layout == ir::Layout::NHWC ? kernel::FilterLayout::OHWI : kernel::FilterLayout::OIHW; + const auto backend_layout = backendLayout(kernel_index); + assert(backend_layout == ir::Layout::NCHW || backend_layout == ir::Layout::NHWC); + const auto backend_filter_layout = + backend_layout == ir::Layout::NHWC ? kernel::FilterLayout::HWIO : kernel::FilterLayout::OIHW; + + ir::OperandInfo backend_info{ + asKernelShape(kernel_obj.shape(), frontend_filter_layout, backend_filter_layout), + kernel_obj.info().typeInfo()}; + _tensor_builder->registerTensorInfo(kernel_index, backend_info, backend_layout, + kernel_obj.isConstant()); +} + +void TensorRegister::visit(const ir::operation::DepthwiseConv2D &node) +{ + // General cases + defaultRegisterTensorInfo(node.getInputs().at(ir::operation::DepthwiseConv2D::INPUT)); + defaultRegisterTensorInfo(node.getInputs().at(ir::operation::DepthwiseConv2D::BIAS)); + defaultRegisterTensorInfo(node.getOutputs().at(0)); + + // Special case + const auto &kernel_index = node.getInputs().at(ir::operation::DepthwiseConv2D::KERNEL); + const auto &kernel_obj = _operands.at(kernel_index); + + const auto frontend_layout = frontendLayout(); + assert(frontend_layout == ir::Layout::NCHW || frontend_layout == ir::Layout::NHWC); + const auto frontend_filter_layout = + frontend_layout == ir::Layout::NHWC ? kernel::FilterLayout::OHWI : kernel::FilterLayout::OIHW; + const auto backend_layout = backendLayout(kernel_index); + assert(backend_layout == ir::Layout::NCHW || backend_layout == ir::Layout::NHWC); + const auto backend_filter_layout = + backend_layout == ir::Layout::NHWC ? kernel::FilterLayout::HWIO : kernel::FilterLayout::OIHW; + + ir::OperandInfo backend_info{ + asKernelShape(kernel_obj.shape(), frontend_filter_layout, backend_filter_layout), + kernel_obj.info().typeInfo()}; + _tensor_builder->registerTensorInfo(kernel_index, backend_info, backend_layout, + kernel_obj.isConstant()); +} + +void TensorRegister::visit(const ir::operation::TransposeConv &node) +{ + // General cases + defaultRegisterTensorInfo(node.getInputs().at(ir::operation::TransposeConv::INPUT)); + defaultRegisterTensorInfo(node.getOutputs().at(0)); + + // Special case + const auto &kernel_index = node.getInputs().at(ir::operation::TransposeConv::KERNEL); + const auto &kernel_obj = _operands.at(kernel_index); + + const auto frontend_layout = frontendLayout(); + assert(frontend_layout == ir::Layout::NCHW || frontend_layout == ir::Layout::NHWC); + const auto frontend_filter_layout = + frontend_layout == ir::Layout::NHWC ? kernel::FilterLayout::OHWI : kernel::FilterLayout::OIHW; + const auto backend_layout = backendLayout(kernel_index); + assert(backend_layout == ir::Layout::NCHW || backend_layout == ir::Layout::NHWC); + const auto backend_filter_layout = + backend_layout == ir::Layout::NHWC ? kernel::FilterLayout::HWOI : kernel::FilterLayout::IOHW; + + ir::OperandInfo backend_info{ + asKernelShape(kernel_obj.shape(), frontend_filter_layout, backend_filter_layout), + kernel_obj.info().typeInfo()}; + _tensor_builder->registerTensorInfo(kernel_index, backend_info, backend_layout, + kernel_obj.isConstant()); +} + +} // namespace srcn +} // namespace backend +} // namespace neurun diff --git a/runtime/neurun/backend/srcn/TensorRegister.h b/runtime/neurun/backend/srcn/TensorRegister.h new file mode 100644 index 000000000..765f29567 --- /dev/null +++ b/runtime/neurun/backend/srcn/TensorRegister.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __NEURUN_BACKEND_SRCN_TENSOR_REGISTER_H__ +#define __NEURUN_BACKEND_SRCN_TENSOR_REGISTER_H__ + +#include <backend/ITensorRegister.h> +#include "TensorBuilder.h" + +namespace neurun +{ +namespace backend +{ +namespace srcn +{ + +class TensorRegister : public ITensorRegister +{ +public: + TensorRegister(const ir::Operands &operands, + const std::shared_ptr<TensorBuilder> &tensor_builder); + +public: + void visit(const ir::operation::Conv2D &) override; + void visit(const ir::operation::DepthwiseConv2D &) override; + void visit(const ir::operation::TransposeConv &) override; + +private: + const ir::Operands &operands() const override { return _operands; } + std::shared_ptr<ITensorBuilder> tensor_builder() const override { return _tensor_builder; } + bool supportSubTensor() const final { return false; } + +private: + const ir::Operands &_operands; + const std::shared_ptr<TensorBuilder> _tensor_builder; +}; + +} // namespace srcn +} // namespace backend +} // namespace neurun + +#endif // __NEURUN_BACKEND_SRCN_TENSOR_REGISTER_H__ diff --git a/runtime/neurun/backend/srcn/kernel/AddLayer.cc b/runtime/neurun/backend/srcn/kernel/AddLayer.cc new file mode 100644 index 000000000..b53dfe89d --- /dev/null +++ b/runtime/neurun/backend/srcn/kernel/AddLayer.cc @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "AddLayer.h" + +#include "OperationUtils.h" +#include "ncnn/layer/binaryop.h" + +#include "cpp14/memory.h" + +namespace +{ +std::unique_ptr<nnfw::ncnn::Mat> +convertMatIgnoreLayout(neurun::backend::srcn::kernel::TensorDescriptor &desc, void *data) +{ + if (desc.dimensions.size() == 1) + { + return nnfw::cpp14::make_unique<nnfw::ncnn::Mat>(desc.dimensions[0], data); + } + else if (desc.dimensions.size() == 2) + { + return nnfw::cpp14::make_unique<nnfw::ncnn::Mat>(desc.dimensions[1], desc.dimensions[0], data); + } + else if (desc.dimensions.size() == 3) + { + return nnfw::cpp14::make_unique<nnfw::ncnn::Mat>(desc.dimensions[2], desc.dimensions[1], + desc.dimensions[0], data); + } + else // rank == 4 and N == 1 + { + return nnfw::cpp14::make_unique<nnfw::ncnn::Mat>(desc.dimensions[3], desc.dimensions[2], + desc.dimensions[1], data); + } +} +} // namespace + +namespace neurun +{ +namespace backend +{ +namespace srcn +{ +namespace kernel +{ + +void AddLayer::addFloat32() +{ + assert(_activation == ir::Activation::NONE); + + // ncnn kernel support + // 1. rank < 4 + // 2. broadcasting + // 2-1 lhs, rhs have same rank, or + // 2-2 model layout and backend layout is same + // For safety, block all broadcasting (enable when ready) + + assert(_lhsDescr.dimensions.size() < 4 || + (_lhsDescr.dimensions.size() == 4 && _lhsDescr.dimensions[0] == 1)); + assert(_rhsDescr.dimensions.size() < 4 || + (_rhsDescr.dimensions.size() == 4 && _rhsDescr.dimensions[0] == 1)); + assert((_lhsDescr.dimensions.size() == _rhsDescr.dimensions.size())); + + nnfw::ncnn::BinaryOpParam param; + param.op_type = nnfw::ncnn::BinaryOp::Operation_ADD; + + auto lhs_mat = convertMatIgnoreLayout(_lhsDescr, _lhsData.v); + auto rhs_mat = convertMatIgnoreLayout(_rhsDescr, _rhsData.v); + auto out_mat = convertMatIgnoreLayout(_outputDescr, _outputData.v); + + ::nnfw::ncnn::ncnn_binary_op(param, *lhs_mat.get(), *rhs_mat.get(), *out_mat.get()); +} + +void AddLayer::addQuant8() +{ + // quant8 add is not implemented yet + throw std::runtime_error{"NYI"}; +} + +void AddLayer::configure(uint8_t *lhsData, const TensorDescriptor &lhsDescr, uint8_t *rhsData, + const TensorDescriptor &rhsDescr, const ir::Activation activation, + uint8_t *outputData, const TensorDescriptor &outputDescr, + const ir::Layout backendLayout) +{ + _lhsData.u8 = lhsData; + _lhsDescr = lhsDescr; + _rhsData.u8 = rhsData; + _rhsDescr = rhsDescr; + _inputType = lhsDescr.type; + _activation = activation; + _outputData.u8 = outputData; + _outputDescr = outputDescr; + _backendLayout = backendLayout; +} + +void AddLayer::run() +{ + if (_inputType == OperandType::FLOAT32) + { + addFloat32(); + } + else if (_inputType == OperandType::QUANT8_ASYMM) + { + addQuant8(); + } +} + +} // namespace kernel +} // namespace srcn +} // namespace backend +} // namespace neurun diff --git a/runtime/neurun/backend/srcn/kernel/AddLayer.h b/runtime/neurun/backend/srcn/kernel/AddLayer.h new file mode 100644 index 000000000..1cae171b5 --- /dev/null +++ b/runtime/neurun/backend/srcn/kernel/AddLayer.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __NEURUN_BACKEND_SRCN_KERNEL_ADD_LAYER_H__ +#define __NEURUN_BACKEND_SRCN_KERNEL_ADD_LAYER_H__ + +#include <exec/IFunction.h> + +#include "OperationUtils.h" + +namespace neurun +{ +namespace backend +{ +namespace srcn +{ +namespace kernel +{ + +class AddLayer : public ::neurun::exec::IFunction +{ +public: + AddLayer() : _lhsData(), _rhsData(), _outputData(), _lhsDescr(), _rhsDescr(), _outputDescr() + { + // DO NOTHING + } + +public: + void addFloat32(); + + void addQuant8(); + + void configure(uint8_t *lhsData, const TensorDescriptor &lhsDescr, uint8_t *rhsData, + const TensorDescriptor &rhsDescr, const ir::Activation activation, + uint8_t *outputData, const TensorDescriptor &outputDescr, + const ir::Layout backendLayout); + + void run(); + void runSync() + { + // this abstract method is used just for profiling and called for + // backend::acl_common::AclFunction + run(); + } + +private: + DataPtr _lhsData; + DataPtr _rhsData; + DataPtr _outputData; + + TensorDescriptor _lhsDescr; + TensorDescriptor _rhsDescr; + TensorDescriptor _outputDescr; + + ir::Activation _activation{ir::Activation::NONE}; + + OperandType _inputType{OperandType::FLOAT32}; + + ir::Layout _backendLayout{ir::Layout::UNKNOWN}; +}; + +} // namespace kernel +} // namespace srcn +} // namespace backend +} // namespace neurun + +#endif // __NEURUN_BACKEND_SRCN_KERNEL_ADD_LAYER_H__ diff --git a/runtime/neurun/backend/srcn/kernel/ConvolutionLayer.cc b/runtime/neurun/backend/srcn/kernel/ConvolutionLayer.cc new file mode 100644 index 000000000..4e70f6319 --- /dev/null +++ b/runtime/neurun/backend/srcn/kernel/ConvolutionLayer.cc @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ConvolutionLayer.h" + +#include "OperationUtils.h" +#include <ncnn/srcn/srcn_conv.h> + +namespace neurun +{ +namespace backend +{ +namespace srcn +{ +namespace kernel +{ + +ConvolutionLayer::ConvolutionLayer() + : _inputData(), _kernelData(), _biasData(), _outputData(), _inputDescr(), _kernelDescr(), + _biasDescr(), _outputDescr(), _paddingType(0), _paddingLeft(0), _paddingTop(0), + _paddingRight(0), _paddingBottom(0), _strideWidth(0), _strideHeight(0), + _inputType(OperandType::FLOAT32), _layout(nnfw::srcn::col_major), _winograd_weights(nullptr), + _sparse_weights(nullptr) +{ + // DO NOTHING +} + +ConvolutionLayer::~ConvolutionLayer() +{ + // TODO Move managing constant _winograd_data and sparse + nnfw::srcn::winograd_release(_winograd_weights); + size_t depth_index = _layout == nnfw::srcn::col_major ? 3 : 1; + nnfw::srcn::sparse_release(_outputDescr.dimensions[depth_index], _sparse_weights); +} + +void ConvolutionLayer::convFloat32() +{ + nnfw::srcn::convMat_t in_mat, out_mat, kernel_mat; + nnfw::srcn::convParams_t in_param; + + assert(_layout == nnfw::srcn::col_major || _layout == nnfw::srcn::row_major); + size_t height_index = _layout == nnfw::srcn::col_major ? 1 : 2; + size_t width_index = _layout == nnfw::srcn::col_major ? 2 : 3; + size_t depth_index = _layout == nnfw::srcn::col_major ? 3 : 1; + size_t kernel_input_depth_index = _layout == nnfw::srcn::col_major ? 3 : 1; + size_t kernel_output_depth_index = 0; + + const int batches = MatchingDim(_inputDescr, 0, _outputDescr, 0); + const int input_height = _inputDescr.dimensions[height_index]; + const int input_width = _inputDescr.dimensions[width_index]; + const int input_depth = + MatchingDim(_inputDescr, depth_index, _kernelDescr, kernel_input_depth_index); + in_mat.c = input_depth; + in_mat.w = input_width; + in_mat.h = input_height; + in_mat.n = batches; + in_mat.data = _inputData.f; + + const int output_height = _outputDescr.dimensions[height_index]; + const int output_width = _outputDescr.dimensions[width_index]; + const int output_depth = + MatchingDim(_kernelDescr, kernel_output_depth_index, _outputDescr, depth_index); + out_mat.c = output_depth; + out_mat.w = output_width; + out_mat.h = output_height; + out_mat.n = batches; + out_mat.data = _outputData.f; + + const int outch = _kernelDescr.dimensions[kernel_output_depth_index]; + const int inch = _kernelDescr.dimensions[kernel_input_depth_index]; + const int ker_height = _kernelDescr.dimensions[height_index]; + const int ker_width = _kernelDescr.dimensions[width_index]; + kernel_mat.c = input_depth; + kernel_mat.w = ker_width; + kernel_mat.h = ker_height; + kernel_mat.n = output_depth; + kernel_mat.data = _kernelData.f; + + in_param.kernel_w = ker_width; + in_param.kernel_h = ker_height; + in_param.stride_w = _strideWidth; + in_param.stride_h = _strideHeight; + in_param.padding = _paddingType; + in_param.pad_w = _paddingLeft; + in_param.pad_h = _paddingTop; + in_param.dilation_w = 1; + in_param.dilation_h = 1; + + nnfw::srcn::winogradParams_t winograd_param; + winograd_param.kernel_w = ker_width; + winograd_param.kernel_h = ker_height; + winograd_param.stride_w = _strideWidth; + winograd_param.stride_h = _strideHeight; + winograd_param.dilation_w = 1; + winograd_param.dilation_h = 1; + winograd_param.batch = batches; + winograd_param.w = ker_width; + winograd_param.h = ker_height; + winograd_param.inch = inch; + winograd_param.outch = outch; + winograd_param.num_threads = 4; + + winograd_param.conv_type = _layout; + winograd_param.weight_data = _kernelData.f; + + // Without winograd + if (nnfw::srcn::check_winograd(winograd_param)) + { + _winograd_weights = nnfw::srcn::trans_weight2winograd(winograd_param, nullptr); + } + _sparse_weights = nnfw::srcn::trans_weight2sparse(kernel_mat); + + nnfw::srcn::srcn_convolution2D(in_mat, kernel_mat, out_mat, in_param, _winograd_weights, 4, + _layout); + + // Add biases + if (_biasData.f == nullptr) + { + return; + } + // TODO Optimize + uint32_t strides[4] = { + _outputDescr.dimensions[1] * _outputDescr.dimensions[2] * _outputDescr.dimensions[3], + _outputDescr.dimensions[2] * _outputDescr.dimensions[3], _outputDescr.dimensions[3], 1}; + if (_layout == nnfw::srcn::convType_t::col_major) + { + for (uint32_t c = 0; c < _outputDescr.dimensions[3]; ++c) + { + if (_biasData.f[c] != 0) + { + for (uint32_t b = 0; b < _outputDescr.dimensions[0]; ++b) + { + for (uint32_t h = 0; h < _outputDescr.dimensions[1]; ++h) + { + for (uint32_t w = 0; w < _outputDescr.dimensions[2]; ++w) + { + _outputData.f[b * strides[0] + h * strides[1] + w * strides[2] + c * strides[3]] += + _biasData.f[c]; + } + } + } + } + } + } + else if (_layout == nnfw::srcn::convType_t::row_major) + { + for (uint32_t c = 0; c < _outputDescr.dimensions[1]; ++c) + { + if (_biasData.f[c] != 0) + { + for (uint32_t b = 0; b < _outputDescr.dimensions[0]; ++b) + { + for (uint32_t h = 0; h < _outputDescr.dimensions[2]; ++h) + { + for (uint32_t w = 0; w < _outputDescr.dimensions[3]; ++w) + { + _outputData.f[b * strides[0] + c * strides[1] + h * strides[2] + w * strides[3]] += + _biasData.f[c]; + } + } + } + } + } + } + else + { + throw std::runtime_error("Wrong Layout"); + } +} + +void ConvolutionLayer::configure(uint8_t *inputData, const TensorDescriptor inputDescr, + uint8_t *kernelData, const TensorDescriptor kernelDescr, + uint8_t *biasData, const TensorDescriptor biasDescr, + const uint32_t 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, uint8_t *outputData, + const TensorDescriptor outputDescr, ir::Layout layout) +{ + assert(inputDescr.dimensions.size() == 4); + assert(kernelDescr.dimensions.size() == 4); + assert(biasDescr.dimensions.size() == 1); + assert(outputDescr.dimensions.size() == 4); + assert(inputDescr.type == kernelDescr.type && inputDescr.type == outputDescr.type); + // TODO Add assertions validating height and width with padding + _layout = convertLayout(layout); + _inputData.u8 = inputData; + _inputDescr = inputDescr; + _inputType = inputDescr.type; + _kernelData.u8 = kernelData; + _kernelDescr = kernelDescr; + _biasData.u8 = biasData; + _biasDescr = biasDescr; + _paddingType = paddingType; + _paddingLeft = paddingLeft; + _paddingRight = paddingRight; + _paddingTop = paddingTop; + _paddingBottom = paddingBottom; + _strideWidth = strideWidth; + _strideHeight = strideHeight; + _outputData.u8 = outputData; + _outputDescr = outputDescr; +} + +void ConvolutionLayer::run() +{ + if (_inputType == OperandType::FLOAT32) + { + convFloat32(); + } + else if (_inputType == OperandType::QUANT8_ASYMM) + { + throw std::runtime_error("NYI"); + } +} + +} // namespace kernel +} // namespace srcn +} // namespace backend +} // namespace neurun diff --git a/runtime/neurun/backend/srcn/kernel/ConvolutionLayer.h b/runtime/neurun/backend/srcn/kernel/ConvolutionLayer.h new file mode 100644 index 000000000..4edafaa87 --- /dev/null +++ b/runtime/neurun/backend/srcn/kernel/ConvolutionLayer.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __NEURUN_BACKEND_SRCN_KERNEL_CONVOLUTION_LAYER_H__ +#define __NEURUN_BACKEND_SRCN_KERNEL_CONVOLUTION_LAYER_H__ + +#include <exec/IFunction.h> +#include <ncnn/srcn/conv_type.h> + +#include "OperationUtils.h" + +namespace neurun +{ +namespace backend +{ +namespace srcn +{ +namespace kernel +{ + +class ConvolutionLayer : public ::neurun::exec::IFunction +{ +public: + ConvolutionLayer(); + ~ConvolutionLayer(); + +public: + void convFloat32(); + void configure(uint8_t *inputData, const TensorDescriptor inputDescr, uint8_t *kernelData, + const TensorDescriptor kernelDescr, uint8_t *biasData, + const TensorDescriptor biasDescr, const uint32_t paddingType, + const uint32_t paddingLeft, const uint32_t paddingRight, const uint32_t paddingTop, + const uint32_t paddingBottom, const uint32_t strideW, const uint32_t strideH, + uint8_t *outputData, const TensorDescriptor outputDescr, ir::Layout layout); + + void run(); + void runSync() + { + // this abstract method is used just for profiling and called for + // backend::acl_common::AclFunction + run(); + } + +private: + DataPtr _inputData; + DataPtr _kernelData; + DataPtr _biasData; + DataPtr _outputData; + + TensorDescriptor _inputDescr; + TensorDescriptor _kernelDescr; + TensorDescriptor _biasDescr; + TensorDescriptor _outputDescr; + + uint32_t _paddingType; + uint32_t _paddingLeft; + uint32_t _paddingTop; + uint32_t _paddingRight; + uint32_t _paddingBottom; + + uint32_t _strideWidth; + uint32_t _strideHeight; + + OperandType _inputType; + nnfw::srcn::convType_t _layout; + + float *_winograd_weights; + void *_sparse_weights; +}; + +} // namespace kernel +} // namespace srcn +} // namespace backend +} // namespace neurun + +#endif // __NEURUN_BACKEND_SRCN_KERNEL_CONVOLUTION_LAYER_H__ diff --git a/runtime/neurun/backend/srcn/kernel/DepthwiseConvolutionLayer.cc b/runtime/neurun/backend/srcn/kernel/DepthwiseConvolutionLayer.cc new file mode 100644 index 000000000..a1718c500 --- /dev/null +++ b/runtime/neurun/backend/srcn/kernel/DepthwiseConvolutionLayer.cc @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "DepthwiseConvolutionLayer.h" + +#include <ncnn/srcn/srcn_conv.h> +#include "OperationUtils.h" + +namespace neurun +{ +namespace backend +{ +namespace srcn +{ +namespace kernel +{ + +DepthwiseConvolutionLayer::DepthwiseConvolutionLayer() + : _inputData(), _kernelData(), _biasData(), _outputData(), _inputDescr(), _kernelDescr(), + _biasDescr(), _outputDescr(), _paddingType(0), _paddingLeft(0), _paddingTop(0), + _paddingRight(0), _paddingBottom(0), _strideWidth(0), _strideHeight(0), + _inputType(OperandType::FLOAT32), _layout(nnfw::srcn::col_major) +{ + // DO NOTHING +} + +void DepthwiseConvolutionLayer::convFloat32() +{ + nnfw::srcn::convMat_t in_mat, out_mat, kernel_mat, bias_mat; + nnfw::srcn::convParams_t in_param; + + assert(_layout == nnfw::srcn::col_major || _layout == nnfw::srcn::row_major); + size_t height_index = _layout == nnfw::srcn::col_major ? 1 : 2; + size_t width_index = _layout == nnfw::srcn::col_major ? 2 : 3; + size_t depth_index = _layout == nnfw::srcn::col_major ? 3 : 1; + + const int batches = MatchingDim(_inputDescr, 0, _outputDescr, 0); + const int input_height = _inputDescr.dimensions[height_index]; + const int input_width = _inputDescr.dimensions[width_index]; + const int input_depth = _inputDescr.dimensions[depth_index]; + in_mat.c = input_depth; + in_mat.w = input_width; + in_mat.h = input_height; + in_mat.n = batches; + in_mat.data = _inputData.f; + + const int output_height = _outputDescr.dimensions[height_index]; + const int output_width = _outputDescr.dimensions[width_index]; + const int output_depth = MatchingDim(_kernelDescr, depth_index, _outputDescr, depth_index); + out_mat.c = output_depth; + out_mat.w = output_width; + out_mat.h = output_height; + out_mat.n = batches; + out_mat.data = _outputData.f; + + const int ker_height = _kernelDescr.dimensions[height_index]; + const int ker_width = _kernelDescr.dimensions[width_index]; + kernel_mat.c = MatchingDim(_kernelDescr, depth_index, _outputDescr, depth_index); + kernel_mat.w = ker_width; + kernel_mat.h = ker_height; + kernel_mat.n = 1; + kernel_mat.data = _kernelData.f; + + const int bias_depth = MatchingDim(_biasDescr, 0, _outputDescr, depth_index); + bias_mat.c = bias_depth; + bias_mat.data = _biasData.f; + + in_param.kernel_w = ker_width; + in_param.kernel_h = ker_height; + in_param.stride_w = _strideWidth; + in_param.stride_h = _strideHeight; + in_param.padding = _paddingType; + in_param.pad_w = _paddingLeft; + in_param.pad_h = _paddingTop; + in_param.dilation_w = 1; + in_param.dilation_h = 1; + + nnfw::srcn::srcn_depthwise_conv(in_mat, kernel_mat, out_mat, bias_mat, in_param, 4, _layout); + + // Add biases + if (_biasData.f == nullptr) + { + return; + } + // TODO Optimize + uint32_t strides[4] = { + _outputDescr.dimensions[1] * _outputDescr.dimensions[2] * _outputDescr.dimensions[3], + _outputDescr.dimensions[2] * _outputDescr.dimensions[3], _outputDescr.dimensions[3], 1}; + if (_layout == nnfw::srcn::convType_t::col_major) + { + for (uint32_t c = 0; c < _outputDescr.dimensions[3]; ++c) + { + if (_biasData.f[c] != 0) + { + for (uint32_t b = 0; b < _outputDescr.dimensions[0]; ++b) + { + for (uint32_t h = 0; h < _outputDescr.dimensions[1]; ++h) + { + for (uint32_t w = 0; w < _outputDescr.dimensions[2]; ++w) + { + _outputData.f[b * strides[0] + h * strides[1] + w * strides[2] + c * strides[3]] += + _biasData.f[c]; + } + } + } + } + } + } + else if (_layout == nnfw::srcn::convType_t::row_major) + { + for (uint32_t c = 0; c < _outputDescr.dimensions[1]; ++c) + { + if (_biasData.f[c] != 0) + { + for (uint32_t b = 0; b < _outputDescr.dimensions[0]; ++b) + { + for (uint32_t h = 0; h < _outputDescr.dimensions[2]; ++h) + { + for (uint32_t w = 0; w < _outputDescr.dimensions[3]; ++w) + { + _outputData.f[b * strides[0] + c * strides[1] + h * strides[2] + w * strides[3]] += + _biasData.f[c]; + } + } + } + } + } + } + else + { + throw std::runtime_error("Wrong Layout"); + } +} + +void DepthwiseConvolutionLayer::configure(uint8_t *inputData, const TensorDescriptor inputDescr, + uint8_t *kernelData, const TensorDescriptor kernelDescr, + uint8_t *biasData, const TensorDescriptor biasDescr, + const uint32_t 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, uint8_t *outputData, + const TensorDescriptor outputDescr, ir::Layout layout) +{ + assert(layout == ir::Layout::NHWC || layout == ir::Layout::NCHW); + + const auto height_index = layout == ir::Layout::NHWC ? 1 : 2; + const auto width_index = layout == ir::Layout::NHWC ? 2 : 3; + + if (layout == ir::Layout::NHWC) + { + throw std::runtime_error("DepthwiseConv of ncnn does not support layout yet in NHWC"); + } + + if (kernelDescr.dimensions[height_index] != 3 || kernelDescr.dimensions[width_index] != 3) + { + throw std::runtime_error("DepthwiseConv of ncnn supports only 3x3 kernel now"); + } + + assert(inputDescr.dimensions.size() == 4); + assert(kernelDescr.dimensions.size() == 4); + assert(biasDescr.dimensions.size() == 1); + assert(outputDescr.dimensions.size() == 4); + assert(inputDescr.type == kernelDescr.type && inputDescr.type == outputDescr.type); + // TODO Add assertions validating height and width with padding + _layout = convertLayout(layout); + _inputData.u8 = inputData; + _inputDescr = inputDescr; + _inputType = inputDescr.type; + _kernelData.u8 = kernelData; + _kernelDescr = kernelDescr; + _biasData.u8 = biasData; + _biasDescr = biasDescr; + _paddingType = paddingType; + _paddingLeft = paddingLeft; + _paddingRight = paddingRight; + _paddingTop = paddingTop; + _paddingBottom = paddingBottom; + _strideWidth = strideWidth; + _strideHeight = strideHeight; + _outputData.u8 = outputData; + _outputDescr = outputDescr; +} + +void DepthwiseConvolutionLayer::run() +{ + if (_inputType == OperandType::FLOAT32) + { + convFloat32(); + } + else if (_inputType == OperandType::QUANT8_ASYMM) + { + throw std::runtime_error("NYI"); + } +} + +} // namespace kernel +} // namespace srcn +} // namespace backend +} // namespace neurun diff --git a/runtime/neurun/backend/srcn/kernel/DepthwiseConvolutionLayer.h b/runtime/neurun/backend/srcn/kernel/DepthwiseConvolutionLayer.h new file mode 100644 index 000000000..e94acff08 --- /dev/null +++ b/runtime/neurun/backend/srcn/kernel/DepthwiseConvolutionLayer.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __NEURUN_BACKEND_SRCN_KERNEL_DEPTHWISE_CONVOLUTION_LAYER_H__ +#define __NEURUN_BACKEND_SRCN_KERNEL_DEPTHWISE_CONVOLUTION_LAYER_H__ + +#include <exec/IFunction.h> +#include <ncnn/srcn/conv_type.h> + +#include "OperationUtils.h" + +namespace neurun +{ +namespace backend +{ +namespace srcn +{ +namespace kernel +{ + +class DepthwiseConvolutionLayer : public ::neurun::exec::IFunction +{ +public: + DepthwiseConvolutionLayer(); + +public: + void convFloat32(); + void configure(uint8_t *inputData, const TensorDescriptor inputDescr, uint8_t *kernelData, + const TensorDescriptor kernelDescr, uint8_t *biasData, + const TensorDescriptor biasDescr, const uint32_t paddingType, + const uint32_t paddingLeft, const uint32_t paddingRight, const uint32_t paddingTop, + const uint32_t paddingBottom, const uint32_t strideW, const uint32_t strideH, + uint8_t *outputData, const TensorDescriptor outputDescr, ir::Layout layout); + + void run(); + void runSync() + { + // this abstract method is used just for profiling and called for + // backend::acl_common::AclFunction + run(); + } + +private: + DataPtr _inputData; + DataPtr _kernelData; + DataPtr _biasData; + DataPtr _outputData; + + TensorDescriptor _inputDescr; + TensorDescriptor _kernelDescr; + TensorDescriptor _biasDescr; + TensorDescriptor _outputDescr; + + uint32_t _paddingType; + uint32_t _paddingLeft; + uint32_t _paddingTop; + uint32_t _paddingRight; + uint32_t _paddingBottom; + + uint32_t _strideWidth; + uint32_t _strideHeight; + + OperandType _inputType; + nnfw::srcn::convType_t _layout; +}; + +} // namespace kernel +} // namespace srcn +} // namespace backend +} // namespace neurun + +#endif // __NEURUN_BACKEND_SRCN_KERNEL_DEPTHWISE_CONVOLUTION_LAYER_H__ diff --git a/runtime/neurun/backend/srcn/kernel/InstanceNormLayer.cc b/runtime/neurun/backend/srcn/kernel/InstanceNormLayer.cc new file mode 100644 index 000000000..c83fe6d67 --- /dev/null +++ b/runtime/neurun/backend/srcn/kernel/InstanceNormLayer.cc @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "InstanceNormLayer.h" + +#include "OperationUtils.h" +#include "ncnn/layer/instance_norm.h" + +namespace neurun +{ +namespace backend +{ +namespace srcn +{ +namespace kernel +{ + +InstanceNormLayer::InstanceNormLayer() + : _inputData(), _gammaData(), _betaData(), _outputData(), _inputDescr(), _gammaDescr(), + _betaDescr(), _outputDescr(), _epsilon(1e-5), _activation(ir::Activation::NONE), + _inputType(OperandType::FLOAT32), _backendLayout(ir::Layout::UNKNOWN) +{ + // DO NOTHING +} + +void InstanceNormLayer::instanceNormFloat32() +{ + // Call kernel for NCHW data layout + if (_backendLayout == ir::Layout::NCHW) + { + // Supports single batch only + assert(_inputDescr.dimensions[0] == 1); + const int input_channels = _inputDescr.dimensions[1]; + const int input_height = _inputDescr.dimensions[2]; + const int input_width = _inputDescr.dimensions[3]; + nnfw::ncnn::Mat in_mat(input_width, input_height, input_channels, _inputData.f); + + const int gamma_channels = _gammaDescr.dimensions[0]; + nnfw::ncnn::Mat gamma_mat(gamma_channels, _gammaData.f); + + const int beta_channels = _betaDescr.dimensions[0]; + nnfw::ncnn::Mat beta_mat(beta_channels, _betaData.f); + + assert(_outputDescr.dimensions[0] == 1); + const int output_channels = _outputDescr.dimensions[1]; + const int output_height = _outputDescr.dimensions[2]; + const int output_width = _outputDescr.dimensions[3]; + nnfw::ncnn::Mat out_mat(output_width, output_height, output_channels, _outputData.f); + + if (_activation == ir::Activation::NONE) + { + nnfw::ncnn::ncnn_instance_norm_rowmajor(in_mat, out_mat, gamma_mat, beta_mat, input_channels, + _epsilon); + } + else if (_activation == ir::Activation::RELU) + { + nnfw::ncnn::ncnn_instance_norm_with_relu_rowmajor(in_mat, out_mat, gamma_mat, beta_mat, + input_channels, _epsilon, 0.f); + } + else + { + std::runtime_error("Unsupported activation type"); + } + } + // Call kernel for NHWC data layout + else if (_backendLayout == ir::Layout::NHWC) + { + // Supports single batch only + assert(_inputDescr.dimensions[0] == 1); + const int input_height = _inputDescr.dimensions[1]; + const int input_width = _inputDescr.dimensions[2]; + const int input_channels = _inputDescr.dimensions[3]; + nnfw::ncnn::Mat in_mat(input_channels, input_width, input_height, _inputData.f); + + const int gamma_channels = _gammaDescr.dimensions[0]; + nnfw::ncnn::Mat gamma_mat(gamma_channels, _gammaData.f); + + const int beta_channels = _betaDescr.dimensions[0]; + nnfw::ncnn::Mat beta_mat(beta_channels, _betaData.f); + + assert(_outputDescr.dimensions[0] == 1); + const int output_height = _outputDescr.dimensions[1]; + const int output_width = _outputDescr.dimensions[2]; + const int output_channels = _outputDescr.dimensions[3]; + nnfw::ncnn::Mat out_mat(output_channels, output_width, output_height, _outputData.f); + + if (_activation == ir::Activation::NONE) + { + nnfw::ncnn::ncnn_instance_norm_colmajor(in_mat, out_mat, gamma_mat, beta_mat, input_channels, + _epsilon); + } + else if (_activation == ir::Activation::RELU) + { + nnfw::ncnn::ncnn_instance_norm_with_relu_colmajor(in_mat, out_mat, gamma_mat, beta_mat, + input_channels, _epsilon, 0.f); + } + { + std::runtime_error("Unsupported activation type"); + } + } + else + { + std::runtime_error("Unsupported backend layout"); + } +} + +void InstanceNormLayer::configure(uint8_t *inputData, const TensorDescriptor inputDescr, + uint8_t *gammaData, const TensorDescriptor gammaDescr, + uint8_t *betaData, const TensorDescriptor betaDescr, + uint8_t *outputData, const TensorDescriptor outputDescr, + float epsilon, ir::Activation activation, + ir::Layout backendLayout) +{ + _inputData.u8 = inputData; + _inputDescr = inputDescr; + _gammaData.u8 = gammaData; + _gammaDescr = gammaDescr; + _betaData.u8 = betaData; + _betaDescr = betaDescr; + _outputData.u8 = outputData; + _outputDescr = outputDescr; + _epsilon = epsilon; + _activation = activation; + _backendLayout = backendLayout; +} + +void InstanceNormLayer::run() +{ + if (_inputType == OperandType::FLOAT32) + { + instanceNormFloat32(); + } + else if (_inputType == OperandType::QUANT8_ASYMM) + { + throw std::runtime_error("NYI"); + } +} + +} // namespace kernel +} // namespace srcn +} // namespace backend +} // namespace neurun diff --git a/runtime/neurun/backend/srcn/kernel/InstanceNormLayer.h b/runtime/neurun/backend/srcn/kernel/InstanceNormLayer.h new file mode 100644 index 000000000..0ac0cef3f --- /dev/null +++ b/runtime/neurun/backend/srcn/kernel/InstanceNormLayer.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __NEURUN_BACKEND_SRCN_KERNEL_INSTANCENORM_LAYER_H__ +#define __NEURUN_BACKEND_SRCN_KERNEL_INSTANCENORM_LAYER_H__ + +#include <exec/IFunction.h> + +#include "OperationUtils.h" + +namespace neurun +{ +namespace backend +{ +namespace srcn +{ +namespace kernel +{ + +class InstanceNormLayer : public ::neurun::exec::IFunction +{ +public: + InstanceNormLayer(); + +public: + void instanceNormFloat32(); + void configure(uint8_t *inputData, const TensorDescriptor inputDescr, uint8_t *gammaData, + const TensorDescriptor gammaDescr, uint8_t *betaData, + const TensorDescriptor betaDescr, uint8_t *outputData, + const TensorDescriptor outputDescr, float epsilon, ir::Activation activation, + ir::Layout backendLayout); + + void run(); + void runSync() + { + // this abstract method is used just for profiling and called for + // backend::acl_common::AclFunction + run(); + } + +private: + DataPtr _inputData; + DataPtr _gammaData; + DataPtr _betaData; + DataPtr _outputData; + + TensorDescriptor _inputDescr; + TensorDescriptor _gammaDescr; + TensorDescriptor _betaDescr; + TensorDescriptor _outputDescr; + + float _epsilon; + ir::Activation _activation; + + OperandType _inputType; + ir::Layout _backendLayout; +}; + +} // namespace kernel +} // namespace srcn +} // namespace backend +} // namespace neurun + +#endif // __NEURUN_BACKEND_SRCN_KERNEL_INSTANCENORM_LAYER_H__ diff --git a/runtime/neurun/backend/srcn/kernel/OperationUtils.cc b/runtime/neurun/backend/srcn/kernel/OperationUtils.cc new file mode 100644 index 000000000..684573a51 --- /dev/null +++ b/runtime/neurun/backend/srcn/kernel/OperationUtils.cc @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "OperationUtils.h" + +#include <cmath> +#include <algorithm> +#include <cassert> +#include <map> + +#include "util/Utils.h" + +namespace neurun +{ +namespace backend +{ +namespace srcn +{ +namespace kernel +{ + +uint32_t MatchingDim(const TensorDescriptor &descr1, int index1, const TensorDescriptor &descr2, + int index2) +{ + UNUSED_RELEASE(descr2); + UNUSED_RELEASE(index2); + assert(descr1.dimensions[index1] == descr2.dimensions[index2]); + return descr1.dimensions[index1]; +} + +std::vector<int32_t> getFilterPermutation(FilterLayout from_layout, FilterLayout to_layout) +{ + static std::map<std::pair<FilterLayout, FilterLayout>, std::vector<int32_t>> filter_permutation = + {{std::make_pair(FilterLayout::OHWI, FilterLayout::HWOI), {1, 2, 0, 3}}, + {std::make_pair(FilterLayout::OHWI, FilterLayout::HWIO), {1, 2, 3, 0}}, + {std::make_pair(FilterLayout::OHWI, FilterLayout::OIHW), {0, 3, 1, 2}}, + {std::make_pair(FilterLayout::OHWI, FilterLayout::IOHW), {3, 0, 1, 2}}, + {std::make_pair(FilterLayout::OIHW, FilterLayout::HWOI), {2, 3, 0, 1}}, + {std::make_pair(FilterLayout::OIHW, FilterLayout::HWIO), {2, 3, 1, 0}}, + {std::make_pair(FilterLayout::OIHW, FilterLayout::OHWI), {0, 2, 3, 1}}, + {std::make_pair(FilterLayout::OIHW, FilterLayout::IOHW), {1, 0, 2, 3}}}; + + const auto pair = std::make_pair(from_layout, to_layout); + const auto it = filter_permutation.find(pair); + if (it == filter_permutation.end()) + { + return std::vector<int32_t>{}; + } + return it->second; +} + +Coordinates convertCoordinates(const Coordinates &coordinates, FilterLayout from_layout, + FilterLayout to_layout) +{ + assert(coordinates.size() == 4); + if (from_layout == to_layout) + { + return coordinates; + } + + const auto permutation = getFilterPermutation(from_layout, to_layout); + if (permutation.size() == 0) + { + throw std::runtime_error("Not supported FilterLayout"); + } + return Coordinates{coordinates[permutation[0]], coordinates[permutation[1]], + coordinates[permutation[2]], coordinates[permutation[3]]}; +} + +nnfw::srcn::convType_t convertLayout(ir::Layout layout) +{ + if (layout == ir::Layout::NHWC) + { + return nnfw::srcn::col_major; + } + else if (layout == ir::Layout::NCHW) + { + return nnfw::srcn::row_major; + } + else + { + throw std::runtime_error("Not supported layout"); + } +} + +TensorDescriptor getTensorDescriptor(const ir::Operand &o, ir::Layout frontend_layout, + ir::Layout backend_layout) +{ + TensorDescriptor descriptor; + + auto dims = o.shape().dims(); + if (frontend_layout == ir::Layout::NHWC && backend_layout == ir::Layout::NCHW && + o.shape().rank() == 4) + { + // NHWC -> NCHW + uint32_t permutation[4] = {0, 3, 1, 2}; + for (int i = 0; i < o.shape().rank(); ++i) + { + dims.at(i) = o.shape().dim(permutation[i]); + } + } + else if (frontend_layout == ir::Layout::NCHW && backend_layout == ir::Layout::NHWC && + o.shape().rank() == 4) + { + // NCHW -> NHWC + uint32_t permutation[4] = {0, 2, 3, 1}; + for (int i = 0; i < o.shape().rank(); ++i) + { + dims.at(i) = o.shape().dim(permutation[i]); + } + } + descriptor.dimensions = std::vector<uint32_t>(dims.begin(), dims.end()); + descriptor.type = static_cast<OperandType>(static_cast<int32_t>(o.typeInfo().type())); + descriptor.scale = o.typeInfo().scale(); + descriptor.offset = o.typeInfo().offset(); + + // CPU backend assume that neurun internal descriptor's rank is always same or less than 4 + assert(descriptor.dimensions.size() <= 4); + + return descriptor; +} + +} // namespace kernel +} // namespace srcn +} // namespace backend +} // namespace neurun diff --git a/runtime/neurun/backend/srcn/kernel/OperationUtils.h b/runtime/neurun/backend/srcn/kernel/OperationUtils.h new file mode 100644 index 000000000..aa163a1f3 --- /dev/null +++ b/runtime/neurun/backend/srcn/kernel/OperationUtils.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __NEURUN_BACKEND_SRCN_OPERATION_UTILS_H__ +#define __NEURUN_BACKEND_SRCN_OPERATION_UTILS_H__ + +#include <iostream> +#include <limits> +#include <vector> + +#include "ir/Operand.h" +#include "ir/DataType.h" +#include <ir/InternalType.h> +#include <ncnn/srcn/conv_type.h> + +using OperandType = neurun::ir::DataType; +using neurun::util::Coordinates; + +namespace neurun +{ +namespace backend +{ +namespace srcn +{ +namespace kernel +{ + +struct TensorDescriptor +{ + OperandType type; + std::vector<uint32_t> dimensions; + float scale; + int32_t offset; +}; + +union DataPtr { + uint8_t *u8; + int8_t *i8; + int32_t *i32; + float *f; + void *v; +}; + +enum FilterLayout +{ + OHWI = 0, // TfLite Kernel Layout when using NHWC image layout + HWOI, // SRCN Transpose Conv Kernel Layout when using NHWC image layout + OIHW, // SRCN Conv Kernel Layout when using NCHW image layout + HWIO, // SRCN Conv Kernel Layout when using NHWC image layout + IOHW, // SRCN Transpose Conv Kernel Layout when using NCHW image layout +}; + +uint32_t MatchingDim(const TensorDescriptor &shape1, int index1, const TensorDescriptor &shape2, + int index2); + +std::vector<int32_t> getFilterPermutation(FilterLayout from_layout, FilterLayout to_layout); + +Coordinates convertCoordinates(const Coordinates &from_coordinates, FilterLayout from_layout, + FilterLayout to_layout); + +nnfw::srcn::convType_t convertLayout(ir::Layout layout); + +TensorDescriptor getTensorDescriptor(const ir::Operand &o, ir::Layout frontend_layout, + ir::Layout backend_layout); + +} // namespace kernel +} // namespace srcn +} // namespace backend +} // namespace neurun + +#endif // __NEURUN_BACKEND_SRCN_OPERATION_UTILS_H__ diff --git a/runtime/neurun/backend/srcn/kernel/TransposeConvLayer.cc b/runtime/neurun/backend/srcn/kernel/TransposeConvLayer.cc new file mode 100644 index 000000000..26469f728 --- /dev/null +++ b/runtime/neurun/backend/srcn/kernel/TransposeConvLayer.cc @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "TransposeConvLayer.h" + +#include <cstring> +#include "OperationUtils.h" +#include "ncnn/srcn/srcn_conv.h" + +namespace neurun +{ +namespace backend +{ +namespace srcn +{ +namespace kernel +{ + +TransposeConvLayer::TransposeConvLayer() + : _inputData(), _kernelData(), _outputData(), _inputDescr(), _kernelDescr(), _outputDescr(), + _paddingType(0), _paddingLeft(0), _paddingTop(0), _paddingRight(0), _paddingBottom(0), + _strideWidth(0), _strideHeight(0), _inputType(OperandType::FLOAT32), + _layout(nnfw::srcn::col_major) +{ + // DO NOTHING +} + +void TransposeConvLayer::convFloat32() +{ + nnfw::srcn::convMat_t in_mat, out_mat, kernel_mat; + nnfw::srcn::convParams_t in_param; + + assert(_layout == nnfw::srcn::col_major || _layout == nnfw::srcn::row_major); + size_t height_index = _layout == nnfw::srcn::col_major ? 1 : 2; + size_t width_index = _layout == nnfw::srcn::col_major ? 2 : 3; + size_t depth_index = _layout == nnfw::srcn::col_major ? 3 : 1; + size_t kernel_input_depth_index = _layout == nnfw::srcn::col_major ? 3 : 1; + size_t kernel_output_depth_index = 0; + const int batches = MatchingDim(_inputDescr, 0, _outputDescr, 0); + const int input_height = _inputDescr.dimensions[height_index]; + const int input_width = _inputDescr.dimensions[width_index]; + const int input_depth = + MatchingDim(_inputDescr, depth_index, _kernelDescr, kernel_input_depth_index); + in_mat.c = input_depth; + in_mat.w = input_width; + in_mat.h = input_height; + in_mat.n = batches; + in_mat.data = _inputData.f; + + const int output_height = _outputDescr.dimensions[height_index]; + const int output_width = _outputDescr.dimensions[width_index]; + const int output_depth = + MatchingDim(_kernelDescr, kernel_output_depth_index, _outputDescr, depth_index); + out_mat.c = output_depth; + out_mat.w = output_width; + out_mat.h = output_height; + out_mat.n = batches; + out_mat.data = _outputData.f; + + const int ker_height = _kernelDescr.dimensions[height_index]; + const int ker_width = _kernelDescr.dimensions[width_index]; + kernel_mat.c = input_depth; + kernel_mat.w = ker_width; + kernel_mat.h = ker_height; + kernel_mat.n = output_depth; + kernel_mat.data = _kernelData.f; + + in_param.kernel_w = ker_width; + in_param.kernel_h = ker_height; + in_param.stride_w = _strideWidth; + in_param.stride_h = _strideHeight; + in_param.padding = _paddingType; + in_param.pad_w = _paddingLeft; + in_param.pad_h = _paddingTop; + in_param.dilation_w = 1; + in_param.dilation_h = 1; + + memset(_outputData.f, 0, out_mat.n * out_mat.h * out_mat.w * out_mat.c * sizeof(float)); + + nnfw::srcn::srcn_deconvolution2D(in_mat, kernel_mat, out_mat, in_param, 4, _layout); +} + +void TransposeConvLayer::configure(uint8_t *inputData, const TensorDescriptor inputDescr, + uint8_t *kernelData, const TensorDescriptor kernelDescr, + const uint32_t 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, uint8_t *outputData, + const TensorDescriptor outputDescr, ir::Layout layout) +{ + _layout = convertLayout(layout); + _inputData.u8 = inputData; + _inputDescr = inputDescr; + _inputType = inputDescr.type; + _kernelData.u8 = kernelData; + _kernelDescr = kernelDescr; + _paddingType = paddingType; + _paddingLeft = paddingLeft; + _paddingRight = paddingRight; + _paddingTop = paddingTop; + _paddingBottom = paddingBottom; + _strideWidth = strideWidth; + _strideHeight = strideHeight; + _outputData.u8 = outputData; + _outputDescr = outputDescr; +} + +void TransposeConvLayer::run() +{ + if (_inputType == OperandType::FLOAT32) + { + convFloat32(); + } + else if (_inputType == OperandType::QUANT8_ASYMM) + { + throw std::runtime_error("NYI"); + } +} + +} // namespace kernel +} // namespace srcn +} // namespace backend +} // namespace neurun diff --git a/runtime/neurun/backend/srcn/kernel/TransposeConvLayer.h b/runtime/neurun/backend/srcn/kernel/TransposeConvLayer.h new file mode 100644 index 000000000..cd88d4127 --- /dev/null +++ b/runtime/neurun/backend/srcn/kernel/TransposeConvLayer.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __NEURUN_BACKEND_SRCN_KERNEL_TRANSPOSECONV_LAYER_H__ +#define __NEURUN_BACKEND_SRCN_KERNEL_TRANSPOSECONV_LAYER_H__ + +#include <exec/IFunction.h> +#include <ncnn/srcn/conv_type.h> + +#include "OperationUtils.h" + +namespace neurun +{ +namespace backend +{ +namespace srcn +{ +namespace kernel +{ + +class TransposeConvLayer : public ::neurun::exec::IFunction +{ +public: + TransposeConvLayer(); + +public: + void convFloat32(); + void configure(uint8_t *inputData, const TensorDescriptor inputDescr, uint8_t *kernelData, + const TensorDescriptor kernelDescr, const uint32_t paddingType, + const uint32_t paddingLeft, const uint32_t paddingRight, const uint32_t paddingTop, + const uint32_t paddingBottom, const uint32_t strideW, const uint32_t strideH, + uint8_t *outputData, const TensorDescriptor outputDescr, + ir::Layout backend_layout); + + void run(); + void runSync() + { + // this abstract method is used just for profiling and called for + // backend::acl_common::AclFunction + run(); + } + +private: + DataPtr _inputData; + DataPtr _kernelData; + DataPtr _outputData; + + TensorDescriptor _inputDescr; + TensorDescriptor _kernelDescr; + TensorDescriptor _outputDescr; + + uint32_t _paddingType; + uint32_t _paddingLeft; + uint32_t _paddingTop; + uint32_t _paddingRight; + uint32_t _paddingBottom; + + uint32_t _strideWidth; + uint32_t _strideHeight; + + OperandType _inputType; + nnfw::srcn::convType_t _layout; +}; + +} // namespace kernel +} // namespace srcn +} // namespace backend +} // namespace neurun + +#endif // __NEURUN_BACKEND_SRCN_KERNEL_TRANSPOSECONV_LAYER_H__ diff --git a/runtime/neurun/backend/srcn/operand/Tensor.cc b/runtime/neurun/backend/srcn/operand/Tensor.cc new file mode 100644 index 000000000..8a53f97c5 --- /dev/null +++ b/runtime/neurun/backend/srcn/operand/Tensor.cc @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Tensor.h" + +namespace neurun +{ +namespace backend +{ +namespace srcn +{ +namespace operand +{ + +size_t Tensor::calcOffset(const neurun::util::Coordinates &coords) const +{ + size_t rank = num_dimensions(); + size_t offset = 0; + for (size_t i = 0; i < rank; ++i) + { + offset = offset * dimension(i) + coords[i]; + } + offset *= sizeOfDataType(data_type()); + return offset; +} + +void Tensor::access(const std::function<void(ITensor &)> &fn) { fn(*this); } + +} // namespace operand +} // namespace srcn +} // namespace backend +} // namespace neurun diff --git a/runtime/neurun/backend/srcn/operand/Tensor.h b/runtime/neurun/backend/srcn/operand/Tensor.h new file mode 100644 index 000000000..e16234a81 --- /dev/null +++ b/runtime/neurun/backend/srcn/operand/Tensor.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __NEURUN_BACKEND_SRCN_OPERAND_TENSOR_H__ +#define __NEURUN_BACKEND_SRCN_OPERAND_TENSOR_H__ + +#include <backend/operand/ITensor.h> +#include <ir/Layout.h> +#include "ir/OperandInfo.h" + +namespace neurun +{ +namespace backend +{ +namespace srcn +{ +namespace operand +{ + +class Tensor : public ::neurun::backend::operand::ITensor +{ +public: + Tensor() = delete; + +public: + Tensor(const ir::OperandInfo &info, ir::Layout layout) : _info(info), _layout(layout) + { + // DO NOTHING + } + +public: + void setBuffer(uint8_t *buffer) { _buffer = buffer; } + ir::DataType data_type() const { return _info.typeInfo().type(); } + +public: + 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().rank(); } + size_t total_size() const override { return _info.total_size(); } + size_t calcOffset(const neurun::util::Coordinates &coords) const override; + ir::Layout layout() const override { return _layout; } + bool has_padding() const override { return false; } + void access(const std::function<void(ITensor &tensor)> &fn) final; + +private: + ir::OperandInfo _info; + uint8_t *_buffer = nullptr; + ir::Layout _layout; +}; + +} // namespace operand +} // namespace srcn +} // namespace backend +} // namespace neurun + +#endif // __NEURUN_BACKEND_SRCN_OPERAND_TENSOR_H__ |