summaryrefslogtreecommitdiff
path: root/runtime/neurun/backend/srcn
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/neurun/backend/srcn')
-rw-r--r--runtime/neurun/backend/srcn/Backend.h64
-rw-r--r--runtime/neurun/backend/srcn/CMakeLists.txt21
-rw-r--r--runtime/neurun/backend/srcn/Config.cc30
-rw-r--r--runtime/neurun/backend/srcn/Config.h46
-rw-r--r--runtime/neurun/backend/srcn/ConstantInitializer.cc191
-rw-r--r--runtime/neurun/backend/srcn/ConstantInitializer.h60
-rw-r--r--runtime/neurun/backend/srcn/Convert.cc75
-rw-r--r--runtime/neurun/backend/srcn/Convert.h46
-rw-r--r--runtime/neurun/backend/srcn/KernelGenerator.cc275
-rw-r--r--runtime/neurun/backend/srcn/KernelGenerator.h59
-rw-r--r--runtime/neurun/backend/srcn/MemoryManager.cc92
-rw-r--r--runtime/neurun/backend/srcn/MemoryManager.h63
-rw-r--r--runtime/neurun/backend/srcn/PluginClassesAllocator.cc33
-rw-r--r--runtime/neurun/backend/srcn/ShapeFixer.cc47
-rw-r--r--runtime/neurun/backend/srcn/ShapeFixer.h53
-rw-r--r--runtime/neurun/backend/srcn/Swizzle.h84
-rw-r--r--runtime/neurun/backend/srcn/TensorBuilder.cc107
-rw-r--r--runtime/neurun/backend/srcn/TensorBuilder.h89
-rw-r--r--runtime/neurun/backend/srcn/TensorManager.cc95
-rw-r--r--runtime/neurun/backend/srcn/TensorManager.h65
-rw-r--r--runtime/neurun/backend/srcn/TensorRegister.cc118
-rw-r--r--runtime/neurun/backend/srcn/TensorRegister.h55
-rw-r--r--runtime/neurun/backend/srcn/kernel/AddLayer.cc123
-rw-r--r--runtime/neurun/backend/srcn/kernel/AddLayer.h80
-rw-r--r--runtime/neurun/backend/srcn/kernel/ConvolutionLayer.cc233
-rw-r--r--runtime/neurun/backend/srcn/kernel/ConvolutionLayer.h89
-rw-r--r--runtime/neurun/backend/srcn/kernel/DepthwiseConvolutionLayer.cc212
-rw-r--r--runtime/neurun/backend/srcn/kernel/DepthwiseConvolutionLayer.h85
-rw-r--r--runtime/neurun/backend/srcn/kernel/InstanceNormLayer.cc155
-rw-r--r--runtime/neurun/backend/srcn/kernel/InstanceNormLayer.h77
-rw-r--r--runtime/neurun/backend/srcn/kernel/OperationUtils.cc139
-rw-r--r--runtime/neurun/backend/srcn/kernel/OperationUtils.h84
-rw-r--r--runtime/neurun/backend/srcn/kernel/TransposeConvLayer.cc136
-rw-r--r--runtime/neurun/backend/srcn/kernel/TransposeConvLayer.h83
-rw-r--r--runtime/neurun/backend/srcn/operand/Tensor.cc45
-rw-r--r--runtime/neurun/backend/srcn/operand/Tensor.h79
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__