From: 이한종/동작제어Lab(SR)/Engineer/삼성전자 Date: Wed, 7 Nov 2018 07:02:25 +0000 (+0900) Subject: [neurun] Introduce ConstantInitializer (#3426) X-Git-Tag: 0.3~458 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=0bf791aa0dce090c7a2723b4eb95c30fefb8e9ce;p=platform%2Fcore%2Fml%2Fnnfw.git [neurun] Introduce ConstantInitializer (#3426) * [neurun] Introduce ConstantInitializer This commit introduces `ConstantIntializer` class that fills operand objects with the constant values which were specified by `ANeuralNetworksModel_setOperandValue`. Plus, this class replaces the InitializerGenerator. NOTE due to FullyConnected operation's implicit reshaping, it is implemented with workarounds. Signed-off-by: Hanjoung Lee * Add license Signed-off-by: Hanjoung Lee --- diff --git a/runtimes/neurun/src/codegen/ConstantInitializer.cc b/runtimes/neurun/src/codegen/ConstantInitializer.cc new file mode 100644 index 0000000..e653120 --- /dev/null +++ b/runtimes/neurun/src/codegen/ConstantInitializer.cc @@ -0,0 +1,195 @@ +/* + * 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 + +#include "backend/interface/operand/IObject.h" +#include "backend/interface/IConfig.h" +#include "backend/acl_cl/kernel/View.h" +#include "backend/BackendManager.h" +#include "internal/nnapi/kernel/Reader.h" +#include "internal/nnapi/kernel/View.h" +#include "util/kernel/IndexIterator.h" +#include "graph/operation/FullyConnected.h" +#include "logging.h" + +namespace neurun +{ +namespace codegen +{ + +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::graph::operand::Index index(ind); + const auto &model_obj = _graph.operands().at(index); + + // For only CONSTANTS + if (model_obj.getUsage() != neurun::graph::operand::OperandUsage::CONSTANT) + return; + + // Only float32 is supported + auto type = model_obj.typeInfo().type(); + if (type != ::neurun::graph::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 = model_obj.data().base(); + auto size = model_obj.data().size(); + + obj.access([&](::arm_compute::ITensor &tensor) { + switch (shape.rank()) + { + case 1: + { + auto vec_size = shape.asVector(); + for (int32_t n = 0; n < vec_size; ++n) + { + const ::arm_compute::Coordinates coordinate{n}; + + float *into = reinterpret_cast(tensor.ptr_to_element(coordinate)); + + const float *from = reinterpret_cast(base) + n; + const auto value = *from; + + *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(operation); + + if (fc_operation == nullptr) + break; + + auto ifm_index = + fc_operation->getInputs().at(neurun::graph::operation::FullyConnected::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::util::kernel::Shape ker_shape{num_output, ifm_shape.C, ifm_shape.H, + ifm_shape.W}; + const ::internal::nnapi::kernel::Reader from{ker_shape, base, size}; + + if (layout == neurun::graph::operand::Layout::NHWC) + { + ::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(tensor.ptr_to_element(coordinate)); + + *into = value; + }; + } + else + { + assert(layout == neurun::graph::operand::Layout::NCHW); + + ::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; + + // '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; + + const ::arm_compute::Coordinates coordinate{offset}; + + auto into = reinterpret_cast(tensor.ptr_to_element(coordinate)); + + *into = value; + }; + } + + break; + } + case 4: + { + auto ker_shape = shape.asKernel(); + auto from = ::internal::nnapi::kernel::Reader{ker_shape, base, size}; + + if (layout == neurun::graph::operand::Layout::NHWC) + { + auto into = ::internal::nnapi::kernel::View{&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; + }; + } + else + { + assert(layout == neurun::graph::operand::Layout::NCHW); + + auto into = ::internal::arm_compute::kernel::View{&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, ch, row, col) = value; + }; + } + break; + } + default: + throw std::runtime_error{"Not yet supported"}; + } + }); + }); +} + +} // namespace codegen +} // namespace neurun diff --git a/runtimes/neurun/src/codegen/ConstantInitializer.h b/runtimes/neurun/src/codegen/ConstantInitializer.h new file mode 100644 index 0000000..6e4de87 --- /dev/null +++ b/runtimes/neurun/src/codegen/ConstantInitializer.h @@ -0,0 +1,43 @@ +/* + * 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_CODEGEN_CONSTANT_INITIALIZER_H__ +#define __NEURUN_CODEGEN_CONSTANT_INITIALIZER_H__ + +#include "graph/Graph.h" +#include "codegen/Plan.h" + +namespace neurun +{ +namespace codegen +{ + +class ConstantInitializer +{ +public: + ConstantInitializer(const graph::Graph &graph, Plan &plan); + + void operator()(); + +private: + const graph::Graph &_graph; + Plan &_plan; +}; + +} // namespace codegen +} // namespace neurun + +#endif // __NEURUN_CODEGEN_CONSTANT_INITIALIZER_H__ diff --git a/runtimes/neurun/src/codegen/PlanBuilder.cc b/runtimes/neurun/src/codegen/PlanBuilder.cc index 575cf78..76187c7 100644 --- a/runtimes/neurun/src/codegen/PlanBuilder.cc +++ b/runtimes/neurun/src/codegen/PlanBuilder.cc @@ -70,15 +70,6 @@ void PlanBuilder::finalize(const backend::TensorBuilderSet &tensor_builders) { tensor_builder->allocate(); } - - // Fill weight/bias - for (auto it = _initializer_ctx.begin(); it != _initializer_ctx.end(); ++it) - { - const ::neurun::graph::operand::Index operand_index{it->first}; - auto object = _plan.operands().at(operand_index); - - object->access(it->second); - } } } // namepsace codegen diff --git a/runtimes/neurun/src/frontend/wrapper/compilation.cc b/runtimes/neurun/src/frontend/wrapper/compilation.cc index 5f448d0..13f4fda 100644 --- a/runtimes/neurun/src/frontend/wrapper/compilation.cc +++ b/runtimes/neurun/src/frontend/wrapper/compilation.cc @@ -23,6 +23,7 @@ #include "codegen/Planner.h" #include "codegen/PlanBuilder.h" #include "middleend/SubTensorAnalyzer.h" +#include "codegen/ConstantInitializer.h" #include "linear/Linear.h" #include "util/EnvVar.h" @@ -72,5 +73,7 @@ int ANeuralNetworksCompilation::finish() // TODO Add optimization passes plan_builder.finalize(tensor_builders); + neurun::codegen::ConstantInitializer{graph, plan}(); + return ANEURALNETWORKS_NO_ERROR; }