diff options
Diffstat (limited to 'runtime/neurun/core/include/backend/IConstantInitializer.h')
-rw-r--r-- | runtime/neurun/core/include/backend/IConstantInitializer.h | 288 |
1 files changed, 288 insertions, 0 deletions
diff --git a/runtime/neurun/core/include/backend/IConstantInitializer.h b/runtime/neurun/core/include/backend/IConstantInitializer.h new file mode 100644 index 000000000..3cc770b29 --- /dev/null +++ b/runtime/neurun/core/include/backend/IConstantInitializer.h @@ -0,0 +1,288 @@ +/* + * 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_ICONSTANT_INITIALIZER_H__ +#define __NEURUN_BACKEND_ICONSTANT_INITIALIZER_H__ + +#include <unordered_map> +#include <functional> + +#include "ITensorBuilder.h" +#include "ir/Layout.h" +#include "ir/Operand.h" +#include "ir/Operands.h" +#include "ir/OperationVisitor.h" +#include "ir/OpSequence.h" +#include "util/logging.h" +#include "util/Utils.h" + +namespace +{ +template <typename T> +static void Init(const neurun::ir::Operand &model_obj, neurun::backend::operand::ITensor &obj, + const bool copy, + const neurun::ir::Layout frontend_layout = neurun::ir::Layout::UNKNOWN) +{ + const auto shape = model_obj.shape(); + auto base = reinterpret_cast<const T *>(model_obj.data().base()); + + obj.access([&](::neurun::backend::operand::ITensor &tensor) { + switch (shape.rank()) + { + case 0: + { + assert(model_obj.data().size() == sizeof(T)); + const auto value = *reinterpret_cast<const T *>(base); + T *into = reinterpret_cast<T *>(tensor.buffer()); + *into = value; + break; + } + case 1: + { + auto vec_size = shape.dim(0); + for (int32_t n = 0; n < vec_size; ++n) + { + const T *from = reinterpret_cast<const T *>(base) + n; + const auto value = *from; + + T *into = reinterpret_cast<T *>(tensor.buffer()) + n; + + *into = value; + } + break; + } + case 2: + { + const int32_t copy_len = shape.dim(1); + + for (auto i = 0; i < shape.dim(0); ++i) + { + neurun::util::Coordinates coords{i, 0}; + memcpy(tensor.buffer() + tensor.calcOffset(coords), base + i * copy_len, + copy_len * sizeof(T)); + } + break; + } + case 3: + { + const int32_t width = shape.dim(1); + const int32_t copy_len = shape.dim(2); + + for (auto i = 0; i < shape.dim(0); ++i) + { + for (auto j = 0; j < shape.dim(1); ++j) + { + neurun::util::Coordinates coords{i, j, 0}; + memcpy(tensor.buffer() + tensor.calcOffset(coords), + base + i * width * copy_len + j * copy_len, copy_len * sizeof(T)); + } + } + break; + } + case 4: + { + const int32_t height = shape.dim(1); + const int32_t width = shape.dim(2); + const int32_t copy_len = shape.dim(3); + for (auto i = 0; i < shape.dim(0); ++i) + { + for (auto j = 0; j < shape.dim(1); ++j) + { + for (auto k = 0; k < shape.dim(2); ++k) + { + if (copy) + { + neurun::util::Coordinates coords{i, j, k, 0}; + memcpy(tensor.buffer() + tensor.calcOffset(coords), + base + i * height * width * copy_len + j * width * copy_len + k * copy_len, + copy_len * sizeof(T)); + } + else + { + for (auto l = 0; l < shape.dim(3); ++l) + { + const auto coords = neurun::util::convertCoordinates( + {i, j, k, l}, frontend_layout, tensor.layout()); + T *into = reinterpret_cast<T *>(tensor.buffer() + tensor.calcOffset(coords)); + T value = *(base + i * height * width * copy_len + j * width * copy_len + + k * copy_len + l); + *into = value; + } + } + } + } + } + break; + } + default: + throw std::runtime_error{"Not yet supported"}; + } + }); +} + +template <typename T> +void copyInit(const neurun::ir::Operand &model_obj, neurun::backend::operand::ITensor &obj) +{ + Init<T>(model_obj, obj, true); +} + +template <typename T> +void permuteInit(const neurun::ir::Operand &model_obj, neurun::backend::operand::ITensor &obj, + const neurun::ir::Layout frontend_layout) +{ + const bool copy = frontend_layout == obj.layout(); + Init<T>(model_obj, obj, copy, frontend_layout); +} + +} // namespace + +namespace neurun +{ +namespace backend +{ + +class IConstantInitializer : ir::OperationVisitor +{ +public: + virtual ~IConstantInitializer() = default; + +public: + void run() + { + assert(tensor_builder().get()); + for (const auto &it : _init_map) + { + const auto &ind = it.first; + const auto &fn = it.second; + + const auto &model_obj = operands().at(ind); + auto tensor_obj = tensor_builder()->tensorAt(ind); + fn(model_obj, *tensor_obj); + VERBOSE(FillOperandData) << "Fill data for operand " << ind.value() << std::endl; + } + _init_map.clear(); + } + +public: + using Initializer = std::function<void(const ir::Operand &, backend::operand::ITensor &)>; + + void generate(const ir::OpSequence &subg, const ir::Operands &operands) + { + _current_subg_layout = subg.getLayout(); + subg.accept(*this); + for (const auto &e : subg.operations()) + { + for (const auto &ind : e.node->getInputs()) + { + const auto &obj = operands.at(ind); + if (obj.isConstant() && !exist(ind)) + { + registerPermuteInitializer(ind, obj); + } + } + } + } + +protected: + using OperationVisitor::visit; + +protected: + virtual const ir::Operands &operands() const = 0; + virtual std::shared_ptr<ITensorBuilder> tensor_builder() const = 0; + +protected: + void registerCopyInitializer(const ir::OperandIndex &index, const ir::Operand &obj) + { + // For only CONSTANTS + // TODO Add to check if tensor has been allocated + if (!obj.isConstant()) + return; + + const auto type = obj.typeInfo().type(); + using ir::DataType; + + switch (type) + { + case DataType::FLOAT32: + _init_map[index] = copyInit<float>; + break; + case DataType::INT32: + _init_map[index] = copyInit<int32_t>; + break; + case DataType::UINT32: + _init_map[index] = copyInit<uint32_t>; + break; + case DataType::BOOL8: + case DataType::QUANT8_ASYMM: + _init_map[index] = copyInit<uint8_t>; + break; + case DataType::QUANT8_SYMM: + _init_map[index] = copyInit<int8_t>; + break; + default: + throw std::runtime_error("Not supported, yet"); + break; + } + } + +protected: + void registerPermuteInitializer(const ir::OperandIndex &index, const ir::Operand &obj) + { + // For only CONSTANTS + // TODO Add to check if tensor has been allocated + if (!obj.isConstant()) + return; + + const auto type = obj.typeInfo().type(); + using ir::DataType; + using namespace std::placeholders; + + switch (type) + { + case DataType::FLOAT32: + _init_map[index] = std::bind(permuteInit<float>, _1, _2, _current_subg_layout); + break; + case DataType::INT32: + _init_map[index] = std::bind(permuteInit<int32_t>, _1, _2, _current_subg_layout); + break; + case DataType::UINT32: + _init_map[index] = std::bind(permuteInit<uint32_t>, _1, _2, _current_subg_layout); + break; + case DataType::BOOL8: + case DataType::QUANT8_ASYMM: + _init_map[index] = std::bind(permuteInit<uint8_t>, _1, _2, _current_subg_layout); + break; + case DataType::QUANT8_SYMM: + _init_map[index] = std::bind(permuteInit<int8_t>, _1, _2, _current_subg_layout); + break; + default: + throw std::runtime_error("Not supported, yet"); + break; + } + } + +private: + bool exist(const ir::OperandIndex &ind) { return _init_map.find(ind) != _init_map.end(); } + +protected: + std::unordered_map<ir::OperandIndex, Initializer> _init_map; + ir::Layout _current_subg_layout; +}; + +} // namespace backend +} // namespace neurun + +#endif // __NEURUN_BACKEND_ICONSTANT_INITIALIZER_H__ |