diff options
Diffstat (limited to 'runtimes/neurun/src/compiler/ConstantInitializer.cc')
-rw-r--r-- | runtimes/neurun/src/compiler/ConstantInitializer.cc | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/runtimes/neurun/src/compiler/ConstantInitializer.cc b/runtimes/neurun/src/compiler/ConstantInitializer.cc new file mode 100644 index 000000000..d6d58e273 --- /dev/null +++ b/runtimes/neurun/src/compiler/ConstantInitializer.cc @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ConstantInitializer.h" + +#include "backend/interface/operand/IObject.h" +#include "backend/interface/IConfig.h" +#include "backend/BackendManager.h" +#include "model/operation/FullyConnectedNode.h" +#include "util/feature/nhwc/Reader.h" +#include "util/feature/nhwc/View.h" +#include "util/feature/nchw/View.h" +#include "misc/feature/IndexIterator.h" +#include "util/logging.h" + +namespace neurun +{ +namespace compiler +{ + +ConstantInitializer::ConstantInitializer(const graph::Graph &graph, Plan &plan) + : _graph{graph}, _plan{plan} +{ +} + +void ConstantInitializer::operator()() +{ + // Fill operand data + _plan.operands().iterate([&](int ind, neurun::backend::operand::IObject &obj) { + neurun::model::operand::Index index(ind); + const auto &model_obj = _graph.operands().at(index); + + // For only CONSTANTS + if (model_obj.getUsage() != neurun::model::operand::OperandUsage::CONSTANT) + return; + + // Only float32 is supported + auto type = model_obj.typeInfo().type(); + if (type != ::neurun::model::operand::DataType::TENSOR_FLOAT32) + throw std::runtime_error{"Unsupported data type. Only TENSOR_FLOAT32 is supported."}; + + VERBOSE(FillOperandData) << "Fill data for operand " << ind << std::endl; + + auto layout = + model_obj.lower_info()->def_backends().getOnlyElement()->config()->getOperandLayout(); + const auto shape = model_obj.shape(); + auto base = reinterpret_cast<const float *>(model_obj.data().base()); + auto size = model_obj.data().size(); + + obj.access([&](::neurun::backend::operand::ITensor &tensor) { + switch (shape.rank()) + { + case 1: + { + auto vec_size = shape.asVector(); + for (int32_t n = 0; n < vec_size; ++n) + { + const float *from = reinterpret_cast<const float *>(base) + n; + const auto value = *from; + + float *into = reinterpret_cast<float *>(tensor.buffer()) + n; + + *into = value; + } + break; + } + case 2: + { + // NOTE This is a WORKAROUND which supports FullyConnected weight only + // For FullyConnected, we must know the IFM shape to deduce 2D weight shape from 4D + // IFM. + // This is because of NHWC/NCHW layout, the order of mapping will be different. + // TODO Support general case - explicitly insert Reshape op for IFM as 2D + + // Find corresponding FullyConnected IFM + auto operation_index = _graph.operands().at(index).getUses().list().front(); + auto operation = &_graph.operations().at(operation_index); + auto fc_operation = + dynamic_cast<const neurun::model::operation::FullyConnectedNode *>(operation); + + if (fc_operation == nullptr) + break; + + auto ifm_index = fc_operation->getInputs().at( + neurun::model::operation::FullyConnectedNode::Input::INPUT); + const auto &ifm = _graph.operands().at(ifm_index); + const auto ifm_shape = ifm.shape().asFeature(); + const auto num_output = shape.dim(0); + + const ::nnfw::misc::feature::Shape ker_shape{num_output, ifm_shape.C, ifm_shape.H, + ifm_shape.W}; + const util::feature::nhwc::Reader<float> from{ker_shape, base, size}; + + if (layout == neurun::graph::operand::Layout::NHWC) + { + ::nnfw::misc::feature::iterate(ker_shape) + << [&](uint32_t nth, uint32_t ch, uint32_t row, uint32_t col) { + const auto value = from.at(nth, ch, row, col); + + uint32_t offset = 0; + + // NNAPI uses NHWC ordering + offset += nth * ifm_shape.H * ifm_shape.W * ifm_shape.C; + offset += row * ifm_shape.W * ifm_shape.C; + offset += col * ifm_shape.C; + offset += ch; + + float *into = reinterpret_cast<float *>(tensor.buffer()) + offset; + + *into = value; + }; + } + else + { + assert(layout == neurun::graph::operand::Layout::NCHW); + + ::nnfw::misc::feature::iterate(ker_shape) + << [&](uint32_t nth, uint32_t ch, uint32_t row, uint32_t col) { + const auto value = from.at(nth, ch, row, col); + + uint32_t offset = 0; + + // 'NCHW' ordering + offset += nth * ifm_shape.C * ifm_shape.H * ifm_shape.W; + offset += ch * ifm_shape.H * ifm_shape.W; + offset += row * ifm_shape.W; + offset += col; + + float *into = reinterpret_cast<float *>(tensor.buffer()) + offset; + + *into = value; + }; + } + + break; + } + case 4: + { + auto ker_shape = shape.asFeature(); + auto from = util::feature::nhwc::Reader<float>{ker_shape, base, size}; + + if (layout == neurun::graph::operand::Layout::NHWC) + { + auto into = util::feature::nhwc::View<float>{ + ker_shape, reinterpret_cast<float *>(tensor.buffer()), size}; + + ::nnfw::misc::feature::iterate(ker_shape) + << [&](uint32_t nth, uint32_t ch, uint32_t row, uint32_t col) { + const auto value = from.at(nth, ch, row, col); + into.at(nth, ch, row, col) = value; + }; + } + else + { + assert(layout == neurun::graph::operand::Layout::NCHW); + + auto into = util::feature::nchw::View<float>{&tensor}; + + ::nnfw::misc::feature::iterate(ker_shape) + << [&](uint32_t nth, uint32_t ch, uint32_t row, uint32_t col) { + const auto value = from.at(nth, ch, row, col); + into.at(nth, ch, row, col) = value; + }; + } + break; + } + default: + throw std::runtime_error{"Not yet supported"}; + } + }); + }); +} + +} // namespace codegen +} // namespace neurun |