diff options
Diffstat (limited to 'runtimes/neurun/src/backend/cpu/InitializerGenerator.cc')
-rw-r--r-- | runtimes/neurun/src/backend/cpu/InitializerGenerator.cc | 208 |
1 files changed, 208 insertions, 0 deletions
diff --git a/runtimes/neurun/src/backend/cpu/InitializerGenerator.cc b/runtimes/neurun/src/backend/cpu/InitializerGenerator.cc new file mode 100644 index 000000000..7b08c7131 --- /dev/null +++ b/runtimes/neurun/src/backend/cpu/InitializerGenerator.cc @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "InitializerGenerator.h" + +#include "internal/nnapi/kernel/Reader.h" +#include "internal/nnapi/kernel/View.h" +#include "util/kernel/IndexIterator.h" + +#include "NeuralNetworks.h" + +namespace neurun +{ +namespace backend +{ +namespace cpu +{ + +InitializerGenerator::InitializerGenerator(const neurun::graph::operand::Set &ctx) : _ctx(ctx) +{ + // DO NOTHING +} + +Initializer +InitializerGenerator::generateWeight(const graph::operation::Conv2D::Implicit::Node &node) +{ + const ::neurun::graph::operand::Index ker_index{node.getInputs().at(1)}; + + const auto ker_shape = _ctx.at(ker_index).shape().asKernel(); + auto ker_base = _ctx.at(ker_index).data().base(); + auto ker_size = _ctx.at(ker_index).data().size(); + + return [ker_shape, ker_base, ker_size](::arm_compute::ITensor &tensor) { + const ::internal::nnapi::kernel::Reader<float> from{ker_shape, ker_base, ker_size}; + ::internal::nnapi::kernel::View<float> into{&tensor}; + + ::nnfw::util::kernel::iterate(ker_shape) + << [&](uint32_t nth, uint32_t ch, uint32_t row, uint32_t col) { + const auto value = from.at(nth, ch, row, col); + into.at(nth, row, col, ch) = value; + }; + }; +} + +Initializer InitializerGenerator::generateWeight(const graph::operation::FullyConnected::Node &node) +{ + const ::neurun::graph::operand::Index weight_index{node.getInputs().at(1)}; + const ::neurun::graph::operand::Index input_index{node.getInputs().at(0)}; + + const auto num_output = _ctx.at(weight_index).shape().dim(0); + auto weight_base = _ctx.at(weight_index).data().base(); + auto weight_size = _ctx.at(weight_index).data().size(); + auto weight_type = _ctx.at(weight_index).typeInfo().type(); + + // NOTE We assume that input is a feature map + // TODO Remove this restriction! + const auto ifm_shape = _ctx.at(input_index).shape().asFeature(); + + switch (weight_type) + { + case ::neurun::graph::operand::DataType::TENSOR_FLOAT32: + { + return [num_output, ifm_shape, weight_base, weight_size](::arm_compute::ITensor &tensor) { + const ::nnfw::util::kernel::Shape ker_shape{num_output, ifm_shape.C, ifm_shape.H, + ifm_shape.W}; + const ::internal::nnapi::kernel::Reader<float> from{ker_shape, weight_base, weight_size}; + + ::nnfw::util::kernel::iterate(ker_shape) + << [&](uint32_t nth, uint32_t ch, uint32_t row, uint32_t col) { + const auto value = from.at(nth, ch, row, col); + + uint32_t offset = 0; + + // NNAPI uses NHWC ordering + offset += nth * ifm_shape.H * ifm_shape.W * ifm_shape.C; + offset += row * ifm_shape.W * ifm_shape.C; + offset += col * ifm_shape.C; + offset += ch; + + const ::arm_compute::Coordinates coordinate{offset}; + + auto into = reinterpret_cast<float *>(tensor.ptr_to_element(coordinate)); + + *into = value; + }; + }; + } + case ::neurun::graph::operand::DataType::TENSOR_QUANT8_ASYMM: + { + return [num_output, ifm_shape, weight_base, weight_size](::arm_compute::ITensor &tensor) { + const ::nnfw::util::kernel::Shape ker_shape{num_output, ifm_shape.C, ifm_shape.H, + ifm_shape.W}; + const ::internal::nnapi::kernel::Reader<uint8_t> from{ker_shape, weight_base, weight_size}; + ::nnfw::util::kernel::iterate(ker_shape) + << [&](uint32_t nth, uint32_t ch, uint32_t row, uint32_t col) { + const auto value = from.at(nth, ch, row, col); + uint32_t offset = 0; + + // NNAPI uses NHWC ordering + offset += nth * ifm_shape.H * ifm_shape.W * ifm_shape.C; + offset += row * ifm_shape.W * ifm_shape.C; + offset += col * ifm_shape.C; + offset += ch; + + const ::arm_compute::Coordinates coordinate{offset}; + + auto into = reinterpret_cast<uint8_t *>(tensor.ptr_to_element(coordinate)); + + *into = value; + }; + }; + } + default: + { + throw std::runtime_error("Not supported weight type"); + } + } +} + +Initializer InitializerGenerator::generateBias(const graph::operation::Conv2D::Implicit::Node &node) +{ + // TODO Refactor so we can reuse the common code + + const ::neurun::graph::operand::Index bias_index{node.getInputs().at(2)}; + + auto bias_base = _ctx.at(bias_index).data().base(); + const auto bias_size = _ctx.at(bias_index).shape().asVector(); + + return [bias_base, bias_size](::arm_compute::ITensor &tensor) { + for (int32_t n = 0; n < bias_size; ++n) + { + const ::arm_compute::Coordinates coordinate{n}; + + float *into = reinterpret_cast<float *>(tensor.ptr_to_element(coordinate)); + + const float *from = reinterpret_cast<const float *>(bias_base) + n; + const auto value = *from; + + *into = value; + } + }; +} + +Initializer InitializerGenerator::generateBias(const graph::operation::FullyConnected::Node &node) +{ + const ::neurun::graph::operand::Index bias_index{node.getInputs().at(2)}; + + auto bias_base = _ctx.at(bias_index).data().base(); + auto bias_type = _ctx.at(bias_index).typeInfo().type(); + const auto bias_size = _ctx.at(bias_index).shape().asVector(); + + switch (bias_type) + { + case ::neurun::graph::operand::DataType::TENSOR_FLOAT32: + { + return [bias_base, bias_size](::arm_compute::ITensor &tensor) { + for (int32_t n = 0; n < bias_size; ++n) + { + const ::arm_compute::Coordinates coordinate{n}; + + float *into = reinterpret_cast<float *>(tensor.ptr_to_element(coordinate)); + + const float *from = reinterpret_cast<const float *>(bias_base) + n; + const auto value = *from; + + *into = value; + } + }; + } + case ::neurun::graph::operand::DataType::TENSOR_QUANT8_ASYMM: + { + return [bias_base, bias_size](::arm_compute::ITensor &tensor) { + for (int32_t n = 0; n < bias_size; ++n) + { + const ::arm_compute::Coordinates coordinate{n}; + + uint8_t *into = reinterpret_cast<uint8_t *>(tensor.ptr_to_element(coordinate)); + + const uint8_t *from = reinterpret_cast<const uint8_t *>(bias_base) + n; + const auto value = *from; + + *into = value; + } + }; + } + default: + { + throw std::runtime_error("Not supported bias type"); + } + } +} + +} // namespace cpu +} // namespace backend +} // namespace neurun |